PKCS5 Padding In BlackBerry 10
PKCS5 (and PKCS7) padding is common in protocols and encryption schemes – but notably absent from the ‘Certicom®’ crypto APIs on BlackBerry® 10.
There are a couple of reasons it isn’t there:
- It’s easy to do yourself
- It’s not very secure
It’s Easy To Do Yourself
Under the scheme;
- padding must always be included.
- padding is appended to the plain text to create a message whose length is an integral multiple of the cipher’s block size. For some messages this means extending by another whole block – just for the padding.
- the number of bytes of padding is between 1 and the cipher’s block size. eg:
- AES – will have between 1 and 16 bytes of padding.
- DES – will have between 1 and 8 bytes of padding.
- each byte in the padding – is the number of bytes of padding.
- {1} is valid.
- {4,4,4,4} is valid.
- {1,2,3} is NOT valid.
- verifying is more work than padding.
It’s Not Very Secure
If you decrypt random data with a random key – the probability of the last byte being 1 is around 1/256. ie: don’t rely on a PKCS5 padding check to verify your data.
Sample Code
Here’s some code showing you how you could pad yourself in Qt®.
#include <QByteArray>
#include <QDebug>
#include <assert.h>
/**
* PKCS#5 pad the given buffer for the given block size.
* @param buffer the buffer to pad.
* @param blockSize the block size to use.
*/
void pad(QByteArray & buffer, const int blockSize) {
// Find the padding value to use.
const char padValue = (char)(blockSize - (buffer.length() % blockSize));
// Append the padding bytes.
for (int i=0; i<padValue; ++i) {
buffer+=padValue;
}
}
/**
* Verify that the PKCS#5 padding in the given buffer is correct for the given
* block size, and remove it.
* @param buffer The buffer to use. Should be plaintext followed by padding.
* @param blockSize The block size to use.
* @return true iff the padding was correct and removed.
*/
bool verifyAndRemovePadding(QByteArray & buffer, const int blockSize) {
int offset = buffer.length();
// Check if met the minimum 1 block.
if (offset < blockSize) {
return false;
}
// Check to see if integral number of blocks.
if (offset % blockSize != 0) {
return false;
}
const char padValue = buffer[--offset];
// Check to see if pad value is within allowed range.
if (padValue<1 || padValue > blockSize) {
return false;
}
// Check remaining padding bytes.
for (int i=1; i<padValue; ++i) {
if (buffer[--offset]!=padValue) {
return false;
}
}
// Remove the padding.
buffer.chop(padValue);
return true;
}
/**
* Run some basic tests against the pad and verify functions.
*/
int main(int argc, char *argv[])
{
const int blockSize = 16;
// Positive test cases.
for (int i=0; i<20; ++i) {
QByteArray b;
for (int j=0; j<i; ++j) {
b.append(i+j*i);
}
QByteArray original(b);
pad(b,blockSize);
qDebug() << b.toHex();
assert(b.length()!=0);
assert(b.length()%blockSize==0);
assert(b.length()>i);
assert(((int)b[b.length()-1])==(blockSize-(i%block Size)));
assert(verifyAndRemovePadding(b,blockSize));
assert(original==b);
}
// Negative test cases.
QByteArray empty;
assert(!verifyAndRemovePadding(empty,blockSize));
// Good padding - but not a block
QByteArray goodPaddingButNotABlock(blockSize-1,blockSize-1);
assert(!verifyAndRemovePadding(goodPaddingButNotAB lock,blockSize));
// Bad padding
QByteArray badSequence(blockSize,blockSize);
badSequence[3] = 5;
assert(!verifyAndRemovePadding(badSequence,blockSi ze));
// Bad length
QByteArray badPadLength(blockSize-1,blockSize-1);
badPadLength.append((char)0);
assert(!verifyAndRemovePadding(badPadLength,blockS ize));
badPadLength[badPadLength.length()-1]=blockSize+1;
assert(!verifyAndRemovePadding(badPadLength,blockS ize));
return 0;
}

