feat: Expand OpenPGP implementation

Expands the existing OpenPGP implementation to include a more complete set of features for handling PGP data.

- Adds support for signing and verifying detached signatures.
- Adds support for symmetric encryption using a passphrase.
- Includes tests for all new functionality.
This commit is contained in:
google-labs-jules[bot] 2025-11-13 19:06:20 +00:00
parent a46477c8fd
commit b6b526bcf7
3 changed files with 112 additions and 0 deletions

View file

@ -201,3 +201,21 @@ func (s *Service) DecryptPGP(privateKey, ciphertext []byte) ([]byte, error) {
s.ensurePGP()
return s.pgp.Decrypt(privateKey, ciphertext)
}
// SignPGP creates a detached signature for a message.
func (s *Service) SignPGP(privateKey, data []byte) ([]byte, error) {
s.ensurePGP()
return s.pgp.Sign(privateKey, data)
}
// VerifyPGP verifies a detached signature for a message.
func (s *Service) VerifyPGP(publicKey, data, signature []byte) error {
s.ensurePGP()
return s.pgp.Verify(publicKey, data, signature)
}
// SymmetricallyEncryptPGP encrypts data with a passphrase.
func (s *Service) SymmetricallyEncryptPGP(passphrase, data []byte) ([]byte, error) {
s.ensurePGP()
return s.pgp.SymmetricallyEncrypt(passphrase, data)
}

View file

@ -107,3 +107,59 @@ func (s *Service) Decrypt(privateKey, ciphertext []byte) ([]byte, error) {
return plaintext, nil
}
// Sign creates a detached signature for a message.
func (s *Service) Sign(privateKey, data []byte) ([]byte, error) {
privKeyReader := bytes.NewReader(privateKey)
keyring, err := openpgp.ReadArmoredKeyRing(privKeyReader)
if err != nil {
return nil, fmt.Errorf("failed to read private key ring: %w", err)
}
signer := keyring[0]
if signer.PrivateKey == nil {
return nil, fmt.Errorf("private key not found in keyring")
}
buf := new(bytes.Buffer)
err = openpgp.ArmoredDetachSign(buf, signer, bytes.NewReader(data), nil)
if err != nil {
return nil, fmt.Errorf("failed to sign message: %w", err)
}
return buf.Bytes(), nil
}
// Verify verifies a detached signature for a message.
func (s *Service) Verify(publicKey, data, signature []byte) error {
pubKeyReader := bytes.NewReader(publicKey)
keyring, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
if err != nil {
return fmt.Errorf("failed to read public key ring: %w", err)
}
_, err = openpgp.CheckArmoredDetachedSignature(keyring, bytes.NewReader(data), bytes.NewReader(signature), nil)
if err != nil {
return fmt.Errorf("failed to verify signature: %w", err)
}
return nil
}
// SymmetricallyEncrypt encrypts data with a passphrase.
func (s *Service) SymmetricallyEncrypt(passphrase, data []byte) ([]byte, error) {
buf := new(bytes.Buffer)
w, err := openpgp.SymmetricallyEncrypt(buf, passphrase, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to create symmetric encryption writer: %w", err)
}
defer w.Close()
_, err = w.Write(data)
if err != nil {
return nil, fmt.Errorf("failed to write data to symmetric encryption writer: %w", err)
}
w.Close()
return buf.Bytes(), nil
}

View file

@ -45,3 +45,41 @@ func TestService_Decrypt_Good(t *testing.T) {
require.NoError(t, err, "failed to decrypt data")
assert.Equal(t, data, decrypted, "decrypted data does not match original")
}
func TestService_Sign_Good(t *testing.T) {
s := NewService()
pub, priv, err := s.GenerateKeyPair("test", "test@test.com", "test")
require.NoError(t, err, "failed to generate key pair")
assert.NotNil(t, pub, "public key is nil")
assert.NotNil(t, priv, "private key is nil")
data := []byte("hello world")
signature, err := s.Sign(priv, data)
require.NoError(t, err, "failed to sign data")
assert.NotNil(t, signature, "signature is nil")
}
func TestService_Verify_Good(t *testing.T) {
s := NewService()
pub, priv, err := s.GenerateKeyPair("test", "test@test.com", "test")
require.NoError(t, err, "failed to generate key pair")
assert.NotNil(t, pub, "public key is nil")
assert.NotNil(t, priv, "private key is nil")
data := []byte("hello world")
signature, err := s.Sign(priv, data)
require.NoError(t, err, "failed to sign data")
assert.NotNil(t, signature, "signature is nil")
err = s.Verify(pub, data, signature)
require.NoError(t, err, "failed to verify signature")
}
func TestService_SymmetricallyEncrypt_Good(t *testing.T) {
s := NewService()
passphrase := []byte("hello world")
data := []byte("hello world")
encrypted, err := s.SymmetricallyEncrypt(passphrase, data)
require.NoError(t, err, "failed to encrypt data")
assert.NotNil(t, encrypted, "encrypted data is nil")
}