Skip to content

Commit e6fc301

Browse files
author
gefeili
committed
Fix the bug if block size of base in GCFBBlockCipher is not equal to 8.
1 parent 2c9faf6 commit e6fc301

File tree

3 files changed

+81
-25
lines changed

3 files changed

+81
-25
lines changed

core/src/main/java/org/bouncycastle/crypto/modes/GCFBBlockCipher.java

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public class GCFBBlockCipher
2828
private ParametersWithIV initParams;
2929

3030
private KeyParameter key;
31-
private long counter = 0;
32-
private boolean forEncryption;
31+
private long counter = 0;
32+
private boolean forEncryption;
3333

3434
public GCFBBlockCipher(BlockCipher engine)
3535
{
@@ -43,13 +43,13 @@ public void init(boolean forEncryption, CipherParameters params)
4343
{
4444
counter = 0;
4545
cfbEngine.init(forEncryption, params);
46-
byte[] iv = null;
47-
46+
byte[] iv = null;
47+
4848
this.forEncryption = forEncryption;
4949

5050
if (params instanceof ParametersWithIV)
5151
{
52-
ParametersWithIV ivParams = (ParametersWithIV) params;
52+
ParametersWithIV ivParams = (ParametersWithIV)params;
5353
params = ivParams.getParameters();
5454
iv = ivParams.getIV();
5555
}
@@ -65,14 +65,14 @@ public void init(boolean forEncryption, CipherParameters params)
6565
}
6666

6767
key = (KeyParameter)params;
68-
69-
/* Pick up key/IV from parameters or most recent parameters */
70-
if (key == null && initParams != null)
71-
{
72-
key = (KeyParameter) initParams.getParameters();
68+
69+
/* Pick up key/IV from parameters or most recent parameters */
70+
if (key == null && initParams != null)
71+
{
72+
key = (KeyParameter)initParams.getParameters();
7373
}
7474
if (iv == null && initParams != null)
75-
{
75+
{
7676
iv = initParams.getIV();
7777
}
7878
else
@@ -105,18 +105,20 @@ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
105105

106106
protected byte calculateByte(byte b)
107107
{
108-
if (counter > 0 && counter % 1024 == 0)
108+
if (counter > 0 && (counter & 1023) == 0)
109109
{
110-
BlockCipher base = cfbEngine.getUnderlyingCipher();
110+
BlockCipher base = cfbEngine.getUnderlyingCipher();
111111

112112
base.init(false, key);
113113

114114
byte[] nextKey = new byte[32];
115-
116-
base.processBlock(C, 0, nextKey, 0);
117-
base.processBlock(C, 8, nextKey, 8);
118-
base.processBlock(C, 16, nextKey, 16);
119-
base.processBlock(C, 24, nextKey, 24);
115+
int blockSize = base.getBlockSize();
116+
//TODO: The for-loop will not function correctly if 32 is not evenly divisible by blocksize
117+
// (i.e., 32 % blocksize != 0), So it's not working for DSTU7624Engine(512), RijndaelEngine(except 256), etc.
118+
for (int i = 0; i < nextKey.length; i += blockSize)
119+
{
120+
base.processBlock(C, i, nextKey, i);
121+
}
120122

121123
key = new KeyParameter(nextKey);
122124

@@ -137,13 +139,13 @@ protected byte calculateByte(byte b)
137139
public void reset()
138140
{
139141
counter = 0;
140-
if (initParams != null)
141-
{
142-
key = (KeyParameter) initParams.getParameters();
142+
if (initParams != null)
143+
{
144+
key = (KeyParameter)initParams.getParameters();
143145
cfbEngine.init(forEncryption, initParams);
144-
}
145-
else
146-
{
146+
}
147+
else
148+
{
147149
cfbEngine.reset();
148150
}
149151
}

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import java.security.SecureRandom;
44

55
import org.bouncycastle.crypto.BlockCipher;
6+
import org.bouncycastle.crypto.BufferedBlockCipher;
67
import org.bouncycastle.crypto.CipherKeyGenerator;
78
import org.bouncycastle.crypto.DataLengthException;
9+
import org.bouncycastle.crypto.DefaultBufferedBlockCipher;
810
import org.bouncycastle.crypto.InvalidCipherTextException;
911
import org.bouncycastle.crypto.KeyGenerationParameters;
1012
import org.bouncycastle.crypto.modes.AEADCipher;
@@ -14,6 +16,7 @@
1416
import org.bouncycastle.util.test.SimpleTest;
1517
import org.bouncycastle.util.test.SimpleTestResult;
1618
import org.bouncycastle.util.test.TestFailedException;
19+
import org.junit.Assert;
1720

1821
public abstract class CipherTest
1922
extends SimpleTest
@@ -251,4 +254,52 @@ static void isEqualTo(
251254
throw new TestFailedException(SimpleTestResult.failed(parent, "no message"));
252255
}
253256
}
257+
258+
static void checkCipher(final BlockCipher pCipher, final int datalen)
259+
throws Exception
260+
{
261+
final SecureRandom random = new SecureRandom();
262+
/* Create the data */
263+
final byte[] myData = new byte[datalen];
264+
random.nextBytes(myData);
265+
266+
/* Create the Key parameters */
267+
final CipherKeyGenerator myGenerator = new CipherKeyGenerator();
268+
final KeyGenerationParameters myGenParams = new KeyGenerationParameters(random, 256);
269+
myGenerator.init(myGenParams);
270+
final byte[] myKey = myGenerator.generateKey();
271+
final KeyParameter myKeyParams = new KeyParameter(myKey);
272+
273+
/* Create the IV */
274+
final byte[] myIV = new byte[16];
275+
random.nextBytes(myIV);
276+
277+
/* Create the initParams */
278+
final ParametersWithIV myParams = new ParametersWithIV(myKeyParams, myIV);
279+
280+
/* Wrap Block Cipher with buffered BlockCipher */
281+
final BufferedBlockCipher myCipher = new DefaultBufferedBlockCipher(pCipher);
282+
283+
/* Initialise the cipher for encryption */
284+
myCipher.init(true, myParams);
285+
286+
/* Encipher the text */
287+
final byte[] myOutput = new byte[myCipher.getOutputSize(datalen)];
288+
int myOutLen = myCipher.processBytes(myData, 0, datalen, myOutput, 0);
289+
myCipher.doFinal(myOutput, myOutLen);
290+
291+
/* Re-Encipher the text (after implicit reset) */
292+
final byte[] myOutput2 = new byte[myCipher.getOutputSize(datalen)];
293+
myOutLen = myCipher.processBytes(myData, 0, datalen, myOutput2, 0);
294+
myCipher.doFinal(myOutput2, myOutLen);
295+
296+
myCipher.init(false, myParams);
297+
final byte[] plaintext = new byte[myCipher.getOutputSize(myOutput.length)];
298+
myOutLen = myCipher.processBytes(myOutput2, 0, datalen, plaintext, 0);
299+
myCipher.doFinal(plaintext, myOutLen);
300+
301+
/* Check that the cipherTexts are identical */
302+
Assert.assertArrayEquals(myOutput, myOutput2);
303+
Assert.assertArrayEquals(myData, plaintext);
304+
}
254305
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import org.bouncycastle.crypto.CipherParameters;
55
import org.bouncycastle.crypto.CryptoException;
66
import org.bouncycastle.crypto.digests.GOST3411Digest;
7+
import org.bouncycastle.crypto.engines.AESEngine;
78
import org.bouncycastle.crypto.engines.GOST28147Engine;
89
import org.bouncycastle.crypto.modes.CBCBlockCipher;
910
import org.bouncycastle.crypto.modes.CFBBlockCipher;
11+
import org.bouncycastle.crypto.modes.GCFBBlockCipher;
1012
import org.bouncycastle.crypto.modes.GOFBBlockCipher;
1113
import org.bouncycastle.crypto.params.KeyParameter;
1214
import org.bouncycastle.crypto.params.ParametersWithIV;
@@ -197,7 +199,8 @@ public void performTest()
197199
throws Exception
198200
{
199201
super.performTest();
200-
202+
checkCipher(new GCFBBlockCipher(new GOST28147Engine()), 2049);
203+
checkCipher(new GCFBBlockCipher(AESEngine.newInstance()), 2049);
201204
//advanced tests with GOST28147KeyGenerator:
202205
//encrypt on hesh message; ECB mode:
203206
byte[] in = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20");

0 commit comments

Comments
 (0)