Skip to content

Commit d78fa18

Browse files
authored
Merge pull request #146 from cconlon/pkcs7Pad
Fixes for PKCS#7 pad/unpad
2 parents cb8594e + 78bbdd2 commit d78fa18

File tree

3 files changed

+108
-8
lines changed

3 files changed

+108
-8
lines changed

src/main/java/com/wolfssl/wolfcrypt/BlockCipher.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,16 @@ public static synchronized int getPKCS7PadSize(int inputSize,
287287

288288
int padSz = 0;
289289

290-
if (inputSize == 0 || blockSize == 0) {
291-
throw new WolfCryptException(
292-
"Input or block size is 0");
290+
if (blockSize == 0) {
291+
throw new WolfCryptException("Block size is 0");
293292
}
294293

295-
padSz = blockSize - (inputSize % blockSize);
294+
/* PKCS#7 padding: if input size is 0, pad with full block */
295+
if (inputSize == 0) {
296+
padSz = blockSize;
297+
} else {
298+
padSz = blockSize - (inputSize % blockSize);
299+
}
296300

297301
return padSz;
298302
}
@@ -366,20 +370,20 @@ public static synchronized byte[] unPadPKCS7(byte[] in, int blockSize) {
366370
padValue = in[in.length - 1];
367371

368372
/* verify pad value is less than or equal to block size */
369-
if (padValue > (byte)blockSize) {
373+
if ((padValue & 0xff) > blockSize) {
370374
throw new WolfCryptException(
371375
"Invalid pad value, larger than block size");
372376
}
373377

374378
/* verify pad bytes are consistent */
375-
for (int i = in.length; i > in.length - padValue; i--) {
379+
for (int i = in.length; i > in.length - (padValue & 0xff); i--) {
376380
if (in[i - 1] != padValue) {
377381
valid = false;
378382
}
379383
}
380384

381-
unpadded = new byte[in.length - padValue];
382-
System.arraycopy(in, 0, unpadded, 0, in.length - padValue);
385+
unpadded = new byte[in.length - (padValue & 0xff)];
386+
System.arraycopy(in, 0, unpadded, 0, in.length - (padValue & 0xff));
383387

384388
if (!valid) {
385389
throw new WolfCryptException(

src/test/java/com/wolfssl/provider/jce/test/WolfCryptCipherTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6381,5 +6381,58 @@ public void testAESAlgorithmParametersWithCipher()
63816381
assertArrayEquals("Should decrypt correctly with cipher parameters",
63826382
plaintext, decrypted2);
63836383
}
6384+
6385+
/**
6386+
* Test that calling getOutputSize(0) doesn't throw an exception
6387+
* when using PKCS5 padding modes.
6388+
*/
6389+
@Test
6390+
public void testGetOutputSizeZeroInputPKCS5Padding() throws Exception {
6391+
6392+
if (!enabledJCEAlgos.contains("AES/ECB/PKCS5Padding")) {
6393+
/* skip test if AES/ECB/PKCS5Padding not supported */
6394+
return;
6395+
}
6396+
6397+
byte[] key = new byte[] {
6398+
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
6399+
(byte)0x88, (byte)0x99, (byte)0xAA, (byte)0xBB,
6400+
(byte)0xCC, (byte)0xDD, (byte)0xEE, (byte)0xFF
6401+
};
6402+
6403+
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
6404+
6405+
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", jceProvider);
6406+
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
6407+
6408+
/* This should not throw an exception and should return block size */
6409+
int outputSize = cipher.getOutputSize(0);
6410+
assertEquals("Output size for zero input should be one block " +
6411+
"(16 bytes)", 16, outputSize);
6412+
6413+
/* Test AES/CBC/PKCS5Padding if available */
6414+
if (enabledJCEAlgos.contains("AES/CBC/PKCS5Padding")) {
6415+
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", jceProvider);
6416+
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
6417+
6418+
outputSize = cipher.getOutputSize(0);
6419+
assertEquals("CBC: Output size for zero input should be one " +
6420+
"block (16 bytes)", 16, outputSize);
6421+
}
6422+
6423+
/* Test DESede if available */
6424+
if (enabledJCEAlgos.contains("DESede/CBC/PKCS5Padding")) {
6425+
byte[] desKey = new byte[24]; /* 3DES requires 24-byte key */
6426+
Arrays.fill(desKey, (byte)0x42);
6427+
SecretKeySpec desKeySpec = new SecretKeySpec(desKey, "DESede");
6428+
6429+
cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding", jceProvider);
6430+
cipher.init(Cipher.ENCRYPT_MODE, desKeySpec);
6431+
6432+
outputSize = cipher.getOutputSize(0);
6433+
assertEquals("DESede: Output size for zero input should be one " +
6434+
"block (8 bytes)", 8, outputSize);
6435+
}
6436+
}
63846437
}
63856438

src/test/java/com/wolfssl/wolfcrypt/test/AesTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,49 @@ public void testPadPKCS7() {
557557
}
558558
}
559559

560+
/**
561+
* Tests that padding bytes with values greater than or equal to 128 are
562+
* handled correctly.
563+
*/
564+
@Test
565+
public void testUnPadPKCS7HighValueBytes() {
566+
567+
/* Test with pad value 0x80 (128) - first problematic value */
568+
byte[] input = new byte[128 - Aes.BLOCK_SIZE]; /* 112 bytes */
569+
Arrays.fill(input, (byte)0xAA);
570+
byte[] padded = new byte[8 * Aes.BLOCK_SIZE]; /* 128 bytes */
571+
System.arraycopy(input, 0, padded, 0, input.length);
572+
/* 16 pad bytes */
573+
Arrays.fill(padded, input.length, padded.length, (byte)0x10);
574+
575+
/* This should work without throwing ArrayIndexOutOfBoundsException */
576+
byte[] unpadded = Aes.unPadPKCS7(padded, Aes.BLOCK_SIZE);
577+
assertEquals(input.length, unpadded.length);
578+
assertArrayEquals(input, unpadded);
579+
580+
/* Test with various high-value padding bytes */
581+
int[] testPadValues = {128, 129, 200, 255};
582+
for (int padValue : testPadValues) {
583+
if (padValue <= Aes.BLOCK_SIZE) {
584+
int dataSize = Aes.BLOCK_SIZE - padValue;
585+
byte[] data = new byte[dataSize];
586+
Arrays.fill(data, (byte)0xBB);
587+
588+
byte[] paddedData = new byte[Aes.BLOCK_SIZE];
589+
System.arraycopy(data, 0, paddedData, 0, dataSize);
590+
Arrays.fill(paddedData, dataSize, paddedData.length,
591+
(byte)(padValue & 0xff));
592+
593+
byte[] unpaddedData =
594+
Aes.unPadPKCS7(paddedData, Aes.BLOCK_SIZE);
595+
assertEquals("Failed for pad value " + padValue,
596+
dataSize, unpaddedData.length);
597+
assertArrayEquals("Data mismatch for pad value " + padValue,
598+
data, unpaddedData);
599+
}
600+
}
601+
}
602+
560603
@Test
561604
public void threadedAesTest() throws InterruptedException {
562605

0 commit comments

Comments
 (0)