Skip to content

Commit 4bfdc4b

Browse files
committed
"bytes", PKCS8/X509 x DER/PEM serialization for every keys
1 parent e15cc22 commit 4bfdc4b

File tree

7 files changed

+400
-14
lines changed

7 files changed

+400
-14
lines changed

verifications/ed25519/VerificationKey2020_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestJsonRoundTrip(t *testing.T) {
2929
require.JSONEq(t, data, string(bytes))
3030
}
3131

32-
func TestSignature(t *testing.T) {
32+
func TestVerify(t *testing.T) {
3333
// test vector from https://datatracker.ietf.org/doc/html/rfc8032#section-7.1
3434

3535
pkHex := "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025"

verifications/ed25519/key.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package ed25519
33
import (
44
"crypto/ed25519"
55
"crypto/rand"
6+
"crypto/x509"
7+
"encoding/pem"
68
"fmt"
79

810
"github.com/INFURA/go-did/verifications/internal"
@@ -27,6 +29,7 @@ func GenerateKeyPair() (PublicKey, PrivateKey, error) {
2729
}
2830

2931
// PublicKeyFromBytes converts a serialized public key to a PublicKey.
32+
// This compact serialization format is the raw key material, without metadata or structure.
3033
// It errors if the slice is not the right size.
3134
func PublicKeyFromBytes(b []byte) (PublicKey, error) {
3235
if len(b) != PublicKeySize {
@@ -37,6 +40,7 @@ func PublicKeyFromBytes(b []byte) (PublicKey, error) {
3740
}
3841

3942
// PublicKeyToBytes converts a public key to a byte slice.
43+
// This compact serialization format is the raw key material, without metadata or structure.
4044
func PublicKeyToBytes(pub PublicKey) []byte {
4145
// Copy the private key to a fixed size buffer that can get allocated on the
4246
// caller's stack after inlining.
@@ -64,7 +68,46 @@ func PublicKeyToMultibase(pub PublicKey) string {
6468
return helpers.MultibaseEncode(MultibaseCode, pub)
6569
}
6670

71+
// PublicKeyFromX509DER decodes an X.509 DER (binary) encoded public key.
72+
func PublicKeyFromX509DER(bytes []byte) (PublicKey, error) {
73+
pub, err := x509.ParsePKIXPublicKey(bytes)
74+
if err != nil {
75+
return nil, err
76+
}
77+
return pub.(PublicKey), nil
78+
}
79+
80+
// PublicKeyToX509DER encodes the public key into the X.509 DER (binary) format.
81+
func PublicKeyToX509DER(pub PublicKey) []byte {
82+
res, _ := x509.MarshalPKIXPublicKey(pub)
83+
return res
84+
}
85+
86+
const pemPubBlockType = "PUBLIC KEY"
87+
88+
// PublicKeyFromX509PEM decodes an X.509 PEM (string) encoded public key.
89+
func PublicKeyFromX509PEM(str string) (PublicKey, error) {
90+
block, _ := pem.Decode([]byte(str))
91+
if block == nil {
92+
return nil, fmt.Errorf("failed to decode PEM block")
93+
}
94+
if block.Type != pemPubBlockType {
95+
return nil, fmt.Errorf("incorrect PEM block type")
96+
}
97+
return PublicKeyFromX509DER(block.Bytes)
98+
}
99+
100+
// PublicKeyToX509PEM encodes the public key into the X.509 PEM (binary) format.
101+
func PublicKeyToX509PEM(pub PublicKey) string {
102+
der := PublicKeyToX509DER(pub)
103+
return string(pem.EncodeToMemory(&pem.Block{
104+
Type: pemPubBlockType,
105+
Bytes: der,
106+
}))
107+
}
108+
67109
// PrivateKeyFromBytes converts a serialized private key to a PrivateKey.
110+
// This compact serialization format is the raw key material, without metadata or structure.
68111
// It errors if the slice is not the right size.
69112
func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
70113
if len(b) != PrivateKeySize {
@@ -75,13 +118,52 @@ func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
75118
}
76119

77120
// PrivateKeyToBytes converts a private key to a byte slice.
121+
// This compact serialization format is the raw key material, without metadata or structure.
78122
func PrivateKeyToBytes(priv PrivateKey) []byte {
79123
// Copy the private key to a fixed size buffer that can get allocated on the
80124
// caller's stack after inlining.
81125
var buf [PrivateKeySize]byte
82126
return append(buf[:0], priv...)
83127
}
84128

129+
// PrivateKeyFromPKCS8DER decodes a PKCS#8 DER (binary) encoded private key.
130+
func PrivateKeyFromPKCS8DER(bytes []byte) (PrivateKey, error) {
131+
priv, err := x509.ParsePKCS8PrivateKey(bytes)
132+
if err != nil {
133+
return nil, err
134+
}
135+
return priv.(PrivateKey), nil
136+
}
137+
138+
// PrivateKeyToPKCS8DER encodes the private key into the PKCS#8 DER (binary) format.
139+
func PrivateKeyToPKCS8DER(priv PrivateKey) []byte {
140+
res, _ := x509.MarshalPKCS8PrivateKey(priv)
141+
return res
142+
}
143+
144+
const pemPrivBlockType = "PRIVATE KEY"
145+
146+
// PrivateKeyFromPKCS8PEM decodes an PKCS#8 PEM (string) encoded private key.
147+
func PrivateKeyFromPKCS8PEM(str string) (PrivateKey, error) {
148+
block, _ := pem.Decode([]byte(str))
149+
if block == nil {
150+
return nil, fmt.Errorf("failed to decode PEM block")
151+
}
152+
if block.Type != pemPrivBlockType {
153+
return nil, fmt.Errorf("incorrect PEM block type")
154+
}
155+
return PrivateKeyFromPKCS8DER(block.Bytes)
156+
}
157+
158+
// PrivateKeyToPKCS8PEM encodes the private key into the PKCS#8 PEM (binary) format.
159+
func PrivateKeyToPKCS8PEM(priv PrivateKey) string {
160+
der := PrivateKeyToPKCS8DER(priv)
161+
return string(pem.EncodeToMemory(&pem.Block{
162+
Type: pemPrivBlockType,
163+
Bytes: der,
164+
}))
165+
}
166+
85167
// Sign signs the message with privateKey and returns a signature.
86168
// It will panic if len(privateKey) is not [PrivateKeySize].
87169
func Sign(privateKey PrivateKey, message []byte) []byte {

verifications/ed25519/key_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ed25519_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/stretchr/testify/require"
@@ -21,11 +22,13 @@ func TestBytesRoundTrip(t *testing.T) {
2122
require.NoError(t, err)
2223

2324
bytes := ed25519.PublicKeyToBytes(pub)
25+
fmt.Println("pub", len(bytes))
2426
rtPub, err := ed25519.PublicKeyFromBytes(bytes)
2527
require.NoError(t, err)
2628
require.True(t, pub.Equal(rtPub))
2729

2830
bytes = ed25519.PrivateKeyToBytes(priv)
31+
fmt.Println("priv", len(bytes))
2932
rtPriv, err := ed25519.PrivateKeyFromBytes(bytes)
3033
require.NoError(t, err)
3134
require.True(t, priv.Equal(rtPriv))
@@ -40,3 +43,47 @@ func TestMultibaseRoundTrip(t *testing.T) {
4043
require.NoError(t, err)
4144
require.Equal(t, pub, rt)
4245
}
46+
47+
func TestPublicKeyX509RoundTrip(t *testing.T) {
48+
pub, _, err := ed25519.GenerateKeyPair()
49+
require.NoError(t, err)
50+
51+
der := ed25519.PublicKeyToX509DER(pub)
52+
fmt.Println("der", len(der))
53+
rt, err := ed25519.PublicKeyFromX509DER(der)
54+
require.NoError(t, err)
55+
require.True(t, pub.Equal(rt))
56+
57+
pem := ed25519.PublicKeyToX509PEM(pub)
58+
fmt.Println("pem", len(pem))
59+
rt, err = ed25519.PublicKeyFromX509PEM(pem)
60+
require.NoError(t, err)
61+
require.True(t, pub.Equal(rt))
62+
}
63+
64+
func TestPrivateKeyPKCS8RoundTrip(t *testing.T) {
65+
pub, priv, err := ed25519.GenerateKeyPair()
66+
require.NoError(t, err)
67+
68+
der := ed25519.PrivateKeyToPKCS8DER(priv)
69+
fmt.Println("der", len(der))
70+
rt, err := ed25519.PrivateKeyFromPKCS8DER(der)
71+
require.NoError(t, err)
72+
require.True(t, priv.Equal(rt))
73+
require.True(t, pub.Equal(rt.Public()))
74+
75+
pem := ed25519.PrivateKeyToPKCS8PEM(priv)
76+
fmt.Println("pem", len(pem))
77+
rt, err = ed25519.PrivateKeyFromPKCS8PEM(pem)
78+
require.NoError(t, err)
79+
require.True(t, priv.Equal(rt))
80+
require.True(t, pub.Equal(rt.Public()))
81+
}
82+
83+
// func TestSignature(t *testing.T) {
84+
// pub, priv, err := ed25519.GenerateKeyPair()
85+
// require.NoError(t, err)
86+
//
87+
// sig := ed25519.Sign(priv, []byte("message"))
88+
//
89+
// }

verifications/p256/key.go

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import (
55
"crypto/elliptic"
66
"crypto/rand"
77
"crypto/x509"
8+
"encoding/pem"
89
"fmt"
10+
"math/big"
911

1012
helpers "github.com/INFURA/go-did/verifications/internal"
1113
)
@@ -15,8 +17,8 @@ type PrivateKey = *ecdsa.PrivateKey
1517

1618
const (
1719
// TODO
18-
PublicKeySize = 123456
19-
PrivateKeySize = 123456
20+
PublicKeySize = 33
21+
PrivateKeySize = 32
2022
SignatureSize = 123456
2123

2224
MultibaseCode = uint64(0x1200)
@@ -31,6 +33,7 @@ func GenerateKeyPair() (PublicKey, PrivateKey, error) {
3133
}
3234

3335
// PublicKeyFromBytes converts a serialized public key to a PublicKey.
36+
// This compact serialization format is the raw key material, without metadata or structure.
3437
// It errors if the slice is not the right size.
3538
func PublicKeyFromBytes(b []byte) (PublicKey, error) {
3639
if len(b) != PublicKeySize {
@@ -41,17 +44,25 @@ func PublicKeyFromBytes(b []byte) (PublicKey, error) {
4144
return nil, fmt.Errorf("invalid P-256 public key")
4245
}
4346
return &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}, nil
47+
48+
// if len(b) != PublicKeySize {
49+
// return nil, fmt.Errorf("invalid P-256 public key size")
50+
// }
51+
// x := new(big.Int).SetBytes(b[:PublicKeySize/2])
52+
// y := new(big.Int).SetBytes(b[PublicKeySize/2:])
53+
// return &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}, nil
4454
}
4555

4656
// PublicKeyToBytes converts a public key to a byte slice.
47-
func PublicKeyToBytes(pub PublicKey) (res []byte, err error) {
48-
defer func() {
49-
if rerr := recover(); rerr != nil {
50-
err = fmt.Errorf("recovered panic: %s", rerr)
51-
res = nil
52-
}
53-
}()
54-
return x509.MarshalPKIXPublicKey(pub)
57+
// This compact serialization format is the raw key material, without metadata or structure.
58+
func PublicKeyToBytes(pub PublicKey) []byte {
59+
return elliptic.MarshalCompressed(elliptic.P256(), pub.X, pub.Y)
60+
61+
// // fixed size buffer that can get allocated on the caller's stack after inlining.
62+
// var buf [PublicKeySize]byte
63+
// pub.X.FillBytes(buf[:PublicKeySize/2])
64+
// pub.Y.FillBytes(buf[PublicKeySize/2:])
65+
// return buf[:]
5566
}
5667

5768
// PublicKeyFromMultibase decodes the public key from its Multibase form
@@ -72,13 +83,106 @@ func PublicKeyToMultibase(pub PublicKey) string {
7283
return helpers.MultibaseEncode(MultibaseCode, bytes)
7384
}
7485

86+
// PublicKeyFromX509DER decodes an X.509 DER (binary) encoded public key.
87+
func PublicKeyFromX509DER(bytes []byte) (PublicKey, error) {
88+
pub, err := x509.ParsePKIXPublicKey(bytes)
89+
if err != nil {
90+
return nil, err
91+
}
92+
return pub.(PublicKey), nil
93+
}
94+
95+
// PublicKeyToX509DER encodes the public key into the X.509 DER (binary) format.
96+
func PublicKeyToX509DER(pub PublicKey) []byte {
97+
res, _ := x509.MarshalPKIXPublicKey(pub)
98+
return res
99+
}
100+
101+
const pemPubBlockType = "PUBLIC KEY"
102+
103+
// PublicKeyFromX509PEM decodes an X.509 PEM (string) encoded public key.
104+
func PublicKeyFromX509PEM(str string) (PublicKey, error) {
105+
block, _ := pem.Decode([]byte(str))
106+
if block == nil {
107+
return nil, fmt.Errorf("failed to decode PEM block")
108+
}
109+
if block.Type != pemPubBlockType {
110+
return nil, fmt.Errorf("incorrect PEM block type")
111+
}
112+
return PublicKeyFromX509DER(block.Bytes)
113+
}
114+
115+
// PublicKeyToX509PEM encodes the public key into the X.509 PEM (binary) format.
116+
func PublicKeyToX509PEM(pub PublicKey) string {
117+
der := PublicKeyToX509DER(pub)
118+
return string(pem.EncodeToMemory(&pem.Block{
119+
Type: pemPubBlockType,
120+
Bytes: der,
121+
}))
122+
}
123+
75124
// PrivateKeyFromBytes converts a serialized public key to a PrivateKey.
125+
// This compact serialization format is the raw key material, without metadata or structure.
76126
// It errors if the slice is not the right size.
77127
func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
78128
if len(b) != PrivateKeySize {
79129
return nil, fmt.Errorf("invalid P-256 private key size")
80130
}
81-
// TODO
82131

83-
return nil, nil
132+
res := &ecdsa.PrivateKey{
133+
D: new(big.Int).SetBytes(b),
134+
PublicKey: ecdsa.PublicKey{Curve: elliptic.P256()},
135+
}
136+
137+
// recompute the public key
138+
res.PublicKey.X, res.PublicKey.Y = res.PublicKey.Curve.ScalarBaseMult(b)
139+
140+
return res, nil
141+
}
142+
143+
// PrivateKeyToBytes converts a private key to a byte slice.
144+
// This compact serialization format is the raw key material, without metadata or structure.
145+
func PrivateKeyToBytes(priv PrivateKey) []byte {
146+
// fixed size buffer that can get allocated on the caller's stack after inlining.
147+
var buf [PrivateKeySize]byte
148+
priv.D.FillBytes(buf[:])
149+
return buf[:]
150+
}
151+
152+
// PrivateKeyFromPKCS8DER decodes a PKCS#8 DER (binary) encoded private key.
153+
func PrivateKeyFromPKCS8DER(bytes []byte) (PrivateKey, error) {
154+
priv, err := x509.ParsePKCS8PrivateKey(bytes)
155+
if err != nil {
156+
return nil, err
157+
}
158+
return priv.(PrivateKey), nil
159+
}
160+
161+
// PrivateKeyToPKCS8DER encodes the private key into the PKCS#8 DER (binary) format.
162+
func PrivateKeyToPKCS8DER(priv PrivateKey) []byte {
163+
res, _ := x509.MarshalPKCS8PrivateKey(priv)
164+
return res
165+
}
166+
167+
const pemPrivBlockType = "PRIVATE KEY"
168+
169+
// PrivateKeyFromPKCS8PEM decodes an PKCS#8 PEM (string) encoded private key.
170+
func PrivateKeyFromPKCS8PEM(str string) (PrivateKey, error) {
171+
block, _ := pem.Decode([]byte(str))
172+
if block == nil {
173+
return nil, fmt.Errorf("failed to decode PEM block")
174+
}
175+
if block.Type != pemPrivBlockType {
176+
return nil, fmt.Errorf("incorrect PEM block type")
177+
}
178+
return PrivateKeyFromPKCS8DER(block.Bytes)
179+
}
180+
181+
// PrivateKeyToPKCS8PEM encodes the private key into the PKCS#8 PEM (binary) format.
182+
func PrivateKeyToPKCS8PEM(priv PrivateKey) string {
183+
der := PrivateKeyToPKCS8DER(priv)
184+
return string(pem.EncodeToMemory(&pem.Block{
185+
Type: pemPrivBlockType,
186+
Bytes: der,
187+
}))
84188
}

0 commit comments

Comments
 (0)