Add sym key

This commit is contained in:
mcrakhman 2023-03-24 13:01:53 +01:00 committed by Mikhail Iudin
parent 3a07939b01
commit 7c4abdbb8c
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
13 changed files with 112 additions and 134 deletions

View File

@ -1,10 +1,11 @@
package aclrecordproto
import (
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/keys/symmetric"
)
func AclReadKeyDerive(signKey []byte, encKey []byte) (*symmetric.Key, error) {
func AclReadKeyDerive(signKey []byte, encKey []byte) (*crypto.AESKey, error) {
concBuf := make([]byte, 0, len(signKey)+len(encKey))
concBuf = append(concBuf, signKey...)
concBuf = append(concBuf, encKey...)

View File

@ -5,7 +5,6 @@ import (
"github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/util/cidutil"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"github.com/gogo/protobuf/proto"
"time"
)
@ -37,7 +36,7 @@ func (a *aclRecordBuilder) BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyByt
if err != nil {
return
}
encSymKey, err := symmetric.FromBytes(encSymKeyBytes)
encSymKey, err := crypto.UnmarshallAESKey(encSymKeyBytes)
if err != nil {
return
}

View File

@ -13,7 +13,6 @@ import (
"github.com/anytypeio/any-sync/util/keys"
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"github.com/gogo/protobuf/proto"
"go.uber.org/zap"
)
@ -44,7 +43,7 @@ type UserPermissionPair struct {
type AclState struct {
id string
currentReadKeyHash uint64
userReadKeys map[uint64]*symmetric.Key
userReadKeys map[uint64]*crypto.AESKey
userStates map[string]*aclrecordproto.AclUserState
userInvites map[string]*aclrecordproto.AclUserInvite
encryptionKey encryptionkey.PrivKey
@ -71,7 +70,7 @@ func newAclStateWithKeys(
identity: string(identity),
signingKey: signingKey,
encryptionKey: encryptionKey,
userReadKeys: make(map[uint64]*symmetric.Key),
userReadKeys: make(map[uint64]*crypto.AESKey),
userStates: make(map[string]*aclrecordproto.AclUserState),
userInvites: make(map[string]*aclrecordproto.AclUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair),
@ -81,7 +80,7 @@ func newAclStateWithKeys(
func newAclState(id string) *AclState {
return &AclState{
id: id,
userReadKeys: make(map[uint64]*symmetric.Key),
userReadKeys: make(map[uint64]*crypto.AESKey),
userStates: make(map[string]*aclrecordproto.AclUserState),
userInvites: make(map[string]*aclrecordproto.AclUserInvite),
permissionsAtRecord: make(map[string][]UserPermissionPair),
@ -92,7 +91,7 @@ func (st *AclState) CurrentReadKeyHash() uint64 {
return st.currentReadKeyHash
}
func (st *AclState) CurrentReadKey() (*symmetric.Key, error) {
func (st *AclState) CurrentReadKey() (*crypto.AESKey, error) {
key, exists := st.userReadKeys[st.currentReadKeyHash]
if !exists {
return nil, ErrNoReadKey
@ -100,7 +99,7 @@ func (st *AclState) CurrentReadKey() (*symmetric.Key, error) {
return key, nil
}
func (st *AclState) UserReadKeys() map[uint64]*symmetric.Key {
func (st *AclState) UserReadKeys() map[uint64]*crypto.AESKey {
return st.userReadKeys
}
@ -195,7 +194,7 @@ func (st *AclState) applyRoot(root *aclrecordproto.AclRoot) (err error) {
}
func (st *AclState) saveReadKeyFromRoot(root *aclrecordproto.AclRoot) (err error) {
var readKey *symmetric.Key
var readKey *crypto.AESKey
if len(root.GetDerivationScheme()) != 0 {
var encPrivKey []byte
encPrivKey, err = st.encryptionKey.Raw()
@ -401,13 +400,13 @@ func (st *AclState) applyUserRemove(ch *aclrecordproto.AclUserRemove) error {
return nil
}
func (st *AclState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, error) {
func (st *AclState) decryptReadKeyAndHash(msg []byte) (*crypto.AESKey, uint64, error) {
decrypted, err := st.encryptionKey.Decrypt(msg)
if err != nil {
return nil, 0, ErrFailedToDecrypt
}
key, err := symmetric.FromBytes(decrypted)
key, err := crypto.UnmarshallAESKey(decrypted)
if err != nil {
return nil, 0, ErrFailedToDecrypt
}

View File

@ -6,14 +6,13 @@ import (
"github.com/anytypeio/any-sync/util/keys"
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"hash/fnv"
"strings"
)
type SymKey struct {
Hash uint64
Key *symmetric.Key
Key *crypto.AESKey
}
type YAMLKeychain struct {
@ -111,11 +110,11 @@ func (k *YAMLKeychain) AddReadKey(key *Key) {
}
var (
rkey *symmetric.Key
rkey *crypto.AESKey
err error
)
if key.Value == "generated" {
rkey, err = symmetric.NewRandom()
rkey, err = crypto.NewRandomAES()
if err != nil {
panic("should be able to generate symmetric key")
}
@ -127,7 +126,7 @@ func (k *YAMLKeychain) AddReadKey(key *Key) {
panic("should be able to derive symmetric key")
}
} else {
rkey, err = symmetric.FromString(key.Value)
rkey, err = crypto.UnmarshallAESKeyString(key.Value)
if err != nil {
panic("should be able to parse symmetric key")
}

View File

@ -7,9 +7,9 @@ import (
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
"github.com/anytypeio/any-sync/commonspace/object/acl/testutils/yamltests"
"github.com/anytypeio/any-sync/util/cidutil"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"gopkg.in/yaml.v3"
"io/ioutil"
"path"
@ -249,7 +249,7 @@ func (t *AclListStorageBuilder) encryptReadKeysWithPubKey(keys []string, encKey
return
}
func (t *AclListStorageBuilder) encryptReadKeysWithSymKey(keys []string, key *symmetric.Key) (enc [][]byte) {
func (t *AclListStorageBuilder) encryptReadKeysWithSymKey(keys []string, key *crypto.AESKey) (enc [][]byte) {
for _, k := range keys {
realKey := t.keychain.GetKey(k).(*SymKey).Key.Bytes()
res, err := key.Encrypt(realKey)

View File

@ -5,8 +5,8 @@ import (
"github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/util/cidutil"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"github.com/gogo/protobuf/proto"
"time"
)
@ -21,7 +21,7 @@ type BuilderContent struct {
Identity []byte
IsSnapshot bool
SigningKey signingkey.PrivKey
ReadKey *symmetric.Key
ReadKey *crypto.AESKey
Content []byte
}

View File

@ -4,6 +4,7 @@ package objecttree
import (
"context"
"errors"
"github.com/anytypeio/any-sync/util/crypto"
"sync"
"time"
@ -11,7 +12,6 @@ import (
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"github.com/anytypeio/any-sync/util/slice"
)
@ -99,7 +99,7 @@ type objectTree struct {
root *Change
tree *Tree
keys map[uint64]*symmetric.Key
keys map[uint64]*crypto.AESKey
// buffers
difSnapshotBuf []*treechangeproto.RawTreeChangeWithId
@ -225,7 +225,7 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
var (
state = ot.aclList.AclState() // special method for own keys
readKey *symmetric.Key
readKey *crypto.AESKey
readKeyHash uint64
)
canWrite := state.HasPermission(content.Identity, aclrecordproto.AclUserPermissions_Writer) ||

View File

@ -5,8 +5,8 @@ import (
"github.com/anytypeio/any-sync/commonspace/object/keychain"
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
"github.com/anytypeio/any-sync/util/keys/symmetric"
"math/rand"
"time"
)
@ -189,7 +189,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
aclList: deps.aclList,
changeBuilder: deps.changeBuilder,
rawChangeLoader: deps.rawChangeLoader,
keys: make(map[uint64]*symmetric.Key),
keys: make(map[uint64]*crypto.AESKey),
newChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
notSeenIdxBuf: make([]int, 0, 10),
@ -225,7 +225,7 @@ func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht History
aclList: deps.aclList,
changeBuilder: deps.changeBuilder,
rawChangeLoader: deps.rawChangeLoader,
keys: make(map[uint64]*symmetric.Key),
keys: make(map[uint64]*crypto.AESKey),
newChangesBuf: make([]*Change, 0, 10),
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
notSeenIdxBuf: make([]int, 0, 10),

View File

@ -1,12 +1,11 @@
package symmetric
package crypto
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/subtle"
"fmt"
"github.com/minio/sha256-simd"
mbase "github.com/multiformats/go-multibase"
)
@ -18,83 +17,65 @@ const (
KeyBytes = 32
)
type Key struct {
type AESKey struct {
raw []byte
}
func DeriveFromBytes(bytes []byte) (*Key, error) {
bArray := sha256.Sum256(bytes)
bSlice := bArray[:]
return FromBytes(bSlice)
}
func (k *Key) Equals(otherKey *Key) bool {
otherRaw := otherKey.raw
keyRaw := k.raw
if len(keyRaw) != len(otherRaw) {
func (k *AESKey) Equals(key Key) bool {
aesKey, ok := key.(*AESKey)
if !ok {
return false
}
for i := 0; i < len(keyRaw); i++ {
if keyRaw[i] != otherRaw[i] {
return false
}
}
return true
return subtle.ConstantTimeCompare(k.raw, aesKey.raw) == 1
}
func (k *Key) Raw() ([]byte, error) {
func (k *AESKey) Raw() ([]byte, error) {
return k.raw, nil
}
// NewRandom returns a random key.
func NewRandom() (*Key, error) {
// NewRandomAES returns a random key.
func NewRandomAES() (*AESKey, error) {
raw := make([]byte, KeyBytes)
if _, err := rand.Read(raw); err != nil {
return nil, err
}
return &Key{raw: raw}, nil
return &AESKey{raw: raw}, nil
}
// New returns Key if err is nil and panics otherwise.
func New() *Key {
k, err := NewRandom()
// NewAES returns AESKey if err is nil and panics otherwise.
func NewAES() *AESKey {
k, err := NewRandomAES()
if err != nil {
panic(err)
}
return k
}
// FromBytes returns a key by decoding bytes.
func FromBytes(k []byte) (*Key, error) {
// UnmarshallAESKey returns a key by decoding bytes.
func UnmarshallAESKey(k []byte) (*AESKey, error) {
if len(k) != KeyBytes {
return nil, fmt.Errorf("invalid key")
}
return &Key{raw: k}, nil
return &AESKey{raw: k}, nil
}
// FromString returns a key by decoding a base32-encoded string.
func FromString(k string) (*Key, error) {
// UnmarshallAESKeyString returns a key by decoding a base32-encoded string.
func UnmarshallAESKeyString(k string) (*AESKey, error) {
_, b, err := mbase.Decode(k)
if err != nil {
return nil, err
}
return FromBytes(b)
return UnmarshallAESKey(b)
}
// Bytes returns raw key bytes.
func (k *Key) Bytes() []byte {
func (k *AESKey) Bytes() []byte {
return k.raw
}
// MarshalBinary implements BinaryMarshaler.
func (k *Key) MarshalBinary() ([]byte, error) {
return k.raw, nil
}
// String returns the base32-encoded string representation of raw key bytes.
func (k *Key) String() string {
func (k *AESKey) String() string {
str, err := mbase.Encode(mbase.Base32, k.raw)
if err != nil {
panic("should not error with hardcoded mbase: " + err.Error())
@ -103,7 +84,7 @@ func (k *Key) String() string {
}
// Encrypt performs AES-256 GCM encryption on plaintext.
func (k *Key) Encrypt(plaintext []byte) ([]byte, error) {
func (k *AESKey) Encrypt(plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(k.raw[:KeyBytes])
if err != nil {
return nil, err
@ -122,7 +103,7 @@ func (k *Key) Encrypt(plaintext []byte) ([]byte, error) {
}
// Decrypt uses key to perform AES-256 GCM decryption on ciphertext.
func (k *Key) Decrypt(ciphertext []byte) ([]byte, error) {
func (k *AESKey) Decrypt(ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(k.raw[:KeyBytes])
if err != nil {
return nil, err

View File

@ -1,20 +1,14 @@
syntax = "proto3";
package utilcrypto;
package crypto;
option go_package = "util/crypto/cryptoproto";
enum KeyType {
RSA = 0;
Ed25519 = 1;
Secp256k1 = 2;
ECDSA = 3;
Ed25519Public = 0;
Ed25519Private = 1;
AES = 2;
}
message PublicKey {
KeyType Type = 1;
bytes Data = 2;
}
message PrivateKey {
message Key {
KeyType Type = 1;
bytes Data = 2;
}

View File

@ -1,52 +0,0 @@
package crypto
import (
"crypto/ed25519"
"crypto/sha512"
"filippo.io/edwards25519"
"golang.org/x/crypto/curve25519"
)
// Ed25519PublicKeyToCurve25519 converts an Ed25519 public key to a Curve25519 public key
func Ed25519PublicKeyToCurve25519(pk ed25519.PublicKey) []byte {
// Unmarshalling public key into edwards curve point
epk, err := (&edwards25519.Point{}).SetBytes(pk)
if err != nil {
panic(err)
}
// converting to curve25519 (see here for more details https://github.com/golang/go/issues/20504)
return epk.BytesMontgomery()
}
// ISC License
//
// Copyright (c) 2013-2020
// Frank Denis <j at pureftpd dot org>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_sign/ed25519/ref10/keypair.c#L69-L83
// Ed25519PrivateKeyToCurve25519 converts an Ed25519 private key to a Curve25519 private key
// This code is originally taken from here https://github.com/jorrizza/ed2curve25519/blob/master/ed2curve25519.go
func Ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {
h := sha512.New()
h.Write(pk.Seed())
out := h.Sum(nil)
// used in libsodium
out[0] &= 248
out[31] &= 127
out[31] |= 64
return out[:curve25519.ScalarSize]
}

View File

@ -25,7 +25,7 @@ type PrivKey interface {
GetPublic() PubKey
}
// PubKey is the public key used to verify the signatures made by SignPrivKey
// PubKey is the public key used to verify the signatures and decrypt messages
type PubKey interface {
Key
@ -35,6 +35,15 @@ type PubKey interface {
Verify(data []byte, sig []byte) (bool, error)
}
type SymKey interface {
Key
// Decrypt decrypts the message and returns the result
Decrypt(message []byte) ([]byte, error)
// Encrypt encrypts the message and returns the result
Encrypt(message []byte) ([]byte, error)
}
func KeyEquals(k1, k2 Key) bool {
a, err := k1.Raw()
if err != nil {

View File

@ -1,14 +1,62 @@
package crypto
import (
"crypto/ed25519"
"crypto/rand"
"crypto/sha512"
"errors"
"filippo.io/edwards25519"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/nacl/box"
)
var ErrX25519DecryptionFailed = errors.New("failed decryption with x25519 key")
// Ed25519PublicKeyToCurve25519 converts an Ed25519 public key to a Curve25519 public key
func Ed25519PublicKeyToCurve25519(pk ed25519.PublicKey) []byte {
// Unmarshalling public key into edwards curve point
epk, err := (&edwards25519.Point{}).SetBytes(pk)
if err != nil {
panic(err)
}
// converting to curve25519 (see here for more details https://github.com/golang/go/issues/20504)
return epk.BytesMontgomery()
}
// ISC License
//
// Copyright (c) 2013-2020
// Frank Denis <j at pureftpd dot org>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_sign/ed25519/ref10/keypair.c#L69-L83
// Ed25519PrivateKeyToCurve25519 converts an Ed25519 private key to a Curve25519 private key
// This code is originally taken from here https://github.com/jorrizza/ed2curve25519/blob/master/ed2curve25519.go
func Ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {
h := sha512.New()
h.Write(pk.Seed())
out := h.Sum(nil)
// used in libsodium
out[0] &= 248
out[31] &= 127
out[31] |= 64
return out[:curve25519.ScalarSize]
}
// EncryptX25519 takes a x25519 public key and encrypts the message
func EncryptX25519(pubKey *[32]byte, msg []byte) []byte {
// see discussion here https://github.com/golang/go/issues/29128