crypto: finish RSA
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user