Skip to content

Commit ee2d965

Browse files
committed
Fix rounding issue with FF1
1 parent 8c3b112 commit ee2d965

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

core/src/main/java/org/bouncycastle/crypto/fpe/SP80038G.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.bouncycastle.crypto.util.RadixConverter;
77
import org.bouncycastle.util.Arrays;
88
import org.bouncycastle.util.BigIntegers;
9+
import org.bouncycastle.util.Integers;
910
import org.bouncycastle.util.Pack;
1011

1112
/*
@@ -64,8 +65,8 @@ static short[] decFF1(BlockCipher cipher, RadixConverter radixConverter, byte[]
6465
{
6566
int radix = radixConverter.getRadix();
6667
int t = T.length;
67-
int b = ((int)Math.ceil(Math.log((double)radix) * (double)v / LOG2) + 7) / 8;
68-
int d = (((b + 3) / 4) * 4) + 4;
68+
int b = calculateB_FF1(radix, v);
69+
int d = (b + 7) & ~3;
6970

7071
byte[] P = calculateP_FF1(radix, (byte)u, n, t);
7172

@@ -172,8 +173,8 @@ private static short[] encFF1(BlockCipher cipher, RadixConverter radixConverter,
172173
int radix = radixConverter.getRadix();
173174
int t = T.length;
174175

175-
int b = ((int)Math.ceil(Math.log((double)radix) * (double)v / LOG2) + 7) / 8;
176-
int d = (((b + 3) / 4) * 4) + 4;
176+
int b = calculateB_FF1(radix, v);
177+
int d = (b + 7) & ~3;
177178

178179
byte[] P = calculateP_FF1(radix, (byte)u, n, t);
179180

@@ -256,6 +257,26 @@ static byte[] encryptFF3_1(BlockCipher cipher, RadixConverter radixConverter, by
256257
return encryptFF3(cipher, radixConverter, tweak64, buf, off, len);
257258
}
258259

260+
protected static int calculateB_FF1(int radix, int v)
261+
{
262+
// return (BigInteger.valueOf(radix).pow(v).subtract(BigInteger.ONE).bitLength() + 7) / 8;
263+
264+
int powersOfTwo = Integers.numberOfTrailingZeros(radix);
265+
int bits = powersOfTwo * v;
266+
267+
int oddPart = radix >>> powersOfTwo;
268+
if (oddPart != 1)
269+
{
270+
// Old version with rounding issues, especially for power of 2 radix, but maybe others.
271+
// bits += (int)Math.ceil(Math.log((double)oddPart) * (double)v / LOG2);
272+
273+
// Exact calculation, with possible performance issues if v is too large.
274+
bits += BigInteger.valueOf(oddPart).pow(v).bitLength();
275+
}
276+
277+
return (bits + 7) / 8;
278+
}
279+
259280
protected static BigInteger[] calculateModUV(BigInteger bigRadix, int u, int v)
260281
{
261282
BigInteger[] modUV = new BigInteger[2];

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,28 @@ public void testFF1Bounds()
496496
}
497497
}
498498

499+
public void testFF1Rounding()
500+
{
501+
int radix = 256;
502+
byte[] key = Hex.decodeStrict("000102030405060708090a0b0c0d0e0f");
503+
byte[] tweak = Hex.decodeStrict("0001020304050607");
504+
byte[] asciiPT = Hex.decodeStrict("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738");
505+
byte[] asciiCT = Hex.decodeStrict("dc18bef8b7d23aa77d1daf7a50c2253c4bacb772129f70805ecd413775bc3bdf7927ce70f455dacf4fdf61b61ac73a5c90fd3d1759dca0bf27");
506+
byte[] result = new byte[asciiPT.length];
507+
508+
FPEEngine fpeEngine = new FPEFF1Engine();
509+
FPEParameters fpeParameters = new FPEParameters(new KeyParameter(key), radix, tweak);
510+
511+
fpeEngine.init(true, fpeParameters);
512+
fpeEngine.processBlock(asciiPT, 0, asciiPT.length, result, 0);
513+
isTrue("Failed FF1 rounding test (encryption)", areEqual(asciiCT, result));
514+
515+
fpeEngine.init(false, fpeParameters);
516+
fpeEngine.processBlock(asciiCT, 0, asciiCT.length, result, 0);
517+
518+
isTrue("Failed FF1 rounding test (decryption)", areEqual(asciiPT, result));
519+
}
520+
499521
private void testFF3_1Bounds()
500522
throws IOException
501523
{
@@ -598,6 +620,7 @@ public void performTest()
598620
testFF1();
599621
testFF1w();
600622
testFF1Bounds();
623+
testFF1Rounding();
601624
testFF3_1();
602625
testFF3_1w();
603626
testFF3_1_255();

0 commit comments

Comments
 (0)