Skip to content

Commit 4b0fdbf

Browse files
committed
Grain128AEAD performance, constant-time
1 parent 802cce1 commit 4b0fdbf

File tree

1 file changed

+57
-102
lines changed

1 file changed

+57
-102
lines changed

core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java

Lines changed: 57 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@
1111
import org.bouncycastle.crypto.modes.AEADCipher;
1212
import org.bouncycastle.crypto.params.KeyParameter;
1313
import org.bouncycastle.crypto.params.ParametersWithIV;
14-
import org.bouncycastle.util.Arrays;
14+
import org.bouncycastle.util.Pack;
1515

1616
/**
1717
* Grain-128 AEAD, based on the current round 3 submission, https://grain-128aead.github.io/
1818
*/
1919
public class Grain128AEADEngine
2020
implements AEADCipher
2121
{
22-
2322
/**
2423
* Constants
2524
*/
@@ -35,10 +34,8 @@ public class Grain128AEADEngine
3534
private int[] nfsr;
3635
private int[] authAcc;
3736
private int[] authSr;
38-
private int output;
3937

4038
private boolean initialised = false;
41-
private boolean isEven = true; // zero treated as even
4239
private boolean aadFinished = false;
4340
private ErasableOutputStream aadData = new ErasableOutputStream();
4441

@@ -56,7 +53,6 @@ public String getAlgorithmName()
5653
* @param params The parameters required to set up the cipher.
5754
* @throws IllegalArgumentException If the params argument is inappropriate.
5855
*/
59-
@Override
6056
public void init(boolean forEncryption, CipherParameters params)
6157
throws IllegalArgumentException
6258
{
@@ -120,15 +116,15 @@ private void initGrain()
120116
{
121117
for (int i = 0; i < 320; ++i)
122118
{
123-
output = getOutput();
119+
int output = getOutput();
124120
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1);
125121
lfsr = shift(lfsr, (getOutputLFSR() ^ output) & 1);
126122
}
127123
for (int quotient = 0; quotient < 8; ++quotient)
128124
{
129125
for (int remainder = 0; remainder < 8; ++remainder)
130126
{
131-
output = getOutput();
127+
int output = getOutput();
132128
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1);
133129
lfsr = shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1);
134130
}
@@ -137,7 +133,7 @@ private void initGrain()
137133
{
138134
for (int remainder = 0; remainder < 32; ++remainder)
139135
{
140-
output = getOutput();
136+
int output = getOutput();
141137
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
142138
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
143139
authAcc[quotient] |= output << remainder;
@@ -147,7 +143,7 @@ private void initGrain()
147143
{
148144
for (int remainder = 0; remainder < 32; ++remainder)
149145
{
150-
output = getOutput();
146+
int output = getOutput();
151147
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
152148
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
153149
authSr[quotient] |= output << remainder;
@@ -238,6 +234,7 @@ private int getOutput()
238234
int s79 = lfsr[2] >>> 15;
239235
int s93 = lfsr[2] >>> 29;
240236
int s94 = lfsr[2] >>> 30;
237+
241238
return ((b12 & s8) ^ (s13 & s20) ^ (b95 & s42) ^ (s60 & s79) ^ (b12 & b95 & s94) ^ s93
242239
^ b2 ^ b15 ^ b36 ^ b45 ^ b64 ^ b73 ^ b89) & 1;
243240
}
@@ -251,12 +248,10 @@ private int getOutput()
251248
*/
252249
private int[] shift(int[] array, int val)
253250
{
254-
255251
array[0] = (array[0] >>> 1) | (array[1] << 31);
256252
array[1] = (array[1] >>> 1) | (array[2] << 31);
257253
array[2] = (array[2] >>> 1) | (array[3] << 31);
258254
array[3] = (array[3] >>> 1) | (val << 31);
259-
260255
return array;
261256
}
262257

@@ -271,35 +266,23 @@ private void setKey(byte[] keyBytes, byte[] ivBytes)
271266
ivBytes[12] = (byte)0xFF;
272267
ivBytes[13] = (byte)0xFF;
273268
ivBytes[14] = (byte)0xFF;
274-
ivBytes[15] = (byte)0x7F;//(byte) 0xFE;
269+
ivBytes[15] = (byte)0x7F;
275270
workingKey = keyBytes;
276271
workingIV = ivBytes;
277272

278273
/**
279274
* Load NFSR and LFSR
280275
*/
281-
int j = 0;
282-
for (int i = 0; i < nfsr.length; i++)
283-
{
284-
nfsr[i] = ((workingKey[j + 3]) << 24) | ((workingKey[j + 2]) << 16)
285-
& 0x00FF0000 | ((workingKey[j + 1]) << 8) & 0x0000FF00
286-
| ((workingKey[j]) & 0x000000FF);
287-
288-
lfsr[i] = ((workingIV[j + 3]) << 24) | ((workingIV[j + 2]) << 16)
289-
& 0x00FF0000 | ((workingIV[j + 1]) << 8) & 0x0000FF00
290-
| ((workingIV[j]) & 0x000000FF);
291-
j += 4;
292-
}
276+
Pack.littleEndianToInt(workingKey, 0, nfsr);
277+
Pack.littleEndianToInt(workingIV, 0, lfsr);
293278
}
294279

295-
public int processBytes(byte[] input, int inOff, int len, byte[] output,
296-
int outOff)
280+
public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
297281
throws DataLengthException
298282
{
299283
if (!initialised)
300284
{
301-
throw new IllegalStateException(getAlgorithmName()
302-
+ " not initialised");
285+
throw new IllegalStateException(getAlgorithmName() + " not initialised");
303286
}
304287

305288
if (!aadFinished)
@@ -328,51 +311,42 @@ public void reset()
328311

329312
private void reset(boolean clearMac)
330313
{
331-
this.isEven = true;
332314
if (clearMac)
333315
{
334316
this.mac = null;
335317
}
336318
this.aadData.reset();
337319
this.aadFinished = false;
320+
338321
setKey(workingKey, workingIV);
339322
initGrain();
340323
}
341324

342325
private byte[] getKeyStream(byte[] input, int inOff, int len, byte[] ciphertext, int outOff)
343326
{
344-
int mCnt = 0, acCnt = 0, cCnt = 0;
345-
byte cc;
346-
byte[] plaintext = new byte[len];
347327
for (int i = 0; i < len; ++i)
348328
{
349-
plaintext[i] = (byte)reverseByte(input[inOff + i]);
350-
}
351-
for (int i = 0; i < len; ++i)
352-
{
353-
cc = 0;
354-
for (int j = 0; j < 16; ++j)
329+
byte cc = 0, input_i = input[inOff + i];
330+
for (int j = 0; j < 8; ++j)
355331
{
356-
output = getOutput();
332+
int output = getOutput();
333+
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
334+
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
335+
336+
int input_i_j = (input_i >> j) & 1;
337+
cc |= (input_i_j ^ output) << j;
338+
339+
// if (input_i_j != 0)
340+
// {
341+
// accumulate();
342+
// }
343+
int mask = -input_i_j;
344+
authAcc[0] ^= authSr[0] & mask;
345+
authAcc[1] ^= authSr[1] & mask;
346+
347+
authShift(getOutput());
357348
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
358349
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
359-
if (isEven)
360-
{
361-
cc |= (((plaintext[mCnt >> 3] >>> (7 - (mCnt & 7))) & 1) ^ output) << (cCnt & 7);
362-
mCnt++;
363-
cCnt++;
364-
isEven = false;
365-
}
366-
else
367-
{
368-
if ((plaintext[acCnt >> 3] & (1 << (7 - (acCnt & 7)))) != 0)
369-
{
370-
accumulate();
371-
}
372-
authShift(output);
373-
acCnt++;
374-
isEven = true;
375-
}
376350
}
377351
ciphertext[outOff + i] = cc;
378352
}
@@ -406,46 +380,47 @@ private void doProcessAADBytes(byte[] input, int inOff, int len)
406380
if (len < 128)
407381
{
408382
ader = new byte[1 + len];
409-
ader[0] = (byte)reverseByte(len);
383+
ader[0] = (byte)len;
410384
aderlen = 0;
411385
}
412386
else
413387
{
414388
// aderlen is the highest bit position divided by 8
415389
aderlen = len_length(len);
416390
ader = new byte[1 + aderlen + len];
417-
ader[0] = (byte)reverseByte(0x80 | aderlen);
391+
ader[0] = (byte)(0x80 | aderlen);
418392
int tmp = len;
419393
for (int i = 0; i < aderlen; ++i)
420394
{
421-
ader[1 + i] = (byte)reverseByte(tmp & 0xff);
395+
ader[1 + i] = (byte)tmp;
422396
tmp >>>= 8;
423397
}
424398
}
425399
for (int i = 0; i < len; ++i)
426400
{
427-
ader[1 + aderlen + i] = (byte)reverseByte(input[inOff + i]);
401+
ader[1 + aderlen + i] = input[inOff + i];
428402
}
429403

430-
byte adval;
431-
int adCnt = 0;
432404
for (int i = 0; i < ader.length; ++i)
433405
{
434-
for (int j = 0; j < 16; ++j)
406+
byte ader_i = ader[i];
407+
for (int j = 0; j < 8; ++j)
435408
{
436-
output = getOutput();
437409
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
438410
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
439-
if ((j & 1) == 1)
440-
{
441-
adval = (byte)(ader[adCnt >> 3] & (1 << (7 - (adCnt & 7))));
442-
if (adval != 0)
443-
{
444-
accumulate();
445-
}
446-
authShift(output);
447-
adCnt++;
448-
}
411+
412+
int ader_i_j = (ader_i >> j) & 1;
413+
// if (ader_i_j != 0)
414+
// {
415+
// accumulate();
416+
// }
417+
int mask = -ader_i_j;
418+
authAcc[0] ^= authSr[0] & mask;
419+
authAcc[1] ^= authSr[1] & mask;
420+
421+
authShift(getOutput());
422+
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
423+
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
449424
}
450425
}
451426
}
@@ -477,21 +452,9 @@ public int doFinal(byte[] out, int outOff)
477452
aadFinished = true;
478453
}
479454

480-
this.mac = new byte[8];
481-
482-
output = getOutput();
483-
nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1);
484-
lfsr = shift(lfsr, (getOutputLFSR()) & 1);
485455
accumulate();
486456

487-
int cCnt = 0;
488-
for (int i = 0; i < 2; ++i)
489-
{
490-
for (int j = 0; j < 4; ++j)
491-
{
492-
mac[cCnt++] = (byte)((authAcc[i] >>> (j << 3)) & 0xff);
493-
}
494-
}
457+
this.mac = Pack.intToLittleEndian(authAcc);
495458

496459
System.arraycopy(mac, 0, out, outOff, mac.length);
497460

@@ -516,15 +479,7 @@ public int getOutputSize(int len)
516479
return len + 8;
517480
}
518481

519-
private int reverseByte(int x)
520-
{
521-
x = (((x & 0x55) << 1) | ((x & (0xAA)) >>> 1)) & 0xFF;
522-
x = (((x & 0x33) << 2) | ((x & (0xCC)) >>> 2)) & 0xFF;
523-
x = (((x & 0x0f) << 4) | ((x & (0xf0)) >>> 4)) & 0xFF;
524-
return x;
525-
}
526-
527-
private int len_length(int v)
482+
private static int len_length(int v)
528483
{
529484
if ((v & 0xff) == v)
530485
{
@@ -554,11 +509,11 @@ public byte[] getBuf()
554509
return buf;
555510
}
556511

557-
public void erase()
558-
{
559-
Arrays.fill(this.buf, (byte)0);
560-
// this for JVM compatibility
561-
this.reset();
562-
}
512+
// public void erase()
513+
// {
514+
// Arrays.fill(this.buf, (byte)0);
515+
// // this for JVM compatibility
516+
// this.reset();
517+
// }
563518
}
564519
}

0 commit comments

Comments
 (0)