package crypto
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"io"
"github.com/libp2p/go-libp2p/core/crypto/pb"
"google.golang.org/protobuf/proto"
)
const (
RSA = iota
Ed25519
Secp256k1
ECDSA
)
var (
ErrBadKeyType = errors .New ("invalid or unsupported key type" )
KeyTypes = []int {
RSA ,
Ed25519 ,
Secp256k1 ,
ECDSA ,
}
)
type PubKeyUnmarshaller func (data []byte ) (PubKey , error )
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 ,
pb .KeyType_ECDSA : UnmarshalECDSAPublicKey ,
}
var PrivKeyUnmarshallers = map [pb .KeyType ]PrivKeyUnmarshaller {
pb .KeyType_RSA : UnmarshalRsaPrivateKey ,
pb .KeyType_Ed25519 : UnmarshalEd25519PrivateKey ,
pb .KeyType_Secp256k1 : UnmarshalSecp256k1PrivateKey ,
pb .KeyType_ECDSA : UnmarshalECDSAPrivateKey ,
}
type Key interface {
Equals (Key ) bool
Raw () ([]byte , error )
Type () pb .KeyType
}
type PrivKey interface {
Key
Sign ([]byte ) ([]byte , error )
GetPublic () PubKey
}
type PubKey interface {
Key
Verify (data []byte , sig []byte ) (bool , error )
}
type GenSharedKey func ([]byte ) ([]byte , error )
func GenerateKeyPair (typ , bits int ) (PrivKey , PubKey , error ) {
return GenerateKeyPairWithReader (typ , bits , rand .Reader )
}
func GenerateKeyPairWithReader (typ , bits int , src io .Reader ) (PrivKey , PubKey , error ) {
switch typ {
case RSA :
return GenerateRSAKeyPair (bits , src )
case Ed25519 :
return GenerateEd25519Key (src )
case Secp256k1 :
return GenerateSecp256k1Key (src )
case ECDSA :
return GenerateECDSAKeyPair (src )
default :
return nil , nil , ErrBadKeyType
}
}
func UnmarshalPublicKey (data []byte ) (PubKey , error ) {
pmes := new (pb .PublicKey )
err := proto .Unmarshal (data , pmes )
if err != nil {
return nil , err
}
return PublicKeyFromProto (pmes )
}
func PublicKeyFromProto (pmes *pb .PublicKey ) (PubKey , error ) {
um , ok := PubKeyUnmarshallers [pmes .GetType ()]
if !ok {
return nil , ErrBadKeyType
}
data := pmes .GetData ()
pk , err := um (data )
if err != nil {
return nil , err
}
switch tpk := pk .(type ) {
case *RsaPublicKey :
tpk .cached , _ = proto .Marshal (pmes )
}
return pk , nil
}
func MarshalPublicKey (k PubKey ) ([]byte , error ) {
pbmes , err := PublicKeyToProto (k )
if err != nil {
return nil , err
}
return proto .Marshal (pbmes )
}
func PublicKeyToProto (k PubKey ) (*pb .PublicKey , error ) {
data , err := k .Raw ()
if err != nil {
return nil , err
}
return &pb .PublicKey {
Type : k .Type ().Enum (),
Data : data ,
}, nil
}
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 ())
}
func MarshalPrivateKey (k PrivKey ) ([]byte , error ) {
data , err := k .Raw ()
if err != nil {
return nil , err
}
return proto .Marshal (&pb .PrivateKey {
Type : k .Type ().Enum (),
Data : data ,
})
}
func ConfigDecodeKey (b string ) ([]byte , error ) {
return base64 .StdEncoding .DecodeString (b )
}
func ConfigEncodeKey (b []byte ) string {
return base64 .StdEncoding .EncodeToString (b )
}
func KeyEqual (k1 , k2 Key ) bool {
if k1 == k2 {
return true
}
return k1 .Equals (k2 )
}
func basicEquals(k1 , k2 Key ) bool {
if k1 .Type () != k2 .Type () {
return false
}
a , err := k1 .Raw ()
if err != nil {
return false
}
b , err := k2 .Raw ()
if err != nil {
return false
}
return subtle .ConstantTimeCompare (a , b ) == 1
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .