Reputation: 7450
I am trying to implement my own PKCS7 padding scheme in JavaCard environment in case a smart card does not support PKCS5 or 7 padding schemes.
I want the block size of the PKCS padding scheme to be flexible in the event that different block size of symmetric ciphers are used. The length
indicates the message input length and the blocksize
indicates the size of a cipher's block.
My algorithm would check two scenarios in the PKCS7 padding namely if all bytes are the same bytes (e.g. 0A, 0A, 0A .. 0A, 0A, 0A
) which means there is no padding involved and would return a value 0
.
The second scenario is the checking if there is padding (e.g. 0A, 0B, 0C, 05, 05, 05, 05, 05
).
I am able to check all the scenarios successfully but when it comes to copying the data to output the result, it doesn't seem to copy correctly.
It seems like the arrayFillGenericNonAtomic()
data that was filled before the arrayCopyRepackNonAtomic()
is called is still stuck in the output byte array and doing the arrayCopyRepackNonAtomic()
is not copying the data properly.
The output byte array format I am using is for the first element in the array to carry the indicator (in byte representation) of the amount of data that has been processed for output (e.g. output[outputOffset] = (byte) 0x10
means 16 data element afterwards that has been processed). Subsequent data elements in the output byte array after the first element contains the processed data.
An example of the problem is I am trying to PKCS7 decode A0, B0, C0, D0, E0, 04, 04, 04, 04
and the outcome should be 05, A0, B0, C0, D0, E0
(where the 05 represents following 5 bytes are processed) but I am getting 05, 04, 04, 04, 04 ..
instead.
How do I fix the problem of the arrayCopyRepackNonAtomic()
not working as expected ?
I am testing the code on an actual JavaCard 2.2.2 and JavaCard 3.0.4 compatible smart card that is in OP_READY mode.
public static void process(byte[] input, short offset, short length,
short blockSize, byte[] output, short outputOffset, short mode) {
if (mode == MODE_DECODE) {
// Data length must be >= blocksize and have to have be a modulus of 0 size.
if ((length >= blockSize) && ((length % blockSize) == 0)) {
output[outputOffset] = (byte) length;
ArrayLogic.arrayFillGenericNonAtomic(output, (short) (outputOffset + 1), (short) (length - 1), output, outputOffset);
if (ArrayLogic.arrayCompareGeneric(input, offset, output, outputOffset, length) == 0x00) {
// If all bytes are the same, return 0.
output[outputOffset] = (byte) 0x00;
} else {
// Bytes are not all the same, check if the last segment of bytes are padded.
if (ArrayLogic.arrayCompareGeneric(input, offset, output, outputOffset, (short) (input[(short) (offset + length - 1)] & 0xFF)) == 0x00) {
// Padded bytes are found.
output[outputOffset] = (byte) (length - input[(short) (offset + length - 1)]);
// Unable to copy correctly to output
ArrayLogic.arrayCopyRepackNonAtomic(input, offset, (short) (output[outputOffset] & 0xFF), output, (short) (outputOffset + 1));
} else {
output[outputOffset] = (byte) length;
// Unable to copy correctly to output
ArrayLogic.arrayCopyRepackNonAtomic(input, offset, length, output, (short) (outputOffset + 1));
}
}
}
}
}
The question have been solved and the problems are wrong variable offsets and also handling of byte to short conversions that caused the problem.
Below is a working version that seems to does the padding after some testing for those interested in using it in the future.
public static void process(byte[] input, short offset, short length,
short blockSize, byte[] workBuff, short buffOffset, byte[] output,
short outputOffset, short mode) {
if (mode == MODE_DECODE) {
// Data length must be >= blocksize and have to have be a modulus of 0 size.
if ((length >= blockSize) && ((length % blockSize) == 0)) {
workBuff[buffOffset] = (byte) input[(short) (length + offset - 1)];
ArrayLogic.arrayFillGenericNonAtomic(workBuff, buffOffset, length, workBuff, buffOffset);
if (ArrayLogic.arrayCompareGeneric(input, offset, workBuff, buffOffset, length) == 0x00) {
// If all bytes are the same, return 0.
output[outputOffset] = (byte) 0x00;
} else {
output[outputOffset] = (byte) (offset + length - (workBuff[buffOffset] & 0xFF));
output[(short) (outputOffset + 1)] = workBuff[buffOffset];
// Bytes are not all the same, check if the last segment of bytes are padded.
if (ArrayLogic.arrayCompareGeneric(input, (short) (offset + length - (workBuff[buffOffset] & 0xFF)), workBuff, buffOffset, (short) (workBuff[buffOffset] & 0xFF)) == 0x00) {
// Padded bytes are found.
output[outputOffset] = (byte) (length - input[(short) (offset + length - 1)]);
ArrayLogic.arrayCopyRepackNonAtomic(input, offset, (short) output[outputOffset], output, (short) (outputOffset + 1));
} else {
// Padded bytes are not found.
output[outputOffset] = (byte) length;
ArrayLogic.arrayCopyRepackNonAtomic(input, offset, length, output, (short) (outputOffset + 1));
}
}
}
}
}
Upvotes: 0
Views: 304
Reputation: 2647
Hmm, I don't think thats the only mistake, but your branch is definitly wrong:
// Bytes are not all the same, check if the last segment of bytes are padded.
if (ArrayLogic.arrayCompareGeneric(input, offset, output, outputOffset, (short) (input[(short) (offset + length - 1)] & 0xFF)) == 0x00) {
You are comparing the right length, but the wrong offsets.
I'm not understanding what the else-case should do in your method. Should throw an error if the padding was wrong?
Upvotes: 1