184c26551a
Signed-off-by: Roman Khimov <roman@nspcc.ru>
85 lines
1.9 KiB
Go
85 lines
1.9 KiB
Go
package accessbox
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/creds/hcs"
|
|
"golang.org/x/crypto/chacha20poly1305"
|
|
"golang.org/x/crypto/curve25519"
|
|
)
|
|
|
|
type encoder struct {
|
|
io.Writer
|
|
|
|
owner hcs.PrivateKey
|
|
keys []hcs.PublicKey
|
|
}
|
|
|
|
// NewEncoder creates encoder.
|
|
func NewEncoder(w io.Writer, owner hcs.PrivateKey, keys ...hcs.PublicKey) Encoder {
|
|
return &encoder{
|
|
Writer: w,
|
|
owner: owner,
|
|
keys: keys,
|
|
}
|
|
}
|
|
|
|
func encrypt(owner hcs.PrivateKey, sender hcs.PublicKey, data []byte) ([]byte, error) {
|
|
key, err := curve25519.X25519(owner.Bytes(), sender.Bytes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
enc, err := chacha20poly1305.NewX(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nonce := make([]byte, enc.NonceSize(), enc.NonceSize()+len(data)+enc.Overhead())
|
|
if _, err := rand.Read(nonce); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return enc.Seal(nonce, nonce, data, nil), nil
|
|
}
|
|
|
|
// Encode and encrypt box through owner private key and public keys.
|
|
func (e *encoder) Encode(box Box) error {
|
|
data, err := box.Marshal()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// write owner public key
|
|
if _, err = e.owner.PublicKey().WriteTo(e); err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, sender := range e.keys {
|
|
encrypted, err := encrypt(e.owner, sender, data)
|
|
if err != nil {
|
|
return fmt.Errorf("%w, sender = %d", err, i)
|
|
}
|
|
|
|
ln := len(encrypted)
|
|
temp := make([]byte, ln+binary.MaxVarintLen64)
|
|
size := binary.PutVarint(temp, int64(ln))
|
|
copy(temp[size:], encrypted)
|
|
if _, err := e.Write(temp[:size+ln]); err != nil {
|
|
return fmt.Errorf("%w, sender = %d", err, i)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Encode and encrypt box through owner private key and public keys.
|
|
func Encode(box Box, owner hcs.PrivateKey, keys ...hcs.PublicKey) ([]byte, error) {
|
|
buf := new(bytes.Buffer)
|
|
err := NewEncoder(buf, owner, keys...).Encode(box)
|
|
return buf.Bytes(), err
|
|
}
|