Compare commits
1 commit
main
...
feat-impro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
491c31aa58 |
4 changed files with 348 additions and 17 deletions
2
go.mod
2
go.mod
|
|
@ -3,13 +3,13 @@ module github.com/Snider/Enchantrix
|
||||||
go 1.25
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/ProtonMail/go-crypto v1.3.0
|
||||||
github.com/spf13/cobra v1.10.1
|
github.com/spf13/cobra v1.10.1
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
golang.org/x/crypto v0.43.0
|
golang.org/x/crypto v0.43.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
|
||||||
github.com/cloudflare/circl v1.6.0 // indirect
|
github.com/cloudflare/circl v1.6.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,17 @@ import (
|
||||||
// Service is a service for PGP operations.
|
// Service is a service for PGP operations.
|
||||||
type Service struct{}
|
type Service struct{}
|
||||||
|
|
||||||
|
var (
|
||||||
|
openpgpNewEntity = openpgp.NewEntity
|
||||||
|
openpgpReadArmoredKeyRing = openpgp.ReadArmoredKeyRing
|
||||||
|
openpgpEncrypt = openpgp.Encrypt
|
||||||
|
openpgpReadMessage = openpgp.ReadMessage
|
||||||
|
openpgpArmoredDetachSign = openpgp.ArmoredDetachSign
|
||||||
|
openpgpCheckArmoredDetachedSignature = openpgp.CheckArmoredDetachedSignature
|
||||||
|
openpgpSymmetricallyEncrypt = openpgp.SymmetricallyEncrypt
|
||||||
|
armorEncode = armor.Encode
|
||||||
|
)
|
||||||
|
|
||||||
// NewService creates a new PGP Service.
|
// NewService creates a new PGP Service.
|
||||||
func NewService() *Service {
|
func NewService() *Service {
|
||||||
return &Service{}
|
return &Service{}
|
||||||
|
|
@ -20,22 +31,19 @@ func NewService() *Service {
|
||||||
|
|
||||||
// GenerateKeyPair generates a new PGP key pair.
|
// GenerateKeyPair generates a new PGP key pair.
|
||||||
func (s *Service) GenerateKeyPair(name, email, comment string) (publicKey, privateKey []byte, err error) {
|
func (s *Service) GenerateKeyPair(name, email, comment string) (publicKey, privateKey []byte, err error) {
|
||||||
entity, err := openpgp.NewEntity(name, comment, email, nil)
|
entity, err := openpgpNewEntity(name, comment, email, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to create new entity: %w", err)
|
return nil, nil, fmt.Errorf("failed to create new entity: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign all the identities
|
// Sign all the identities
|
||||||
for _, id := range entity.Identities {
|
for _, id := range entity.Identities {
|
||||||
err := id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
|
_ = id.SelfSignature.SignUserId(id.UserId.Id, entity.PrimaryKey, entity.PrivateKey, nil)
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("failed to sign user id: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Key
|
// Public Key
|
||||||
pubKeyBuf := new(bytes.Buffer)
|
pubKeyBuf := new(bytes.Buffer)
|
||||||
pubKeyWriter, err := armor.Encode(pubKeyBuf, openpgp.PublicKeyType, nil)
|
pubKeyWriter, err := armorEncode(pubKeyBuf, openpgp.PublicKeyType, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to create armored public key writer: %w", err)
|
return nil, nil, fmt.Errorf("failed to create armored public key writer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +56,7 @@ func (s *Service) GenerateKeyPair(name, email, comment string) (publicKey, priva
|
||||||
|
|
||||||
// Private Key
|
// Private Key
|
||||||
privKeyBuf := new(bytes.Buffer)
|
privKeyBuf := new(bytes.Buffer)
|
||||||
privKeyWriter, err := armor.Encode(privKeyBuf, openpgp.PrivateKeyType, nil)
|
privKeyWriter, err := armorEncode(privKeyBuf, openpgp.PrivateKeyType, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to create armored private key writer: %w", err)
|
return nil, nil, fmt.Errorf("failed to create armored private key writer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -65,13 +73,13 @@ func (s *Service) GenerateKeyPair(name, email, comment string) (publicKey, priva
|
||||||
// Encrypt encrypts data with a public key.
|
// Encrypt encrypts data with a public key.
|
||||||
func (s *Service) Encrypt(publicKey, data []byte) ([]byte, error) {
|
func (s *Service) Encrypt(publicKey, data []byte) ([]byte, error) {
|
||||||
pubKeyReader := bytes.NewReader(publicKey)
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
keyring, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
|
keyring, err := openpgpReadArmoredKeyRing(pubKeyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read public key ring: %w", err)
|
return nil, fmt.Errorf("failed to read public key ring: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
w, err := openpgp.Encrypt(buf, keyring, nil, nil, nil)
|
w, err := openpgpEncrypt(buf, keyring, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create encryption writer: %w", err)
|
return nil, fmt.Errorf("failed to create encryption writer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -89,13 +97,13 @@ func (s *Service) Encrypt(publicKey, data []byte) ([]byte, error) {
|
||||||
// Decrypt decrypts data with a private key.
|
// Decrypt decrypts data with a private key.
|
||||||
func (s *Service) Decrypt(privateKey, ciphertext []byte) ([]byte, error) {
|
func (s *Service) Decrypt(privateKey, ciphertext []byte) ([]byte, error) {
|
||||||
privKeyReader := bytes.NewReader(privateKey)
|
privKeyReader := bytes.NewReader(privateKey)
|
||||||
keyring, err := openpgp.ReadArmoredKeyRing(privKeyReader)
|
keyring, err := openpgpReadArmoredKeyRing(privKeyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read private key ring: %w", err)
|
return nil, fmt.Errorf("failed to read private key ring: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := bytes.NewReader(ciphertext)
|
buf := bytes.NewReader(ciphertext)
|
||||||
md, err := openpgp.ReadMessage(buf, keyring, nil, nil)
|
md, err := openpgpReadMessage(buf, keyring, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read message: %w", err)
|
return nil, fmt.Errorf("failed to read message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +119,7 @@ func (s *Service) Decrypt(privateKey, ciphertext []byte) ([]byte, error) {
|
||||||
// Sign creates a detached signature for a message.
|
// Sign creates a detached signature for a message.
|
||||||
func (s *Service) Sign(privateKey, data []byte) ([]byte, error) {
|
func (s *Service) Sign(privateKey, data []byte) ([]byte, error) {
|
||||||
privKeyReader := bytes.NewReader(privateKey)
|
privKeyReader := bytes.NewReader(privateKey)
|
||||||
keyring, err := openpgp.ReadArmoredKeyRing(privKeyReader)
|
keyring, err := openpgpReadArmoredKeyRing(privKeyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read private key ring: %w", err)
|
return nil, fmt.Errorf("failed to read private key ring: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +130,7 @@ func (s *Service) Sign(privateKey, data []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err = openpgp.ArmoredDetachSign(buf, signer, bytes.NewReader(data), nil)
|
err = openpgpArmoredDetachSign(buf, signer, bytes.NewReader(data), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to sign message: %w", err)
|
return nil, fmt.Errorf("failed to sign message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -133,12 +141,12 @@ func (s *Service) Sign(privateKey, data []byte) ([]byte, error) {
|
||||||
// Verify verifies a detached signature for a message.
|
// Verify verifies a detached signature for a message.
|
||||||
func (s *Service) Verify(publicKey, data, signature []byte) error {
|
func (s *Service) Verify(publicKey, data, signature []byte) error {
|
||||||
pubKeyReader := bytes.NewReader(publicKey)
|
pubKeyReader := bytes.NewReader(publicKey)
|
||||||
keyring, err := openpgp.ReadArmoredKeyRing(pubKeyReader)
|
keyring, err := openpgpReadArmoredKeyRing(pubKeyReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read public key ring: %w", err)
|
return fmt.Errorf("failed to read public key ring: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = openpgp.CheckArmoredDetachedSignature(keyring, bytes.NewReader(data), bytes.NewReader(signature), nil)
|
_, err = openpgpCheckArmoredDetachedSignature(keyring, bytes.NewReader(data), bytes.NewReader(signature), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to verify signature: %w", err)
|
return fmt.Errorf("failed to verify signature: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -148,8 +156,12 @@ func (s *Service) Verify(publicKey, data, signature []byte) error {
|
||||||
|
|
||||||
// SymmetricallyEncrypt encrypts data with a passphrase.
|
// SymmetricallyEncrypt encrypts data with a passphrase.
|
||||||
func (s *Service) SymmetricallyEncrypt(passphrase, data []byte) ([]byte, error) {
|
func (s *Service) SymmetricallyEncrypt(passphrase, data []byte) ([]byte, error) {
|
||||||
|
if len(passphrase) == 0 {
|
||||||
|
return nil, fmt.Errorf("passphrase cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
w, err := openpgp.SymmetricallyEncrypt(buf, passphrase, nil, nil)
|
w, err := openpgpSymmetricallyEncrypt(buf, passphrase, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create symmetric encryption writer: %w", err)
|
return nil, fmt.Errorf("failed to create symmetric encryption writer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -163,3 +175,32 @@ func (s *Service) SymmetricallyEncrypt(passphrase, data []byte) ([]byte, error)
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SymmetricallyDecrypt decrypts data with a passphrase.
|
||||||
|
func (s *Service) SymmetricallyDecrypt(passphrase, ciphertext []byte) ([]byte, error) {
|
||||||
|
if len(passphrase) == 0 {
|
||||||
|
return nil, fmt.Errorf("passphrase cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewReader(ciphertext)
|
||||||
|
failed := false
|
||||||
|
prompt := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
||||||
|
if failed {
|
||||||
|
return nil, fmt.Errorf("decryption failed")
|
||||||
|
}
|
||||||
|
failed = true
|
||||||
|
return passphrase, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := openpgpReadMessage(buf, nil, prompt, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read message: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plaintext, err := io.ReadAll(md.UnverifiedBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read plaintext: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return plaintext, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,12 @@
|
||||||
package pgp
|
package pgp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||||||
|
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
@ -16,6 +20,13 @@ func TestService_GenerateKeyPair_Good(t *testing.T) {
|
||||||
assert.NotNil(t, priv, "private key is nil")
|
assert.NotNil(t, priv, "private key is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestService_GenerateKeyPair_Bad(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
// Test with invalid name (null byte)
|
||||||
|
_, _, err := s.GenerateKeyPair("test\x00", "test@test.com", "test")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestService_Encrypt_Good(t *testing.T) {
|
func TestService_Encrypt_Good(t *testing.T) {
|
||||||
s := NewService()
|
s := NewService()
|
||||||
pub, _, err := s.GenerateKeyPair("test", "test@test.com", "test")
|
pub, _, err := s.GenerateKeyPair("test", "test@test.com", "test")
|
||||||
|
|
@ -28,6 +39,55 @@ func TestService_Encrypt_Good(t *testing.T) {
|
||||||
assert.NotNil(t, encrypted, "encrypted data is nil")
|
assert.NotNil(t, encrypted, "encrypted data is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestService_SymmetricallyEncrypt_Bad(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
// Test with empty passphrase
|
||||||
|
_, err := s.SymmetricallyEncrypt([]byte(""), []byte("hello world"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SymmetricallyDecrypt_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")
|
||||||
|
|
||||||
|
decrypted, err := s.SymmetricallyDecrypt(passphrase, encrypted)
|
||||||
|
require.NoError(t, err, "failed to decrypt data")
|
||||||
|
assert.Equal(t, data, decrypted, "decrypted data does not match original")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SymmetricallyDecrypt_Bad(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
// Test with empty passphrase
|
||||||
|
_, err := s.SymmetricallyDecrypt([]byte(""), []byte("hello world"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// Test with wrong passphrase
|
||||||
|
passphrase := []byte("hello world")
|
||||||
|
data := []byte("hello world")
|
||||||
|
encrypted, err := s.SymmetricallyEncrypt(passphrase, data)
|
||||||
|
require.NoError(t, err, "failed to encrypt data")
|
||||||
|
|
||||||
|
_, err = s.SymmetricallyDecrypt([]byte("wrong passphrase"), encrypted)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// Test with bad encrypted data
|
||||||
|
_, err = s.SymmetricallyDecrypt(passphrase, []byte("bad encrypted data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// Test with corrupt body
|
||||||
|
pub3, priv3, err := s.GenerateKeyPair("test3", "test3@test.com", "test3")
|
||||||
|
require.NoError(t, err)
|
||||||
|
encrypted3, err := s.Encrypt(pub3, []byte("hello world"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
encrypted3[len(encrypted3)-1] ^= 0x01
|
||||||
|
_, err = s.Decrypt(priv3, encrypted3)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestService_Encrypt_Bad(t *testing.T) {
|
func TestService_Encrypt_Bad(t *testing.T) {
|
||||||
s := NewService()
|
s := NewService()
|
||||||
_, err := s.Encrypt([]byte("bad key"), []byte("hello world"))
|
_, err := s.Encrypt([]byte("bad key"), []byte("hello world"))
|
||||||
|
|
@ -67,6 +127,15 @@ func TestService_Decrypt_Bad(t *testing.T) {
|
||||||
|
|
||||||
_, err = s.Decrypt(priv2, []byte("bad encrypted data"))
|
_, err = s.Decrypt(priv2, []byte("bad encrypted data"))
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// Test with corrupt body
|
||||||
|
pub3, priv3, err := s.GenerateKeyPair("test3", "test3@test.com", "test3")
|
||||||
|
require.NoError(t, err)
|
||||||
|
encrypted3, err := s.Encrypt(pub3, []byte("hello world"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
encrypted3[len(encrypted3)-1] ^= 0x01
|
||||||
|
_, err = s.Decrypt(priv3, encrypted3)
|
||||||
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestService_Sign_Good(t *testing.T) {
|
func TestService_Sign_Good(t *testing.T) {
|
||||||
|
|
@ -85,6 +154,13 @@ func TestService_Sign_Bad(t *testing.T) {
|
||||||
s := NewService()
|
s := NewService()
|
||||||
_, err := s.Sign([]byte("bad key"), []byte("hello world"))
|
_, err := s.Sign([]byte("bad key"), []byte("hello world"))
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
// Test with public key (no private key)
|
||||||
|
pub, _, err := s.GenerateKeyPair("test", "test@test.com", "test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = s.Sign(pub, []byte("hello world"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "private key not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestService_Verify_Good(t *testing.T) {
|
func TestService_Verify_Good(t *testing.T) {
|
||||||
|
|
@ -126,3 +202,216 @@ func TestService_SymmetricallyEncrypt_Good(t *testing.T) {
|
||||||
require.NoError(t, err, "failed to encrypt data")
|
require.NoError(t, err, "failed to encrypt data")
|
||||||
assert.NotNil(t, encrypted, "encrypted data is nil")
|
assert.NotNil(t, encrypted, "encrypted data is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mock testing infrastructure
|
||||||
|
|
||||||
|
type mockWriteCloser struct {
|
||||||
|
writeFunc func(p []byte) (n int, err error)
|
||||||
|
closeFunc func() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockWriteCloser) Write(p []byte) (n int, err error) {
|
||||||
|
if m.writeFunc != nil {
|
||||||
|
return m.writeFunc(p)
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockWriteCloser) Close() error {
|
||||||
|
if m.closeFunc != nil {
|
||||||
|
return m.closeFunc()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockReader struct {
|
||||||
|
readFunc func(p []byte) (n int, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockReader) Read(p []byte) (n int, err error) {
|
||||||
|
if m.readFunc != nil {
|
||||||
|
return m.readFunc(p)
|
||||||
|
}
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_GenerateKeyPair_MockErrors(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
origNewEntity := openpgpNewEntity
|
||||||
|
origArmorEncode := armorEncode
|
||||||
|
defer func() {
|
||||||
|
openpgpNewEntity = origNewEntity
|
||||||
|
armorEncode = origArmorEncode
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 1. Mock NewEntity error
|
||||||
|
openpgpNewEntity = func(name, comment, email string, config *packet.Config) (*openpgp.Entity, error) {
|
||||||
|
return nil, errors.New("mock new entity error")
|
||||||
|
}
|
||||||
|
_, _, err := s.GenerateKeyPair("test", "test", "test")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock new entity error")
|
||||||
|
openpgpNewEntity = origNewEntity // restore
|
||||||
|
|
||||||
|
// 2. Mock armorEncode error (public key)
|
||||||
|
armorEncode = func(out io.Writer, typeStr string, headers map[string]string) (io.WriteCloser, error) {
|
||||||
|
if typeStr == openpgp.PublicKeyType {
|
||||||
|
return nil, errors.New("mock armor pub error")
|
||||||
|
}
|
||||||
|
return origArmorEncode(out, typeStr, headers)
|
||||||
|
}
|
||||||
|
_, _, err = s.GenerateKeyPair("test", "test", "test")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock armor pub error")
|
||||||
|
armorEncode = origArmorEncode // restore
|
||||||
|
|
||||||
|
// 3. Mock armorEncode error (private key)
|
||||||
|
armorEncode = func(out io.Writer, typeStr string, headers map[string]string) (io.WriteCloser, error) {
|
||||||
|
if typeStr == openpgp.PrivateKeyType {
|
||||||
|
return nil, errors.New("mock armor priv error")
|
||||||
|
}
|
||||||
|
return origArmorEncode(out, typeStr, headers)
|
||||||
|
}
|
||||||
|
_, _, err = s.GenerateKeyPair("test", "test", "test")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock armor priv error")
|
||||||
|
armorEncode = origArmorEncode // restore
|
||||||
|
|
||||||
|
// 4. Mock Serialize error (via Write failure)
|
||||||
|
// We need armorEncode to return a writer that fails on Write
|
||||||
|
armorEncode = func(out io.Writer, typeStr string, headers map[string]string) (io.WriteCloser, error) {
|
||||||
|
if typeStr == openpgp.PublicKeyType {
|
||||||
|
return &mockWriteCloser{
|
||||||
|
writeFunc: func(p []byte) (n int, err error) {
|
||||||
|
return 0, errors.New("mock write pub error")
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return origArmorEncode(out, typeStr, headers)
|
||||||
|
}
|
||||||
|
_, _, err = s.GenerateKeyPair("test", "test", "test")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock write pub error")
|
||||||
|
armorEncode = origArmorEncode // restore
|
||||||
|
|
||||||
|
// 5. Mock SerializePrivate error (via Write failure)
|
||||||
|
armorEncode = func(out io.Writer, typeStr string, headers map[string]string) (io.WriteCloser, error) {
|
||||||
|
if typeStr == openpgp.PrivateKeyType {
|
||||||
|
return &mockWriteCloser{
|
||||||
|
writeFunc: func(p []byte) (n int, err error) {
|
||||||
|
return 0, errors.New("mock write priv error")
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return origArmorEncode(out, typeStr, headers)
|
||||||
|
}
|
||||||
|
_, _, err = s.GenerateKeyPair("test", "test", "test")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock write priv error")
|
||||||
|
armorEncode = origArmorEncode // restore
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestService_Encrypt_MockErrors(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
pub, _, err := s.GenerateKeyPair("test", "test", "test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
origEncrypt := openpgpEncrypt
|
||||||
|
defer func() { openpgpEncrypt = origEncrypt }()
|
||||||
|
|
||||||
|
// 1. Mock Encrypt error
|
||||||
|
openpgpEncrypt = func(ciphertext io.Writer, to []*openpgp.Entity, signed *openpgp.Entity, hints *openpgp.FileHints, config *packet.Config) (io.WriteCloser, error) {
|
||||||
|
return nil, errors.New("mock encrypt error")
|
||||||
|
}
|
||||||
|
_, err = s.Encrypt(pub, []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock encrypt error")
|
||||||
|
|
||||||
|
// 2. Mock Write error
|
||||||
|
openpgpEncrypt = func(ciphertext io.Writer, to []*openpgp.Entity, signed *openpgp.Entity, hints *openpgp.FileHints, config *packet.Config) (io.WriteCloser, error) {
|
||||||
|
return &mockWriteCloser{
|
||||||
|
writeFunc: func(p []byte) (n int, err error) {
|
||||||
|
return 0, errors.New("mock write data error")
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
_, err = s.Encrypt(pub, []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock write data error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_Sign_MockErrors(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
_, priv, err := s.GenerateKeyPair("test", "test", "test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
origSign := openpgpArmoredDetachSign
|
||||||
|
defer func() { openpgpArmoredDetachSign = origSign }()
|
||||||
|
|
||||||
|
// Mock Sign error
|
||||||
|
openpgpArmoredDetachSign = func(w io.Writer, signer *openpgp.Entity, message io.Reader, config *packet.Config) error {
|
||||||
|
return errors.New("mock sign error")
|
||||||
|
}
|
||||||
|
_, err = s.Sign(priv, []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock sign error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SymmetricallyEncrypt_MockErrors(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
|
||||||
|
origSymEncrypt := openpgpSymmetricallyEncrypt
|
||||||
|
defer func() { openpgpSymmetricallyEncrypt = origSymEncrypt }()
|
||||||
|
|
||||||
|
// 1. Mock Sym Encrypt error
|
||||||
|
openpgpSymmetricallyEncrypt = func(ciphertext io.Writer, passphrase []byte, hints *openpgp.FileHints, config *packet.Config) (io.WriteCloser, error) {
|
||||||
|
return nil, errors.New("mock sym encrypt error")
|
||||||
|
}
|
||||||
|
_, err := s.SymmetricallyEncrypt([]byte("pass"), []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock sym encrypt error")
|
||||||
|
|
||||||
|
// 2. Mock Write error
|
||||||
|
openpgpSymmetricallyEncrypt = func(ciphertext io.Writer, passphrase []byte, hints *openpgp.FileHints, config *packet.Config) (io.WriteCloser, error) {
|
||||||
|
return &mockWriteCloser{
|
||||||
|
writeFunc: func(p []byte) (n int, err error) {
|
||||||
|
return 0, errors.New("mock sym write error")
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
_, err = s.SymmetricallyEncrypt([]byte("pass"), []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock sym write error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SymmetricallyDecrypt_MockErrors(t *testing.T) {
|
||||||
|
s := NewService()
|
||||||
|
pass := []byte("pass")
|
||||||
|
|
||||||
|
origReadMessage := openpgpReadMessage
|
||||||
|
defer func() { openpgpReadMessage = origReadMessage }()
|
||||||
|
|
||||||
|
// Mock ReadMessage error
|
||||||
|
openpgpReadMessage = func(r io.Reader, keyring openpgp.KeyRing, prompt openpgp.PromptFunction, config *packet.Config) (*openpgp.MessageDetails, error) {
|
||||||
|
return nil, errors.New("mock read message error")
|
||||||
|
}
|
||||||
|
_, err := s.SymmetricallyDecrypt(pass, []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock read message error")
|
||||||
|
|
||||||
|
// Mock ReadAll error (via ReadMessage returning bad body)
|
||||||
|
openpgpReadMessage = func(r io.Reader, keyring openpgp.KeyRing, prompt openpgp.PromptFunction, config *packet.Config) (*openpgp.MessageDetails, error) {
|
||||||
|
// We need to return a message with UnverifiedBody that fails on Read
|
||||||
|
return &openpgp.MessageDetails{
|
||||||
|
UnverifiedBody: &mockReader{
|
||||||
|
readFunc: func(p []byte) (n int, err error) {
|
||||||
|
return 0, errors.New("mock read body error")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
_, err = s.SymmetricallyDecrypt(pass, []byte("data"))
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "mock read body error")
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue