Skip to content

Commit 89286d2

Browse files
author
gefeili
committed
Fix the issues in BufferedBlockCipher and CTSBlockCipher
1 parent d80712e commit 89286d2

File tree

4 files changed

+160
-48
lines changed

4 files changed

+160
-48
lines changed

core/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,24 @@ public int processBytes(
235235
if (len > gapLen)
236236
{
237237
System.arraycopy(in, inOff, buf, bufOff, gapLen);
238+
inOff += gapLen;
239+
len -= gapLen;
240+
if (in == out)
241+
{
242+
int inEnd = inOff + len;
243+
int outEnd = outOff + length;
244+
if ((inOff <= outOff && outOff <= inEnd) ||
245+
(outOff <= inOff && inOff <= outEnd))
246+
{
247+
in = new byte[len];
248+
System.arraycopy(out, inOff, in, 0, len);
249+
inOff = 0;
250+
}
251+
}
238252

239253
resultLen += cipher.processBlock(buf, 0, out, outOff);
240254

241255
bufOff = 0;
242-
len -= gapLen;
243-
inOff += gapLen;
244256

245257
if (mbCipher != null)
246258
{

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,25 @@ public int processBytes(
146146
if (len > gapLen)
147147
{
148148
System.arraycopy(in, inOff, buf, bufOff, gapLen);
149-
149+
inOff += gapLen;
150+
len -= gapLen;
151+
if (in == out)
152+
{
153+
int inEnd = inOff + len;
154+
int outEnd = outOff + length;
155+
if ((inOff <= outOff && outOff <= inEnd) ||
156+
(outOff <= inOff && inOff <= outEnd))
157+
{
158+
in = new byte[len];
159+
System.arraycopy(out, inOff, in, 0, len);
160+
inOff = 0;
161+
}
162+
}
150163
resultLen += cipher.processBlock(buf, 0, out, outOff);
151164
System.arraycopy(buf, blockSize, buf, 0, blockSize);
152165

153166
bufOff = blockSize;
154167

155-
len -= gapLen;
156-
inOff += gapLen;
157-
158168
while (len > blockSize)
159169
{
160170
System.arraycopy(in, inOff, buf, bufOff, blockSize);

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

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.bouncycastle.crypto.test;
22

3+
import java.security.SecureRandom;
4+
35
import org.bouncycastle.crypto.BlockCipher;
46
import org.bouncycastle.crypto.BufferedBlockCipher;
57
import org.bouncycastle.crypto.CipherParameters;
@@ -14,6 +16,7 @@
1416
import org.bouncycastle.crypto.modes.SICBlockCipher;
1517
import org.bouncycastle.crypto.params.KeyParameter;
1618
import org.bouncycastle.crypto.params.ParametersWithIV;
19+
import org.bouncycastle.util.Arrays;
1720
import org.bouncycastle.util.encoders.Hex;
1821
import org.bouncycastle.util.test.SimpleTest;
1922

@@ -23,22 +26,22 @@
2326
public class CTSTest
2427
extends SimpleTest
2528
{
26-
static byte[] in1 = Hex.decode("4e6f7720697320746865207420");
27-
static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa");
28-
static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98");
29-
static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994");
30-
static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6");
31-
29+
static byte[] in1 = Hex.decode("4e6f7720697320746865207420");
30+
static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa");
31+
static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98");
32+
static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994");
33+
static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6");
34+
3235
private void testCTS(
33-
int id,
34-
BlockCipher cipher,
35-
CipherParameters params,
36-
byte[] input,
37-
byte[] output)
36+
int id,
37+
BlockCipher cipher,
38+
CipherParameters params,
39+
byte[] input,
40+
byte[] output)
3841
throws Exception
3942
{
40-
byte[] out = new byte[input.length];
41-
BufferedBlockCipher engine = new CTSBlockCipher(cipher);
43+
byte[] out = new byte[input.length];
44+
BufferedBlockCipher engine = new CTSBlockCipher(cipher);
4245

4346
engine.init(true, params);
4447

@@ -64,15 +67,15 @@ private void testCTS(
6467
}
6568

6669
private void testOldCTS(
67-
int id,
68-
BlockCipher cipher,
69-
CipherParameters params,
70-
byte[] input,
71-
byte[] output)
72-
throws Exception
70+
int id,
71+
BlockCipher cipher,
72+
CipherParameters params,
73+
byte[] input,
74+
byte[] output)
75+
throws Exception
7376
{
74-
byte[] out = new byte[input.length];
75-
BufferedBlockCipher engine = new OldCTSBlockCipher(cipher);
77+
byte[] out = new byte[input.length];
78+
BufferedBlockCipher engine = new OldCTSBlockCipher(cipher);
7679

7780
engine.init(true, params);
7881

@@ -97,77 +100,121 @@ private void testOldCTS(
97100
}
98101
}
99102

100-
private void testExceptions() throws InvalidCipherTextException
103+
private void testExceptions()
104+
throws InvalidCipherTextException
101105
{
102106
BufferedBlockCipher engine = new CTSBlockCipher(new DESEngine());
103107
CipherParameters params = new KeyParameter(new byte[engine.getBlockSize()]);
104108
engine.init(true, params);
105109

106110
byte[] out = new byte[engine.getOutputSize(engine.getBlockSize())];
107-
111+
108112
engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0);
109-
try
113+
try
110114
{
111115
engine.doFinal(out, 0);
112116
fail("Expected CTS encrypt error on < 1 block input");
113-
} catch(DataLengthException e)
117+
}
118+
catch (DataLengthException e)
114119
{
115120
// Expected
116121
}
117122

118123
engine.init(true, params);
119124
engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0);
120-
try
125+
try
121126
{
122127
engine.doFinal(out, 0);
123-
} catch(DataLengthException e)
128+
}
129+
catch (DataLengthException e)
124130
{
125131
fail("Unexpected CTS encrypt error on == 1 block input");
126132
}
127133

128134
engine.init(false, params);
129135
engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0);
130-
try
136+
try
131137
{
132138
engine.doFinal(out, 0);
133139
fail("Expected CTS decrypt error on < 1 block input");
134-
} catch(DataLengthException e)
140+
}
141+
catch (DataLengthException e)
135142
{
136143
// Expected
137144
}
138145

139146
engine.init(false, params);
140147
engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0);
141-
try
148+
try
142149
{
143150
engine.doFinal(out, 0);
144-
} catch(DataLengthException e)
151+
}
152+
catch (DataLengthException e)
145153
{
146154
fail("Unexpected CTS decrypt error on == 1 block input");
147155
}
148156

149-
try
157+
try
150158
{
151159
new CTSBlockCipher(SICBlockCipher.newInstance(AESEngine.newInstance()));
152160
fail("Expected CTS construction error - only ECB/CBC supported.");
153-
} catch(IllegalArgumentException e)
161+
}
162+
catch (IllegalArgumentException e)
154163
{
155164
// Expected
156165
}
157166

158167
}
159168

169+
private void testOverlapping()
170+
throws Exception
171+
{
172+
//Skip the dofinal of the test
173+
CTSBlockCipher bc = new CTSBlockCipher(AESEngine.newInstance());
174+
SecureRandom random = new SecureRandom();
175+
byte[] keyBytes = new byte[16];
176+
random.nextBytes(keyBytes);
177+
KeyParameter key = new KeyParameter(keyBytes);
178+
179+
int offset = 1 + random.nextInt(bc.getBlockSize() - 1) + bc.getBlockSize();
180+
byte[] data = new byte[bc.getBlockSize() * 4 + offset];
181+
byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 3)];
182+
random.nextBytes(data);
183+
184+
bc.init(true, key);
185+
int len = bc.processBytes(data, 0, expected.length, expected, 0);
186+
bc.doFinal(expected, len);
187+
bc.init(true, key);
188+
len = bc.processBytes(data, 0, expected.length, data, offset);
189+
bc.doFinal(data, offset + len);
190+
191+
if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length)))
192+
{
193+
fail("failed to overlapping of encryption");
194+
}
195+
196+
bc.init(false, key);
197+
bc.processBytes(data, 0, expected.length, expected, 0);
198+
bc.init(false, key);
199+
bc.processBytes(data, 0, expected.length, data, offset);
200+
201+
if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length)))
202+
{
203+
fail("failed to overlapping of encryption");
204+
}
205+
}
206+
160207
public String getName()
161208
{
162209
return "CTS";
163210
}
164211

165-
public void performTest()
212+
public void performTest()
166213
throws Exception
167214
{
168-
byte[] key1 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF };
169-
byte[] key2 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0xee, (byte)0xff };
170-
byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
215+
byte[] key1 = {(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF};
216+
byte[] key2 = {(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0xee, (byte)0xff};
217+
byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8};
171218

172219
testCTS(1, new DESEngine(), new KeyParameter(key1), in1, out1);
173220
testCTS(2, new CBCBlockCipher(new DESEngine()), new ParametersWithIV(new KeyParameter(key1), iv), in1, out2);
@@ -177,11 +224,11 @@ public void performTest()
177224
// test vectors from rfc3962
178225
//
179226
byte[] aes128 = Hex.decode("636869636b656e207465726979616b69");
180-
byte[] aesIn1 = Hex.decode("4920776f756c64206c696b652074686520");
227+
byte[] aesIn1 = Hex.decode("4920776f756c64206c696b652074686520");
181228
byte[] aesOut1 = Hex.decode("c6353568f2bf8cb4d8a580362da7ff7f97");
182-
byte[] aesIn2 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c20476175277320");
229+
byte[] aesIn2 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c20476175277320");
183230
byte[] aesOut2 = Hex.decode("fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5");
184-
byte[] aesIn3 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c2047617527732043");
231+
byte[] aesIn3 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c2047617527732043");
185232
byte[] aesOut3 = Hex.decode("39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584");
186233

187234
testCTS(4, new CBCBlockCipher(AESEngine.newInstance()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn1, aesOut1);
@@ -202,16 +249,17 @@ public void performTest()
202249
testOldCTS(9, new CBCBlockCipher(AESEngine.newInstance()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aes1Block, preErrata);
203250

204251
byte[] aes128b = Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f6");
205-
byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f");
252+
byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f");
206253
byte[] aesOut1b = Hex.decode("6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04");
207254

208255
testCTS(10, new CBCBlockCipher(AESEngine.newInstance()), new ParametersWithIV(new KeyParameter(aes128b), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1b);
209256

210257
testExceptions();
258+
testOverlapping();
211259
}
212260

213261
public static void main(
214-
String[] args)
262+
String[] args)
215263
{
216264
runTest(new CTSTest());
217265
}

prov/src/test/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
import javax.crypto.spec.RC5ParameterSpec;
3939
import javax.crypto.spec.SecretKeySpec;
4040

41+
import org.bouncycastle.crypto.BufferedBlockCipher;
42+
import org.bouncycastle.crypto.engines.AESEngine;
43+
import org.bouncycastle.crypto.engines.DESEngine;
44+
import org.bouncycastle.crypto.paddings.PKCS7Padding;
45+
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
46+
import org.bouncycastle.crypto.params.KeyParameter;
4147
import org.bouncycastle.jce.provider.BouncyCastleProvider;
4248
import org.bouncycastle.util.Arrays;
4349
import org.bouncycastle.util.encoders.Hex;
@@ -1740,6 +1746,7 @@ public void performTest()
17401746
testExceptions();
17411747
testIncorrectCipherModes();
17421748
doFinalTest();
1749+
testOverlapping();
17431750
}
17441751

17451752
private void doFinalTest()
@@ -1764,6 +1771,41 @@ private void doFinalTest()
17641771
}
17651772
}
17661773

1774+
private void testOverlapping()
1775+
{
1776+
//Skip the dofinal of the test
1777+
BufferedBlockCipher bc = new BufferedBlockCipher(AESEngine.newInstance());
1778+
SecureRandom random = new SecureRandom();
1779+
byte[] keyBytes = new byte[16];
1780+
random.nextBytes(keyBytes);
1781+
KeyParameter key = new KeyParameter(keyBytes);
1782+
1783+
int offset = 2 + random.nextInt(bc.getBlockSize() - 1);
1784+
byte[] data = new byte[bc.getBlockSize() * 2 + offset];
1785+
byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 2)];
1786+
random.nextBytes(data);
1787+
1788+
bc.init(true, key);
1789+
bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, expected, 0);
1790+
bc.init(true, key);
1791+
bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, data, offset);
1792+
1793+
if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2)))
1794+
{
1795+
fail("failed to overlapping of encryption");
1796+
}
1797+
1798+
bc.init(false, key);
1799+
bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, expected, 0);
1800+
bc.init(false, key);
1801+
bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, data, offset);
1802+
1803+
if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2)))
1804+
{
1805+
fail("failed to overlapping of encryption");
1806+
}
1807+
}
1808+
17671809
public static void main(
17681810
String[] args)
17691811
{

0 commit comments

Comments
 (0)