crypto: finish RSA
This commit is contained in:
@@ -190,16 +190,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
|
||||
pub, priv, err := harness.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
spub, ok := (crypto.PublicKey(pub)).(crypto.PublicKeySigning)
|
||||
if !ok {
|
||||
t.Skip("Signature is not implemented")
|
||||
}
|
||||
spriv, ok := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
|
||||
if !ok {
|
||||
t.Skip("Signature is not implemented")
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
type testcase struct {
|
||||
name string
|
||||
signer func(msg []byte, opts ...crypto.SigningOption) ([]byte, error)
|
||||
verifier func(msg []byte, sig []byte, opts ...crypto.SigningOption) bool
|
||||
@@ -207,25 +198,43 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
|
||||
stats *int
|
||||
defaultHash crypto.Hash
|
||||
otherHashes []crypto.Hash
|
||||
}{
|
||||
{
|
||||
name: "Bytes signature",
|
||||
signer: spriv.SignToBytes,
|
||||
verifier: spub.VerifyBytes,
|
||||
expectedSize: harness.SignatureBytesSize,
|
||||
stats: &stats.sigRawSize,
|
||||
defaultHash: harness.DefaultHash,
|
||||
otherHashes: harness.OtherHashes,
|
||||
},
|
||||
{
|
||||
name: "ASN.1 signature",
|
||||
signer: spriv.SignToASN1,
|
||||
verifier: spub.VerifyASN1,
|
||||
stats: &stats.sigAsn1Size,
|
||||
defaultHash: harness.DefaultHash,
|
||||
otherHashes: harness.OtherHashes,
|
||||
},
|
||||
} {
|
||||
}
|
||||
var tcs []testcase
|
||||
|
||||
if pubImplements[PubT, crypto.PublicKeySigningBytes]() {
|
||||
t.Run("Bytes signature", func(t *testing.T) {
|
||||
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningBytes)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes)
|
||||
|
||||
tcs = append(tcs, testcase{
|
||||
name: "Bytes signature",
|
||||
signer: spriv.SignToBytes,
|
||||
verifier: spub.VerifyBytes,
|
||||
expectedSize: harness.SignatureBytesSize,
|
||||
stats: &stats.sigRawSize,
|
||||
defaultHash: harness.DefaultHash,
|
||||
otherHashes: harness.OtherHashes,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if pubImplements[PubT, crypto.PublicKeySigningASN1]() {
|
||||
t.Run("ASN.1 signature", func(t *testing.T) {
|
||||
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningASN1)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningASN1)
|
||||
|
||||
tcs = append(tcs, testcase{
|
||||
name: "ASN.1 signature",
|
||||
signer: spriv.SignToASN1,
|
||||
verifier: spub.VerifyASN1,
|
||||
stats: &stats.sigAsn1Size,
|
||||
defaultHash: harness.DefaultHash,
|
||||
otherHashes: harness.OtherHashes,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
msg := []byte("message")
|
||||
|
||||
@@ -455,15 +464,15 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
|
||||
})
|
||||
|
||||
b.Run("Signatures", func(b *testing.B) {
|
||||
if !pubImplements[PubT, crypto.PublicKeySigning]() {
|
||||
b.Skip("Signature is not implemented")
|
||||
}
|
||||
|
||||
b.Run("Sign to Bytes signature", func(b *testing.B) {
|
||||
if !pubImplements[PubT, crypto.PublicKeySigningBytes]() {
|
||||
b.Skip("Signature to bytes is not implemented")
|
||||
}
|
||||
|
||||
_, priv, err := harness.GenerateKeyPair()
|
||||
require.NoError(b, err)
|
||||
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
@@ -474,11 +483,15 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
|
||||
})
|
||||
|
||||
b.Run("Verify from Bytes signature", func(b *testing.B) {
|
||||
if !pubImplements[PubT, crypto.PublicKeySigningBytes]() {
|
||||
b.Skip("Signature to bytes is not implemented")
|
||||
}
|
||||
|
||||
pub, priv, err := harness.GenerateKeyPair()
|
||||
require.NoError(b, err)
|
||||
|
||||
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigning)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
|
||||
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningBytes)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes)
|
||||
sig, err := spriv.SignToBytes([]byte("message"))
|
||||
require.NoError(b, err)
|
||||
|
||||
@@ -491,10 +504,14 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
|
||||
})
|
||||
|
||||
b.Run("Sign to ASN.1 signature", func(b *testing.B) {
|
||||
if !pubImplements[PubT, crypto.PublicKeySigningASN1]() {
|
||||
b.Skip("Signature to ASN.1 is not implemented")
|
||||
}
|
||||
|
||||
_, priv, err := harness.GenerateKeyPair()
|
||||
require.NoError(b, err)
|
||||
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningASN1)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
@@ -505,11 +522,15 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
|
||||
})
|
||||
|
||||
b.Run("Verify from ASN.1 signature", func(b *testing.B) {
|
||||
if !pubImplements[PubT, crypto.PublicKeySigningASN1]() {
|
||||
b.Skip("Signature to ASN.1 is not implemented")
|
||||
}
|
||||
|
||||
pub, priv, err := harness.GenerateKeyPair()
|
||||
require.NoError(b, err)
|
||||
|
||||
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigning)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
|
||||
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningASN1)
|
||||
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningASN1)
|
||||
sig, err := spriv.SignToASN1([]byte("message"))
|
||||
require.NoError(b, err)
|
||||
|
||||
@@ -524,7 +545,7 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
|
||||
|
||||
b.Run("Key exchange", func(b *testing.B) {
|
||||
if !privImplements[PrivT, crypto.PrivateKeyKeyExchange]() {
|
||||
b.Skip("Key echange is not implemented")
|
||||
b.Skip("Key exchange is not implemented")
|
||||
}
|
||||
|
||||
b.Run("KeyExchange", func(b *testing.B) {
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.PrivateKeySigning = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
|
||||
|
||||
type PrivateKey struct {
|
||||
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
"github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKeySigning = PublicKey{}
|
||||
var _ crypto.PublicKeySigningBytes = PublicKey{}
|
||||
var _ crypto.PublicKeySigningASN1 = PublicKey{}
|
||||
var _ crypto.PublicKeyToBytes = PublicKey{}
|
||||
|
||||
type PublicKey struct {
|
||||
|
||||
@@ -26,13 +26,17 @@ type PublicKeyToBytes interface {
|
||||
ToBytes() []byte
|
||||
}
|
||||
|
||||
type PublicKeySigning interface {
|
||||
type PublicKeySigningBytes interface {
|
||||
PublicKey
|
||||
|
||||
// VerifyBytes checks a signature in the "raw bytes" format.
|
||||
// This format can make some assumptions and may not be what you expect.
|
||||
// Ideally, this format is defined by the same specification as the underlying crypto scheme.
|
||||
VerifyBytes(message, signature []byte, opts ...SigningOption) bool
|
||||
}
|
||||
|
||||
type PublicKeySigningASN1 interface {
|
||||
PublicKey
|
||||
|
||||
// VerifyASN1 checks a signature in the ASN.1 format.
|
||||
VerifyASN1(message, signature []byte, opts ...SigningOption) bool
|
||||
@@ -63,13 +67,17 @@ type PrivateKeyToBytes interface {
|
||||
ToBytes() []byte
|
||||
}
|
||||
|
||||
type PrivateKeySigning interface {
|
||||
type PrivateKeySigningBytes interface {
|
||||
PrivateKey
|
||||
|
||||
// SignToBytes creates a signature in the "raw bytes" format.
|
||||
// This format can make some assumptions and may not be what you expect.
|
||||
// Ideally, this format is defined by the same specification as the underlying crypto scheme.
|
||||
SignToBytes(message []byte, opts ...SigningOption) ([]byte, error)
|
||||
}
|
||||
|
||||
type PrivateKeySigningASN1 interface {
|
||||
PrivateKey
|
||||
|
||||
// SignToASN1 creates a signature in the ASN.1 format.
|
||||
SignToASN1(message []byte, opts ...SigningOption) ([]byte, error)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package p256
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/_testsuite"
|
||||
)
|
||||
@@ -32,3 +35,25 @@ func TestSuite(t *testing.T) {
|
||||
func BenchmarkSuite(b *testing.B) {
|
||||
testsuite.BenchSuite(b, harness)
|
||||
}
|
||||
|
||||
func TestSignatureASN1(t *testing.T) {
|
||||
// openssl ecparam -genkey -name prime256v1 -noout -out private.pem
|
||||
// openssl ec -in private.pem -pubout -out public.pem
|
||||
// echo -n "message" | openssl dgst -sha256 -sign private.pem -out signature.der
|
||||
// echo -n "message" | openssl dgst -sha256 -verify public.pem -signature signature.der
|
||||
|
||||
pubPem := `-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+UhEHZqcaKn+qhNtMmW843ZTRkX/
|
||||
6GzxOWoRD2nv3EewARM90akj2UAKwQjJR9ibm78XtdlryvWG1v8TWb8INA==
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
pub, err := PublicKeyFromX509PEM(pubPem)
|
||||
require.NoError(t, err)
|
||||
|
||||
b64sig := `MEQCIHPslthrLAYgwfqYaUmtGJqwmH7sRf5FEnnKgzcHIF8fAiB9+qovdvN6yJKkBwoQCw798uWr
|
||||
0nOUE55ftB8EgX/Jbg==`
|
||||
sig, err := base64.StdEncoding.DecodeString(b64sig)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, pub.VerifyASN1([]byte("message"), sig))
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.PrivateKeySigning = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKeySigning = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningBytes = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningASN1 = &PublicKey{}
|
||||
var _ crypto.PublicKeyToBytes = &PublicKey{}
|
||||
|
||||
type PublicKey struct {
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.PrivateKeySigning = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKeySigning = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningBytes = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningASN1 = &PublicKey{}
|
||||
var _ crypto.PublicKeyToBytes = &PublicKey{}
|
||||
|
||||
type PublicKey struct {
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.PrivateKeySigning = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKeySigning = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningBytes = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningASN1 = &PublicKey{}
|
||||
var _ crypto.PublicKeyToBytes = &PublicKey{}
|
||||
|
||||
type PublicKey struct {
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,3 +30,14 @@ const (
|
||||
pemPubBlockType = "PUBLIC KEY"
|
||||
pemPrivBlockType = "PRIVATE KEY"
|
||||
)
|
||||
|
||||
func defaultSigHash(keyLen int) crypto.Hash {
|
||||
switch {
|
||||
case keyLen <= 2048:
|
||||
return crypto.SHA256
|
||||
case keyLen <= 3072:
|
||||
return crypto.SHA384
|
||||
default:
|
||||
return crypto.SHA512
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package rsa
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/_testsuite"
|
||||
)
|
||||
|
||||
var harness = testsuite.TestHarness[*PublicKey, *PrivateKey]{
|
||||
var harness2048 = testsuite.TestHarness[*PublicKey, *PrivateKey]{
|
||||
Name: "rsa-2048",
|
||||
GenerateKeyPair: func() (*PublicKey, *PrivateKey, error) { return GenerateKeyPair(2048) },
|
||||
PublicKeyFromPublicKeyMultibase: PublicKeyFromPublicKeyMultibase,
|
||||
@@ -17,15 +19,58 @@ var harness = testsuite.TestHarness[*PublicKey, *PrivateKey]{
|
||||
PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER,
|
||||
PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM,
|
||||
MultibaseCode: MultibaseCode,
|
||||
SignatureBytesSize: 123456,
|
||||
DefaultHash: crypto.SHA256,
|
||||
OtherHashes: []crypto.Hash{crypto.SHA384, crypto.SHA512},
|
||||
}
|
||||
|
||||
func TestSuite(t *testing.T) {
|
||||
testsuite.TestSuite(t, harness)
|
||||
var harness3072 = testsuite.TestHarness[*PublicKey, *PrivateKey]{
|
||||
Name: "rsa-3072",
|
||||
GenerateKeyPair: func() (*PublicKey, *PrivateKey, error) { return GenerateKeyPair(3072) },
|
||||
PublicKeyFromPublicKeyMultibase: PublicKeyFromPublicKeyMultibase,
|
||||
PublicKeyFromX509DER: PublicKeyFromX509DER,
|
||||
PublicKeyFromX509PEM: PublicKeyFromX509PEM,
|
||||
PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER,
|
||||
PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM,
|
||||
MultibaseCode: MultibaseCode,
|
||||
DefaultHash: crypto.SHA384,
|
||||
OtherHashes: []crypto.Hash{crypto.SHA512},
|
||||
}
|
||||
|
||||
func BenchmarkSuite(b *testing.B) {
|
||||
testsuite.BenchSuite(b, harness)
|
||||
var harness4096 = testsuite.TestHarness[*PublicKey, *PrivateKey]{
|
||||
Name: "rsa-4096",
|
||||
GenerateKeyPair: func() (*PublicKey, *PrivateKey, error) { return GenerateKeyPair(4096) },
|
||||
PublicKeyFromPublicKeyMultibase: PublicKeyFromPublicKeyMultibase,
|
||||
PublicKeyFromX509DER: PublicKeyFromX509DER,
|
||||
PublicKeyFromX509PEM: PublicKeyFromX509PEM,
|
||||
PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER,
|
||||
PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM,
|
||||
MultibaseCode: MultibaseCode,
|
||||
DefaultHash: crypto.SHA512,
|
||||
OtherHashes: []crypto.Hash{},
|
||||
}
|
||||
|
||||
func TestSuite2048(t *testing.T) {
|
||||
testsuite.TestSuite(t, harness2048)
|
||||
}
|
||||
|
||||
func TestSuite3072(t *testing.T) {
|
||||
testsuite.TestSuite(t, harness3072)
|
||||
}
|
||||
|
||||
func TestSuite4096(t *testing.T) {
|
||||
testsuite.TestSuite(t, harness4096)
|
||||
}
|
||||
|
||||
func BenchmarkSuite2048(b *testing.B) {
|
||||
testsuite.BenchSuite(b, harness2048)
|
||||
}
|
||||
|
||||
func BenchmarkSuite3072(b *testing.B) {
|
||||
testsuite.BenchSuite(b, harness3072)
|
||||
}
|
||||
|
||||
func BenchmarkSuite4096(b *testing.B) {
|
||||
testsuite.BenchSuite(b, harness4096)
|
||||
}
|
||||
|
||||
func TestPublicKeyX509(t *testing.T) {
|
||||
@@ -87,3 +132,33 @@ XnARctVkIcUYORcYwvuu9meDkw==
|
||||
rt := priv.ToPKCS8PEM()
|
||||
require.Equal(t, pem, rt)
|
||||
}
|
||||
|
||||
func TestSignatureASN1(t *testing.T) {
|
||||
// openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
|
||||
// openssl pkey -in private.pem -pubout -out public.pem
|
||||
// echo -n "message" | openssl dgst -sha256 -sign private.pem -out signature.der
|
||||
// echo -n "message" | openssl dgst -sha256 -verify public.pem -signature signature.der
|
||||
|
||||
pubPem := `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtKXCTkUDcKbZGsEEUTo
|
||||
16xblCyh6zmA8pXVGgmC66QiTNdKzxdwTykXTDs9sEre9ea34h2M7dwrA1weAmBu
|
||||
grAXe0QmIXIqjFKRKdfty09yWVtKF7FGwEMlhKftWC225R+tRuLwbKG4cCSzHxcf
|
||||
JfqCYqGDM7BrF39ilQzFYw5sUiWn3ppRPWa2oEV3cw19zFnHMbEHIQIdFyCcIv5x
|
||||
GUSJ6sJVp0YvsODsZbA+Zyb2UMRfXD8fDHm9bJQCY0x/wGJLfvJmWtZLciwc145U
|
||||
BN3SezY30NviZtZBKWjXgb6gL69L94U10/8ghmA30DY7bKs4+/7R2nOw91CO4rCo
|
||||
1QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
pub, err := PublicKeyFromX509PEM(pubPem)
|
||||
require.NoError(t, err)
|
||||
|
||||
b64sig := `BdvBkZWxIVE2mfM48H1WlOs3k9NzyS4oUxAMOZWNNTYDU6+DLbhZ7Hnt3rRKX3m6f1cX5DCsHcPC
|
||||
6sNtsR8Xp9u09GWCN/K28fF7Pcl0E87MdhAUL7jKNK5bb1XWx/GCUmoKXRZiR/gA10iB2Lmjd1MC
|
||||
HItTCig91gmFm5PO67u9yM+cqE2nGyOh13/kT5Np9MUyaE9dkjoQGum23Ta6m7v0atWsPhO5aVVI
|
||||
76vLwGhYAhQe22RxBlPRXyRInr0EnVgHQOe211o//erPZYQAm+N1kK+yjV8NbPxJX+r5sYUE19NL
|
||||
MCB+kOgWk51uJwuiuHlffGMBPxku/t+skxI7Bw==`
|
||||
sig, err := base64.StdEncoding.DecodeString(b64sig)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, pub.VerifyASN1([]byte("message"), sig))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package rsa
|
||||
|
||||
import (
|
||||
stdcrypto "crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
@@ -10,7 +12,7 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.PrivateKeySigning = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
|
||||
|
||||
type PrivateKey struct {
|
||||
k *rsa.PrivateKey
|
||||
@@ -148,34 +150,18 @@ func (p *PrivateKey) ToPKCS8PEM() string {
|
||||
}))
|
||||
}
|
||||
|
||||
func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
// SignToASN1 produce a PKCS#1 v1.5 signature.
|
||||
// The default signing hash is:
|
||||
// - SHA-256 for keys of length 2048 bits and under
|
||||
// - SHA-384 for keys of length 3072 bits and under
|
||||
// - SHA-512 for higher key length
|
||||
func (p *PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
params := crypto.CollectSigningOptions(opts)
|
||||
|
||||
// func (p *PrivateKey) PublicKeyIsCompatible(remote crypto.PublicKey) bool {
|
||||
// if _, ok := remote.(*PublicKey); ok {
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// func (p *PrivateKey) KeyExchange(remote crypto.PublicKey) ([]byte, error) {
|
||||
// if remote, ok := remote.(*PublicKey); ok {
|
||||
// // First, we need to convert the ECDSA (signing only) to the equivalent ECDH keys
|
||||
// ecdhPriv, err := p.k.ECDH()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// ecdhPub, err := remote.k.ECDH()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return ecdhPriv.ECDH(ecdhPub)
|
||||
// }
|
||||
// return nil, fmt.Errorf("incompatible public key")
|
||||
// }
|
||||
hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen()))
|
||||
hasher := hashCode.New()
|
||||
hasher.Write(message)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
return rsa.SignPKCS1v15(rand.Reader, p.k, stdcrypto.Hash(hashCode), hash)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package rsa
|
||||
|
||||
import (
|
||||
stdcrypto "crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKeySigning = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningASN1 = &PublicKey{}
|
||||
|
||||
type PublicKey struct {
|
||||
k *rsa.PublicKey
|
||||
@@ -125,10 +126,19 @@ func (p *PublicKey) ToX509PEM() string {
|
||||
}))
|
||||
}
|
||||
|
||||
func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// VerifyASN1 verifies a PKCS#1 v1.5 signature.
|
||||
// The default signing hash is:
|
||||
// - SHA-256 for keys of length 2048 bits and under
|
||||
// - SHA-384 for keys of length 3072 bits and under
|
||||
// - SHA-512 for higher key length
|
||||
func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
|
||||
return false
|
||||
params := crypto.CollectSigningOptions(opts)
|
||||
|
||||
hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen()))
|
||||
hasher := hashCode.New()
|
||||
hasher.Write(message)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
err := rsa.VerifyPKCS1v15(p.k, stdcrypto.Hash(hashCode), hash, signature)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const (
|
||||
// PrivateKeyBytesSize is the size, in bytes, of private keys in raw bytes.
|
||||
PrivateKeyBytesSize = secp256k1.PrivKeyBytesLen
|
||||
// SignatureBytesSize is the size, in bytes, of signatures in raw bytes.
|
||||
SignatureBytesSize = 123456
|
||||
SignatureBytesSize = 64
|
||||
|
||||
MultibaseCode = uint64(0xe7)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package secp256k1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -80,3 +81,25 @@ Uwyag4V8qWsP8e5ZSOOXDSYMplwbsAzsko9NYw4Jy9RHYHwFQ7dV
|
||||
_, _ = PrivateKeyFromPKCS8PEM(data)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSignatureASN1(t *testing.T) {
|
||||
// openssl ecparam -genkey -name secp256k1 -noout -out private.pem
|
||||
// openssl ec -in private.pem -pubout -out public.pem
|
||||
// echo -n "message" | openssl dgst -sha256 -sign private.pem -out signature.der
|
||||
// echo -n "message" | openssl dgst -sha256 -verify public.pem -signature signature.der
|
||||
|
||||
pubPem := `-----BEGIN PUBLIC KEY-----
|
||||
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEszL1+ZFqUMAHjLAyzMW7xMBPZek/8cNj
|
||||
1qI7EgQooB3f8Sh7JwvXu8cosRnjjvYVvS7OliRsbvuceCQ7HBC4fA==
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
pub, err := PublicKeyFromX509PEM(pubPem)
|
||||
require.NoError(t, err)
|
||||
|
||||
b64sig := `MEYCIQDv5SLy768FbOafzDlrxIeeoEn7tKpYBSK6WcKaOZ6AJAIhAKXV6VAwiPq4uk9TpGyFN5JK
|
||||
8jZPrQ7hdRR5veKKDX2w`
|
||||
sig, err := base64.StdEncoding.DecodeString(b64sig)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, pub.VerifyASN1([]byte("message"), sig))
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.PrivateKeySigning = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningBytes = &PrivateKey{}
|
||||
var _ crypto.PrivateKeySigningASN1 = &PrivateKey{}
|
||||
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
|
||||
|
||||
type PrivateKey struct {
|
||||
@@ -179,17 +180,28 @@ func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) (
|
||||
hasher.Write(message)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
// TODO
|
||||
return ecdsa.SignCompact(p.k, hash[:], false), nil
|
||||
sig := ecdsa.Sign(p.k, hash)
|
||||
r := sig.R()
|
||||
s := sig.S()
|
||||
|
||||
res := make([]byte, SignatureBytesSize)
|
||||
r.PutBytesUnchecked(res[:SignatureBytesSize/2])
|
||||
s.PutBytesUnchecked(res[SignatureBytesSize/2:])
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// The default signing hash is SHA-256.
|
||||
func (p *PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
|
||||
// // Hash the message with SHA-256
|
||||
// hash := sha256.Sum256(message)
|
||||
//
|
||||
// return ecdsa.SignASN1(rand.Reader, p.k.ToECDSA(), hash[:])
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
params := crypto.CollectSigningOptions(opts)
|
||||
|
||||
hasher := params.HashOrDefault(crypto.SHA256).New()
|
||||
hasher.Write(message)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
sig := ecdsa.Sign(p.k, hash)
|
||||
|
||||
return sig.Serialize(), nil
|
||||
}
|
||||
|
||||
func (p *PrivateKey) PublicKeyIsCompatible(remote crypto.PublicKey) bool {
|
||||
@@ -200,19 +212,8 @@ func (p *PrivateKey) PublicKeyIsCompatible(remote crypto.PublicKey) bool {
|
||||
}
|
||||
|
||||
func (p *PrivateKey) KeyExchange(remote crypto.PublicKey) ([]byte, error) {
|
||||
// if remote, ok := remote.(*PublicKey); ok {
|
||||
// // First, we need to convert the ECDSA (signing only) to the equivalent ECDH keys
|
||||
// ecdhPriv, err := p.k.ECDH()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// ecdhPub, err := remote.k.ECDH()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return ecdhPriv.ECDH(ecdhPub)
|
||||
// }
|
||||
// return nil, fmt.Errorf("incompatible public key")
|
||||
panic("not implemented")
|
||||
if remote, ok := remote.(*PublicKey); ok {
|
||||
return secp256k1.GenerateSharedSecret(p.k, remote.k), nil
|
||||
}
|
||||
return nil, fmt.Errorf("incompatible public key")
|
||||
}
|
||||
|
||||
@@ -7,12 +7,14 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKeySigning = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningBytes = &PublicKey{}
|
||||
var _ crypto.PublicKeySigningASN1 = &PublicKey{}
|
||||
|
||||
type PublicKey struct {
|
||||
k *secp256k1.PublicKey
|
||||
@@ -166,33 +168,39 @@ func (p *PublicKey) ToX509PEM() string {
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
Note: signatures for the crypto.PrivateKeySigning interface assumes SHA256,
|
||||
which should be correct almost always. If there is a need to use a different
|
||||
hash function, we can add separate functions that have that flexibility.
|
||||
*/
|
||||
|
||||
// The default signing hash is SHA-256.
|
||||
func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool {
|
||||
// if len(signature) != SignatureBytesSize {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// // Hash the message with SHA-256
|
||||
// hash := sha256.Sum256(message)
|
||||
//
|
||||
// r := new(big.Int).SetBytes(signature[:SignatureBytesSize/2])
|
||||
// s := new(big.Int).SetBytes(signature[SignatureBytesSize/2:])
|
||||
//
|
||||
// return ecdsa.Verify(p.k, hash[:], r, s)
|
||||
panic("not implemented")
|
||||
if len(signature) != SignatureBytesSize {
|
||||
return false
|
||||
}
|
||||
|
||||
params := crypto.CollectSigningOptions(opts)
|
||||
|
||||
hasher := params.HashOrDefault(crypto.SHA256).New()
|
||||
hasher.Write(message)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
var r, s secp256k1.ModNScalar
|
||||
r.SetByteSlice(signature[:32])
|
||||
s.SetByteSlice(signature[32:])
|
||||
|
||||
return ecdsa.NewSignature(&r, &s).Verify(hash, p.k)
|
||||
}
|
||||
|
||||
// The default signing hash is SHA-256.
|
||||
func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
|
||||
// // Hash the message with SHA-256
|
||||
// hash := sha256.Sum256(message)
|
||||
//
|
||||
// return ecdsa.VerifyASN1(p.k, hash[:], signature)
|
||||
panic("not implemented")
|
||||
params := crypto.CollectSigningOptions(opts)
|
||||
|
||||
hasher := params.HashOrDefault(crypto.SHA256).New()
|
||||
hasher.Write(message)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
sig, err := ecdsa.ParseDERSignature(signature)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return sig.Verify(hash, p.k)
|
||||
}
|
||||
|
||||
func must[T any](v T, err error) T {
|
||||
|
||||
@@ -94,7 +94,7 @@ func (j JsonWebKey2020) JsonLdContext() string {
|
||||
}
|
||||
|
||||
func (j JsonWebKey2020) Verify(data []byte, sig []byte) (bool, error) {
|
||||
if pub, ok := j.pubkey.(crypto.PublicKeySigning); ok {
|
||||
if pub, ok := j.pubkey.(crypto.PublicKeySigningBytes); ok {
|
||||
return pub.VerifyBytes(data, sig), nil
|
||||
}
|
||||
return false, errors.New("not a signing public key")
|
||||
|
||||
@@ -96,7 +96,7 @@ func (m MultiKey) JsonLdContext() string {
|
||||
}
|
||||
|
||||
func (m MultiKey) Verify(data []byte, sig []byte) (bool, error) {
|
||||
if pub, ok := m.pubkey.(crypto.PublicKeySigning); ok {
|
||||
if pub, ok := m.pubkey.(crypto.PublicKeySigningBytes); ok {
|
||||
return pub.VerifyBytes(data, sig), nil
|
||||
}
|
||||
return false, errors.New("not a signing public key")
|
||||
|
||||
Reference in New Issue
Block a user