any-sync/util/keys/keys.go
2022-07-08 10:19:43 +02:00

257 lines
6.2 KiB
Go

package keys
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/subtle"
"crypto/x509"
"errors"
"io"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/strkey"
"github.com/libp2p/go-libp2p-core/crypto"
crypto_pb "github.com/libp2p/go-libp2p-core/crypto/pb"
)
type SigningPubKey crypto.PubKey
type SigningPrivKey crypto.PrivKey
var MinRsaKeyBits = 2048
var ErrKeyLengthTooSmall = errors.New("error key length too small")
type Key interface {
Equals(Key) bool
Raw() ([]byte, error)
}
type EncryptionPrivKey interface {
Key
Decrypt([]byte) ([]byte, error)
GetPublic() EncryptionPubKey
}
type EncryptionPubKey interface {
Key
Encrypt(data []byte) ([]byte, error)
}
type EncryptionRsaPrivKey struct {
privKey rsa.PrivateKey
}
type EncryptionRsaPubKey struct {
pubKey rsa.PublicKey
}
func (e *EncryptionRsaPubKey) Equals(key Key) bool {
other, ok := (key).(*EncryptionRsaPubKey)
if !ok {
return keyEquals(e, key)
}
return e.pubKey.N.Cmp(other.pubKey.N) == 0 && e.pubKey.E == other.pubKey.E
}
func (e *EncryptionRsaPubKey) Raw() ([]byte, error) {
return x509.MarshalPKIXPublicKey(&e.pubKey)
}
func (e *EncryptionRsaPubKey) Encrypt(data []byte) ([]byte, error) {
hash := sha512.New()
return rsa.EncryptOAEP(hash, rand.Reader, &e.pubKey, data, nil)
}
func (e *EncryptionRsaPrivKey) Equals(key Key) bool {
other, ok := (key).(*EncryptionRsaPrivKey)
if !ok {
return keyEquals(e, key)
}
return e.privKey.N.Cmp(other.privKey.N) == 0 && e.privKey.E == other.privKey.E
}
func (e *EncryptionRsaPrivKey) Raw() ([]byte, error) {
b := x509.MarshalPKCS1PrivateKey(&e.privKey)
return b, nil
}
func (e *EncryptionRsaPrivKey) Decrypt(bytes []byte) ([]byte, error) {
hash := sha512.New()
return rsa.DecryptOAEP(hash, rand.Reader, &e.privKey, bytes, nil)
}
func (e *EncryptionRsaPrivKey) GetPublic() EncryptionPubKey {
return &EncryptionRsaPubKey{pubKey: e.privKey.PublicKey}
}
func GenerateRandomRSAKeyPair(bits int) (EncryptionPrivKey, EncryptionPubKey, error) {
return GenerateRSAKeyPair(bits, rand.Reader)
}
func GenerateRSAKeyPair(bits int, src io.Reader) (EncryptionPrivKey, EncryptionPubKey, error) {
if bits < MinRsaKeyBits {
return nil, nil, ErrKeyLengthTooSmall
}
priv, err := rsa.GenerateKey(src, bits)
if err != nil {
return nil, nil, err
}
pk := priv.PublicKey
return &EncryptionRsaPrivKey{privKey: *priv}, &EncryptionRsaPubKey{pubKey: pk}, nil
}
func NewEncryptionRsaPrivKeyFromBytes(bytes []byte) (EncryptionPrivKey, error) {
sk, err := x509.ParsePKCS1PrivateKey(bytes)
if err != nil {
return nil, err
}
if sk.N.BitLen() < MinRsaKeyBits {
return nil, ErrKeyLengthTooSmall
}
return &EncryptionRsaPrivKey{privKey: *sk}, nil
}
func NewEncryptionRsaPubKeyFromBytes(bytes []byte) (EncryptionPubKey, error) {
pub, err := x509.ParsePKIXPublicKey(bytes)
if err != nil {
return nil, err
}
pk, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, errors.New("not actually an rsa public key")
}
if pk.N.BitLen() < MinRsaKeyBits {
return nil, ErrKeyLengthTooSmall
}
return &EncryptionRsaPubKey{pubKey: *pk}, nil
}
func NewSigningEd25519PubKeyFromBytes(bytes []byte) (SigningPubKey, error) {
return crypto.UnmarshalEd25519PublicKey(bytes)
}
func GenerateRandomEd25519KeyPair() (SigningPrivKey, SigningPubKey, error) {
return crypto.GenerateEd25519Key(rand.Reader)
}
func keyEquals(k1, k2 Key) bool {
a, err := k1.Raw()
if err != nil {
return false
}
b, err := k2.Raw()
if err != nil {
return false
}
return subtle.ConstantTimeCompare(a, b) == 1
}
type Ed25519SigningPubKeyDecoder struct{}
func NewEd25519Decoder() *Ed25519SigningPubKeyDecoder {
return &Ed25519SigningPubKeyDecoder{}
}
func (e *Ed25519SigningPubKeyDecoder) DecodeFromBytes(bytes []byte) (SigningPubKey, error) {
return NewSigningEd25519PubKeyFromBytes(bytes)
}
func (e *Ed25519SigningPubKeyDecoder) DecodeFromString(identity string) (SigningPubKey, error) {
pubKeyRaw, err := strkey.Decode(0x5b, identity)
if err != nil {
return nil, err
}
return e.DecodeFromBytes(pubKeyRaw)
}
func (e *Ed25519SigningPubKeyDecoder) DecodeFromStringIntoBytes(identity string) ([]byte, error) {
return strkey.Decode(0x5b, identity)
}
func (e *Ed25519SigningPubKeyDecoder) EncodeToString(pubkey crypto.PubKey) (string, error) {
raw, err := pubkey.Raw()
if err != nil {
return "", err
}
return strkey.Encode(0x5b, raw)
}
type SigningPubKeyDecoder interface {
DecodeFromBytes(bytes []byte) (SigningPubKey, error)
DecodeFromString(identity string) (SigningPubKey, error)
DecodeFromStringIntoBytes(identity string) ([]byte, error)
}
// Below keys are required for testing and mocking purposes
type EmptyRecorderEncryptionKey struct {
recordedEncrypted [][]byte
recordedDecrypted [][]byte
}
func (f *EmptyRecorderEncryptionKey) Equals(key Key) bool {
return true
}
func (f *EmptyRecorderEncryptionKey) Raw() ([]byte, error) {
panic("can't get bytes from this key")
}
func (f *EmptyRecorderEncryptionKey) GetPublic() EncryptionPubKey {
panic("this key doesn't have a public key")
}
func (f *EmptyRecorderEncryptionKey) Encrypt(msg []byte) ([]byte, error) {
f.recordedEncrypted = append(f.recordedEncrypted, msg)
return msg, nil
}
func (f *EmptyRecorderEncryptionKey) Decrypt(msg []byte) ([]byte, error) {
f.recordedDecrypted = append(f.recordedDecrypted, msg)
return msg, nil
}
type SignatureVerificationPayload struct {
message []byte
signature []byte
}
type EmptyRecorderVerificationKey struct {
verifications []SignatureVerificationPayload
}
func (e *EmptyRecorderVerificationKey) Bytes() ([]byte, error) {
panic("can't get bytes from this key")
}
func (e *EmptyRecorderVerificationKey) Equals(key crypto.Key) bool {
return true
}
func (e *EmptyRecorderVerificationKey) Raw() ([]byte, error) {
panic("can't get bytes from this key")
}
func (e *EmptyRecorderVerificationKey) Type() crypto_pb.KeyType {
panic("can't get type from this key")
}
func (e *EmptyRecorderVerificationKey) Verify(data []byte, sig []byte) (bool, error) {
e.verifications = append(e.verifications, SignatureVerificationPayload{
message: data,
signature: sig,
})
return true, nil
}
func NewMockSigningPubKeyFromBytes(bytes []byte) (SigningPubKey, error) {
return &EmptyRecorderVerificationKey{}, nil
}