diff options
Diffstat (limited to 'crypto')
| -rw-r--r-- | crypto/ecdsa.go | 72 | ||||
| -rw-r--r-- | crypto/ecdsa_test.go | 82 |
2 files changed, 154 insertions, 0 deletions
diff --git a/crypto/ecdsa.go b/crypto/ecdsa.go new file mode 100644 index 00000000..16b8dcaa --- /dev/null +++ b/crypto/ecdsa.go @@ -0,0 +1,72 @@ +package crypto + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "fmt" +) + +// ECDSAGenerateKey - +func ECDSAGenerateKey(curve string) ([]byte, error) { + var c elliptic.Curve + + if curve == "P-224" { + c = elliptic.P224() + } else if curve == "P-256" { + c = elliptic.P256() + } else if curve == "P-384" { + c = elliptic.P384() + } else if curve == "P-521" { + c = elliptic.P521() + } else { + return nil, fmt.Errorf("unknow curve: %s", curve) + } + + priv, err := ecdsa.GenerateKey(c, rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate ECDSA private key: %w", err) + } + der, err := x509.MarshalECPrivateKey(priv) + if err != nil { + return nil, fmt.Errorf("failed to marshal ECDSA private key: %w", err) + } + block := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: der, + } + buf := &bytes.Buffer{} + err = pem.Encode(buf, block) + if err != nil { + return nil, fmt.Errorf("failed to encode generated ECDSA private key: pem encoding failed: %w", err) + } + return buf.Bytes(), nil +} + +// ECDSADerivePublicKey - +func ECDSADerivePublicKey(privatekey []byte) ([]byte, error) { + block, _ := pem.Decode(privatekey) + if block == nil { + return nil, fmt.Errorf("failed to read key: no key found") + } + + priv, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("invalid private key: %w", err) + } + + b, err := x509.MarshalPKIXPublicKey(&priv.PublicKey) + if err != nil { + return nil, fmt.Errorf("failed to marshal PKIX public key: %w", err) + } + + block = &pem.Block{ + Type: "PUBLIC KEY", + Bytes: b, + } + + return pem.EncodeToMemory(block), nil +} diff --git a/crypto/ecdsa_test.go b/crypto/ecdsa_test.go new file mode 100644 index 00000000..815f7a23 --- /dev/null +++ b/crypto/ecdsa_test.go @@ -0,0 +1,82 @@ +package crypto + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func genECDSAPrivKey() (*ecdsa.PrivateKey, string) { + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + der, _ := x509.MarshalECPrivateKey(priv) + privBlock := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: der, + } + return priv, string(pem.EncodeToMemory(privBlock)) +} + +func deriveECPubkey(priv *ecdsa.PrivateKey) string { + b, _ := x509.MarshalPKIXPublicKey(&priv.PublicKey) + pubBlock := &pem.Block{ + Type: "PUBLIC KEY", + Bytes: b, + } + testPubKey := string(pem.EncodeToMemory(pubBlock)) + return testPubKey +} + +func TestECDSAGenerateKey(t *testing.T) { + key, err := ECDSAGenerateKey("P-224") + assert.NoError(t, err) + assert.True(t, strings.HasPrefix(string(key), + "-----BEGIN EC PRIVATE KEY-----")) + assert.True(t, strings.HasSuffix(string(key), + "-----END EC PRIVATE KEY-----\n")) + + key, err = ECDSAGenerateKey("P-256") + assert.NoError(t, err) + assert.True(t, strings.HasPrefix(string(key), + "-----BEGIN EC PRIVATE KEY-----")) + assert.True(t, strings.HasSuffix(string(key), + "-----END EC PRIVATE KEY-----\n")) + + key, err = ECDSAGenerateKey("P-384") + assert.NoError(t, err) + assert.True(t, strings.HasPrefix(string(key), + "-----BEGIN EC PRIVATE KEY-----")) + assert.True(t, strings.HasSuffix(string(key), + "-----END EC PRIVATE KEY-----\n")) + + key, err = ECDSAGenerateKey("P-521") + assert.NoError(t, err) + assert.True(t, strings.HasPrefix(string(key), + "-----BEGIN EC PRIVATE KEY-----")) + assert.True(t, strings.HasSuffix(string(key), + "-----END EC PRIVATE KEY-----\n")) + + key, err = ECDSAGenerateKey("P-999") + assert.Error(t, err) +} + +func TestECDSADerivePublicKey(t *testing.T) { + _, err := ECDSADerivePublicKey(nil) + assert.Error(t, err) + + _, err = ECDSADerivePublicKey([]byte(`-----BEGIN FOO----- + -----END FOO-----`)) + assert.Error(t, err) + + priv, privKey := genECDSAPrivKey() + expected := deriveECPubkey(priv) + + actual, err := ECDSADerivePublicKey([]byte(privKey)) + assert.NoError(t, err) + assert.Equal(t, expected, string(actual)) +} |
