From 06a3510ae44b7c462d39aa325dfaf8a9ff0520b7 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Wed, 8 Jul 2020 14:02:41 +0300 Subject: [PATCH] satellite/orders: add EncryptionKey encryption Add encryption using nacl/secretbox. Change-Id: I0add31a9fd2359be1bf9d3e43b6c4b9ff3b6fb03 --- satellite/orders/encryptionkey.go | 29 ++++++++++ satellite/orders/encryptionkey_test.go | 78 ++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/satellite/orders/encryptionkey.go b/satellite/orders/encryptionkey.go index 564b77743..7bc33df87 100644 --- a/satellite/orders/encryptionkey.go +++ b/satellite/orders/encryptionkey.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/zeebo/errs" + "golang.org/x/crypto/nacl/secretbox" "storj.io/common/storj" ) @@ -40,6 +41,34 @@ type EncryptionKey struct { Key storj.Key } +// When this fails to compile, then `serialToNonce` should be adjusted accordingly. +var _ = ([16]byte)(storj.SerialNumber{}) + +func serialToNonce(serial storj.SerialNumber) (x [24]byte) { + copy(x[:], serial[:]) + return x +} + +// Encrypt encrypts data and nonce using the key. +func (key *EncryptionKey) Encrypt(plaintext []byte, nonce storj.SerialNumber) []byte { + out := make([]byte, 0, len(plaintext)+secretbox.Overhead) + n := serialToNonce(nonce) + k := ([32]byte)(key.Key) + return secretbox.Seal(out, plaintext, &n, &k) +} + +// Decrypt decrypts data and nonce using the key. +func (key *EncryptionKey) Decrypt(ciphertext []byte, nonce storj.SerialNumber) ([]byte, error) { + out := make([]byte, 0, len(ciphertext)-secretbox.Overhead) + n := serialToNonce(nonce) + k := ([32]byte)(key.Key) + dec, ok := secretbox.Open(out, ciphertext, &n, &k) + if !ok { + return nil, ErrEncryptionKey.New("unable to decrypt") + } + return dec, nil +} + // IsZero returns whether they key contains some data. func (key *EncryptionKey) IsZero() bool { return key.ID.IsZero() || key.Key.IsZero() diff --git a/satellite/orders/encryptionkey_test.go b/satellite/orders/encryptionkey_test.go index f93738a30..12e931176 100644 --- a/satellite/orders/encryptionkey_test.go +++ b/satellite/orders/encryptionkey_test.go @@ -4,12 +4,14 @@ package orders_test import ( + "encoding/hex" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "storj.io/common/storj" + "storj.io/common/testrand" "storj.io/storj/satellite/orders" ) @@ -135,3 +137,79 @@ func TestEncryptionKeys_Set_Invalid(t *testing.T) { assert.Error(t, err, test.Hex) } } + +func randEncryptionKey() orders.EncryptionKey { + k := orders.EncryptionKey{} + r := testrand.Nonce() + copy(k.ID[:], r[:]) + k.Key = testrand.Key() + return k +} + +func TestEncryptionKey_EncryptDecrypt(t *testing.T) { + for i := 0; i < 10; i++ { + key := randEncryptionKey() + data := testrand.BytesInt(16) + serial := testrand.SerialNumber() + + encrypted := key.Encrypt(data, serial) + require.NotEqual(t, encrypted, data) + + decrypted, err := key.Decrypt(encrypted, serial) + require.NoError(t, err) + require.Equal(t, data, decrypted) + } +} + +func TestEncryptionKey_BackwardsCompatibility(t *testing.T) { + type Test struct { + Key string + DataHex string + Serial storj.SerialNumber + EncryptedHex string + } + + tests := []Test{ + { + Key: "1d729566c74d1003=0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784", + DataHex: "045d87f3c67cf22746e995af5a253679", + Serial: storj.SerialNumber{81, 186, 162, 255, 108, 212, 113, 196, 131, 241, 95, 185, 11, 173, 179, 124}, + EncryptedHex: "5fe4c9fc734baed429afe24502ffe9d4c6efd99de5d5ae07433f7449bc55e4e1", + }, { + Key: "5821b6d95526a41a=86216325253fec738dd7a9e28bf921119c160f0702448615bbda08313f6a8eb6", + DataHex: "68d20bf5059875921e668a5bdf2c7fc4", + Serial: storj.SerialNumber{132, 69, 146, 210, 87, 43, 205, 6, 104, 210, 214, 197, 47, 80, 84, 226}, + EncryptedHex: "335eb0ab85e0624862b63c6bad78c4bdd1d52db621332773aef29b977626bcd0", + }, { + Key: "d0836bf84c7174cb=358b0c3b525da1786f9fff094279db1944ebd7a19d0f7bbacbe0255aa5b7d44b", + DataHex: "ec40f84c892b9bffd43629b0223beea5", + Serial: storj.SerialNumber{244, 247, 67, 145, 244, 69, 209, 90, 253, 66, 148, 4, 3, 116, 246, 146}, + EncryptedHex: "2615a21b9968f4fa7fdc5eb423f708a0630ec25295852e513c658eecaee0493e", + }, { + Key: "4b98cbf8713f8d96=b586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6de0374366c4719e4", + DataHex: "3a1b067d89bc7f01f1f573981659a44f", + Serial: storj.SerialNumber{241, 122, 76, 114, 21, 163, 181, 57, 235, 30, 88, 73, 198, 7, 125, 187}, + EncryptedHex: "e57f0b0e936bff96895aae6f963e0ff0a14350d2f787dda47116de0e1a7bf390", + }, { + Key: "5722f5717a289a26=5e82ed6f4125c8fa7311e4d7defa922daae7786667f7e936cd4f24abf7df866b", + DataHex: "aa56038367ad6145de1ee8f4a8b0993e", + Serial: storj.SerialNumber{189, 248, 136, 58, 10, 216, 190, 156, 57, 120, 176, 72, 131, 229, 106, 21}, + EncryptedHex: "8a238f268df2ae5a58134e2f52a813ffc157e0f12d8430268f55712c6bf8aae9", + }, + } + + for _, test := range tests { + var key orders.EncryptionKey + require.NoError(t, key.Set(test.Key)) + + data, err := hex.DecodeString(test.DataHex) + require.NoError(t, err) + encrypted, err := hex.DecodeString(test.EncryptedHex) + require.NoError(t, err) + + decrypted, err := key.Decrypt(encrypted, test.Serial) + require.NoError(t, err) + + require.Equal(t, data, decrypted) + } +}