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

Allow passing a message size hint #321

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
2 changes: 1 addition & 1 deletion crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,6 @@ func (p *PGPHandle) LockKey(key *Key, passphrase []byte) (*Key, error) {

// GenerateSessionKey generates a random session key for the profile.
func (p *PGPHandle) GenerateSessionKey() (*SessionKey, error) {
config := p.profile.EncryptionConfig()
config := p.profile.EncryptionConfig(0)
return generateSessionKey(config)
}
2 changes: 1 addition & 1 deletion crypto/decryption_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func createPasswordPrompt(password []byte) func(keys []openpgp.Key, symmetric bo
}

func (dh *decryptionHandle) decryptionConfig(configTime int64) *packet.Config {
config := dh.profile.EncryptionConfig()
config := dh.profile.EncryptionConfig(0)

// Check intended recipients in signatures.
checkIntendedRecipients := !dh.DisableIntendedRecipients
Expand Down
7 changes: 6 additions & 1 deletion crypto/encryption.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ package crypto
import "github.com/ProtonMail/go-crypto/openpgp/packet"

type EncryptionProfile interface {
EncryptionConfig() *packet.Config
EncryptionConfig(messageSizeHint uint64) *packet.Config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might need more options here in the future without breaking backward compatibility.
What about introducing a struct EncHandleSettings and passing &encHandleSettings instead with default nil?

CompressionConfig() *packet.Config
}

// PGPEncryption is an interface for encrypting messages with GopenPGP.
// Use an EncryptionHandleBuilder to create a PGPEncryption handle.
type PGPEncryption interface {
// SetMessageSizeHint gives the encryption handle a hint about the
// expected size of the message, in order to set an appropriate chunk
// size when using AEAD. Nothing will break when the message size hint
// turns out to be wrong.
SetMessageSizeHint(messageSizeHint uint64)
// EncryptingWriter returns a wrapper around underlying output Writer,
// such that any write-operation via the wrapper results in a write to an encrypted pgp message.
// If the output Writer is of type PGPSplitWriter, the output can be split to multiple writers
Expand Down
6 changes: 3 additions & 3 deletions crypto/encryption_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (eh *encryptionHandle) prepareEncryptAndSign(
ModTime: time.Unix(plainMessageMetadata.Time(), 0),
}

config = eh.profile.EncryptionConfig()
config = eh.profile.EncryptionConfig(eh.messageSizeHint)
config.Time = eh.clock

compressionConfig := eh.selectCompression()
Expand Down Expand Up @@ -324,7 +324,7 @@ func (eh *encryptionHandle) encryptSignDetachedStreamWithSessionKey(
eh.IsUTF8,
eh.SigningContext,
eh.clock,
eh.profile.EncryptionConfig(),
eh.profile.EncryptionConfig(eh.messageSizeHint),
)
if err != nil {
return nil, err
Expand All @@ -345,7 +345,7 @@ func (eh *encryptionHandle) encryptSignDetachedStreamToRecipients(
keyPacketWriter io.Writer,
encryptSignature bool,
) (plaintextWriter io.WriteCloser, err error) {
configInput := eh.profile.EncryptionConfig()
configInput := eh.profile.EncryptionConfig(eh.messageSizeHint)
configInput.Time = NewConstantClock(eh.clock().Unix())
// Generate a session key for encryption.
if eh.SessionKey == nil {
Expand Down
14 changes: 12 additions & 2 deletions crypto/encryption_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type encryptionHandle struct {

encryptionTimeOverride Clock
clock Clock

messageSizeHint uint64
}

// --- Default decryption handle to build from
Expand All @@ -74,6 +76,13 @@ func defaultEncryptionHandle(profile EncryptionProfile, clock Clock) *encryption
}

// --- Implements PGPEncryption interface
// SetMessageSizeHint gives the encryption handle a hint about the
// expected size of the message, in order to set an appropriate chunk
// size when using AEAD. Nothing will break when the message size hint
// turns out to be wrong.
func (eh *encryptionHandle) SetMessageSizeHint(messageSizeHint uint64) {
eh.messageSizeHint = messageSizeHint
}

// EncryptingWriter returns a wrapper around underlying output Writer,
// such that any write-operation via the wrapper results in a write to an encrypted pgp message.
Expand All @@ -95,6 +104,7 @@ func (eh *encryptionHandle) EncryptingWriter(outputWriter Writer, encoding int8)

// Encrypt encrypts a plaintext message.
func (eh *encryptionHandle) Encrypt(message []byte) (*PGPMessage, error) {
eh.messageSizeHint = uint64(len(message))
pgpMessageBuffer := NewPGPMessageBuffer()
// Enforce that for a PGPMessage struct the output should not be armored.
encryptingWriter, err := eh.EncryptingWriter(pgpMessageBuffer, Bytes)
Expand All @@ -116,7 +126,7 @@ func (eh *encryptionHandle) Encrypt(message []byte) (*PGPMessage, error) {
// EncryptSessionKey encrypts a session key with the encryption handle.
// To encrypt a session key, the handle must contain either recipients or a password.
func (eh *encryptionHandle) EncryptSessionKey(sessionKey *SessionKey) ([]byte, error) {
config := eh.profile.EncryptionConfig()
config := eh.profile.EncryptionConfig(0)
config.Time = NewConstantClock(eh.clock().Unix())
switch {
case eh.Password != nil:
Expand Down Expand Up @@ -159,7 +169,7 @@ func (eh *encryptionHandle) armorChecksumRequired() bool {
// the logic for the RFC9580 check.
return false
}
encryptionConfig := eh.profile.EncryptionConfig()
encryptionConfig := eh.profile.EncryptionConfig(0)
if encryptionConfig.AEADConfig == nil {
return true
}
Expand Down
2 changes: 1 addition & 1 deletion crypto/sessionkey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func TestSymmetricKeyPacketWrongSize(t *testing.T) {

password := []byte("I like encryption")

_, err = encryptSessionKeyWithPassword(sk, password, testPGP.profile.EncryptionConfig())
_, err = encryptSessionKeyWithPassword(sk, password, testPGP.profile.EncryptionConfig(0))
if err == nil {
t.Fatal("Expected error while generating key packet with wrong sized key")
}
Expand Down
12 changes: 11 additions & 1 deletion profile/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,24 @@ func (p *Custom) KeyGenerationConfig(securityLevel int8) *packet.Config {
return cfg
}

func (p *Custom) EncryptionConfig() *packet.Config {
func (p *Custom) EncryptionConfig(messageSizeHint uint64) *packet.Config {
config := &packet.Config{
DefaultHash: p.Hash,
DefaultCipher: p.CipherEncryption,
AEADConfig: p.AeadEncryption,
S2KConfig: p.S2kEncryption,
InsecureAllowDecryptionWithSigningKeys: p.InsecureAllowDecryptionWithSigningKeys,
}
if config.AEADConfig != nil && messageSizeHint != 0 {
chunkSize := config.AEADConfig.ChunkSize
if messageSizeHint*2 < 1<<(config.AEADConfig.ChunkSizeByte()+6) {
chunkSize = messageSizeHint * 2
}
config.AEADConfig = &packet.AEADConfig{
DefaultMode: config.AEADConfig.DefaultMode,
ChunkSize: chunkSize,
}
}
if p.DisableIntendedRecipients {
intendedRecipients := false
config.CheckIntendedRecipients = &intendedRecipients
Expand Down
Loading