diff --git a/encrypterdecrypter/asymmetric/rsa.go b/encrypterdecrypter/asymmetric/rsa.go new file mode 100644 index 0000000..e719072 --- /dev/null +++ b/encrypterdecrypter/asymmetric/rsa.go @@ -0,0 +1,69 @@ +package asymmetric + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "fmt" + + sv "github.com/secure-systems-lab/go-securesystemslib/signerverifier" +) + +type RSAEncrypterDecrypter struct { + keyID string + private *rsa.PrivateKey + public *rsa.PublicKey +} + +func NewRSAEncrypterDecrypterFromSSLibKey(key *sv.SSLibKey) (*RSAEncrypterDecrypter, error) { + if len(key.KeyVal.Public) == 0 { + return nil, sv.ErrInvalidKey + } + + _, publicParsedKey, err := sv.DecodeAndParsePEM([]byte(key.KeyVal.Public)) + if err != nil { + return nil, fmt.Errorf("unable to create RSA encrypterdecrypter: %w", err) + } + + if len(key.KeyVal.Private) > 0 { + _, privateParsedKey, err := sv.DecodeAndParsePEM([]byte(key.KeyVal.Private)) + if err != nil { + return nil, fmt.Errorf("unable to create RSA encrypterdecrypter: %w", err) + } + + return &RSAEncrypterDecrypter{ + keyID: key.KeyID, + public: publicParsedKey.(*rsa.PublicKey), + private: privateParsedKey.(*rsa.PrivateKey), + }, nil + } + + return &RSAEncrypterDecrypter{ + keyID: key.KeyID, + public: publicParsedKey.(*rsa.PublicKey), + private: nil, + }, nil +} + +// Encrypt encrypts the provided data with the public key of the RSA +// EncrypterDecrypter instance. +func (ed *RSAEncrypterDecrypter) Encrypt(data []byte) ([]byte, error) { + rng := rand.Reader + return rsa.EncryptOAEP(sha256.New(), rng, ed.public, data, nil) +} + +// Decrypt decrypts the provided data with the private key of the RSA +// EncrypterDecrypter instance. +func (ed *RSAEncrypterDecrypter) Decrypt(data []byte) ([]byte, error) { + if ed.private == nil { + return nil, sv.ErrNotPrivateKey + } + + return rsa.DecryptOAEP(sha256.New(), nil, ed.private, data, nil) +} + +// KeyID returns the key ID of the key used to create the RSA EncrypterDecrypter +// instance. +func (ed *RSAEncrypterDecrypter) KeyID() (string, error) { + return ed.keyID, nil +} diff --git a/encrypterdecrypter/asymmetric/rsa_test.go b/encrypterdecrypter/asymmetric/rsa_test.go new file mode 100644 index 0000000..7c717c1 --- /dev/null +++ b/encrypterdecrypter/asymmetric/rsa_test.go @@ -0,0 +1,72 @@ +package asymmetric + +import ( + "crypto/rsa" + "path/filepath" + "testing" + + sv "github.com/secure-systems-lab/go-securesystemslib/signerverifier" + "github.com/stretchr/testify/assert" +) + +var plaintext = []byte("reallyimportant") + +func TestNewRSAEncrypterDecrypterFromSSLibKey(t *testing.T) { + key, err := sv.LoadRSAPSSKeyFromFile(filepath.Join("..", "..", "signerverifier", "test-data", "rsa-test-key.pub")) + if err != nil { + t.Error(err) + } + + ed, err := NewRSAEncrypterDecrypterFromSSLibKey(key) + if err != nil { + t.Error(err) + } + + expectedPublicString := "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA04egZRic+dZMVtiQc56D\nejU4FF1q3aOkUKnD+Q4lTbj1zp6ODKJTcktupmrad68jqtMiSGG8he6ELFs377q8\nbbgEUMWgAf+06Q8oFvUSfOXzZNFI7H5SMPOJY5aDWIMIEZ8DlcO7TfkA7D3iAEJX\nxxTOVS3UAIk5umO7Y7t7yXr8O/C4u78krGazCnoblcekMLJZV4O/5BloWNAe/B1c\nvZdaZUf3brD4ZZrxEtXw/tefhn1aHsSUajVW2wwjSpKhqj7Z0XS3bDS3T95/3xsN\n6+hlS6A7rJfiWpKIRHj0vh2SXLDmmhQl1In8TD/aiycTUyWcBRHVPlYFgYPt6SaT\nVQSgMzSxC43/2fINb2fyt8SbUHJ3Ct+mzRzd/1AQikWhBdstJLxInewzjYE/sb+c\n2CmCxMPQG2BwmAWXaaumeJcXVPBlMgAcjMatM8bPByTbXpKDnQslOE7g/gswDIwn\nEm53T13mZzYUvbLJ0q3aljZVLIC3IZn3ZwA2yCWchBkVAgMBAAE=\n-----END PUBLIC KEY-----" + _, expectedPublicKey, err := sv.DecodeAndParsePEM([]byte(expectedPublicString)) + assert.Nil(t, err) + + assert.Equal(t, "4e8d20af09fcaed6c388a186427f94a5f7ff5591ec295f4aab2cff49ffe39e9b", ed.keyID) + assert.Equal(t, expectedPublicKey.(*rsa.PublicKey), ed.public) + assert.Nil(t, ed.private) +} + +func TestRoundtrip(t *testing.T) { + key, err := sv.LoadRSAPSSKeyFromFile(filepath.Join("..", "..", "signerverifier", "test-data", "rsa-test-key")) + if err != nil { + t.Error(err) + } + + ed, err := NewRSAEncrypterDecrypterFromSSLibKey(key) + if err != nil { + t.Error(err) + } + + ciphertext, err := ed.Encrypt(plaintext) + assert.Nil(t, err) + + decryptedPlaintext, err := ed.Decrypt(ciphertext) + assert.Nil(t, err) + + assert.Equal(t, plaintext, decryptedPlaintext) +} + +func TestRoundtripCorrupted(t *testing.T) { + key, err := sv.LoadRSAPSSKeyFromFile(filepath.Join("..", "..", "signerverifier", "test-data", "rsa-test-key")) + if err != nil { + t.Error(err) + } + + ed, err := NewRSAEncrypterDecrypterFromSSLibKey(key) + if err != nil { + t.Error(err) + } + + ciphertext, err := ed.Encrypt(plaintext) + assert.Nil(t, err) + + ciphertext[0] = ^ciphertext[0] + + _, err = ed.Decrypt(ciphertext) + assert.ErrorContains(t, err, "decryption error") +} diff --git a/encrypterdecrypter/encrypterdecrypter.go b/encrypterdecrypter/encrypterdecrypter.go new file mode 100644 index 0000000..aa3d680 --- /dev/null +++ b/encrypterdecrypter/encrypterdecrypter.go @@ -0,0 +1,22 @@ +package encrypterdecrypter + +// Encrypter is the interface for an abstract asymmetric or symmetric block +// encryption algorithm. The Encrypter interface is used to encrypt arbitrary +// byte payloads, and returns the ciphertext, or an error. It is +// cipher-agnostic. +type Encrypter interface { + Encrypt([]byte) ([]byte, error) + KeyID() (string, error) +} + +// Decrypter is the interface to decrypt ciphertext. +type Decrypter interface { + Decrypt([]byte) ([]byte, error) + KeyID() (string, error) +} + +// EncrypterDecrypter is the combined interface of Encrypter and Decrypter. +type EncrypterDecrypter interface { + Encrypter + Decrypter +} diff --git a/encrypterdecrypter/symmetric/aes.go b/encrypterdecrypter/symmetric/aes.go new file mode 100644 index 0000000..a5583e7 --- /dev/null +++ b/encrypterdecrypter/symmetric/aes.go @@ -0,0 +1,103 @@ +package symmetric + +import ( + "crypto/aes" + "crypto/cipher" + "errors" +) + +var ( + ErrInvalidKeyLength = errors.New("invalid key length") + ErrInvalidMode = errors.New("invalid mode") +) + +type AESMode uint8 + +const ( + GCM AESMode = iota +) + +type AESEncrypterDecrypter struct { + keyID string + keyBytes []byte + mode AESMode +} + +// NewAESEncrypterDecrypterFromSSLibSymmetricKey creates an +// AESEncrypterDecrypter from an SSLibSymmetricKey. +func NewAESEncrypterDecrypterFromSSLibSymmetricKey(key *SSLibSymmetricKey, mode AESMode) (*AESEncrypterDecrypter, error) { + switch mode { + case GCM: + break + default: + return nil, ErrInvalidMode + } + + return &AESEncrypterDecrypter{ + keyID: key.KeyID, + keyBytes: key.KeyVal, + mode: mode, + }, nil +} + +// Encrypt encrypts the provided data with the key of the AES +// EncrypterDecrypter. +func (ed *AESEncrypterDecrypter) Encrypt(data []byte) ([]byte, error) { + block, err := aes.NewCipher(ed.keyBytes) + if err != nil { + return nil, err + } + + var ciphertext []byte + + switch ed.mode { + case GCM: + gcm, err := cipher.NewGCMWithRandomNonce(block) + if err != nil { + return nil, err + } + + ciphertext = gcm.Seal(nil, nil, data, nil) + } + return ciphertext, nil +} + +// Decrypt decrypts the provided data with the key of the AES +// EncrypterDecrypter. +func (ed *AESEncrypterDecrypter) Decrypt(data []byte) ([]byte, error) { + block, err := aes.NewCipher(ed.keyBytes) + if err != nil { + return nil, err + } + + var plaintext []byte + switch ed.mode { + case GCM: + gcm, err := cipher.NewGCMWithRandomNonce(block) + if err != nil { + return nil, err + } + + plaintext, err = gcm.Open(nil, nil, data, nil) + if err != nil { + return nil, err + } + } + return plaintext, nil +} + +// KeyID returns the key ID of the key used to create the AES EncrypterDecrypter +// instance. +func (ed *AESEncrypterDecrypter) KeyID() (string, error) { + return ed.keyID, nil +} + +func validateAESKeySize(key []byte) (int, error) { + switch len(key) { + // AES-128, AES-192, AES-256 + case 16, 24, 32: + return len(key) / 8, nil + default: + return 0, ErrInvalidKeyLength + } +} diff --git a/encrypterdecrypter/symmetric/aes_test.go b/encrypterdecrypter/symmetric/aes_test.go new file mode 100644 index 0000000..15156df --- /dev/null +++ b/encrypterdecrypter/symmetric/aes_test.go @@ -0,0 +1,53 @@ +package symmetric + +import ( + "encoding/hex" + "fmt" + "testing" + + "github.com/secure-systems-lab/go-securesystemslib/encrypterdecrypter/symmetric/testdata" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var plaintext = []byte("reallyimportant") + +func TestRoundtrip(t *testing.T) { + key, err := hex.DecodeString(string(testdata.AESKey)) + require.Nil(t, err) + + fmt.Println(key) + + ed := &AESEncrypterDecrypter{ + keyID: "super secret key", + keyBytes: key, + mode: GCM, + } + + ciphertext, err := ed.Encrypt(plaintext) + assert.Nil(t, err) + + decryptedPlaintext, err := ed.Decrypt(ciphertext) + assert.Nil(t, err) + + assert.Equal(t, plaintext, decryptedPlaintext) +} + +func TestRoundtripCorrupted(t *testing.T) { + key, err := hex.DecodeString(string(testdata.AESKey)) + require.Nil(t, err) + + ed := &AESEncrypterDecrypter{ + keyID: "super secret key", + keyBytes: key, + mode: GCM, + } + + ciphertext, err := ed.Encrypt(plaintext) + assert.Nil(t, err) + + ciphertext[0] = ^ciphertext[0] + + _, err = ed.Decrypt(ciphertext) + assert.ErrorContains(t, err, "message authentication failed") +} diff --git a/encrypterdecrypter/symmetric/symmetric.go b/encrypterdecrypter/symmetric/symmetric.go new file mode 100644 index 0000000..d1d79bb --- /dev/null +++ b/encrypterdecrypter/symmetric/symmetric.go @@ -0,0 +1,56 @@ +package symmetric + +import ( + "encoding/hex" + "errors" +) + +var ErrUnknownKeyType = errors.New("unknown key type") + +type SSLibSymmetricCipher uint8 + +const ( + AES SSLibSymmetricCipher = iota +) + +type SSLibSymmetricKey struct { + KeyID string `json:"keyid"` + Cipher SSLibSymmetricCipher `json:"scheme"` + KeySize int `json:"keysize"` + KeyVal []byte `json:"keyval"` +} + +// LoadSymmetricKey returns an SSLibSymmetricKey object when provided a byte +// array and cipher. Currently, AES-128/192/256 are supported. +func LoadSymmetricKey(keyBytes []byte, cipher SSLibSymmetricCipher) (*SSLibSymmetricKey, error) { + var key *SSLibSymmetricKey + + switch cipher { + case AES: + keyBytes, err := hex.DecodeString(string(keyBytes)) + if err != nil { + return nil, err + } + + keySize, err := validateAESKeySize(keyBytes) + if err != nil { + return nil, err + } + + key = &SSLibSymmetricKey{ + KeyID: "", + Cipher: cipher, + KeySize: keySize, + KeyVal: keyBytes, + } + default: + return nil, ErrUnknownKeyType + } + + keyID, err := CalculateSymmetricKeyID(key) + if err != nil { + return nil, err + } + key.KeyID = keyID + return key, nil +} diff --git a/encrypterdecrypter/symmetric/symmetric_test.go b/encrypterdecrypter/symmetric/symmetric_test.go new file mode 100644 index 0000000..da6f7f0 --- /dev/null +++ b/encrypterdecrypter/symmetric/symmetric_test.go @@ -0,0 +1,30 @@ +package symmetric + +import ( + "fmt" + "testing" + + "github.com/secure-systems-lab/go-securesystemslib/encrypterdecrypter/symmetric/testdata" + "github.com/stretchr/testify/assert" +) + +func TestLoadSymmetricKey(t *testing.T) { + tests := map[string]struct { + keyBytes []byte + cipher SSLibSymmetricCipher + expectedKeyID string + }{ + "AES key": { + keyBytes: testdata.AESKey, + cipher: AES, + expectedKeyID: "3365676914098a99b563b1d5b90822916e78d1109640bbdaf196208db3edf908", + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + key, err := LoadSymmetricKey(test.keyBytes, test.cipher) + assert.Nil(t, err, fmt.Sprintf("unexpected error in test '%s'", name)) + assert.Equal(t, test.expectedKeyID, key.KeyID) + }) + } +} diff --git a/encrypterdecrypter/symmetric/testdata/aes-key b/encrypterdecrypter/symmetric/testdata/aes-key new file mode 100644 index 0000000..f355f59 --- /dev/null +++ b/encrypterdecrypter/symmetric/testdata/aes-key @@ -0,0 +1 @@ +6368616e676520746869732070617373776f726420746f206120736563726574 \ No newline at end of file diff --git a/encrypterdecrypter/symmetric/testdata/testdata.go b/encrypterdecrypter/symmetric/testdata/testdata.go new file mode 100644 index 0000000..9074956 --- /dev/null +++ b/encrypterdecrypter/symmetric/testdata/testdata.go @@ -0,0 +1,8 @@ +package testdata + +import ( + _ "embed" +) + +//go:embed aes-key +var AESKey []byte diff --git a/encrypterdecrypter/symmetric/utils.go b/encrypterdecrypter/symmetric/utils.go new file mode 100644 index 0000000..8c5f526 --- /dev/null +++ b/encrypterdecrypter/symmetric/utils.go @@ -0,0 +1,22 @@ +package symmetric + +import ( + "crypto/sha256" + "encoding/hex" + + "github.com/secure-systems-lab/go-securesystemslib/cjson" +) + +func CalculateSymmetricKeyID(k *SSLibSymmetricKey) (string, error) { + key := map[string]any{ + "cipher": k.Cipher, + "keysize": k.KeySize, + "keyval": k.KeyVal, + } + canonical, err := cjson.EncodeCanonical(key) + if err != nil { + return "", err + } + digest := sha256.Sum256(canonical) + return hex.EncodeToString(digest[:]), nil +} diff --git a/signerverifier/ecdsa.go b/signerverifier/ecdsa.go index 691091a..d8397f8 100644 --- a/signerverifier/ecdsa.go +++ b/signerverifier/ecdsa.go @@ -32,7 +32,7 @@ func NewECDSASignerVerifierFromSSLibKey(key *SSLibKey) (*ECDSASignerVerifier, er return nil, ErrInvalidKey } - _, publicParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Public)) + _, publicParsedKey, err := DecodeAndParsePEM([]byte(key.KeyVal.Public)) if err != nil { return nil, fmt.Errorf("unable to create ECDSA signerverifier: %w", err) } @@ -45,7 +45,7 @@ func NewECDSASignerVerifierFromSSLibKey(key *SSLibKey) (*ECDSASignerVerifier, er } if len(key.KeyVal.Private) > 0 { - _, privateParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Private)) + _, privateParsedKey, err := DecodeAndParsePEM([]byte(key.KeyVal.Private)) if err != nil { return nil, fmt.Errorf("unable to create ECDSA signerverifier: %w", err) } diff --git a/signerverifier/ecdsa_test.go b/signerverifier/ecdsa_test.go index d695412..65480b1 100644 --- a/signerverifier/ecdsa_test.go +++ b/signerverifier/ecdsa_test.go @@ -24,7 +24,7 @@ func TestNewECDSASignerVerifierFromSSLibKey(t *testing.T) { } expectedPublicString := "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu+HEqqpXLa48lXH9rkRygsfsCKq1\nXM36oXymJ9wxpM68nCqkrZCVnZ9lkEeCwD8qWYTNxD5yfWXwJjFh+K7qLQ==\n-----END PUBLIC KEY-----" - _, expectedPublicKey, err := decodeAndParsePEM([]byte(expectedPublicString)) + _, expectedPublicKey, err := DecodeAndParsePEM([]byte(expectedPublicString)) assert.Nil(t, err) assert.Equal(t, "98adf38602c48c5479e9a991ee3f8cbf541ee4f985e00f7a5fc4148d9a45b704", sv.keyID) diff --git a/signerverifier/rsa.go b/signerverifier/rsa.go index 2abfcb2..da2654e 100644 --- a/signerverifier/rsa.go +++ b/signerverifier/rsa.go @@ -33,13 +33,13 @@ func NewRSAPSSSignerVerifierFromSSLibKey(key *SSLibKey) (*RSAPSSSignerVerifier, return nil, ErrInvalidKey } - _, publicParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Public)) + _, publicParsedKey, err := DecodeAndParsePEM([]byte(key.KeyVal.Public)) if err != nil { return nil, fmt.Errorf("unable to create RSA-PSS signerverifier: %w", err) } if len(key.KeyVal.Private) > 0 { - _, privateParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Private)) + _, privateParsedKey, err := DecodeAndParsePEM([]byte(key.KeyVal.Private)) if err != nil { return nil, fmt.Errorf("unable to create RSA-PSS signerverifier: %w", err) } @@ -116,7 +116,7 @@ func LoadRSAPSSKeyFromFile(path string) (*SSLibKey, error) { // Deprecated: use LoadKey() for all key types, RSA is no longer the only key // that uses PEM serialization. func LoadRSAPSSKeyFromBytes(contents []byte) (*SSLibKey, error) { - pemData, keyObj, err := decodeAndParsePEM(contents) + pemData, keyObj, err := DecodeAndParsePEM(contents) if err != nil { return nil, fmt.Errorf("unable to load RSA key from file: %w", err) } @@ -135,11 +135,11 @@ func LoadRSAPSSKeyFromBytes(contents []byte) (*SSLibKey, error) { key.KeyVal.Public = strings.TrimSpace(string(pubKeyBytes)) if _, ok := keyObj.(*rsa.PrivateKey); ok { - key.KeyVal.Private = strings.TrimSpace(string(generatePEMBlock(pemData.Bytes, RSAPrivateKeyPEM))) + key.KeyVal.Private = strings.TrimSpace(string(GeneratePEMBlock(pemData.Bytes, RSAPrivateKeyPEM))) } if len(key.KeyID) == 0 { - keyID, err := calculateKeyID(key) + keyID, err := CalculateAsymmetricKeyID(key) if err != nil { return nil, fmt.Errorf("unable to load RSA key from file: %w", err) } @@ -166,5 +166,5 @@ func marshalAndGeneratePEM(key interface{}) ([]byte, error) { return nil, err } - return generatePEMBlock(pubKeyBytes, PublicKeyPEM), nil + return GeneratePEMBlock(pubKeyBytes, PublicKeyPEM), nil } diff --git a/signerverifier/rsa_test.go b/signerverifier/rsa_test.go index 1ca3412..b1ff38f 100644 --- a/signerverifier/rsa_test.go +++ b/signerverifier/rsa_test.go @@ -25,7 +25,7 @@ func TestNewRSAPSSSignerVerifierFromSSLibKey(t *testing.T) { } expectedPublicString := "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA04egZRic+dZMVtiQc56D\nejU4FF1q3aOkUKnD+Q4lTbj1zp6ODKJTcktupmrad68jqtMiSGG8he6ELFs377q8\nbbgEUMWgAf+06Q8oFvUSfOXzZNFI7H5SMPOJY5aDWIMIEZ8DlcO7TfkA7D3iAEJX\nxxTOVS3UAIk5umO7Y7t7yXr8O/C4u78krGazCnoblcekMLJZV4O/5BloWNAe/B1c\nvZdaZUf3brD4ZZrxEtXw/tefhn1aHsSUajVW2wwjSpKhqj7Z0XS3bDS3T95/3xsN\n6+hlS6A7rJfiWpKIRHj0vh2SXLDmmhQl1In8TD/aiycTUyWcBRHVPlYFgYPt6SaT\nVQSgMzSxC43/2fINb2fyt8SbUHJ3Ct+mzRzd/1AQikWhBdstJLxInewzjYE/sb+c\n2CmCxMPQG2BwmAWXaaumeJcXVPBlMgAcjMatM8bPByTbXpKDnQslOE7g/gswDIwn\nEm53T13mZzYUvbLJ0q3aljZVLIC3IZn3ZwA2yCWchBkVAgMBAAE=\n-----END PUBLIC KEY-----" - _, expectedPublicKey, err := decodeAndParsePEM([]byte(expectedPublicString)) + _, expectedPublicKey, err := DecodeAndParsePEM([]byte(expectedPublicString)) assert.Nil(t, err) assert.Equal(t, "4e8d20af09fcaed6c388a186427f94a5f7ff5591ec295f4aab2cff49ffe39e9b", sv.keyID) diff --git a/signerverifier/signerverifier.go b/signerverifier/signerverifier.go index 3a8259d..d79da74 100644 --- a/signerverifier/signerverifier.go +++ b/signerverifier/signerverifier.go @@ -45,7 +45,7 @@ type KeyVal struct { // LoadKey returns an SSLibKey object when provided a PEM encoded key. // Currently, RSA, ED25519, and ECDSA keys are supported. func LoadKey(keyBytes []byte) (*SSLibKey, error) { - pemBlock, rawKey, err := decodeAndParsePEM(keyBytes) + pemBlock, rawKey, err := DecodeAndParsePEM(keyBytes) if err != nil { return nil, err } @@ -61,7 +61,7 @@ func LoadKey(keyBytes []byte) (*SSLibKey, error) { KeyIDHashAlgorithms: KeyIDHashAlgorithms, KeyType: RSAKeyType, KeyVal: KeyVal{ - Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, PublicKeyPEM))), + Public: strings.TrimSpace(string(GeneratePEMBlock(pubKeyBytes, PublicKeyPEM))), }, Scheme: RSAKeyScheme, } @@ -75,8 +75,8 @@ func LoadKey(keyBytes []byte) (*SSLibKey, error) { KeyIDHashAlgorithms: KeyIDHashAlgorithms, KeyType: RSAKeyType, KeyVal: KeyVal{ - Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, PublicKeyPEM))), - Private: strings.TrimSpace(string(generatePEMBlock(pemBlock.Bytes, pemBlock.Type))), + Public: strings.TrimSpace(string(GeneratePEMBlock(pubKeyBytes, PublicKeyPEM))), + Private: strings.TrimSpace(string(GeneratePEMBlock(pemBlock.Bytes, pemBlock.Type))), }, Scheme: RSAKeyScheme, } @@ -112,7 +112,7 @@ func LoadKey(keyBytes []byte) (*SSLibKey, error) { KeyIDHashAlgorithms: KeyIDHashAlgorithms, KeyType: ECDSAKeyType, KeyVal: KeyVal{ - Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, PublicKeyPEM))), + Public: strings.TrimSpace(string(GeneratePEMBlock(pubKeyBytes, PublicKeyPEM))), }, Scheme: ECDSAKeyScheme, } @@ -126,8 +126,8 @@ func LoadKey(keyBytes []byte) (*SSLibKey, error) { KeyIDHashAlgorithms: KeyIDHashAlgorithms, KeyType: ECDSAKeyType, KeyVal: KeyVal{ - Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, PublicKeyPEM))), - Private: strings.TrimSpace(string(generatePEMBlock(pemBlock.Bytes, PrivateKeyPEM))), + Public: strings.TrimSpace(string(GeneratePEMBlock(pubKeyBytes, PublicKeyPEM))), + Private: strings.TrimSpace(string(GeneratePEMBlock(pemBlock.Bytes, PrivateKeyPEM))), }, Scheme: ECDSAKeyScheme, } @@ -136,7 +136,7 @@ func LoadKey(keyBytes []byte) (*SSLibKey, error) { return nil, ErrUnknownKeyType } - keyID, err := calculateKeyID(key) + keyID, err := CalculateAsymmetricKeyID(key) if err != nil { return nil, err } diff --git a/signerverifier/utils.go b/signerverifier/utils.go index e8a30b5..043dccc 100644 --- a/signerverifier/utils.go +++ b/signerverifier/utils.go @@ -36,7 +36,7 @@ func LoadKeyFromSSLibBytes(contents []byte) (*SSLibKey, error) { return LoadRSAPSSKeyFromBytes(contents) } if len(key.KeyID) == 0 { - keyID, err := calculateKeyID(key) + keyID, err := CalculateAsymmetricKeyID(key) if err != nil { return nil, err } @@ -46,7 +46,7 @@ func LoadKeyFromSSLibBytes(contents []byte) (*SSLibKey, error) { return key, nil } -func calculateKeyID(k *SSLibKey) (string, error) { +func CalculateAsymmetricKeyID(k *SSLibKey) (string, error) { key := map[string]any{ "keytype": k.KeyType, "scheme": k.Scheme, @@ -64,12 +64,12 @@ func calculateKeyID(k *SSLibKey) (string, error) { } /* -generatePEMBlock creates a PEM block from scratch via the keyBytes and the pemType. +GeneratePEMBlock creates a PEM block from scratch via the keyBytes and the pemType. If successful it returns a PEM block as []byte slice. This function should always succeed, if keyBytes is empty the PEM block will have an empty byte block. Therefore only header and footer will exist. */ -func generatePEMBlock(keyBytes []byte, pemType string) []byte { +func GeneratePEMBlock(keyBytes []byte, pemType string) []byte { // construct PEM block pemBlock := &pem.Block{ Type: pemType, @@ -80,7 +80,7 @@ func generatePEMBlock(keyBytes []byte, pemType string) []byte { } /* -decodeAndParsePEM receives potential PEM bytes decodes them via pem.Decode +DecodeAndParsePEM receives potential PEM bytes decodes them via pem.Decode and pushes them to parseKey. If any error occurs during this process, the function will return nil and an error (either ErrFailedPEMParsing or ErrNoPEMBlock). On success it will return the decoded pemData, the @@ -88,7 +88,7 @@ key object interface and nil as error. We need the decoded pemData, because LoadKey relies on decoded pemData for operating system interoperability. */ -func decodeAndParsePEM(pemBytes []byte) (*pem.Block, any, error) { +func DecodeAndParsePEM(pemBytes []byte) (*pem.Block, any, error) { // pem.Decode returns the parsed pem block and a rest. // The rest is everything, that could not be parsed as PEM block. // Therefore we can drop this via using the blank identifier "_"