@@ -42,10 +42,14 @@ type Cipher struct {
42
42
43
43
// The last len bytes of buf are leftover key stream bytes from the previous
44
44
// XORKeyStream invocation. The size of buf depends on how many blocks are
45
- // computed at a time.
45
+ // computed at a time by xorKeyStreamBlocks .
46
46
buf [bufSize ]byte
47
47
len int
48
48
49
+ // overflow is set when the counter overflowed, no more blocks can be
50
+ // generated, and the next XORKeyStream call should panic.
51
+ overflow bool
52
+
49
53
// The counter-independent results of the first round are cached after they
50
54
// are computed the first time.
51
55
precompDone bool
@@ -139,15 +143,18 @@ func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
139
143
// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
140
144
// behave as if (64 * counter) bytes had been encrypted so far.
141
145
//
142
- // To prevent accidental counter reuse, SetCounter panics if counter is
143
- // less than the current value.
146
+ // To prevent accidental counter reuse, SetCounter panics if counter is less
147
+ // than the current value.
148
+ //
149
+ // Note that the execution time of XORKeyStream is not independent of the
150
+ // counter value.
144
151
func (s * Cipher ) SetCounter (counter uint32 ) {
145
152
// Internally, s may buffer multiple blocks, which complicates this
146
153
// implementation slightly. When checking whether the counter has rolled
147
154
// back, we must use both s.counter and s.len to determine how many blocks
148
155
// we have already output.
149
156
outputCounter := s .counter - uint32 (s .len )/ blockSize
150
- if counter < outputCounter {
157
+ if s . overflow || counter < outputCounter {
151
158
panic ("chacha20: SetCounter attempted to rollback counter" )
152
159
}
153
160
@@ -196,34 +203,52 @@ func (s *Cipher) XORKeyStream(dst, src []byte) {
196
203
dst [i ] = src [i ] ^ b
197
204
}
198
205
s .len -= len (keyStream )
199
- src = src [len (keyStream ):]
200
- dst = dst [len (keyStream ):]
206
+ dst , src = dst [len (keyStream ):], src [len (keyStream ):]
207
+ }
208
+ if len (src ) == 0 {
209
+ return
201
210
}
202
211
203
- const blocksPerBuf = bufSize / blockSize
204
- numBufs := (uint64 (len (src )) + bufSize - 1 ) / bufSize
205
- if uint64 (s .counter )+ numBufs * blocksPerBuf >= 1 << 32 {
212
+ // If we'd need to let the counter overflow and keep generating output,
213
+ // panic immediately. If instead we'd only reach the last block, remember
214
+ // not to generate any more output after the buffer is drained.
215
+ numBlocks := (uint64 (len (src )) + blockSize - 1 ) / blockSize
216
+ if s .overflow || uint64 (s .counter )+ numBlocks > 1 << 32 {
206
217
panic ("chacha20: counter overflow" )
218
+ } else if uint64 (s .counter )+ numBlocks == 1 << 32 {
219
+ s .overflow = true
207
220
}
208
221
209
222
// xorKeyStreamBlocks implementations expect input lengths that are a
210
223
// multiple of bufSize. Platform-specific ones process multiple blocks at a
211
224
// time, so have bufSizes that are a multiple of blockSize.
212
225
213
- rem := len (src ) % bufSize
214
- full := len (src ) - rem
215
-
226
+ full := len (src ) - len (src )% bufSize
216
227
if full > 0 {
217
228
s .xorKeyStreamBlocks (dst [:full ], src [:full ])
218
229
}
230
+ dst , src = dst [full :], src [full :]
231
+
232
+ // If using a multi-block xorKeyStreamBlocks would overflow, use the generic
233
+ // one that does one block at a time.
234
+ const blocksPerBuf = bufSize / blockSize
235
+ if uint64 (s .counter )+ blocksPerBuf > 1 << 32 {
236
+ s .buf = [bufSize ]byte {}
237
+ numBlocks := (len (src ) + blockSize - 1 ) / blockSize
238
+ buf := s .buf [bufSize - numBlocks * blockSize :]
239
+ copy (buf , src )
240
+ s .xorKeyStreamBlocksGeneric (buf , buf )
241
+ s .len = bufSize - copy (dst , buf )
242
+ return
243
+ }
219
244
220
245
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
221
246
// keep the leftover keystream for the next XORKeyStream invocation.
222
- if rem > 0 {
247
+ if len ( src ) > 0 {
223
248
s .buf = [bufSize ]byte {}
224
- copy (s .buf [:], src [ full :] )
249
+ copy (s .buf [:], src )
225
250
s .xorKeyStreamBlocks (s .buf [:], s .buf [:])
226
- s .len = bufSize - copy (dst [ full :] , s .buf [:])
251
+ s .len = bufSize - copy (dst , s .buf [:])
227
252
}
228
253
}
229
254
@@ -304,9 +329,6 @@ func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
304
329
x15 += c15
305
330
306
331
s .counter += 1
307
- if s .counter == 0 {
308
- panic ("chacha20: internal error: counter overflow" )
309
- }
310
332
311
333
in , out := src [i :], dst [i :]
312
334
in , out = in [:blockSize ], out [:blockSize ] // bounds check elimination hint
0 commit comments