Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
32 changes: 32 additions & 0 deletions lib/ocrypto/asym_encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"errors"
"fmt"
"io"
"strconv"
"strings"

"golang.org/x/crypto/hkdf"
Expand All @@ -36,6 +37,9 @@ type PublicKeyEncryptor interface {
// Type required to use the scheme for encryption - notably, if it procduces extra metadata.
Type() SchemeType

// KeyType returns the key type, e.g. RSA or EC.
KeyType() KeyType

// For EC schemes, this method returns the public part of the ephemeral key.
// Otherwise, it returns nil.
EphemeralKey() []byte
Expand Down Expand Up @@ -139,10 +143,38 @@ func (e AsymEncryption) Type() SchemeType {
return RSA
}

func (e AsymEncryption) KeyType() KeyType {
switch e.PublicKey.Size() {
case RSA2048Size / 8: //nolint:mnd // standard key size in bytes
return RSA2048Key
case RSA4096Size / 8: //nolint:mnd // large key size in bytes
return RSA4096Key
default:
bitlen := e.PublicKey.Size() * 8 //nolint:mnd // convert to bits
return KeyType("rsa:" + strconv.Itoa(bitlen))
}
}

func (e ECEncryptor) Type() SchemeType {
return EC
}

func (e ECEncryptor) KeyType() KeyType {
switch e.pub.Curve() {
case ecdh.P256():
return EC256Key
case ecdh.P384():
return EC384Key
case ecdh.P521():
return EC521Key
default:
if n, ok := e.pub.Curve().(fmt.Stringer); ok {
return KeyType("ec:" + n.String())
}
return KeyType("ec:[unknown]")
}
}

func (e AsymEncryption) EphemeralKey() []byte {
return nil
}
Expand Down
137 changes: 137 additions & 0 deletions lib/ocrypto/asym_encryption_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package ocrypto

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestFromPublicPEM(t *testing.T) {
testCases := []struct {
name string
filename string
expectedType KeyType
}{
{
name: "EC secp256r1 public key",
filename: "sample-ec-secp256r1-01-public.pem",
expectedType: EC256Key,
},
{
name: "EC secp384r1 public key",
filename: "sample-ec-secp384r1-01-public.pem",
expectedType: EC384Key,
},
{
name: "EC secp521r1 public key",
filename: "sample-ec-secp521r1-01-public.pem",
expectedType: EC521Key,
},
{
name: "RSA 2048 public key",
filename: "sample-rsa-2048-01-public.pem",
expectedType: RSA2048Key,
},
{
name: "RSA 4096 public key",
filename: "sample-rsa-4096-01-public.pem",
expectedType: RSA4096Key,
},
{
name: "Unsupported RSA 1024 public key",
filename: "sample-rsa-1024-01-public.pem",
expectedType: KeyType("rsa:1024"),
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Read the PEM file
testDataPath := filepath.Join("testdata", tc.filename)
pemData, err := os.ReadFile(testDataPath)
require.NoError(t, err, "Failed to read test file %s", tc.filename)

// Load the public key using FromPublicPEM
encryptor, err := FromPublicPEM(string(pemData))
require.NoError(t, err, "Failed to load public key from %s", tc.filename)
require.NotNil(t, encryptor, "Encryptor should not be nil") // Test that KeyType() returns the expected type
keyType := encryptor.KeyType()
assert.Equal(t, tc.expectedType, keyType, "KeyType() returned unexpected value for %s", tc.name)

// Also test that we can get the public key back in PEM format
pubKeyPEM, err := encryptor.PublicKeyInPemFormat()
require.NoError(t, err, "Failed to get public key in PEM format")
assert.NotEmpty(t, pubKeyPEM, "Public key PEM should not be empty")
})
}
}

func TestFromPublicPEM_UnsupportedFiles(t *testing.T) {
testCases := []struct {
name string
filename string
}{
{
name: "Unsupported EC secp256k1 public key",
filename: "sample-ec-secp256k1-01-public.pem",
},
{
name: "Unsupported EC brainpoolP160r1 public key",
filename: "sample-ec-brainpoolP160r1-01-public.pem",
},
{
name: "Loading a private key should fail",
filename: "sample-ec-secp256r1-01-private.pem",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Read the PEM file
testDataPath := filepath.Join("testdata", tc.filename)
pemData, err := os.ReadFile(testDataPath)
require.NoError(t, err, "Failed to read test file %s", tc.filename)

// Load the public key using FromPublicPEM - should fail for unsupported curves
_, err = FromPublicPEM(string(pemData))
assert.Error(t, err, "Expected error for unsupported curve %s", tc.name)
})
}
}

func TestFromPublicPEM_InvalidInput(t *testing.T) {
testCases := []struct {
name string
pemData string
errorMsg string
}{
{
name: "Empty string",
pemData: "",
errorMsg: "failed to parse PEM formatted public key",
},
{
name: "Invalid PEM format",
pemData: "not a pem file",
errorMsg: "failed to parse PEM formatted public key",
},
{
name: "Invalid PEM content",
pemData: `-----BEGIN PUBLIC KEY-----
invalid base64 content!!!
-----END PUBLIC KEY-----`,
errorMsg: "failed to parse PEM formatted public key",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, err := FromPublicPEM(tc.pemData)
require.Error(t, err)
assert.Contains(t, err.Error(), tc.errorMsg)
})
}
}
40 changes: 40 additions & 0 deletions lib/ocrypto/testdata/genkeys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash
# genkeys.sh
# Generate test keys for ocrypto unit tests

set -e

# Ensure we're in the correct directory
cd "$(dirname "$0")"

echo "Generating test keys..."

# Which EC curves we are using to generate keys
ec_curves=(
"secp256r1"
"secp384r1"
"secp521r1"
"secp256k1"
"brainpoolP160r1"
)

# Generate EC keys
for curve_name in "${ec_curves[@]}"; do
echo "Generating EC $curve_name keys..."
openssl ecparam -name "$curve_name" -genkey -noout -out "sample-ec-$curve_name-01-private.pem"
openssl ec -in "sample-ec-$curve_name-01-private.pem" -pubout -out "sample-ec-$curve_name-01-public.pem"
done

# What RSA bit lengths we want to test
rsa_bits=(2048 4096 1024)

# Generate RSA keys
for bits in "${rsa_bits[@]}"; do
echo "Generating RSA $bits keys..."
openssl genpkey -algorithm RSA -out "sample-rsa-$bits-01-private.pem" -pkeyopt "rsa_keygen_bits:$bits"
openssl rsa -in "sample-rsa-$bits-01-private.pem" -pubout -out "sample-rsa-$bits-01-public.pem"
done

echo "Test key generation complete!"
echo "Generated keys:"
ls -la sample-*.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN EC PRIVATE KEY-----
MFQCAQEEFHp8z00th6pcyzd45TD4mVz3iDRCoAsGCSskAwMCCAEBAaEsAyoABCSG
cu/mTV74q8bJUDDgA3gJ8nWojRgEt5WwkT9j0viJT2OLMWlf+7o=
-----END EC PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MEIwFAYHKoZIzj0CAQYJKyQDAwIIAQEBAyoABCSGcu/mTV74q8bJUDDgA3gJ8nWo
jRgEt5WwkT9j0viJT2OLMWlf+7o=
-----END PUBLIC KEY-----
5 changes: 5 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp256k1-01-private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIDmKI51/sEYpwoPhQSOzcIGI+e0VE7Kux9bCfC8p0qJroAcGBSuBBAAK
oUQDQgAEadV+Y82QMEpZyzFtdu5K5LA7eO+3Yu0Ms/4Gic7O0IEi6S1SZOCzALJb
e6mC5IcF1nm/dDC7xCQVgMHughWVPw==
-----END EC PRIVATE KEY-----
4 changes: 4 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp256k1-01-public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEadV+Y82QMEpZyzFtdu5K5LA7eO+3Yu0M
s/4Gic7O0IEi6S1SZOCzALJbe6mC5IcF1nm/dDC7xCQVgMHughWVPw==
-----END PUBLIC KEY-----
5 changes: 5 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp256r1-01-private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP1yOQQkE1gy3ktmG3dsk/M3AcXYTf7DwRhFmSv8XJ4LoAoGCCqGSM49
AwEHoUQDQgAENM4HHVFcRnCBycNVgYo1ArhtVz65ddbkQCCdIwsi8NFSHza6tZyM
s3LzQ1n46CnnXsgg/V26pYouAKOUcuRaOA==
-----END EC PRIVATE KEY-----
4 changes: 4 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp256r1-01-public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENM4HHVFcRnCBycNVgYo1ArhtVz65
ddbkQCCdIwsi8NFSHza6tZyMs3LzQ1n46CnnXsgg/V26pYouAKOUcuRaOA==
-----END PUBLIC KEY-----
6 changes: 6 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp384r1-01-private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAJxnVCC6ZJpuIDKz4S2sBV1TWMC8j4slIDKUWd+zueNPRxAINfACpP
r10ZCFofJxqgBwYFK4EEACKhZANiAATXFxgvsn7o3/kwlWTTP9Ue44ddtX173FwB
7q8WCs5THpnhHwG4uepfQWlyI5owHwIpO7aqGaJ0zyswikTH8E6wOv2W2iLYMAgW
L2S+8GNimGcGLwwdg9kTggUxf+BPOFI=
-----END EC PRIVATE KEY-----
5 changes: 5 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp384r1-01-public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE1xcYL7J+6N/5MJVk0z/VHuOHXbV9e9xc
Ae6vFgrOUx6Z4R8BuLnqX0FpciOaMB8CKTu2qhmidM8rMIpEx/BOsDr9ltoi2DAI
Fi9kvvBjYphnBi8MHYPZE4IFMX/gTzhS
-----END PUBLIC KEY-----
7 changes: 7 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp521r1-01-private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIAdSyAcDXV5TQHs1Q1jk41srxicAmZdMY2z7uXqBOysp2hpEq13lYk
cfSfpFE3zzu/iFf808AouXiK6EsBIqXu6SCgBwYFK4EEACOhgYkDgYYABABainiG
YYOEHe6kgIKvfZfQ8GygjvSCE3sjLsEQvf0d3KH07sGiHgUYJLEyhKI/I4a1rHvw
Z8oYuyxyNisSKAT+fAE7Xf/JpWFFeon60N1+/f/Bm+xZ3YKqriEktJnz8tsPFedM
w94tyYFptM69fHrKij+JfTnYtVzIm+rPHQrCOs/JaA==
-----END EC PRIVATE KEY-----
6 changes: 6 additions & 0 deletions lib/ocrypto/testdata/sample-ec-secp521r1-01-public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAWop4hmGDhB3upICCr32X0PBsoI70
ghN7Iy7BEL39Hdyh9O7Boh4FGCSxMoSiPyOGtax78GfKGLsscjYrEigE/nwBO13/
yaVhRXqJ+tDdfv3/wZvsWd2Cqq4hJLSZ8/LbDxXnTMPeLcmBabTOvXx6yoo/iX05
2LVcyJvqzx0KwjrPyWg=
-----END PUBLIC KEY-----
16 changes: 16 additions & 0 deletions lib/ocrypto/testdata/sample-rsa-1024-01-private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANO/UmUeB9MY5z26
uT/Qwdn1tHEySzewCsWnnDHMgQeQlCjB+6go1XXxpOYv4PiArnp+vINmj1TKkL2L
pFS1/JvD6d564ecba7SgpcH/iToRi13kuXwrocNrsT4zxWO+lpoR1G+CzJ5JSH0H
b+NG4QQ6DwQT6Nj6A5Zd/j6V0GSnAgMBAAECgYBWVnJgLIiAOG1BLDuQm6wPFTJH
3Xvx7uPVh+wWGg6aaQcgP0g/Xrb66laUTP1sFfwOklKHOXBD4Hx37NJKgBHJKt3b
CXs9FCDIqJak+9LLVBgbSuzJ+XUN4HSEfgXveJ7PLEyrxVpwYzIybgTEbO2IA+51
fC67jnSw4pq7Eu10AQJBAP2xqKEfbdFHJ3FfLoGT0aSfst91sZFQUvQL8zs+2skJ
iWSpX+64QGyeVgKXqaevzDGmkMnIqXQdYyBGjJSG/wECQQDVrA3ZsxUu9Kma9oJ0
Pxs4aGNQJGrgOVeVOa4LEYwia/BmZEq06w9FKLWbfXpZGsEIoiW97ZrnohxoqMqv
ywunAkEAu43TcELvClBDbcKDfFKPI9jZAfFd9GNg4IHRMZS3ZPdC9wNtI+xd3K92
QPZk+86w9GgDFNrfxDNRrHPbzJa9AQJAZiBiTldGHLdcCXEhUSaIgCGEtl1xp9JA
hlaXVTsB28HzmTz+aBKhrdCTXMpQnB4pfVLi7zCOBYB6S5vBpNxLqQJBAJ7peIHi
8rWqOtSElK97nwtjrtnyeqHGXz2yI+awU9OyFDnMgBUuowwmIoApiMKTpZ+zfH8N
mtpo5D7DfLSqkNU=
-----END PRIVATE KEY-----
6 changes: 6 additions & 0 deletions lib/ocrypto/testdata/sample-rsa-1024-01-public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTv1JlHgfTGOc9urk/0MHZ9bRx
Mks3sArFp5wxzIEHkJQowfuoKNV18aTmL+D4gK56fryDZo9UypC9i6RUtfybw+ne
euHnG2u0oKXB/4k6EYtd5Ll8K6HDa7E+M8VjvpaaEdRvgsyeSUh9B2/jRuEEOg8E
E+jY+gOWXf4+ldBkpwIDAQAB
-----END PUBLIC KEY-----
28 changes: 28 additions & 0 deletions lib/ocrypto/testdata/sample-rsa-2048-01-private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCzv7o3b1JcNFpM
pgUyIRatTqxTdCfA6PTltAQDFK37ZM/Zg1mC+QmNMaTXPxNXYlmNKzLnACKn/nEZ
15n+x/t2uHKSE2tM9hxQnBJkJrtm7zM6z5ztNO8fbqIFEB98bRzck7/WXFVfOrKS
Tc9tUku9xk8NRDSHKK0A6w/9Y51NnwwalLC8G66WonsXyRQOurcuxtcUHRKLOOo0
XZ65vKsZgGfYXQpsWb+N6sf7yDA28yn7aLX53qUFXZmeV8+7KLTopEFZdnNUJNzu
WqRY1dHC8DLi1/mzsSf9pg7/uzuV34J/mbiPkYcXPXuLnvRbFBOZ7Nn9YH2prWVA
0ck7tTqFAgMBAAECggEAE6TbKsZDe7ir+q71J+iWVBviON+bnZlH9FeTTavjpLL8
hSK19FqXmOLpRy3JRRZGP6eOMVEiOHZV8XNOzNmZqXyYZs7w/dDywLuBxgi2l9YB
5QY9+e18SZTbZ46+xigdjJyoDTr7iIP/cn5G8kVZajTDPGmtDO1c1Nobnf9WOF5/
raFPN8ouWLaBoL3EQ2CKH/rCPLZIDVWQoawcKgtHshLDy4q5Hi94foAifKvK8cbl
sP2MzuDYWvZ3Bp/0+C5S4W2qbJdo4bv/XAkxzO0hujiaX+hJTa4ZZC2k8/9JgEYz
2P31NloH7Hofy5wKNtDv6nP+v6vBCRmRZm1/nw9TwQKBgQDiTOAxgvMBNxhF0zuo
CX3J7mlU7YSkGJQGhjdltbB4OwcZSaC1pUwN0x7O4lATBZHJ2LeYj2r/mMmaY2a0
+XgF+eTwVzaiYv8GS6/G//ILnd6ufS8P1k1UmsT408OfMVtq9DrVNtAlaqLWl3Y5
SJVf7zpykj2YFSXwogikyqZpxQKBgQDLVteg+FMk2QtcrKqfsNH3RIiSJ90X2PH4
ZM4YaahuecT9BFRQPdCzkAICBjh17Bt0WigDGkZZ/I6izf91/E6chBa0TW59Dpq0
ojyRVePHBpg85uH6g2bOxkCYlXQ4SIozHPe1bshAkSkkTCxPtJ6cq4yJObQmF68o
M7QUPTJZwQKBgQCX1gTGs5ngQtsiXmw0fsnLZw99UDAi+eq3xe39bD6PLOvCZ8hQ
mCvDStfs76PSX3ZF/AaTcgbUn+sEj5Ul8Aw71kNpjtq1cb6ytq2l06zPZok2gf/F
nIAeOAnY+hzS/wbbaCrhS/m0YSwI128XWEABMj4BCWYSWH4wSkeKaf3mEQKBgBXW
J6XzxQoJ/Pxg1pn7pTDGvVvkyAuNkr64JKHehuYGUa9STbOoT8dYyb5p6JpRVslx
/SYIJlH3m2HEeZC0HcUVMlL+lcT8UoTff12kOaff/21a5h2/CsVd6QX51tdMgvrm
O3vSf9LfQ+nP/Fo67WWpzpfWCJCmrnrEwqwBvmyBAoGBAKZ3YWGpSPnLV2TZpZ8m
NY0EykcKoghDwGFFtSPLb5hzSTiSs5eBEzNpuNnWdePdg3rTYG7I1ojhTkYngDn9
2GPb7XHPADZFvQdsZ2V9D4ahio8sWUtlcZq+KLjt86KVBJdswgfuiUKGwITPZfOG
JJAivPZMBCoF0NFP2mCyibAj
-----END PRIVATE KEY-----
9 changes: 9 additions & 0 deletions lib/ocrypto/testdata/sample-rsa-2048-01-public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs7+6N29SXDRaTKYFMiEW
rU6sU3QnwOj05bQEAxSt+2TP2YNZgvkJjTGk1z8TV2JZjSsy5wAip/5xGdeZ/sf7
drhykhNrTPYcUJwSZCa7Zu8zOs+c7TTvH26iBRAffG0c3JO/1lxVXzqykk3PbVJL
vcZPDUQ0hyitAOsP/WOdTZ8MGpSwvBuulqJ7F8kUDrq3LsbXFB0SizjqNF2eubyr
GYBn2F0KbFm/jerH+8gwNvMp+2i1+d6lBV2ZnlfPuyi06KRBWXZzVCTc7lqkWNXR
wvAy4tf5s7En/aYO/7s7ld+Cf5m4j5GHFz17i570WxQTmezZ/WB9qa1lQNHJO7U6
hQIDAQAB
-----END PUBLIC KEY-----
Loading
Loading