Skip to content

Commit 8161aa7

Browse files
author
gefeili
committed
TODO: Fix the bug in PhotonBeetleEngine
1 parent c9b07f6 commit 8161aa7

File tree

3 files changed

+119
-63
lines changed

3 files changed

+119
-63
lines changed

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

Lines changed: 109 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package org.bouncycastle.crypto.engines;
22

3-
import java.io.ByteArrayOutputStream;
4-
53
import org.bouncycastle.crypto.CipherParameters;
64
import org.bouncycastle.crypto.DataLengthException;
75
import org.bouncycastle.crypto.InvalidCipherTextException;
86
import org.bouncycastle.crypto.OutputLengthException;
97
import org.bouncycastle.util.Arrays;
108

119
/**
12-
* Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
10+
* Photon-Beetle, <a href="https://www.isical.ac.in/~lightweight/beetle/"></a>
1311
* https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/photon-beetle-spec-final.pdf
1412
* <p>
1513
* Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
@@ -31,15 +29,16 @@ public enum PhotonBeetleParameters
3129
private byte[] state;
3230
private byte[][] state_2d;
3331
private boolean initialised;
34-
private final byte[] aadData;
35-
private int aadOff;
32+
private final byte[] buffer;
33+
private int bufferOff;
3634
private int aadLen;
37-
private final ByteArrayOutputStream message = new ByteArrayOutputStream();
35+
private int messageLen;
3836
private final int RATE_INBYTES;
3937
private final int RATE_INBYTES_HALF;
4038
private final int STATE_INBYTES;
4139
private final int LAST_THREE_BITS_OFFSET;
4240
private final int D = 8;
41+
private boolean aadFinished;
4342
private final byte[][] RC = {
4443
{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10},
4544
{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11},
@@ -87,7 +86,7 @@ public PhotonBeetleEngine(PhotonBeetleParameters pbp)
8786
LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3);
8887
initialised = false;
8988
algorithmName = "Photon-Beetle AEAD";
90-
aadData = new byte[RATE_INBYTES];
89+
buffer = new byte[RATE_INBYTES + (forEncryption ? 0 : MAC_SIZE)];
9190
}
9291

9392
@Override
@@ -107,13 +106,13 @@ public void init(boolean forEncryption, CipherParameters params)
107106
@Override
108107
public void processAADByte(byte input)
109108
{
110-
if (aadOff >= aadData.length)
109+
if (bufferOff >= RATE_INBYTES)
111110
{
112111
PHOTON_Permutation();
113-
XOR(aadData, 0, RATE_INBYTES);
114-
aadOff = 0;
112+
XOR(buffer, 0, RATE_INBYTES);
113+
bufferOff = 0;
115114
}
116-
aadData[aadOff++] = input;
115+
buffer[bufferOff++] = input;
117116
aadLen++;
118117
}
119118

@@ -126,15 +125,15 @@ public void processAADBytes(byte[] input, int inOff, int len)
126125
}
127126
int tmp;
128127
aadLen += len;
129-
if (aadOff + len >= RATE_INBYTES)
128+
if (bufferOff + len >= RATE_INBYTES)
130129
{
131-
tmp = RATE_INBYTES - aadOff;
132-
System.arraycopy(input, inOff, aadData, aadOff, tmp);
130+
tmp = RATE_INBYTES - bufferOff;
131+
System.arraycopy(input, inOff, buffer, bufferOff, tmp);
133132
PHOTON_Permutation();
134-
XOR(aadData, 0, RATE_INBYTES);
133+
XOR(buffer, 0, RATE_INBYTES);
135134
inOff += tmp;
136135
len -= tmp;
137-
aadOff = 0;
136+
bufferOff = 0;
138137
}
139138
while (len >= RATE_INBYTES)
140139
{
@@ -143,9 +142,8 @@ public void processAADBytes(byte[] input, int inOff, int len)
143142
inOff += RATE_INBYTES;
144143
len -= RATE_INBYTES;
145144
}
146-
System.arraycopy(input, inOff, aadData, aadOff, len);
147-
aadOff += len;
148-
145+
System.arraycopy(input, inOff, buffer, bufferOff, len);
146+
bufferOff += len;
149147
}
150148

151149
@Override
@@ -156,8 +154,40 @@ public int processBytes(byte[] input, int inOff, int len, byte[] output, int out
156154
{
157155
throw new DataLengthException("input buffer too short");
158156
}
159-
message.write(input, inOff, len);
160-
return 0;
157+
messageLen += len;
158+
// bufferOff will be set back to 0 if processFinalAADBlock is processed
159+
processFinalAADBlock(messageLen - (forEncryption ? 0 : MAC_SIZE) > 0);
160+
int blockLen = len + bufferOff - (forEncryption ? 0 : MAC_SIZE);
161+
int tmp;
162+
int rv = 0;
163+
164+
int originalInOff = inOff;
165+
if (blockLen >= RATE_INBYTES)
166+
{
167+
tmp = Math.max(RATE_INBYTES - bufferOff, 0);
168+
System.arraycopy(input, inOff, buffer, bufferOff, tmp);
169+
170+
PHOTON_Permutation();
171+
rhoohr(output, outOff, buffer, 0, RATE_INBYTES);
172+
inOff += tmp;
173+
rv += RATE_INBYTES;
174+
blockLen -= RATE_INBYTES;
175+
outOff += RATE_INBYTES;
176+
bufferOff = 0;
177+
}
178+
while (blockLen >= RATE_INBYTES)
179+
{
180+
PHOTON_Permutation();
181+
rhoohr(output, outOff, input, inOff, RATE_INBYTES);
182+
outOff += RATE_INBYTES;
183+
inOff += RATE_INBYTES;
184+
rv += RATE_INBYTES;
185+
blockLen -= RATE_INBYTES;
186+
}
187+
len -= inOff - originalInOff;
188+
System.arraycopy(input, inOff, buffer, bufferOff, len);
189+
bufferOff += len;
190+
return rv;
161191
}
162192

163193
@Override
@@ -168,51 +198,32 @@ public int doFinal(byte[] output, int outOff)
168198
{
169199
throw new IllegalArgumentException("Need call init function before encryption/decryption");
170200
}
171-
int len = message.size() - (forEncryption ? 0 : MAC_SIZE);
172-
if ((forEncryption && len + MAC_SIZE + outOff > output.length) ||
173-
(!forEncryption && len + outOff > output.length))
201+
processFinalAADBlock(false);
202+
int len = messageLen - (forEncryption ? 0 : MAC_SIZE);
203+
int bufferLen = bufferOff - (forEncryption ? 0 : MAC_SIZE);
204+
if ((forEncryption && bufferLen + MAC_SIZE + outOff > output.length) ||
205+
(!forEncryption && bufferLen + outOff > output.length))
174206
{
175207
throw new OutputLengthException("output buffer too short");
176208
}
177-
byte[] input = message.toByteArray();
178-
int inOff = 0;
179-
180209
int i;
181210
if (aadLen != 0 || len != 0)
182211
{
183212
input_empty = false;
184213
}
185-
byte c0 = select((len != 0), ((aadLen % RATE_INBYTES) == 0), (byte)3, (byte)4);
186214
byte c1 = select((aadLen != 0), ((len % RATE_INBYTES) == 0), (byte)5, (byte)6);
187-
int Dlen_inblocks, LastDBlocklen;
188-
if (aadLen != 0)
189-
{
190-
if (aadOff != 0)
191-
{
192-
PHOTON_Permutation();
193-
XOR(aadData, 0, aadOff);
194-
state[aadOff] ^= 0x01; // ozs
195-
}
196-
state[STATE_INBYTES - 1] ^= c0 << LAST_THREE_BITS_OFFSET;
197-
}
215+
198216
if (len != 0)
199217
{
200-
Dlen_inblocks = (len + RATE_INBYTES - 1) / RATE_INBYTES;
201-
for (i = 0; i < Dlen_inblocks - 1; i++)
218+
if (bufferLen != 0)
202219
{
203220
PHOTON_Permutation();
204-
rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, RATE_INBYTES);
205-
}
206-
PHOTON_Permutation();
207-
LastDBlocklen = len - i * RATE_INBYTES;
208-
rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, LastDBlocklen);
209-
if (LastDBlocklen < RATE_INBYTES)
210-
{
211-
state[LastDBlocklen] ^= 0x01; // ozs
221+
rhoohr(output, outOff, buffer, 0, bufferLen);
222+
state[bufferLen] ^= 0x01; // ozs
212223
}
213224
state[STATE_INBYTES - 1] ^= c1 << LAST_THREE_BITS_OFFSET;
214225
}
215-
outOff += len;
226+
outOff += bufferLen;
216227
if (input_empty)
217228
{
218229
state[STATE_INBYTES - 1] ^= 1 << LAST_THREE_BITS_OFFSET;
@@ -223,33 +234,71 @@ public int doFinal(byte[] output, int outOff)
223234
if (forEncryption)
224235
{
225236
System.arraycopy(mac, 0, output, outOff, MAC_SIZE);
226-
len += MAC_SIZE;
237+
bufferLen += MAC_SIZE;
227238
}
228239
else
229240
{
230241
for (i = 0; i < MAC_SIZE; ++i)
231242
{
232-
if (mac[i] != input[len + i])
243+
if (mac[i] != buffer[bufferLen + i])
233244
{
234245
throw new IllegalArgumentException("Mac does not match");
235246
}
236247
}
237248
}
238249
reset(false);
239-
return len;
250+
return bufferLen;
251+
}
252+
253+
private void processFinalAADBlock(boolean lenIsNotZero)
254+
{
255+
if (!aadFinished)
256+
{
257+
if (aadLen != 0)
258+
{
259+
if (bufferOff != 0)
260+
{
261+
PHOTON_Permutation();
262+
XOR(buffer, 0, bufferOff);
263+
if (bufferOff < RATE_INBYTES)
264+
{
265+
state[bufferOff] ^= 0x01; // ozs
266+
}
267+
}
268+
state[STATE_INBYTES - 1] ^= select(lenIsNotZero, ((aadLen % RATE_INBYTES) == 0), (byte)3, (byte)4) << LAST_THREE_BITS_OFFSET;
269+
}
270+
bufferOff = 0;
271+
aadFinished = true;
272+
}
240273
}
241274

242275
@Override
243276
public int getUpdateOutputSize(int len)
244277
{
245-
int total = Math.max(0, len + message.size() + (forEncryption ? 0 : -MAC_SIZE));
278+
int total;
279+
if (aadFinished)
280+
{
281+
total = Math.max(0, len + bufferOff + (forEncryption ? 0 : -MAC_SIZE));
282+
}
283+
else
284+
{
285+
total = Math.max(0, len + (forEncryption ? 0 : -MAC_SIZE));
286+
}
246287
return total - total % RATE_INBYTES;
247288
}
248289

249290
@Override
250291
public int getOutputSize(int len)
251292
{
252-
return Math.max(0, len + message.size() + (forEncryption ? MAC_SIZE : -MAC_SIZE));
293+
if (aadFinished)
294+
{
295+
return Math.max(0, len + bufferOff + (forEncryption ? MAC_SIZE : -MAC_SIZE));
296+
}
297+
else
298+
{
299+
return Math.max(0, len + (forEncryption ? MAC_SIZE : -MAC_SIZE));
300+
}
301+
253302
}
254303

255304
@Override
@@ -266,10 +315,11 @@ public void reset()
266315
protected void reset(boolean clearMac)
267316
{
268317
input_empty = true;
269-
Arrays.fill(aadData, (byte)0);
270-
aadOff = 0;
318+
Arrays.fill(buffer, (byte)0);
319+
bufferOff = 0;
271320
aadLen = 0;
272-
message.reset();
321+
aadFinished = false;
322+
messageLen = 0;
273323
System.arraycopy(K, 0, state, 0, K.length);
274324
System.arraycopy(N, 0, state, K.length, N.length);
275325
super.reset(clearMac);
@@ -386,7 +436,7 @@ private void rhoohr(byte[] ciphertext, int outOff, byte[] plaintext, int inOff,
386436
}
387437
else
388438
{
389-
XOR(ciphertext, inOff, DBlen_inbytes);
439+
XOR(ciphertext, outOff, DBlen_inbytes);
390440
}
391441
}
392442

core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ static void checkAEADParemeter(SimpleTest test, int keySize, int ivSize, final i
262262
final byte[] iv = new byte[ivSize];
263263
int tmpLength = random.nextInt(blockSize - 1) + 1;
264264
final byte[] plaintext = new byte[blockSize * 2 + tmpLength];
265-
byte[] aad = new byte[random.nextInt(100)];
265+
byte[] aad = new byte[random.nextInt(100) + 2];
266266
random.nextBytes(key);
267267
random.nextBytes(iv);
268268
random.nextBytes(plaintext);
@@ -275,7 +275,7 @@ static void checkAEADParemeter(SimpleTest test, int keySize, int ivSize, final i
275275
}
276276
int len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext1, 0);
277277
len += cipher.doFinal(ciphertext1, len);
278-
int aadSplit = random.nextInt(aad.length);
278+
int aadSplit = random.nextInt(aad.length) + 1;
279279
cipher.init(true, new AEADParameters(new KeyParameter(key), macSize * 8, iv, Arrays.copyOf(aad, aadSplit)));
280280
cipher.processAADBytes(aad, aadSplit, aad.length - aadSplit);
281281
byte[] ciphertext2 = new byte[cipher.getOutputSize(plaintext.length)];

core/src/test/java/org/bouncycastle/crypto/test/PhotonBeetleTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public String getName()
3030
public void performTest()
3131
throws Exception
3232
{
33+
testVectors(PhotonBeetleEngine.PhotonBeetleParameters.pb32, "v32");
34+
testVectors(PhotonBeetleEngine.PhotonBeetleParameters.pb128, "v128");
3335
DigestTest.checkDigestReset(this, new PhotonBeetleDigest());
3436
testVectorsHash();
3537
PhotonBeetleEngine pb = new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32);
@@ -38,8 +40,7 @@ public void performTest()
3840
pb = new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128);
3941
testExceptions(pb, pb.getKeyBytesSize(), pb.getIVBytesSize(), pb.getBlockSize());
4042
testParameters(pb, 16, 16, 16);
41-
testVectors(PhotonBeetleEngine.PhotonBeetleParameters.pb32, "v32");
42-
testVectors(PhotonBeetleEngine.PhotonBeetleParameters.pb128, "v128");
43+
4344
testExceptions(new PhotonBeetleDigest(), 32);
4445
CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128));
4546
CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32));
@@ -95,6 +96,10 @@ private void testVectors(PhotonBeetleEngine.PhotonBeetleParameters pbp, String f
9596
int a = line.indexOf('=');
9697
if (a < 0)
9798
{
99+
if (map.get("Count").equals("5"))
100+
{
101+
System.out.println("test");
102+
}
98103
byte[] key = Hex.decode(map.get("Key"));
99104
byte[] nonce = Hex.decode(map.get("Nonce"));
100105
byte[] ad = Hex.decode(map.get("AD"));
@@ -124,6 +129,7 @@ private void testVectors(PhotonBeetleEngine.PhotonBeetleParameters pbp, String f
124129
mismatch("Reccover Keystream " + map.get("Count"), (String)map.get("PT"), pt_recovered);
125130
}
126131
PhotonBeetle.reset();
132+
//System.out.println(map.get("Count") + " pass");
127133
map.clear();
128134

129135
}

0 commit comments

Comments
 (0)