feat(did): strengthen DID crypto
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -84,6 +86,8 @@ func GenerateECDSAWithCurve(code multicodec.Code) (crypto.PrivKey, DID, error) {
|
||||
|
||||
}
|
||||
|
||||
// FromPrivKey is a convenience function that returns the DID associated
|
||||
// with the public key associated with the provided private key.
|
||||
func FromPrivKey(privKey crypto.PrivKey) (DID, error) {
|
||||
return FromPubKey(privKey.GetPublic())
|
||||
}
|
||||
@@ -117,17 +121,53 @@ func FromPubKey(pubKey crypto.PubKey) (DID, error) {
|
||||
}
|
||||
}
|
||||
|
||||
pubBytes, err := pubKey.Raw()
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
var bytes []byte
|
||||
|
||||
switch pubKey.Type() {
|
||||
case pb.KeyType_ECDSA:
|
||||
pkix, err := pubKey.Raw()
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
|
||||
publicKey, err := x509.ParsePKIXPublicKey(pkix)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
|
||||
ecdsaPublicKey := publicKey.(*ecdsa.PublicKey)
|
||||
|
||||
bytes = elliptic.MarshalCompressed(ecdsaPublicKey.Curve, ecdsaPublicKey.X, ecdsaPublicKey.Y)
|
||||
case pb.KeyType_Ed25519, pb.KeyType_Secp256k1:
|
||||
var err error
|
||||
|
||||
if bytes, err = pubKey.Raw(); err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
case pb.KeyType_RSA:
|
||||
var err error
|
||||
|
||||
pkix, err := pubKey.Raw()
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
|
||||
publicKey, err := x509.ParsePKIXPublicKey(pkix)
|
||||
if err != nil {
|
||||
return Undef, err
|
||||
}
|
||||
|
||||
bytes = x509.MarshalPKCS1PublicKey(publicKey.(*rsa.PublicKey))
|
||||
}
|
||||
|
||||
return DID{
|
||||
code: code,
|
||||
bytes: string(append(varint.ToUvarint(uint64(code)), pubBytes...)),
|
||||
bytes: string(append(varint.ToUvarint(uint64(code)), bytes...)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToPubKey returns the crypto.PubKey encapsulated in the DID formed by
|
||||
// parsing the provided string.
|
||||
func ToPubKey(s string) (crypto.PubKey, error) {
|
||||
id, err := Parse(s)
|
||||
if err != nil {
|
||||
|
||||
@@ -27,6 +27,10 @@ func TestFromPubKey(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
_, ecdsaP521, err := crypto.GenerateECDSAKeyPairWithCurve(elliptic.P521(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
_, ed25519, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
require.NoError(t, err)
|
||||
_, rsa, err := crypto.GenerateRSAKeyPair(2048, rand.Reader)
|
||||
require.NoError(t, err)
|
||||
_, secp256k1PubKey1, err := crypto.GenerateSecp256k1Key(rand.Reader)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -47,7 +51,9 @@ func TestFromPubKey(t *testing.T) {
|
||||
t.Run("ECDSA with P256 curve", test(ecdsaP256, did.P256))
|
||||
t.Run("ECDSA with P384 curve", test(ecdsaP384, did.P384))
|
||||
t.Run("ECDSA with P521 curve", test(ecdsaP521, did.P521))
|
||||
t.Run("With secp256k1 (secp256k1)", test(secp256k1PubKey1, did.Secp256k1))
|
||||
t.Run("Ed25519", test(ed25519, did.Ed25519))
|
||||
t.Run("RSA", test(rsa, did.RSA))
|
||||
t.Run("secp256k1", test(secp256k1PubKey1, did.Secp256k1))
|
||||
|
||||
id, err := did.FromPubKey(examplePubKey(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
51
did/did.go
51
did/did.go
@@ -1,6 +1,9 @@
|
||||
package did
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -34,6 +37,10 @@ type DID struct {
|
||||
bytes string // as string instead of []byte to allow the == operator
|
||||
}
|
||||
|
||||
// Parse returns the DID from the string representation or an error if
|
||||
// the prefix and method are incorrect, if an unknown encryption algorithm
|
||||
// is specified or if the method-specific-identifier's bytes don't
|
||||
// represent a public key for the specified encryption algorithm.
|
||||
func Parse(str string) (DID, error) {
|
||||
const keyPrefix = "did:key:"
|
||||
|
||||
@@ -60,6 +67,7 @@ func Parse(str string) (DID, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics instead of returning an error.
|
||||
func MustParse(str string) DID {
|
||||
did, err := Parse(str)
|
||||
if err != nil {
|
||||
@@ -73,16 +81,16 @@ func (d DID) Defined() bool {
|
||||
return d.code == 0 || len(d.bytes) > 0
|
||||
}
|
||||
|
||||
// PubKey returns the public key encapsulated in the did:key.
|
||||
// PubKey returns the public key encapsulated by the did:key.
|
||||
func (d DID) PubKey() (crypto.PubKey, error) {
|
||||
unmarshaler, ok := map[multicodec.Code]crypto.PubKeyUnmarshaller{
|
||||
X25519: crypto.UnmarshalEd25519PublicKey,
|
||||
Ed25519: crypto.UnmarshalEd25519PublicKey,
|
||||
P256: crypto.UnmarshalECDSAPublicKey,
|
||||
P384: crypto.UnmarshalECDSAPublicKey,
|
||||
P521: crypto.UnmarshalECDSAPublicKey,
|
||||
P256: ecdsaPubKeyUnmarshaler(elliptic.P256()),
|
||||
P384: ecdsaPubKeyUnmarshaler(elliptic.P384()),
|
||||
P521: ecdsaPubKeyUnmarshaler(elliptic.P521()),
|
||||
Secp256k1: crypto.UnmarshalSecp256k1PublicKey,
|
||||
RSA: crypto.UnmarshalRsaPublicKey,
|
||||
RSA: rsaPubKeyUnmarshaller,
|
||||
}[d.code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported multicodec: %d", d.code)
|
||||
@@ -97,3 +105,36 @@ func (d DID) String() string {
|
||||
key, _ := mbase.Encode(mbase.Base58BTC, []byte(d.bytes))
|
||||
return "did:key:" + key
|
||||
}
|
||||
|
||||
func ecdsaPubKeyUnmarshaler(curve elliptic.Curve) crypto.PubKeyUnmarshaller {
|
||||
return func(data []byte) (crypto.PubKey, error) {
|
||||
x, y := elliptic.UnmarshalCompressed(curve, data)
|
||||
|
||||
ecdsaPublicKey := &ecdsa.PublicKey{
|
||||
Curve: curve,
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
|
||||
pkix, err := x509.MarshalPKIXPublicKey(ecdsaPublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return crypto.UnmarshalECDSAPublicKey(pkix)
|
||||
}
|
||||
}
|
||||
|
||||
func rsaPubKeyUnmarshaller(data []byte) (crypto.PubKey, error) {
|
||||
rsaPublicKey, err := x509.ParsePKCS1PublicKey(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkix, err := x509.MarshalPKIXPublicKey(rsaPublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return crypto.UnmarshalRsaPublicKey(pkix)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user