[#529] Use salt when deriving the encryption key
Salt is used when generating encryption keys for data (tokens) in the access box. Now frostfs-s3-authmate always derivation an encryption key with salt. Signed-off-by: Roman Loginov <r.loginov@yadro.com>
This commit is contained in:
parent
f215d200e8
commit
d1812cefc0
7 changed files with 107 additions and 107 deletions
|
@ -19,6 +19,11 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
secretLength = 32
|
||||||
|
saltLength = 16
|
||||||
|
)
|
||||||
|
|
||||||
// Box represents friendly AccessBox.
|
// Box represents friendly AccessBox.
|
||||||
type Box struct {
|
type Box struct {
|
||||||
Gate *GateData
|
Gate *GateData
|
||||||
|
@ -109,7 +114,7 @@ func PackTokens(gatesData []*GateData, secret []byte, isCustomSecret bool) (*Acc
|
||||||
box.IsCustom = isCustomSecret
|
box.IsCustom = isCustomSecret
|
||||||
|
|
||||||
if secret == nil {
|
if secret == nil {
|
||||||
secret, err = generateSecret()
|
secret, err = generateRandomBytes(secretLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to generate accessKey as hex: %w", err)
|
return nil, nil, fmt.Errorf("failed to generate accessKey as hex: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -212,7 +217,12 @@ func encodeGate(ephemeralKey *keys.PrivateKey, seedKey *keys.PublicKey, tokens *
|
||||||
return nil, fmt.Errorf("encode tokens: %w", err)
|
return nil, fmt.Errorf("encode tokens: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
encrypted, err := encrypt(ephemeralKey, seedKey, data)
|
salt, err := generateRandomBytes(saltLength)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to generate salt for encryption key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted, err := encrypt(ephemeralKey, seedKey, data, salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ecrypt tokens: %w", err)
|
return nil, fmt.Errorf("ecrypt tokens: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -220,11 +230,12 @@ func encodeGate(ephemeralKey *keys.PrivateKey, seedKey *keys.PublicKey, tokens *
|
||||||
gate := new(AccessBox_Gate)
|
gate := new(AccessBox_Gate)
|
||||||
gate.GatePublicKey = seedKey.Bytes()
|
gate.GatePublicKey = seedKey.Bytes()
|
||||||
gate.Tokens = encrypted
|
gate.Tokens = encrypted
|
||||||
|
gate.EncryptionKeySalt = salt
|
||||||
return gate, nil
|
return gate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AccessBox) decodeGate(gate *AccessBox_Gate, owner *keys.PrivateKey, seedKey *keys.PublicKey) (*GateData, error) {
|
func (x *AccessBox) decodeGate(gate *AccessBox_Gate, owner *keys.PrivateKey, seedKey *keys.PublicKey) (*GateData, error) {
|
||||||
data, err := decrypt(owner, seedKey, gate.Tokens)
|
data, err := decrypt(owner, seedKey, gate.Tokens, gate.EncryptionKeySalt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("decrypt tokens: %w", err)
|
return nil, fmt.Errorf("decrypt tokens: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -273,16 +284,16 @@ func generateShared256(prv *keys.PrivateKey, pub *keys.PublicKey) (sk []byte, er
|
||||||
return sk, nil
|
return sk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deriveKey(secret []byte) ([]byte, error) {
|
func deriveKey(secret, salt []byte) ([]byte, error) {
|
||||||
hash := sha256.New
|
hash := sha256.New
|
||||||
kdf := hkdf.New(hash, secret, nil, nil)
|
kdf := hkdf.New(hash, secret, salt, nil)
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
_, err := io.ReadFull(kdf, key)
|
_, err := io.ReadFull(kdf, key)
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func encrypt(owner *keys.PrivateKey, seedKey *keys.PublicKey, data []byte) ([]byte, error) {
|
func encrypt(owner *keys.PrivateKey, seedKey *keys.PublicKey, data, salt []byte) ([]byte, error) {
|
||||||
enc, err := getCipher(owner, seedKey)
|
enc, err := getCipher(owner, seedKey, salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get chiper: %w", err)
|
return nil, fmt.Errorf("get chiper: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -295,8 +306,8 @@ func encrypt(owner *keys.PrivateKey, seedKey *keys.PublicKey, data []byte) ([]by
|
||||||
return enc.Seal(nonce, nonce, data, nil), nil
|
return enc.Seal(nonce, nonce, data, nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decrypt(owner *keys.PrivateKey, seedKey *keys.PublicKey, data []byte) ([]byte, error) {
|
func decrypt(owner *keys.PrivateKey, seedKey *keys.PublicKey, data, salt []byte) ([]byte, error) {
|
||||||
dec, err := getCipher(owner, seedKey)
|
dec, err := getCipher(owner, seedKey, salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get chiper: %w", err)
|
return nil, fmt.Errorf("get chiper: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -309,13 +320,13 @@ func decrypt(owner *keys.PrivateKey, seedKey *keys.PublicKey, data []byte) ([]by
|
||||||
return dec.Open(nil, nonce, cypher, nil)
|
return dec.Open(nil, nonce, cypher, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCipher(owner *keys.PrivateKey, seedKey *keys.PublicKey) (cipher.AEAD, error) {
|
func getCipher(owner *keys.PrivateKey, seedKey *keys.PublicKey, salt []byte) (cipher.AEAD, error) {
|
||||||
secret, err := generateShared256(owner, seedKey)
|
secret, err := generateShared256(owner, seedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("generate shared key: %w", err)
|
return nil, fmt.Errorf("generate shared key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := deriveKey(secret)
|
key, err := deriveKey(secret, salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("derive key: %w", err)
|
return nil, fmt.Errorf("derive key: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -323,8 +334,8 @@ func getCipher(owner *keys.PrivateKey, seedKey *keys.PublicKey) (cipher.AEAD, er
|
||||||
return chacha20poly1305.NewX(key)
|
return chacha20poly1305.NewX(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSecret() ([]byte, error) {
|
func generateRandomBytes(length int) ([]byte, error) {
|
||||||
b := make([]byte, 32)
|
b := make([]byte, length)
|
||||||
_, err := io.ReadFull(rand.Reader, b)
|
_, err := io.ReadFull(rand.Reader, b)
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,7 @@ type AccessBox_Gate struct {
|
||||||
|
|
||||||
Tokens []byte `protobuf:"bytes,1,opt,name=tokens,proto3" json:"tokens,omitempty"`
|
Tokens []byte `protobuf:"bytes,1,opt,name=tokens,proto3" json:"tokens,omitempty"`
|
||||||
GatePublicKey []byte `protobuf:"bytes,2,opt,name=gatePublicKey,proto3" json:"gatePublicKey,omitempty"`
|
GatePublicKey []byte `protobuf:"bytes,2,opt,name=gatePublicKey,proto3" json:"gatePublicKey,omitempty"`
|
||||||
|
EncryptionKeySalt []byte `protobuf:"bytes,3,opt,name=encryptionKeySalt,proto3" json:"encryptionKeySalt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AccessBox_Gate) Reset() {
|
func (x *AccessBox_Gate) Reset() {
|
||||||
|
@ -209,6 +210,13 @@ func (x *AccessBox_Gate) GetGatePublicKey() []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *AccessBox_Gate) GetEncryptionKeySalt() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.EncryptionKeySalt
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type AccessBox_ContainerPolicy struct {
|
type AccessBox_ContainerPolicy struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
@ -269,7 +277,7 @@ var File_creds_accessbox_accessbox_proto protoreflect.FileDescriptor
|
||||||
var file_creds_accessbox_accessbox_proto_rawDesc = []byte{
|
var file_creds_accessbox_accessbox_proto_rawDesc = []byte{
|
||||||
0x0a, 0x1f, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f,
|
0x0a, 0x1f, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f,
|
||||||
0x78, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x78, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x6f, 0x12, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x22, 0xe3, 0x02, 0x0a,
|
0x6f, 0x12, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x22, 0x91, 0x03, 0x0a,
|
||||||
0x09, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65,
|
0x09, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x42, 0x6f, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65,
|
||||||
0x65, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x65, 0x65,
|
0x65, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x65, 0x65,
|
||||||
0x64, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20,
|
0x64, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x67, 0x61, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20,
|
||||||
|
@ -282,29 +290,31 @@ var file_creds_accessbox_accessbox_proto_rawDesc = []byte{
|
||||||
0x6c, 0x69, 0x63, 0x79, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50,
|
0x6c, 0x69, 0x63, 0x79, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50,
|
||||||
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x43, 0x75, 0x73, 0x74, 0x6f,
|
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x43, 0x75, 0x73, 0x74, 0x6f,
|
||||||
0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x43, 0x75, 0x73, 0x74, 0x6f,
|
0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x43, 0x75, 0x73, 0x74, 0x6f,
|
||||||
0x6d, 0x1a, 0x44, 0x0a, 0x04, 0x47, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x6b,
|
0x6d, 0x1a, 0x72, 0x0a, 0x04, 0x47, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x6b,
|
||||||
0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||||
0x73, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
0x73, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||||
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75,
|
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x50, 0x75,
|
||||||
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x1a, 0x59, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61,
|
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79,
|
||||||
0x69, 0x6e, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x6c, 0x6f,
|
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x53, 0x61, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74,
|
0x28, 0x0c, 0x52, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
0x79, 0x53, 0x61, 0x6c, 0x74, 0x1a, 0x59, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
|
||||||
0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f,
|
0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2e, 0x0a, 0x12, 0x6c, 0x6f, 0x63, 0x61,
|
||||||
0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69,
|
0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x18, 0x01,
|
||||||
0x63, 0x79, 0x22, 0x6e, 0x0a, 0x06, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f,
|
||||||
0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69,
|
||||||
0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x65,
|
0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
||||||
0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
0x22, 0x6e, 0x0a, 0x06, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65,
|
||||||
0x0b, 0x62, 0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x24, 0x0a, 0x0d,
|
0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73,
|
||||||
0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x03, 0x20,
|
0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x65, 0x61, 0x72,
|
||||||
0x03, 0x28, 0x0c, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65,
|
0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62,
|
||||||
0x6e, 0x73, 0x42, 0x46, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x2e, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66,
|
0x65, 0x61, 0x72, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x65,
|
||||||
0x73, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x54, 0x72, 0x75, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64,
|
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||||
0x4c, 0x61, 0x62, 0x2f, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2d, 0x73, 0x33, 0x2d, 0x67,
|
0x0c, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73,
|
||||||
0x77, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x62, 0x6f, 0x78,
|
0x42, 0x46, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x2e, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2e,
|
||||||
0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x54, 0x72, 0x75, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x4c, 0x61,
|
||||||
0x6f, 0x33,
|
0x62, 0x2f, 0x66, 0x72, 0x6f, 0x73, 0x74, 0x66, 0x73, 0x2d, 0x73, 0x33, 0x2d, 0x67, 0x77, 0x2f,
|
||||||
|
0x63, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x62, 0x6f, 0x78, 0x3b, 0x61,
|
||||||
|
0x63, 0x63, 0x65, 0x73, 0x73, 0x62, 0x6f, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -10,6 +10,7 @@ message AccessBox {
|
||||||
message Gate {
|
message Gate {
|
||||||
bytes tokens = 1 [json_name = "tokens"];
|
bytes tokens = 1 [json_name = "tokens"];
|
||||||
bytes gatePublicKey = 2 [json_name = "gatePublicKey"];
|
bytes gatePublicKey = 2 [json_name = "gatePublicKey"];
|
||||||
|
bytes encryptionKeySalt = 3 [json_name = "encryptionKeySalt"];
|
||||||
}
|
}
|
||||||
|
|
||||||
message ContainerPolicy {
|
message ContainerPolicy {
|
||||||
|
|
|
@ -23,6 +23,10 @@ func TestTokensEncryptDecrypt(t *testing.T) {
|
||||||
tkn bearer.Token
|
tkn bearer.Token
|
||||||
tkn2 bearer.Token
|
tkn2 bearer.Token
|
||||||
)
|
)
|
||||||
|
|
||||||
|
salt, err := generateRandomBytes(saltLength)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
sec, err := keys.NewPrivateKey()
|
sec, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -32,16 +36,47 @@ func TestTokensEncryptDecrypt(t *testing.T) {
|
||||||
tkn.SetEACLTable(*eacl.NewTable())
|
tkn.SetEACLTable(*eacl.NewTable())
|
||||||
require.NoError(t, tkn.Sign(sec.PrivateKey))
|
require.NoError(t, tkn.Sign(sec.PrivateKey))
|
||||||
|
|
||||||
data, err := encrypt(cred, cred.PublicKey(), tkn.Marshal())
|
t.Run("positive case without salt", func(t *testing.T) {
|
||||||
|
data, err := encrypt(cred, cred.PublicKey(), tkn.Marshal(), nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
rawTkn2, err := decrypt(cred, cred.PublicKey(), data)
|
rawTkn2, err := decrypt(cred, cred.PublicKey(), data, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = tkn2.Unmarshal(rawTkn2)
|
err = tkn2.Unmarshal(rawTkn2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assertBearerToken(t, tkn, tkn2)
|
assertBearerToken(t, tkn, tkn2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("positive case with salt", func(t *testing.T) {
|
||||||
|
data, err := encrypt(cred, cred.PublicKey(), tkn.Marshal(), salt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rawTkn2, err := decrypt(cred, cred.PublicKey(), data, salt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = tkn2.Unmarshal(rawTkn2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assertBearerToken(t, tkn, tkn2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("wrang salt", func(t *testing.T) {
|
||||||
|
data, err := encrypt(cred, cred.PublicKey(), tkn.Marshal(), salt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = decrypt(cred, cred.PublicKey(), data, nil)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("wrang private key", func(t *testing.T) {
|
||||||
|
data, err := encrypt(cred, cred.PublicKey(), tkn.Marshal(), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = decrypt(sec, cred.PublicKey(), data, nil)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBearerTokenInAccessBox(t *testing.T) {
|
func TestBearerTokenInAccessBox(t *testing.T) {
|
||||||
|
|
|
@ -199,6 +199,7 @@ It contains:
|
||||||
in [spec](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/commit/4c68d92468503b10282c8a92af83a56f170c8a3a/acl/types.proto#L189)
|
in [spec](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/commit/4c68d92468503b10282c8a92af83a56f170c8a3a/acl/types.proto#L189)
|
||||||
* Marshaled session token - more detail
|
* Marshaled session token - more detail
|
||||||
in [spec](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/commit/4c68d92468503b10282c8a92af83a56f170c8a3a/session/types.proto#L89)
|
in [spec](https://git.frostfs.info/TrueCloudLab/frostfs-api/src/commit/4c68d92468503b10282c8a92af83a56f170c8a3a/session/types.proto#L89)
|
||||||
|
* Encryption Key Salt - randomly generated 16 bytes that are used to derivation the encryption key
|
||||||
* Container placement policies:
|
* Container placement policies:
|
||||||
* `LocationsConstraint` - name of location constraint that can be used to create bucket/container using s3
|
* `LocationsConstraint` - name of location constraint that can be used to create bucket/container using s3
|
||||||
credentials related to this `AccessBox`
|
credentials related to this `AccessBox`
|
||||||
|
@ -258,19 +259,20 @@ secp256r1 or prime256v1) is used (unless otherwise stated).
|
||||||
* Create ephemeral key (`SeedKey`), it's need to generate shared secret
|
* Create ephemeral key (`SeedKey`), it's need to generate shared secret
|
||||||
* Generate random 32-byte (that after hex-encoded be `SecretAccessKey`) or use existing secret access key
|
* Generate random 32-byte (that after hex-encoded be `SecretAccessKey`) or use existing secret access key
|
||||||
(if `AccessBox` is being updated rather than creating brand new) or use arbitrary user-provided string
|
(if `AccessBox` is being updated rather than creating brand new) or use arbitrary user-provided string
|
||||||
|
* Generate random 16-byte salt
|
||||||
* Generate shared secret as [ECDH](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman)
|
* Generate shared secret as [ECDH](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman)
|
||||||
* Derive 32-byte key using shared secret from previous step with key derivation function based on
|
* Derive 32-byte key using shared secret from previous step and the salt with key derivation function based on
|
||||||
HMAC with SHA256 [HKDF](https://en.wikipedia.org/wiki/HKDF)
|
HMAC with SHA256 [HKDF](https://en.wikipedia.org/wiki/HKDF)
|
||||||
* Encrypt marshaled [Tokens](../creds/accessbox) using derived key
|
* Encrypt marshaled [Tokens](../creds/accessbox) using derived key
|
||||||
with [ChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305) algorithm without additional data.
|
with [ChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305) algorithm without additional data.
|
||||||
|
|
||||||
**Decryption:**
|
**Decryption:**
|
||||||
|
|
||||||
* Get public part of `SeedKey` from `AccessBox`
|
* Get public part of `SeedKey` and the salt from `AccessBox`
|
||||||
* Generate shared secret as follows:
|
* Generate shared secret as follows:
|
||||||
* Make scalar curve multiplication of public part of `SeedKey` and private part of s3-gw key
|
* Make scalar curve multiplication of public part of `SeedKey` and private part of s3-gw key
|
||||||
* Use `X` part of multiplication (with zero padding at the beginning to fit 32-byte)
|
* Use `X` part of multiplication (with zero padding at the beginning to fit 32-byte)
|
||||||
* Derive 32-byte key using shared secret from previous step with key derivation function based on
|
* Derive 32-byte key using shared secret from previous step and the salt with key derivation function based on
|
||||||
HMAC with SHA256 [HKDF](https://en.wikipedia.org/wiki/HKDF)
|
HMAC with SHA256 [HKDF](https://en.wikipedia.org/wiki/HKDF)
|
||||||
* Decrypt encrypted marshaled [Tokens](../creds/accessbox) using derived key
|
* Decrypt encrypted marshaled [Tokens](../creds/accessbox) using derived key
|
||||||
with [ChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305) algorithm without additional data.
|
with [ChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305) algorithm without additional data.
|
||||||
|
|
|
@ -10,6 +10,7 @@ package AccessBox {
|
||||||
map Gate {
|
map Gate {
|
||||||
GateKey => Encoded public gate key
|
GateKey => Encoded public gate key
|
||||||
Encrypted tokens *--> Tokens
|
Encrypted tokens *--> Tokens
|
||||||
|
EncryptionKeySalt => Salt for derivation the encryption key
|
||||||
}
|
}
|
||||||
|
|
||||||
map ContainerPolicy {
|
map ContainerPolicy {
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
Loading…
Reference in a new issue