// Package crypto implements various cryptographic utilities used by libp2p. // This includes a Public and Private key interface and key implementations // for supported key algorithms.
package crypto import ( ) const ( // RSA is an enum for the supported RSA key type RSA = iota // Ed25519 is an enum for the supported Ed25519 key type Ed25519 // Secp256k1 is an enum for the supported Secp256k1 key type Secp256k1 // ECDSA is an enum for the supported ECDSA key type ECDSA ) var ( // ErrBadKeyType is returned when a key is not supported ErrBadKeyType = errors.New("invalid or unsupported key type") // KeyTypes is a list of supported keys KeyTypes = []int{ RSA, Ed25519, Secp256k1, ECDSA, } ) // 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) // PubKeyUnmarshallers is a map of unmarshallers by key type var PubKeyUnmarshallers = map[pb.KeyType]PubKeyUnmarshaller{ pb.KeyType_RSA: UnmarshalRsaPublicKey, pb.KeyType_Ed25519: UnmarshalEd25519PublicKey, pb.KeyType_Secp256k1: UnmarshalSecp256k1PublicKey, pb.KeyType_ECDSA: UnmarshalECDSAPublicKey, } // PrivKeyUnmarshallers is a map of unmarshallers by key type var PrivKeyUnmarshallers = map[pb.KeyType]PrivKeyUnmarshaller{ pb.KeyType_RSA: UnmarshalRsaPrivateKey, pb.KeyType_Ed25519: UnmarshalEd25519PrivateKey, pb.KeyType_Secp256k1: UnmarshalSecp256k1PrivateKey, pb.KeyType_ECDSA: UnmarshalECDSAPrivateKey, } // Key represents a crypto key that can be compared to another key type Key interface { // Equals checks whether two PubKeys are the same Equals(Key) bool // Raw returns the raw bytes of the key (not wrapped in the // libp2p-crypto protobuf). // // This function is the inverse of {Priv,Pub}KeyUnmarshaler. Raw() ([]byte, error) // Type returns the protobuf key type. Type() pb.KeyType } // PrivKey represents a private key that can be used to generate a public key and sign data type PrivKey interface { Key // Cryptographically sign the given bytes Sign([]byte) ([]byte, error) // Return a public key paired with this private key GetPublic() PubKey } // PubKey is a public key that can be used to verify data signed with the corresponding private key type PubKey interface { Key // Verify that 'sig' is the signed hash of 'data' Verify(data []byte, sig []byte) (bool, error) } // GenSharedKey generates the shared key from a given private key type GenSharedKey func([]byte) ([]byte, error) // GenerateKeyPair generates a private and public key func (, int) (PrivKey, PubKey, error) { return GenerateKeyPairWithReader(, , rand.Reader) } // GenerateKeyPairWithReader returns a keypair of the given type and bit-size func (, int, io.Reader) (PrivKey, PubKey, error) { switch { case RSA: return GenerateRSAKeyPair(, ) case Ed25519: return GenerateEd25519Key() case Secp256k1: return GenerateSecp256k1Key() case ECDSA: return GenerateECDSAKeyPair() default: return nil, nil, ErrBadKeyType } } // UnmarshalPublicKey converts a protobuf serialized public key into its // representative object func ( []byte) (PubKey, error) { := new(pb.PublicKey) := proto.Unmarshal(, ) if != nil { return nil, } return PublicKeyFromProto() } // PublicKeyFromProto converts an unserialized protobuf PublicKey message // into its representative object. func ( *pb.PublicKey) (PubKey, error) { , := PubKeyUnmarshallers[.GetType()] if ! { return nil, ErrBadKeyType } := .GetData() , := () if != nil { return nil, } switch tpk := .(type) { case *RsaPublicKey: .cached, _ = proto.Marshal() } return , nil } // MarshalPublicKey converts a public key object into a protobuf serialized // public key func ( PubKey) ([]byte, error) { , := PublicKeyToProto() if != nil { return nil, } return proto.Marshal() } // PublicKeyToProto converts a public key object into an unserialized // protobuf PublicKey message. func ( PubKey) (*pb.PublicKey, error) { , := .Raw() if != nil { return nil, } return &pb.PublicKey{ Type: .Type().Enum(), Data: , }, nil } // UnmarshalPrivateKey converts a protobuf serialized private key into its // representative object func ( []byte) (PrivKey, error) { := new(pb.PrivateKey) := proto.Unmarshal(, ) if != nil { return nil, } , := PrivKeyUnmarshallers[.GetType()] if ! { return nil, ErrBadKeyType } return (.GetData()) } // MarshalPrivateKey converts a key object into its protobuf serialized form. func ( PrivKey) ([]byte, error) { , := .Raw() if != nil { return nil, } return proto.Marshal(&pb.PrivateKey{ Type: .Type().Enum(), Data: , }) } // ConfigDecodeKey decodes from b64 (for config file) to a byte array that can be unmarshalled. func ( string) ([]byte, error) { return base64.StdEncoding.DecodeString() } // ConfigEncodeKey encodes a marshalled key to b64 (for config file). func ( []byte) string { return base64.StdEncoding.EncodeToString() } // KeyEqual checks whether two Keys are equivalent (have identical byte representations). func (, Key) bool { if == { return true } return .Equals() } func basicEquals(, Key) bool { if .Type() != .Type() { return false } , := .Raw() if != nil { return false } , := .Raw() if != nil { return false } return subtle.ConstantTimeCompare(, ) == 1 }