Skip to content

Commit d9f3052

Browse files
committed
Allow passing message size hint
Also, set the AEAD chunk size to twice the message size hint (or the actual message size, when known), so that we don't generate an overly large chunk size when the message could fit in a smaller chunk size.
1 parent d3fe807 commit d9f3052

File tree

7 files changed

+35
-10
lines changed

7 files changed

+35
-10
lines changed

crypto/crypto.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,6 @@ func (p *PGPHandle) LockKey(key *Key, passphrase []byte) (*Key, error) {
7474

7575
// GenerateSessionKey generates a random session key for the profile.
7676
func (p *PGPHandle) GenerateSessionKey() (*SessionKey, error) {
77-
config := p.profile.EncryptionConfig()
77+
config := p.profile.EncryptionConfig(0)
7878
return generateSessionKey(config)
7979
}

crypto/decryption_core.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ func createPasswordPrompt(password []byte) func(keys []openpgp.Key, symmetric bo
330330
}
331331

332332
func (dh *decryptionHandle) decryptionConfig(configTime int64) *packet.Config {
333-
config := dh.profile.EncryptionConfig()
333+
config := dh.profile.EncryptionConfig(0)
334334

335335
// Check intended recipients in signatures.
336336
checkIntendedRecipients := !dh.DisableIntendedRecipients

crypto/encryption.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ package crypto
33
import "github.com/ProtonMail/go-crypto/openpgp/packet"
44

55
type EncryptionProfile interface {
6-
EncryptionConfig() *packet.Config
6+
EncryptionConfig(messageSizeHint int) *packet.Config
77
CompressionConfig() *packet.Config
88
}
99

1010
// PGPEncryption is an interface for encrypting messages with GopenPGP.
1111
// Use an EncryptionHandleBuilder to create a PGPEncryption handle.
1212
type PGPEncryption interface {
13+
// SetMessageSizeHint gives the encryption handle a hint about the
14+
// expected size of the message, in order to set an appropriate chunk
15+
// size when using AEAD. Nothing will break when the message size hint
16+
// turns out to be wrong.
17+
SetMessageSizeHint(messageSizeHint int)
1318
// EncryptingWriter returns a wrapper around underlying output Writer,
1419
// such that any write-operation via the wrapper results in a write to an encrypted pgp message.
1520
// If the output Writer is of type PGPSplitWriter, the output can be split to multiple writers

crypto/encryption_core.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (eh *encryptionHandle) prepareEncryptAndSign(
9191
ModTime: time.Unix(plainMessageMetadata.Time(), 0),
9292
}
9393

94-
config = eh.profile.EncryptionConfig()
94+
config = eh.profile.EncryptionConfig(eh.messageSizeHint)
9595
config.Time = eh.clock
9696

9797
compressionConfig := eh.selectCompression()
@@ -324,7 +324,7 @@ func (eh *encryptionHandle) encryptSignDetachedStreamWithSessionKey(
324324
eh.IsUTF8,
325325
eh.SigningContext,
326326
eh.clock,
327-
eh.profile.EncryptionConfig(),
327+
eh.profile.EncryptionConfig(eh.messageSizeHint),
328328
)
329329
if err != nil {
330330
return nil, err
@@ -345,7 +345,7 @@ func (eh *encryptionHandle) encryptSignDetachedStreamToRecipients(
345345
keyPacketWriter io.Writer,
346346
encryptSignature bool,
347347
) (plaintextWriter io.WriteCloser, err error) {
348-
configInput := eh.profile.EncryptionConfig()
348+
configInput := eh.profile.EncryptionConfig(eh.messageSizeHint)
349349
configInput.Time = NewConstantClock(eh.clock().Unix())
350350
// Generate a session key for encryption.
351351
if eh.SessionKey == nil {

crypto/encryption_handle.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ type encryptionHandle struct {
6262

6363
encryptionTimeOverride Clock
6464
clock Clock
65+
66+
messageSizeHint int
6567
}
6668

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

7678
// --- Implements PGPEncryption interface
79+
// SetMessageSizeHint gives the encryption handle a hint about the
80+
// expected size of the message, in order to set an appropriate chunk
81+
// size when using AEAD. Nothing will break when the message size hint
82+
// turns out to be wrong.
83+
func (eh *encryptionHandle) SetMessageSizeHint(messageSizeHint int) {
84+
eh.messageSizeHint = messageSizeHint
85+
}
7786

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

96105
// Encrypt encrypts a plaintext message.
97106
func (eh *encryptionHandle) Encrypt(message []byte) (*PGPMessage, error) {
107+
eh.messageSizeHint = len(message)
98108
pgpMessageBuffer := NewPGPMessageBuffer()
99109
// Enforce that for a PGPMessage struct the output should not be armored.
100110
encryptingWriter, err := eh.EncryptingWriter(pgpMessageBuffer, Bytes)
@@ -116,7 +126,7 @@ func (eh *encryptionHandle) Encrypt(message []byte) (*PGPMessage, error) {
116126
// EncryptSessionKey encrypts a session key with the encryption handle.
117127
// To encrypt a session key, the handle must contain either recipients or a password.
118128
func (eh *encryptionHandle) EncryptSessionKey(sessionKey *SessionKey) ([]byte, error) {
119-
config := eh.profile.EncryptionConfig()
129+
config := eh.profile.EncryptionConfig(0)
120130
config.Time = NewConstantClock(eh.clock().Unix())
121131
switch {
122132
case eh.Password != nil:
@@ -159,7 +169,7 @@ func (eh *encryptionHandle) armorChecksumRequired() bool {
159169
// the logic for the RFC9580 check.
160170
return false
161171
}
162-
encryptionConfig := eh.profile.EncryptionConfig()
172+
encryptionConfig := eh.profile.EncryptionConfig(0)
163173
if encryptionConfig.AEADConfig == nil {
164174
return true
165175
}

crypto/sessionkey_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func TestSymmetricKeyPacketWrongSize(t *testing.T) {
104104

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

107-
_, err = encryptSessionKeyWithPassword(sk, password, testPGP.profile.EncryptionConfig())
107+
_, err = encryptSessionKeyWithPassword(sk, password, testPGP.profile.EncryptionConfig(0))
108108
if err == nil {
109109
t.Fatal("Expected error while generating key packet with wrong sized key")
110110
}

profile/profile.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,24 @@ func (p *Custom) KeyGenerationConfig(securityLevel int8) *packet.Config {
6868
return cfg
6969
}
7070

71-
func (p *Custom) EncryptionConfig() *packet.Config {
71+
func (p *Custom) EncryptionConfig(messageSizeHint int) *packet.Config {
7272
config := &packet.Config{
7373
DefaultHash: p.Hash,
7474
DefaultCipher: p.CipherEncryption,
7575
AEADConfig: p.AeadEncryption,
7676
S2KConfig: p.S2kEncryption,
7777
InsecureAllowDecryptionWithSigningKeys: p.InsecureAllowDecryptionWithSigningKeys,
7878
}
79+
if config.AEADConfig != nil {
80+
chunkSize := config.AEADConfig.ChunkSize
81+
if messageSizeHint*2 < 1<<(config.AEADConfig.ChunkSizeByte()+6) {
82+
chunkSize = uint64(messageSizeHint * 2)
83+
}
84+
config.AEADConfig = &packet.AEADConfig{
85+
DefaultMode: config.AEADConfig.DefaultMode,
86+
ChunkSize: chunkSize,
87+
}
88+
}
7989
if p.DisableIntendedRecipients {
8090
intendedRecipients := false
8191
config.CheckIntendedRecipients = &intendedRecipients

0 commit comments

Comments
 (0)