mirror of
https://github.com/status-im/status-go.git
synced 2025-02-19 18:28:18 +00:00
Update vendor Integrate rendezvous into status node Add a test with failover using rendezvous Use multiple servers in client Use discovery V5 by default and test that node can be started with rendezvous discovet Fix linter Update rendezvous client to one with instrumented stream Address feedback Fix test with updated topic limits Apply several suggestions Change log to debug for request errors because we continue execution Remove web3js after rebase Update rendezvous package
319 lines
7.0 KiB
Go
319 lines
7.0 KiB
Go
// Package crypto implements various cryptographic utilities used by ipfs.
|
|
// This includes a Public and Private key interface and an RSA key implementation
|
|
// that satisfies it.
|
|
package crypto
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"crypto/elliptic"
|
|
"crypto/hmac"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha1"
|
|
"crypto/sha512"
|
|
"hash"
|
|
|
|
pb "github.com/libp2p/go-libp2p-crypto/pb"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
sha256 "github.com/minio/sha256-simd"
|
|
)
|
|
|
|
var ErrBadKeyType = errors.New("invalid or unsupported key type")
|
|
|
|
const (
|
|
RSA = iota
|
|
Ed25519
|
|
Secp256k1
|
|
)
|
|
|
|
var KeyTypes = []int{
|
|
RSA,
|
|
Ed25519,
|
|
Secp256k1,
|
|
}
|
|
|
|
// PubKeyUnmarshaller is a func that creates a PubKey from a given slice of bytes
|
|
type PubKeyUnmarshaller func(data []byte) (PubKey, error)
|
|
|
|
// PrivKeyUnmarshaller is a func that creates a PrivKey from a given slice of bytes
|
|
type PrivKeyUnmarshaller func(data []byte) (PrivKey, error)
|
|
|
|
var PubKeyUnmarshallers = map[pb.KeyType]PubKeyUnmarshaller{
|
|
pb.KeyType_RSA: UnmarshalRsaPublicKey,
|
|
pb.KeyType_Ed25519: UnmarshalEd25519PublicKey,
|
|
pb.KeyType_Secp256k1: UnmarshalSecp256k1PublicKey,
|
|
}
|
|
|
|
var PrivKeyUnmarshallers = map[pb.KeyType]PrivKeyUnmarshaller{
|
|
pb.KeyType_RSA: UnmarshalRsaPrivateKey,
|
|
pb.KeyType_Ed25519: UnmarshalEd25519PrivateKey,
|
|
pb.KeyType_Secp256k1: UnmarshalSecp256k1PrivateKey,
|
|
}
|
|
|
|
// Key represents a crypto key that can be compared to another key
|
|
type Key interface {
|
|
// Bytes returns a serialized, storeable representation of this key
|
|
Bytes() ([]byte, error)
|
|
|
|
// Equals checks whether two PubKeys are the same
|
|
Equals(Key) bool
|
|
}
|
|
|
|
// PrivKey represents a private key that can be used to generate a public key,
|
|
// sign data, and decrypt data that was encrypted with a public key
|
|
type PrivKey interface {
|
|
Key
|
|
|
|
// Cryptographically sign the given bytes
|
|
Sign([]byte) ([]byte, error)
|
|
|
|
// Return a public key paired with this private key
|
|
GetPublic() PubKey
|
|
}
|
|
|
|
type PubKey interface {
|
|
Key
|
|
|
|
// Verify that 'sig' is the signed hash of 'data'
|
|
Verify(data []byte, sig []byte) (bool, error)
|
|
}
|
|
|
|
// Given a public key, generates the shared key.
|
|
type GenSharedKey func([]byte) ([]byte, error)
|
|
|
|
func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
|
|
return GenerateKeyPairWithReader(typ, bits, rand.Reader)
|
|
}
|
|
|
|
// Generates a keypair of the given type and bitsize
|
|
func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) {
|
|
switch typ {
|
|
case RSA:
|
|
priv, err := rsa.GenerateKey(src, bits)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
pk := &priv.PublicKey
|
|
return &RsaPrivateKey{sk: priv}, &RsaPublicKey{pk}, nil
|
|
case Ed25519:
|
|
return GenerateEd25519Key(src)
|
|
case Secp256k1:
|
|
return GenerateSecp256k1Key(src)
|
|
default:
|
|
return nil, nil, ErrBadKeyType
|
|
}
|
|
}
|
|
|
|
// Generates an ephemeral public key and returns a function that will compute
|
|
// the shared secret key. Used in the identify module.
|
|
//
|
|
// Focuses only on ECDH now, but can be made more general in the future.
|
|
func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) {
|
|
var curve elliptic.Curve
|
|
|
|
switch curveName {
|
|
case "P-256":
|
|
curve = elliptic.P256()
|
|
case "P-384":
|
|
curve = elliptic.P384()
|
|
case "P-521":
|
|
curve = elliptic.P521()
|
|
}
|
|
|
|
priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
pubKey := elliptic.Marshal(curve, x, y)
|
|
|
|
done := func(theirPub []byte) ([]byte, error) {
|
|
// Verify and unpack node's public key.
|
|
x, y := elliptic.Unmarshal(curve, theirPub)
|
|
if x == nil {
|
|
return nil, fmt.Errorf("Malformed public key: %d %v", len(theirPub), theirPub)
|
|
}
|
|
|
|
if !curve.IsOnCurve(x, y) {
|
|
return nil, errors.New("Invalid public key.")
|
|
}
|
|
|
|
// Generate shared secret.
|
|
secret, _ := curve.ScalarMult(x, y, priv)
|
|
|
|
return secret.Bytes(), nil
|
|
}
|
|
|
|
return pubKey, done, nil
|
|
}
|
|
|
|
type StretchedKeys struct {
|
|
IV []byte
|
|
MacKey []byte
|
|
CipherKey []byte
|
|
}
|
|
|
|
// Generates a set of keys for each party by stretching the shared key.
|
|
// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
|
|
func KeyStretcher(cipherType string, hashType string, secret []byte) (StretchedKeys, StretchedKeys) {
|
|
var cipherKeySize int
|
|
var ivSize int
|
|
switch cipherType {
|
|
case "AES-128":
|
|
ivSize = 16
|
|
cipherKeySize = 16
|
|
case "AES-256":
|
|
ivSize = 16
|
|
cipherKeySize = 32
|
|
case "Blowfish":
|
|
ivSize = 8
|
|
// Note: 24 arbitrarily selected, needs more thought
|
|
cipherKeySize = 32
|
|
}
|
|
|
|
hmacKeySize := 20
|
|
|
|
seed := []byte("key expansion")
|
|
|
|
result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize))
|
|
|
|
var h func() hash.Hash
|
|
|
|
switch hashType {
|
|
case "SHA1":
|
|
h = sha1.New
|
|
case "SHA256":
|
|
h = sha256.New
|
|
case "SHA512":
|
|
h = sha512.New
|
|
default:
|
|
panic("Unrecognized hash function, programmer error?")
|
|
}
|
|
|
|
m := hmac.New(h, secret)
|
|
m.Write(seed)
|
|
|
|
a := m.Sum(nil)
|
|
|
|
j := 0
|
|
for j < len(result) {
|
|
m.Reset()
|
|
m.Write(a)
|
|
m.Write(seed)
|
|
b := m.Sum(nil)
|
|
|
|
todo := len(b)
|
|
|
|
if j+todo > len(result) {
|
|
todo = len(result) - j
|
|
}
|
|
|
|
copy(result[j:j+todo], b)
|
|
|
|
j += todo
|
|
|
|
m.Reset()
|
|
m.Write(a)
|
|
a = m.Sum(nil)
|
|
}
|
|
|
|
half := len(result) / 2
|
|
r1 := result[:half]
|
|
r2 := result[half:]
|
|
|
|
var k1 StretchedKeys
|
|
var k2 StretchedKeys
|
|
|
|
k1.IV = r1[0:ivSize]
|
|
k1.CipherKey = r1[ivSize : ivSize+cipherKeySize]
|
|
k1.MacKey = r1[ivSize+cipherKeySize:]
|
|
|
|
k2.IV = r2[0:ivSize]
|
|
k2.CipherKey = r2[ivSize : ivSize+cipherKeySize]
|
|
k2.MacKey = r2[ivSize+cipherKeySize:]
|
|
|
|
return k1, k2
|
|
}
|
|
|
|
// UnmarshalPublicKey converts a protobuf serialized public key into its
|
|
// representative object
|
|
func UnmarshalPublicKey(data []byte) (PubKey, error) {
|
|
pmes := new(pb.PublicKey)
|
|
err := proto.Unmarshal(data, pmes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
um, ok := PubKeyUnmarshallers[pmes.GetType()]
|
|
if !ok {
|
|
return nil, ErrBadKeyType
|
|
}
|
|
|
|
return um(pmes.GetData())
|
|
}
|
|
|
|
// MarshalPublicKey converts a public key object into a protobuf serialized
|
|
// public key
|
|
func MarshalPublicKey(k PubKey) ([]byte, error) {
|
|
return k.Bytes()
|
|
}
|
|
|
|
// UnmarshalPrivateKey converts a protobuf serialized private key into its
|
|
// representative object
|
|
func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
|
|
pmes := new(pb.PrivateKey)
|
|
err := proto.Unmarshal(data, pmes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
um, ok := PrivKeyUnmarshallers[pmes.GetType()]
|
|
if !ok {
|
|
return nil, ErrBadKeyType
|
|
}
|
|
|
|
return um(pmes.GetData())
|
|
}
|
|
|
|
// MarshalPrivateKey converts a key object into its protobuf serialized form.
|
|
func MarshalPrivateKey(k PrivKey) ([]byte, error) {
|
|
|
|
switch k.(type) {
|
|
case *Ed25519PrivateKey:
|
|
return k.Bytes()
|
|
case *RsaPrivateKey:
|
|
return k.Bytes()
|
|
case *Secp256k1PrivateKey:
|
|
return k.Bytes()
|
|
default:
|
|
return nil, ErrBadKeyType
|
|
}
|
|
}
|
|
|
|
// ConfigDecodeKey decodes from b64 (for config file), and unmarshals.
|
|
func ConfigDecodeKey(b string) ([]byte, error) {
|
|
return base64.StdEncoding.DecodeString(b)
|
|
}
|
|
|
|
// ConfigEncodeKey encodes to b64 (for config file), and marshals.
|
|
func ConfigEncodeKey(b []byte) string {
|
|
return base64.StdEncoding.EncodeToString(b)
|
|
}
|
|
|
|
// KeyEqual checks whether two
|
|
func KeyEqual(k1, k2 Key) bool {
|
|
if k1 == k2 {
|
|
return true
|
|
}
|
|
|
|
b1, err1 := k1.Bytes()
|
|
b2, err2 := k2.Bytes()
|
|
return bytes.Equal(b1, b2) && err1 == err2
|
|
}
|