From b6b526bcf71bb82dc09b92e21f760da5a3e41f42 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 19:06:20 +0000 Subject: [PATCH] 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. --- pkg/crypt/crypt.go | 18 +++++++++++ pkg/crypt/std/pgp/pgp.go | 56 +++++++++++++++++++++++++++++++++++ pkg/crypt/std/pgp/pgp_test.go | 38 ++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/pkg/crypt/crypt.go b/pkg/crypt/crypt.go index db9db5c..0325385 100644 --- a/pkg/crypt/crypt.go +++ b/pkg/crypt/crypt.go @@ -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) +} diff --git a/pkg/crypt/std/pgp/pgp.go b/pkg/crypt/std/pgp/pgp.go index 0a70b5c..2f8eddc 100644 --- a/pkg/crypt/std/pgp/pgp.go +++ b/pkg/crypt/std/pgp/pgp.go @@ -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 +} diff --git a/pkg/crypt/std/pgp/pgp_test.go b/pkg/crypt/std/pgp/pgp_test.go index 768f92e..57fe0f6 100644 --- a/pkg/crypt/std/pgp/pgp_test.go +++ b/pkg/crypt/std/pgp/pgp_test.go @@ -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") +}