Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keyring_message: introduce EncryptWithOptions #277

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
49 changes: 49 additions & 0 deletions crypto/encryption_option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package crypto

import (
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/ProtonMail/gopenpgp/v2/constants"
)

// EncryptionOption defines an interface to apply configurations to packet.Config
type EncryptionOption interface {
apply(*packet.Config)
}

type configFunc func(*packet.Config)

func (f configFunc) apply(cfg *packet.Config) {
f(cfg)
}

// WithDefault applies default settings for encryption
func WithDefault() EncryptionOption {
return configFunc(func(config *packet.Config) {
config.DefaultCipher = packet.CipherAES256
config.DefaultCompressionAlgo = constants.DefaultCompression
config.CompressionConfig = &packet.CompressionConfig{Level: constants.DefaultCompressionLevel}
})
}

// WithCompression allows None, Zip or Zlib compression algorithms and sets compression level
func WithCompression(compressionAlgo packet.CompressionAlgo,
compressionConfig *packet.CompressionConfig) EncryptionOption {
return configFunc(func(config *packet.Config) {
config.DefaultCompressionAlgo = compressionAlgo
config.CompressionConfig = compressionConfig
})
}

// WithCipher allows Cipher3DES, CipherCAST5, CipherAES128, CipherAES192, CipherAES256 ciphers to be set
func WithCipher(cipher packet.CipherFunction) EncryptionOption {
return configFunc(func(config *packet.Config) {
config.DefaultCipher = cipher
})
}

// WithSigningContext defines signing context in encryption configuration
func WithSigningContext(signingContext *SigningContext) EncryptionOption {
return configFunc(func(config *packet.Config) {
config.SignatureNotations = append(config.SignatureNotations, signingContext.getNotation())
})
}
18 changes: 17 additions & 1 deletion crypto/keyring_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ func (keyRing *KeyRing) EncryptWithContextAndCompression(message *PlainMessage,
return asymmetricEncrypt(message, keyRing, privateKey, true, signingContext)
}

// EncryptWithOptions encrypts a PlainMessage to PGPMessage using public/private keys.
// * message : The plain data as a PlainMessage.
// * privateKey : (optional) an unlocked private keyring to include signature in the message.
// * opts : (optional) options to specify compression type and signing context.
// * output : The encrypted data as PGPMessage.
func (keyRing *KeyRing) EncryptWithOptions(message *PlainMessage, privateKey *KeyRing, opts ...EncryptionOption) (*PGPMessage, error) {
return asymmetricEncrypt(message, keyRing, privateKey, false, nil, opts...)
}

// Decrypt decrypts encrypted string using pgp keys, returning a PlainMessage
// * message : The encrypted input as a PGPMessage
// * verifyKey : Public key for signature verification (optional)
Expand Down Expand Up @@ -201,6 +210,7 @@ func asymmetricEncrypt(
publicKey, privateKey *KeyRing,
compress bool,
signingContext *SigningContext,
opts ...EncryptionOption,
) (*PGPMessage, error) {
var outBuf bytes.Buffer
var encryptWriter io.WriteCloser
Expand All @@ -212,7 +222,7 @@ func asymmetricEncrypt(
ModTime: plainMessage.getFormattedTime(),
}

encryptWriter, err = asymmetricEncryptStream(hints, &outBuf, &outBuf, publicKey, privateKey, compress, signingContext)
encryptWriter, err = asymmetricEncryptStream(hints, &outBuf, &outBuf, publicKey, privateKey, compress, signingContext, opts...)
if err != nil {
return nil, err
}
Expand All @@ -238,6 +248,7 @@ func asymmetricEncryptStream(
publicKey, privateKey *KeyRing,
compress bool,
signingContext *SigningContext,
opts ...EncryptionOption,
) (encryptWriter io.WriteCloser, err error) {
config := &packet.Config{
DefaultCipher: packet.CipherAES256,
Expand All @@ -253,6 +264,11 @@ func asymmetricEncryptStream(
config.SignatureNotations = append(config.SignatureNotations, signingContext.getNotation())
}

// Overwrite defaults if EncryptionOptions are provided
for _, opt := range opts {
opt.apply(config)
}

var signEntity *openpgp.Entity
if privateKey != nil && len(privateKey.entities) > 0 {
var err error
Expand Down
26 changes: 26 additions & 0 deletions crypto/keyring_message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"io/ioutil"
"testing"

"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/ProtonMail/gopenpgp/v2/constants"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -78,3 +80,27 @@ func TestTextMessageEncryptionWithSignatureAndContextAndCompression(t *testing.T
}
assert.Exactly(t, message.GetString(), decrypted.GetString())
}

func TestTextMessageEncryptionWithOptions(t *testing.T) {
var message = NewPlainMessageFromString("plain text")
var testContext = "test-context"

ciphertext, err := keyRingTestPublic.EncryptWithOptions(message, keyRingTestPrivate,
WithCompression(packet.CompressionZIP, &packet.CompressionConfig{Level: constants.DefaultCompressionLevel}),
WithCipher(packet.CipherAES256),
WithSigningContext(NewSigningContext(testContext, true)))
if err != nil {
t.Fatal("Expected no error when encrypting, got:", err)
}

decrypted, err := keyRingTestPrivate.DecryptWithContext(
ciphertext,
keyRingTestPublic,
GetUnixTime(),
NewVerificationContext(testContext, true, 0),
)
if err != nil {
t.Fatal("Expected no error when decrypting, got:", err)
}
assert.Exactly(t, message.GetString(), decrypted.GetString())
}