satellite/orders: add encryption keys

This adds EncryptionKey definition that can be used as a flag.
These order.EncryptionKey-s will be used to encrypt data in
order limits.

This helps to avoid storing lots of transient data in the
main database.

This code doesn't yet contain encryption itself.

Change-Id: I2efae102a89b851d33342a0106f8d8b3f35119bb
This commit is contained in:
Egon Elbre 2020-06-02 16:51:33 +03:00
parent 9b90712aa0
commit 735dc6e163
2 changed files with 285 additions and 0 deletions

View File

@ -0,0 +1,148 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package orders
import (
"encoding/hex"
"fmt"
"strings"
"github.com/zeebo/errs"
"storj.io/common/storj"
)
// ErrEncryptionKey is error class used for keys.
var ErrEncryptionKey = errs.Class("order encryption key")
// EncryptionKeyID is used to identify an encryption key.
type EncryptionKeyID [8]byte
// IsZero returns whether the key contains no data.
func (key EncryptionKeyID) IsZero() bool { return key == EncryptionKeyID{} }
// EncryptionKeys contains a collection of keys.
//
// Can be used as a flag.
type EncryptionKeys struct {
Default EncryptionKey
List []EncryptionKey
KeyByID map[EncryptionKeyID]storj.Key
}
// EncryptionKey contains an identifier and an encryption key that is used to
// encrypt transient metadata in orders.
//
// Can be used as a flag.
type EncryptionKey struct {
ID EncryptionKeyID
Key storj.Key
}
// IsZero returns whether they key contains some data.
func (key *EncryptionKey) IsZero() bool {
return key.ID.IsZero() || key.Key.IsZero()
}
// Type implements pflag.Value.
func (EncryptionKey) Type() string { return "orders.EncryptionKey" }
// String is required for pflag.Value.
func (key *EncryptionKey) String() string {
return hex.EncodeToString(key.ID[:]) + "=" + hex.EncodeToString(key.Key[:])
}
// Set sets the value from an hex encoded string "hex(id)=hex(key)".
func (key *EncryptionKey) Set(s string) error {
tokens := strings.SplitN(s, "=", 2)
if len(tokens) != 2 {
return ErrEncryptionKey.New("invalid definition %q", s)
}
err := setHexEncodedArray(key.ID[:], tokens[0])
if err != nil {
return ErrEncryptionKey.New("invalid id %q: %v", tokens[0], err)
}
err = setHexEncodedArray(key.Key[:], tokens[1])
if err != nil {
return ErrEncryptionKey.New("invalid key %q: %v", tokens[1], err)
}
if key.ID.IsZero() || key.Key.IsZero() {
return ErrEncryptionKey.New("neither identifier or key can be zero")
}
return nil
}
// Type implements pflag.Value.
func (EncryptionKeys) Type() string { return "orders.EncryptionKeys" }
// Set adds the values from a comma delimited hex encoded strings "hex(id1)=hex(key1),hex(id2)=hex(key2)".
func (keys *EncryptionKeys) Set(s string) error {
if keys.KeyByID == nil {
keys.KeyByID = map[EncryptionKeyID]storj.Key{}
}
for _, x := range strings.Split(s, ",") {
x = strings.TrimSpace(x)
var ekey EncryptionKey
if err := ekey.Set(x); err != nil {
return ErrEncryptionKey.New("invalid keys %q: %v", s, err)
}
if ekey.IsZero() {
continue
}
if keys.Default.IsZero() {
keys.Default = ekey
}
if _, exists := keys.KeyByID[ekey.ID]; exists {
return ErrEncryptionKey.New("duplicate key identifier %q", s)
}
keys.List = append(keys.List, ekey)
keys.KeyByID[ekey.ID] = ekey.Key
}
return nil
}
// String is required for pflag.Value.
func (keys *EncryptionKeys) String() string {
var s strings.Builder
if keys.Default.IsZero() {
return ""
}
s.WriteString(keys.Default.String())
for _, key := range keys.List {
if key.ID == keys.Default.ID {
continue
}
s.WriteString(",")
s.WriteString(key.String())
}
return s.String()
}
// setHexEncodedArray sets dst bytes to hex decoded s, verify that the result matches dst.
func setHexEncodedArray(dst []byte, s string) error {
s = strings.TrimSpace(s)
if len(s) != len(dst)*2 {
return fmt.Errorf("wrong hex length %d, expected %d", len(s), len(dst)*2)
}
bytes, err := hex.DecodeString(s)
if err != nil {
return err
}
copy(dst, bytes)
return nil
}

View File

@ -0,0 +1,137 @@
// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package orders_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"storj.io/common/storj"
"storj.io/storj/satellite/orders"
)
func TestEncryptionKey_Set_Valid(t *testing.T) {
type Test struct {
Hex string
Key orders.EncryptionKey
}
tests := []Test{
{
Hex: `0100000000000000=0100000000000000000000000000000000000000000000000000000000000000`,
Key: orders.EncryptionKey{
ID: orders.EncryptionKeyID{0x01},
Key: storj.Key{0x01},
},
},
{
Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF`,
Key: orders.EncryptionKey{
ID: orders.EncryptionKeyID{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xFF},
Key: storj.Key{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xFF,
},
},
},
}
for _, test := range tests {
var got orders.EncryptionKey
err := got.Set(test.Hex)
assert.NoError(t, err, test.Hex)
assert.Equal(t, test.Key, got, test.Hex)
}
}
func TestEncryptionKey_Set_Invalid(t *testing.T) {
type Test struct {
Hex string
}
tests := []Test{
{Hex: ``},
{Hex: `=`},
{Hex: `01=`},
{Hex: `=01`},
{Hex: `1=1`},
{Hex: `=1122334455667788112233445566778811223344556677881122334455667788`},
{Hex: `112233445566778=1122334455667788112233445566778811223344556677881122334455667788`},
{Hex: `1122334455667788=`},
{Hex: `1122334455667788=112233445566778811223344556677881122334455667788112233445566778`},
{Hex: `11223344556677QQ=11223344556677881122334455667788112233445566778811223344556677QQ`},
}
for _, test := range tests {
var got orders.EncryptionKey
err := got.Set(test.Hex)
assert.Error(t, err, test.Hex)
}
}
func TestEncryptionKeys_Set_Valid(t *testing.T) {
var keys orders.EncryptionKeys
err := keys.Set(`11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,0100000000000000=0100000000000000000000000000000000000000000000000000000000000000`)
require.NoError(t, err)
first := orders.EncryptionKey{
ID: orders.EncryptionKeyID{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xFF},
Key: storj.Key{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xFF,
},
}
second := orders.EncryptionKey{
ID: orders.EncryptionKeyID{0x01},
Key: storj.Key{0x01},
}
assert.Equal(t, first, keys.Default)
assert.EqualValues(t, []orders.EncryptionKey{first, second}, keys.List)
assert.Equal(t, first.Key, keys.KeyByID[first.ID])
assert.Equal(t, second.Key, keys.KeyByID[second.ID])
}
func TestEncryptionKeys_Set_Invalid(t *testing.T) {
type Test struct {
Hex string
}
tests := []Test{
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,=`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,01=`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,=01`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,1=1`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,=1122334455667788112233445566778811223344556677881122334455667788`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,112233445566778=1122334455667788112233445566778811223344556677881122334455667788`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,1122334455667788=`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,1122334455667788=112233445566778811223344556677881122334455667788112233445566778`},
{Hex: `11223344556677FF=11223344556677881122334455667788112233445566778811223344556677FF,11223344556677QQ=11223344556677881122334455667788112233445566778811223344556677QQ`},
}
for _, test := range tests {
var got orders.EncryptionKeys
err := got.Set(test.Hex)
assert.Error(t, err, test.Hex)
}
}