package crypto
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"errors"
"io"
"math/big"
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
"github.com/libp2p/go-libp2p/core/internal/catch"
)
type ECDSAPrivateKey struct {
priv *ecdsa .PrivateKey
}
type ECDSAPublicKey struct {
pub *ecdsa .PublicKey
}
type ECDSASig struct {
R, S *big .Int
}
var (
ErrNotECDSAPubKey = errors .New ("not an ecdsa public key" )
ErrNilSig = errors .New ("sig is nil" )
ErrNilPrivateKey = errors .New ("private key is nil" )
ErrNilPublicKey = errors .New ("public key is nil" )
ECDSACurve = elliptic .P256 ()
)
func GenerateECDSAKeyPair (src io .Reader ) (PrivKey , PubKey , error ) {
return GenerateECDSAKeyPairWithCurve (ECDSACurve , src )
}
func GenerateECDSAKeyPairWithCurve (curve elliptic .Curve , src io .Reader ) (PrivKey , PubKey , error ) {
priv , err := ecdsa .GenerateKey (curve , src )
if err != nil {
return nil , nil , err
}
return &ECDSAPrivateKey {priv }, &ECDSAPublicKey {&priv .PublicKey }, nil
}
func ECDSAKeyPairFromKey (priv *ecdsa .PrivateKey ) (PrivKey , PubKey , error ) {
if priv == nil {
return nil , nil , ErrNilPrivateKey
}
return &ECDSAPrivateKey {priv }, &ECDSAPublicKey {&priv .PublicKey }, nil
}
func ECDSAPublicKeyFromPubKey (pub ecdsa .PublicKey ) (PubKey , error ) {
return &ECDSAPublicKey {pub : &pub }, nil
}
func MarshalECDSAPrivateKey (ePriv ECDSAPrivateKey ) (res []byte , err error ) {
defer func () { catch .HandlePanic (recover (), &err , "ECDSA private-key marshal" ) }()
return x509 .MarshalECPrivateKey (ePriv .priv )
}
func MarshalECDSAPublicKey (ePub ECDSAPublicKey ) (res []byte , err error ) {
defer func () { catch .HandlePanic (recover (), &err , "ECDSA public-key marshal" ) }()
return x509 .MarshalPKIXPublicKey (ePub .pub )
}
func UnmarshalECDSAPrivateKey (data []byte ) (res PrivKey , err error ) {
defer func () { catch .HandlePanic (recover (), &err , "ECDSA private-key unmarshal" ) }()
priv , err := x509 .ParseECPrivateKey (data )
if err != nil {
return nil , err
}
return &ECDSAPrivateKey {priv }, nil
}
func UnmarshalECDSAPublicKey (data []byte ) (key PubKey , err error ) {
defer func () { catch .HandlePanic (recover (), &err , "ECDSA public-key unmarshal" ) }()
pubIfc , err := x509 .ParsePKIXPublicKey (data )
if err != nil {
return nil , err
}
pub , ok := pubIfc .(*ecdsa .PublicKey )
if !ok {
return nil , ErrNotECDSAPubKey
}
return &ECDSAPublicKey {pub }, nil
}
func (ePriv *ECDSAPrivateKey ) Type () pb .KeyType {
return pb .KeyType_ECDSA
}
func (ePriv *ECDSAPrivateKey ) Raw () (res []byte , err error ) {
defer func () { catch .HandlePanic (recover (), &err , "ECDSA private-key marshal" ) }()
return x509 .MarshalECPrivateKey (ePriv .priv )
}
func (ePriv *ECDSAPrivateKey ) Equals (o Key ) bool {
return basicEquals (ePriv , o )
}
func (ePriv *ECDSAPrivateKey ) Sign (data []byte ) (sig []byte , err error ) {
defer func () { catch .HandlePanic (recover (), &err , "ECDSA signing" ) }()
hash := sha256 .Sum256 (data )
r , s , err := ecdsa .Sign (rand .Reader , ePriv .priv , hash [:])
if err != nil {
return nil , err
}
return asn1 .Marshal (ECDSASig {
R : r ,
S : s ,
})
}
func (ePriv *ECDSAPrivateKey ) GetPublic () PubKey {
return &ECDSAPublicKey {&ePriv .priv .PublicKey }
}
func (ePub *ECDSAPublicKey ) Type () pb .KeyType {
return pb .KeyType_ECDSA
}
func (ePub *ECDSAPublicKey ) Raw () ([]byte , error ) {
return x509 .MarshalPKIXPublicKey (ePub .pub )
}
func (ePub *ECDSAPublicKey ) Equals (o Key ) bool {
return basicEquals (ePub , o )
}
func (ePub *ECDSAPublicKey ) Verify (data , sigBytes []byte ) (success bool , err error ) {
defer func () {
catch .HandlePanic (recover (), &err , "ECDSA signature verification" )
if err != nil {
success = false
}
}()
sig := new (ECDSASig )
if _ , err := asn1 .Unmarshal (sigBytes , sig ); err != nil {
return false , err
}
hash := sha256 .Sum256 (data )
return ecdsa .Verify (ePub .pub , hash [:], sig .R , sig .S ), nil
}
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 .