2023-03-24 13:01:53 +01:00

195 lines
4.5 KiB
Go

package acllistbuilder
import (
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
"github.com/anytypeio/any-sync/util/crypto"
"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"
"hash/fnv"
"strings"
)
type SymKey struct {
Hash uint64
Key *crypto.AESKey
}
type YAMLKeychain struct {
SigningKeysByYAMLName map[string]signingkey.PrivKey
SigningKeysByRealIdentity map[string]signingkey.PrivKey
EncryptionKeysByYAMLName map[string]encryptionkey.PrivKey
ReadKeysByYAMLName map[string]*SymKey
ReadKeysByHash map[uint64]*SymKey
GeneratedIdentities map[string]string
}
func NewKeychain() *YAMLKeychain {
return &YAMLKeychain{
SigningKeysByYAMLName: map[string]signingkey.PrivKey{},
SigningKeysByRealIdentity: map[string]signingkey.PrivKey{},
EncryptionKeysByYAMLName: map[string]encryptionkey.PrivKey{},
GeneratedIdentities: map[string]string{},
ReadKeysByYAMLName: map[string]*SymKey{},
ReadKeysByHash: map[uint64]*SymKey{},
}
}
func (k *YAMLKeychain) ParseKeys(keys *Keys) {
for _, encKey := range keys.Enc {
k.AddEncryptionKey(encKey)
}
for _, signKey := range keys.Sign {
k.AddSigningKey(signKey)
}
for _, readKey := range keys.Read {
k.AddReadKey(readKey)
}
}
func (k *YAMLKeychain) AddEncryptionKey(key *Key) {
if _, exists := k.EncryptionKeysByYAMLName[key.Name]; exists {
return
}
var (
newPrivKey encryptionkey.PrivKey
err error
)
if key.Value == "generated" {
newPrivKey, _, err = encryptionkey.GenerateRandomRSAKeyPair(2048)
if err != nil {
panic(err)
}
} else {
newPrivKey, err = keys.DecodeKeyFromString(key.Value, encryptionkey.NewEncryptionRsaPrivKeyFromBytes, nil)
if err != nil {
panic(err)
}
}
k.EncryptionKeysByYAMLName[key.Name] = newPrivKey
}
func (k *YAMLKeychain) AddSigningKey(key *Key) {
if _, exists := k.SigningKeysByYAMLName[key.Name]; exists {
return
}
var (
newPrivKey signingkey.PrivKey
pubKey signingkey.PubKey
err error
)
if key.Value == "generated" {
newPrivKey, pubKey, err = crypto.GenerateRandomEd25519KeyPair()
if err != nil {
panic(err)
}
} else {
newPrivKey, err = keys.DecodeKeyFromString(key.Value, crypto.NewSigningEd25519PrivKeyFromBytes, nil)
if err != nil {
panic(err)
}
pubKey = newPrivKey.GetPublic()
}
k.SigningKeysByYAMLName[key.Name] = newPrivKey
rawPubKey, err := pubKey.Raw()
if err != nil {
panic(err)
}
encoded := string(rawPubKey)
k.SigningKeysByRealIdentity[encoded] = newPrivKey
k.GeneratedIdentities[key.Name] = encoded
}
func (k *YAMLKeychain) AddReadKey(key *Key) {
if _, exists := k.ReadKeysByYAMLName[key.Name]; exists {
return
}
var (
rkey *crypto.AESKey
err error
)
if key.Value == "generated" {
rkey, err = crypto.NewRandomAES()
if err != nil {
panic("should be able to generate symmetric key")
}
} else if key.Value == "derived" {
signKey, _ := k.SigningKeysByYAMLName[key.Name].Raw()
encKey, _ := k.EncryptionKeysByYAMLName[key.Name].Raw()
rkey, err = aclrecordproto.AclReadKeyDerive(signKey, encKey)
if err != nil {
panic("should be able to derive symmetric key")
}
} else {
rkey, err = crypto.UnmarshallAESKeyString(key.Value)
if err != nil {
panic("should be able to parse symmetric key")
}
}
hasher := fnv.New64()
hasher.Write(rkey.Bytes())
k.ReadKeysByYAMLName[key.Name] = &SymKey{
Hash: hasher.Sum64(),
Key: rkey,
}
k.ReadKeysByHash[hasher.Sum64()] = &SymKey{
Hash: hasher.Sum64(),
Key: rkey,
}
}
func (k *YAMLKeychain) AddKey(key *Key) {
parts := strings.Split(key.Name, ".")
if len(parts) != 3 {
panic("cannot parse a key")
}
switch parts[1] {
case "Signature":
k.AddSigningKey(key)
case "Enc":
k.AddEncryptionKey(key)
case "Read":
k.AddReadKey(key)
default:
panic("incorrect format")
}
}
func (k *YAMLKeychain) GetKey(key string) interface{} {
parts := strings.Split(key, ".")
if len(parts) != 3 {
panic("cannot parse a key")
}
name := parts[2]
switch parts[1] {
case "Sign":
if key, exists := k.SigningKeysByYAMLName[name]; exists {
return key
}
case "Enc":
if key, exists := k.EncryptionKeysByYAMLName[name]; exists {
return key
}
case "Read":
if key, exists := k.ReadKeysByYAMLName[name]; exists {
return key
}
default:
panic("incorrect format")
}
return nil
}
func (k *YAMLKeychain) GetIdentity(name string) string {
return k.GeneratedIdentities[name]
}