1
0
mirror of https://github.com/libp2p/go-libp2p-core.git synced 2025-04-27 17:00:21 +08:00

sync w/ go-libp2p-crypto master: rsa openssl.

This commit is contained in:
Raúl Kripalani 2019-05-18 18:16:55 +02:00
parent c1c817c31a
commit 09ae22d49d
15 changed files with 430 additions and 158 deletions

132
crypto/fixture_test.go Normal file
View File

@ -0,0 +1,132 @@
package crypto_test
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"io/ioutil"
"testing"
crypto "github.com/libp2p/go-libp2p-core/crypto"
crypto_pb "github.com/libp2p/go-libp2p-core/crypto/pb"
)
var message = []byte("Libp2p is the _best_!")
type testCase struct {
keyType crypto_pb.KeyType
gen func(i io.Reader) (crypto.PrivKey, crypto.PubKey, error)
sigDeterministic bool
}
var keyTypes = []testCase{
{
keyType: crypto_pb.KeyType_ECDSA,
gen: crypto.GenerateECDSAKeyPair,
},
{
keyType: crypto_pb.KeyType_Secp256k1,
sigDeterministic: true,
gen: crypto.GenerateSecp256k1Key,
},
{
keyType: crypto_pb.KeyType_RSA,
sigDeterministic: true,
gen: func(i io.Reader) (crypto.PrivKey, crypto.PubKey, error) {
return crypto.GenerateRSAKeyPair(2048, i)
},
},
}
func fname(kt crypto_pb.KeyType, ext string) string {
return fmt.Sprintf("test_data/%d.%s", kt, ext)
}
func TestFixtures(t *testing.T) {
for _, tc := range keyTypes {
t.Run(tc.keyType.String(), func(t *testing.T) {
pubBytes, err := ioutil.ReadFile(fname(tc.keyType, "pub"))
if err != nil {
t.Fatal(err)
}
privBytes, err := ioutil.ReadFile(fname(tc.keyType, "priv"))
if err != nil {
t.Fatal(err)
}
sigBytes, err := ioutil.ReadFile(fname(tc.keyType, "sig"))
if err != nil {
t.Fatal(err)
}
pub, err := crypto.UnmarshalPublicKey(pubBytes)
if err != nil {
t.Fatal(err)
}
pubBytes2, err := pub.Bytes()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pubBytes2, pubBytes) {
t.Fatal("encoding round-trip failed")
}
priv, err := crypto.UnmarshalPrivateKey(privBytes)
if err != nil {
t.Fatal(err)
}
privBytes2, err := priv.Bytes()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(privBytes2, privBytes) {
t.Fatal("encoding round-trip failed")
}
ok, err := pub.Verify(message, sigBytes)
if !ok || err != nil {
t.Fatal("failed to validate signature with public key")
}
if tc.sigDeterministic {
sigBytes2, err := priv.Sign(message)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(sigBytes2, sigBytes) {
t.Fatal("signature not deterministic")
}
}
})
}
}
func init() {
// set to true to re-generate test data
if false {
generate()
panic("generated")
}
}
// generate re-generates test data
func generate() {
for _, tc := range keyTypes {
priv, pub, err := tc.gen(rand.Reader)
if err != nil {
panic(err)
}
pubb, err := pub.Bytes()
if err != nil {
panic(err)
}
privb, err := priv.Bytes()
if err != nil {
panic(err)
}
sig, err := priv.Sign(message)
if err != nil {
panic(err)
}
ioutil.WriteFile(fname(tc.keyType, "pub"), pubb, 0666)
ioutil.WriteFile(fname(tc.keyType, "priv"), privb, 0666)
ioutil.WriteFile(fname(tc.keyType, "sig"), sig, 0666)
}
}

98
crypto/openssl_common.go Normal file
View File

@ -0,0 +1,98 @@
// +build openssl
package crypto
import (
pb "github.com/libp2p/go-libp2p-core/crypto/pb"
openssl "github.com/spacemonkeygo/openssl"
)
// define these as separate types so we can add more key types later and reuse
// code.
type opensslPublicKey struct {
key openssl.PublicKey
}
type opensslPrivateKey struct {
key openssl.PrivateKey
}
func unmarshalOpensslPrivateKey(b []byte) (opensslPrivateKey, error) {
sk, err := openssl.LoadPrivateKeyFromDER(b)
if err != nil {
return opensslPrivateKey{}, err
}
return opensslPrivateKey{sk}, nil
}
func unmarshalOpensslPublicKey(b []byte) (opensslPublicKey, error) {
sk, err := openssl.LoadPublicKeyFromDER(b)
if err != nil {
return opensslPublicKey{}, err
}
return opensslPublicKey{sk}, nil
}
// Verify compares a signature against input data
func (pk *opensslPublicKey) Verify(data, sig []byte) (bool, error) {
err := pk.key.VerifyPKCS1v15(openssl.SHA256_Method, data, sig)
return err == nil, err
}
func (pk *opensslPublicKey) Type() pb.KeyType {
switch pk.key.KeyType() {
case openssl.KeyTypeRSA:
return pb.KeyType_RSA
default:
return -1
}
}
// Bytes returns protobuf bytes of a public key
func (pk *opensslPublicKey) Bytes() ([]byte, error) {
return MarshalPublicKey(pk)
}
func (pk *opensslPublicKey) Raw() ([]byte, error) {
return pk.key.MarshalPKIXPublicKeyDER()
}
// Equals checks whether this key is equal to another
func (pk *opensslPublicKey) Equals(k Key) bool {
return KeyEqual(pk, k)
}
// Sign returns a signature of the input data
func (sk *opensslPrivateKey) Sign(message []byte) ([]byte, error) {
return sk.key.SignPKCS1v15(openssl.SHA256_Method, message)
}
// GetPublic returns a public key
func (sk *opensslPrivateKey) GetPublic() PubKey {
return &opensslPublicKey{sk.key}
}
func (sk *opensslPrivateKey) Type() pb.KeyType {
switch sk.key.KeyType() {
case openssl.KeyTypeRSA:
return pb.KeyType_RSA
default:
return -1
}
}
// Bytes returns protobuf bytes from a private key
func (sk *opensslPrivateKey) Bytes() ([]byte, error) {
return MarshalPrivateKey(sk)
}
func (sk *opensslPrivateKey) Raw() ([]byte, error) {
return sk.key.MarshalPKCS1PrivateKeyDER()
}
// Equals checks whether this key is equal to another
func (sk *opensslPrivateKey) Equals(k Key) bool {
return KeyEqual(sk, k)
}

View File

@ -1,158 +0,0 @@
package crypto
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"errors"
"io"
pb "github.com/libp2p/go-libp2p-core/crypto/pb"
sha256 "github.com/minio/sha256-simd"
)
// ErrRsaKeyTooSmall is returned when trying to generate or parse an RSA key
// that's smaller than 512 bits. Keys need to be larger enough to sign a 256bit
// hash so this is a reasonable absolute minimum.
var ErrRsaKeyTooSmall = errors.New("rsa keys must be >= 512 bits to be useful")
// RsaPrivateKey is an RSA private key.
type RsaPrivateKey struct {
sk *rsa.PrivateKey
pk *rsa.PublicKey
}
// RsaPublicKey is an RSA public key.
type RsaPublicKey struct {
k *rsa.PublicKey
}
// GenerateRSAKeyPair generates a new RSA private and public key.
func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) {
if bits < 512 {
return nil, nil, ErrRsaKeyTooSmall
}
priv, err := rsa.GenerateKey(src, bits)
if err != nil {
return nil, nil, err
}
pk := &priv.PublicKey
return &RsaPrivateKey{sk: priv}, &RsaPublicKey{pk}, nil
}
// Verify compares a signature against input data.
// In the case of RSA keys, verification applies PKCS1v15 RSA signature verification
// upon the SHA-256 hash of the input data.
func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
hashed := sha256.Sum256(data)
err := rsa.VerifyPKCS1v15(pk.k, crypto.SHA256, hashed[:], sig)
if err != nil {
return false, err
}
return true, nil
}
func (pk *RsaPublicKey) Type() pb.KeyType {
return pb.KeyType_RSA
}
// Bytes returns protobuf bytes of a public key.
func (pk *RsaPublicKey) Bytes() ([]byte, error) {
return MarshalPublicKey(pk)
}
// Raw returns a binary representation of the key in a type-specific format.
// In the case of RSA keys, returns an X.509 PKIX encoded public key.
func (pk *RsaPublicKey) Raw() ([]byte, error) {
return x509.MarshalPKIXPublicKey(pk.k)
}
// Encrypt returns encrypted bytes from the input data.
func (pk *RsaPublicKey) Encrypt(b []byte) ([]byte, error) {
return rsa.EncryptPKCS1v15(rand.Reader, pk.k, b)
}
// Equals checks whether this key is equal to another.
func (pk *RsaPublicKey) Equals(k Key) bool {
return KeyEqual(pk, k)
}
// Sign returns a signature of the input data.
func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
hashed := sha256.Sum256(message)
return rsa.SignPKCS1v15(rand.Reader, sk.sk, crypto.SHA256, hashed[:])
}
// GetPublic returns a public key.
func (sk *RsaPrivateKey) GetPublic() PubKey {
if sk.pk == nil {
sk.pk = &sk.sk.PublicKey
}
return &RsaPublicKey{sk.pk}
}
// Decrypt returns decrypted bytes of the input encrypted bytes.
func (sk *RsaPrivateKey) Decrypt(b []byte) ([]byte, error) {
return rsa.DecryptPKCS1v15(rand.Reader, sk.sk, b)
}
func (sk *RsaPrivateKey) Type() pb.KeyType {
return pb.KeyType_RSA
}
// Bytes returns protobuf bytes from a private key.
func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
return MarshalPrivateKey(sk)
}
// Raw returns a binary representation of a private key in a type-specific format.
// In the case of RSA keys, returns the key in ASN.1 DER encoded form.
func (sk *RsaPrivateKey) Raw() ([]byte, error) {
b := x509.MarshalPKCS1PrivateKey(sk.sk)
return b, nil
}
// Equals checks whether this key is equal to another.
func (sk *RsaPrivateKey) Equals(k Key) bool {
return KeyEqual(sk, k)
}
// UnmarshalRsaPrivateKey returns a private key from the input X.509 bytes.
func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) {
sk, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
return nil, err
}
if sk.N.BitLen() < 512 {
return nil, ErrRsaKeyTooSmall
}
return &RsaPrivateKey{sk: sk}, nil
}
// MarshalRsaPrivateKey returns the X.509 bytes of the private key.
func MarshalRsaPrivateKey(k *RsaPrivateKey) []byte {
return x509.MarshalPKCS1PrivateKey(k.sk)
}
// UnmarshalRsaPublicKey returns a public key from the input X.509 bytes.
func UnmarshalRsaPublicKey(b []byte) (PubKey, error) {
pub, err := x509.ParsePKIXPublicKey(b)
if err != nil {
return nil, err
}
pk, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, errors.New("not actually an rsa public key")
}
if pk.N.BitLen() < 512 {
return nil, ErrRsaKeyTooSmall
}
return &RsaPublicKey{pk}, nil
}
// MarshalRsaPublicKey returns the X.509 bytes from the public key.
func MarshalRsaPublicKey(k *RsaPublicKey) ([]byte, error) {
return x509.MarshalPKIXPublicKey(k.k)
}

10
crypto/rsa_common.go Normal file
View File

@ -0,0 +1,10 @@
package crypto
import (
"errors"
)
// ErrRsaKeyTooSmall is returned when trying to generate or parse an RSA key
// that's smaller than 512 bits. Keys need to be larger enough to sign a 256bit
// hash so this is a reasonable absolute minimum.
var ErrRsaKeyTooSmall = errors.New("rsa keys must be >= 512 bits to be useful")

125
crypto/rsa_go.go Normal file
View File

@ -0,0 +1,125 @@
// +build !openssl
package crypto
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"errors"
"io"
pb "github.com/libp2p/go-libp2p-core/crypto/pb"
"github.com/minio/sha256-simd"
)
// RsaPrivateKey is an rsa private key
type RsaPrivateKey struct {
sk rsa.PrivateKey
}
// RsaPublicKey is an rsa public key
type RsaPublicKey struct {
k rsa.PublicKey
}
// GenerateRSAKeyPair generates a new rsa private and public key
func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) {
if bits < 512 {
return nil, nil, ErrRsaKeyTooSmall
}
priv, err := rsa.GenerateKey(src, bits)
if err != nil {
return nil, nil, err
}
pk := priv.PublicKey
return &RsaPrivateKey{sk: *priv}, &RsaPublicKey{pk}, nil
}
// Verify compares a signature against input data
func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
hashed := sha256.Sum256(data)
err := rsa.VerifyPKCS1v15(&pk.k, crypto.SHA256, hashed[:], sig)
if err != nil {
return false, err
}
return true, nil
}
func (pk *RsaPublicKey) Type() pb.KeyType {
return pb.KeyType_RSA
}
// Bytes returns protobuf bytes of a public key
func (pk *RsaPublicKey) Bytes() ([]byte, error) {
return MarshalPublicKey(pk)
}
func (pk *RsaPublicKey) Raw() ([]byte, error) {
return x509.MarshalPKIXPublicKey(&pk.k)
}
// Equals checks whether this key is equal to another
func (pk *RsaPublicKey) Equals(k Key) bool {
return KeyEqual(pk, k)
}
// Sign returns a signature of the input data
func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
hashed := sha256.Sum256(message)
return rsa.SignPKCS1v15(rand.Reader, &sk.sk, crypto.SHA256, hashed[:])
}
// GetPublic returns a public key
func (sk *RsaPrivateKey) GetPublic() PubKey {
return &RsaPublicKey{sk.sk.PublicKey}
}
func (sk *RsaPrivateKey) Type() pb.KeyType {
return pb.KeyType_RSA
}
// Bytes returns protobuf bytes from a private key
func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
return MarshalPrivateKey(sk)
}
func (sk *RsaPrivateKey) Raw() ([]byte, error) {
b := x509.MarshalPKCS1PrivateKey(&sk.sk)
return b, nil
}
// Equals checks whether this key is equal to another
func (sk *RsaPrivateKey) Equals(k Key) bool {
return KeyEqual(sk, k)
}
// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes
func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) {
sk, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
return nil, err
}
if sk.N.BitLen() < 512 {
return nil, ErrRsaKeyTooSmall
}
return &RsaPrivateKey{sk: *sk}, nil
}
// UnmarshalRsaPublicKey returns a public key from the input x509 bytes
func UnmarshalRsaPublicKey(b []byte) (PubKey, error) {
pub, err := x509.ParsePKIXPublicKey(b)
if err != nil {
return nil, err
}
pk, ok := pub.(*rsa.PublicKey)
if !ok {
return nil, errors.New("not actually an rsa public key")
}
if pk.N.BitLen() < 512 {
return nil, ErrRsaKeyTooSmall
}
return &RsaPublicKey{*pk}, nil
}

62
crypto/rsa_openssl.go Normal file
View File

@ -0,0 +1,62 @@
// +build openssl
package crypto
import (
"errors"
"io"
openssl "github.com/spacemonkeygo/openssl"
)
// RsaPrivateKey is an rsa private key
type RsaPrivateKey struct {
opensslPrivateKey
}
// RsaPublicKey is an rsa public key
type RsaPublicKey struct {
opensslPublicKey
}
// GenerateRSAKeyPair generates a new rsa private and public key
func GenerateRSAKeyPair(bits int, _ io.Reader) (PrivKey, PubKey, error) {
if bits < 512 {
return nil, nil, ErrRsaKeyTooSmall
}
key, err := openssl.GenerateRSAKey(bits)
if err != nil {
return nil, nil, err
}
return &RsaPrivateKey{opensslPrivateKey{key}}, &RsaPublicKey{opensslPublicKey{key}}, nil
}
// GetPublic returns a public key
func (sk *RsaPrivateKey) GetPublic() PubKey {
return &RsaPublicKey{opensslPublicKey{sk.opensslPrivateKey.key}}
}
// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes
func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) {
key, err := unmarshalOpensslPrivateKey(b)
if err != nil {
return nil, err
}
if key.Type() != RSA {
return nil, errors.New("not actually an rsa public key")
}
return &RsaPrivateKey{key}, nil
}
// UnmarshalRsaPublicKey returns a public key from the input x509 bytes
func UnmarshalRsaPublicKey(b []byte) (PubKey, error) {
key, err := unmarshalOpensslPublicKey(b)
if err != nil {
return nil, err
}
if key.Type() != RSA {
return nil, errors.New("not actually an rsa public key")
}
return &RsaPublicKey{key}, nil
}

BIN
crypto/test_data/0.priv Normal file

Binary file not shown.

BIN
crypto/test_data/0.pub Normal file

Binary file not shown.

BIN
crypto/test_data/0.sig Normal file

Binary file not shown.

1
crypto/test_data/2.priv Normal file
View File

@ -0,0 +1 @@
 1A½`jPLDò4”ØóNò[¹µ-ªÐX¾ƒ¶àF±X

1
crypto/test_data/2.pub Normal file
View File

@ -0,0 +1 @@
!5@­„*ψ¤5Q©Mƒƒ¥U©&Pk<50>ωS<CF89>磡³ΦΆ

1
crypto/test_data/2.sig Normal file
View File

@ -0,0 +1 @@
0D 1§Ö3ÂóäZŤCuú¨Ü›˘@ĹőłĘŇČţLó<4C>ň IęŤ!źE†<EFBFBD>ŇGuŐCꏲ<EFBFBD>pCGű5I<@;ÂÂY˛ťž

BIN
crypto/test_data/3.priv Normal file

Binary file not shown.

BIN
crypto/test_data/3.pub Normal file

Binary file not shown.

BIN
crypto/test_data/3.sig Normal file

Binary file not shown.