Skip to content

Commit 04cfaf2

Browse files
committed
Reuse plaintext slice for ciphertext when encrypting
1 parent fee7824 commit 04cfaf2

File tree

4 files changed

+49
-42
lines changed

4 files changed

+49
-42
lines changed

ocb/ocb.go

+15-16
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,10 @@ func (o *ocb) Seal(dst, nonce, plaintext, adata []byte) []byte {
109109
if len(nonce) > o.nonceSize {
110110
panic("crypto/ocb: Incorrect nonce length given to OCB")
111111
}
112-
ret, out := byteutil.SliceForAppend(dst, len(plaintext)+o.tagSize)
113-
tag := o.crypt(enc, out, nonce, adata, plaintext)
114-
copy(out[len(plaintext):], tag)
112+
sep := len(plaintext)
113+
ret, out := byteutil.SliceForAppend(dst, sep+o.tagSize)
114+
tag := o.crypt(enc, out[:sep], nonce, adata, plaintext)
115+
copy(out[sep:], tag)
115116
return ret
116117
}
117118

@@ -194,13 +195,14 @@ func (o *ocb) crypt(instruction int, Y, nonce, adata, X []byte) []byte {
194195
byteutil.XorBytesMut(offset, o.mask.L[bits.TrailingZeros(uint(i+1))])
195196
blockX := X[i*blockSize : (i+1)*blockSize]
196197
blockY := Y[i*blockSize : (i+1)*blockSize]
197-
byteutil.XorBytes(blockY, blockX, offset)
198198
switch instruction {
199199
case enc:
200+
byteutil.XorBytesMut(checksum, blockX)
201+
byteutil.XorBytes(blockY, blockX, offset)
200202
o.block.Encrypt(blockY, blockY)
201203
byteutil.XorBytesMut(blockY, offset)
202-
byteutil.XorBytesMut(checksum, blockX)
203204
case dec:
205+
byteutil.XorBytes(blockY, blockX, offset)
204206
o.block.Decrypt(blockY, blockY)
205207
byteutil.XorBytesMut(blockY, offset)
206208
byteutil.XorBytesMut(checksum, blockY)
@@ -216,26 +218,23 @@ func (o *ocb) crypt(instruction int, Y, nonce, adata, X []byte) []byte {
216218
o.block.Encrypt(pad, offset)
217219
chunkX := X[blockSize*m:]
218220
chunkY := Y[blockSize*m : len(X)]
219-
byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
220-
// P_* || bit(1) || zeroes(127) - len(P_*)
221221
switch instruction {
222222
case enc:
223223
byteutil.XorBytesMut(checksum, chunkX)
224224
checksum[len(chunkX)] ^= 128
225+
byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
226+
// P_* || bit(1) || zeroes(127) - len(P_*)
225227
case dec:
228+
byteutil.XorBytes(chunkY, chunkX, pad[:len(chunkX)])
229+
// P_* || bit(1) || zeroes(127) - len(P_*)
226230
byteutil.XorBytesMut(checksum, chunkY)
227231
checksum[len(chunkY)] ^= 128
228232
}
229-
byteutil.XorBytes(tag, checksum, offset)
230-
byteutil.XorBytesMut(tag, o.mask.lDol)
231-
o.block.Encrypt(tag, tag)
232-
byteutil.XorBytesMut(tag, o.hash(adata))
233-
} else {
234-
byteutil.XorBytes(tag, checksum, offset)
235-
byteutil.XorBytesMut(tag, o.mask.lDol)
236-
o.block.Encrypt(tag, tag)
237-
byteutil.XorBytesMut(tag, o.hash(adata))
238233
}
234+
byteutil.XorBytes(tag, checksum, offset)
235+
byteutil.XorBytesMut(tag, o.mask.lDol)
236+
o.block.Encrypt(tag, tag)
237+
byteutil.XorBytesMut(tag, o.hash(adata))
239238
return tag[:o.tagSize]
240239
}
241240

openpgp/packet/aead_crypter.go

+24-23
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ type aeadCrypter struct {
2020
chunkIndex []byte // Chunk counter
2121
packetTag packetType // SEIP packet (v2) or AEAD Encrypted Data packet
2222
bytesProcessed int // Amount of plaintext bytes encrypted/decrypted
23-
buffer bytes.Buffer // Buffered bytes across chunks
2423
}
2524

2625
// computeNonce takes the incremental index and computes an eXclusive OR with
@@ -60,10 +59,11 @@ func (wo *aeadCrypter) incrementIndex() error {
6059
// aeadDecrypter reads and decrypts bytes. It buffers extra decrypted bytes when
6160
// necessary, similar to aeadEncrypter.
6261
type aeadDecrypter struct {
63-
aeadCrypter // Embedded ciphertext opener
64-
reader io.Reader // 'reader' is a partialLengthReader
62+
aeadCrypter // Embedded ciphertext opener
63+
reader io.Reader // 'reader' is a partialLengthReader
6564
chunkBytes []byte
66-
peekedBytes []byte // Used to detect last chunk
65+
peekedBytes []byte // Used to detect last chunk
66+
buffer bytes.Buffer // Buffered decrypted bytes
6767
}
6868

6969
// Read decrypts bytes and reads them into dst. It decrypts when necessary and
@@ -163,27 +163,29 @@ func (ar *aeadDecrypter) validateFinalTag(tag []byte) error {
163163
type aeadEncrypter struct {
164164
aeadCrypter // Embedded plaintext sealer
165165
writer io.WriteCloser // 'writer' is a partialLengthWriter
166+
chunkBytes []byte
167+
offset int
166168
}
167169

168170
// Write encrypts and writes bytes. It encrypts when necessary and buffers extra
169171
// plaintext bytes for next call. When the stream is finished, Close() MUST be
170172
// called to append the final tag.
171173
func (aw *aeadEncrypter) Write(plaintextBytes []byte) (n int, err error) {
172-
// Append plaintextBytes to existing buffered bytes
173-
n, err = aw.buffer.Write(plaintextBytes)
174-
if err != nil {
175-
return n, err
176-
}
177-
// Encrypt and write chunks
178-
for aw.buffer.Len() >= aw.chunkSize {
179-
plainChunk := aw.buffer.Next(aw.chunkSize)
180-
encryptedChunk, err := aw.sealChunk(plainChunk)
181-
if err != nil {
182-
return n, err
183-
}
184-
_, err = aw.writer.Write(encryptedChunk)
185-
if err != nil {
186-
return n, err
174+
for n != len(plaintextBytes) {
175+
copied := copy(aw.chunkBytes[aw.offset:aw.chunkSize], plaintextBytes[n:])
176+
n += copied
177+
aw.offset += copied
178+
179+
if aw.offset == aw.chunkSize {
180+
encryptedChunk, err := aw.sealChunk(aw.chunkBytes[:aw.offset])
181+
if err != nil {
182+
return n, err
183+
}
184+
_, err = aw.writer.Write(encryptedChunk)
185+
if err != nil {
186+
return n, err
187+
}
188+
aw.offset = 0
187189
}
188190
}
189191
return
@@ -195,9 +197,8 @@ func (aw *aeadEncrypter) Write(plaintextBytes []byte) (n int, err error) {
195197
func (aw *aeadEncrypter) Close() (err error) {
196198
// Encrypt and write a chunk if there's buffered data left, or if we haven't
197199
// written any chunks yet.
198-
if aw.buffer.Len() > 0 || aw.bytesProcessed == 0 {
199-
plainChunk := aw.buffer.Bytes()
200-
lastEncryptedChunk, err := aw.sealChunk(plainChunk)
200+
if aw.offset > 0 || aw.bytesProcessed == 0 {
201+
lastEncryptedChunk, err := aw.sealChunk(aw.chunkBytes[:aw.offset])
201202
if err != nil {
202203
return err
203204
}
@@ -243,7 +244,7 @@ func (aw *aeadEncrypter) sealChunk(data []byte) ([]byte, error) {
243244
}
244245

245246
nonce := aw.computeNextNonce()
246-
encrypted := aw.aead.Seal(data[:0:len(data)], nonce, data, adata)
247+
encrypted := aw.aead.Seal(data[:0], nonce, data, adata)
247248
aw.bytesProcessed += len(data)
248249
if err := aw.aeadCrypter.incrementIndex(); err != nil {
249250
return nil, err

openpgp/packet/aead_encrypted_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,8 @@ func SerializeAEADEncrypted(w io.Writer, key []byte, config *Config) (io.WriteCl
449449
alg := aeadConf.Mode().new(blockCipher)
450450

451451
chunkSize := decodeAEADChunkSize(aeadConf.ChunkSizeByte())
452+
tagLen := alg.Overhead()
453+
chunkBytes := make([]byte, chunkSize+tagLen)
452454
return &aeadEncrypter{
453455
aeadCrypter: aeadCrypter{
454456
aead: alg,
@@ -458,6 +460,7 @@ func SerializeAEADEncrypted(w io.Writer, key []byte, config *Config) (io.WriteCl
458460
nonce: nonce,
459461
packetTag: packetTypeAEADEncrypted,
460462
},
461-
writer: writer,
463+
writer: writer,
464+
chunkBytes: chunkBytes,
462465
}, nil
463466
}

openpgp/packet/symmetrically_encrypted_aead.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,20 @@ func serializeSymmetricallyEncryptedAead(ciphertext io.WriteCloser, cipherSuite
133133

134134
aead, nonce := getSymmetricallyEncryptedAeadInstance(cipherSuite.Cipher, cipherSuite.Mode, inputKey, salt, prefix)
135135

136+
chunkSize := decodeAEADChunkSize(chunkSizeByte)
137+
tagLen := aead.Overhead()
138+
chunkBytes := make([]byte, chunkSize+tagLen)
136139
return &aeadEncrypter{
137140
aeadCrypter: aeadCrypter{
138141
aead: aead,
139-
chunkSize: decodeAEADChunkSize(chunkSizeByte),
142+
chunkSize: chunkSize,
140143
associatedData: prefix,
141144
nonce: nonce,
142145
chunkIndex: nonce[len(nonce)-8:],
143146
packetTag: packetTypeSymmetricallyEncryptedIntegrityProtected,
144147
},
145-
writer: ciphertext,
148+
writer: ciphertext,
149+
chunkBytes: chunkBytes,
146150
}, nil
147151
}
148152

0 commit comments

Comments
 (0)