Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions lib/ocrypto/ec_key_pair.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package ocrypto

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
)

type eccMode uint8

const (
eccModeSecp256r1 eccMode = 0
eccModeSecp384r1 eccMode = 1
eccModeSecp521r1 eccMode = 2
eccModeSecp256k1 eccMode = 3
)

type EcKeyPair struct {
privateKey *ecdsa.PrivateKey
}

// NewECKeyPair Generates an EC key pair of the given bit size.
func NewECKeyPair(mode eccMode) (EcKeyPair, error) {

var c elliptic.Curve
switch mode {
case eccModeSecp256r1:
c = elliptic.P256()
break
case eccModeSecp384r1:
c = elliptic.P384()
break
case eccModeSecp521r1:
c = elliptic.P521()
break
case eccModeSecp256k1:
// TODO FIXME - unsupported?
return EcKeyPair{}, errors.New("unsupported ec key pair mode")
default:
return EcKeyPair{}, fmt.Errorf("invalid ec key pair mode %d", mode)
}

privateKey, err := ecdsa.GenerateKey(c, rand.Reader)
if err != nil {
return EcKeyPair{}, fmt.Errorf("ec.GenerateKey failed: %w", err)
}

ecKeyPair := EcKeyPair{privateKey: privateKey}
return ecKeyPair, nil
}

// PrivateKeyInPemFormat Returns private key in pem format.
func (keyPair EcKeyPair) PrivateKeyInPemFormat() (string, error) {
if keyPair.privateKey == nil {
return "", errors.New("failed to generate PEM formatted private key")
}

privateKeyBytes, err := x509.MarshalPKCS8PrivateKey(keyPair.privateKey)
if err != nil {
return "", fmt.Errorf("x509.MarshalPKCS8PrivateKey failed: %w", err)
}

privateKeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "PRIVATE KEY",
Bytes: privateKeyBytes,
},
)
return string(privateKeyPem), nil
}

// PublicKeyInPemFormat Returns public key in pem format.
func (keyPair EcKeyPair) PublicKeyInPemFormat() (string, error) {
if keyPair.privateKey == nil {
return "", errors.New("failed to generate PEM formatted public key")
}

publicKeyBytes, err := x509.MarshalPKIXPublicKey(&keyPair.privateKey.PublicKey)
if err != nil {
return "", fmt.Errorf("x509.MarshalPKIXPublicKey failed: %w", err)
}

publicKeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeyBytes,
},
)

return string(publicKeyPem), nil
}

// KeySize Return the size of this ec key pair.
func (keyPair EcKeyPair) KeySize() (int, error) {
if keyPair.privateKey == nil {
return -1, errors.New("failed to return key size")
}
return keyPair.privateKey.Params().N.BitLen(), nil
}
75 changes: 75 additions & 0 deletions lib/ocrypto/ec_key_pair_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package ocrypto

import (
"testing"
)

func TestECKeyPair(t *testing.T) {
for _, modeGood := range []eccMode{eccModeSecp256r1, eccModeSecp384r1, eccModeSecp521r1} {
ecKeyPair, err := NewECKeyPair(modeGood)
if err != nil {
t.Fatalf("NewECKeyPair(%d): %v", modeGood, err)
}

_, err = ecKeyPair.PublicKeyInPemFormat()
if err != nil {
t.Fatalf("ec PublicKeyInPemFormat() error - %v", err)
}

_, err = ecKeyPair.PrivateKeyInPemFormat()
if err != nil {
t.Fatalf("ec PrivateKeyInPemFormat() error - %v", err)
}

keySize, err := ecKeyPair.KeySize()
if err != nil {
t.Fatalf("ec keysize error - %v", err)
}

// Set expected size based on mode
size := 0
switch modeGood {
case eccModeSecp256r1:
size = 256
break
case eccModeSecp384r1:
size = 384
break
case eccModeSecp521r1:
size = 521
break
default:
size = 99999 // deliberately bad value
}

if keySize != size {
t.Fatalf("invalid key size for mode %d, expected:%d actual:%d",
modeGood, size, keySize)
}
}

// Fail case
emptyECKeyPair := EcKeyPair{}

_, err := emptyECKeyPair.PrivateKeyInPemFormat()
if err == nil {
t.Fatal("EcKeyPair.PrivateKeyInPemFormat() fail to return error")
}

_, err = emptyECKeyPair.PublicKeyInPemFormat()
if err == nil {
t.Fatal("EcKeyPair.PublicKeyInPemFormat() fail to return error")
}

_, err = emptyECKeyPair.KeySize()
if err == nil {
t.Fatal("EcKeyPair.keySize() fail to return error")
}

for _, modeBad := range []eccMode{eccModeSecp256k1} {
_, err := NewECKeyPair(modeBad)
if err == nil {
t.Fatalf("did not fail as expected: NewECKeyPair(%d): %v", modeBad, err)
}
}
}
9 changes: 0 additions & 9 deletions sdk/nanotdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,6 @@ const (
urlProtocolShared urlProtocol = 255
)

type eccMode uint8

const (
eccModeSecp256r1 eccMode = 0
eccModeSecp384r1 eccMode = 1
eccModeSecp521r1 eccMode = 2
eccModeSecp256k1 eccMode = 3
)

type cipherMode int

const (
Expand Down