PKCS5 Padding In BlackBerry 10

by Retired on ‎11-08-2012 10:33 AM (2,966 Views)

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:

  1. It’s easy to do yourself
  2. 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%blockSize)));

        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(goodPaddingButNotABlock,blockSize));

    // Bad padding
    QByteArray badSequence(blockSize,blockSize);
    badSequence[3] = 5;
    assert(!verifyAndRemovePadding(badSequence,blockSize));

    // Bad length
    QByteArray badPadLength(blockSize-1,blockSize-1);
    badPadLength.append((char)0);
    assert(!verifyAndRemovePadding(badPadLength,blockSize));

    badPadLength[badPadLength.length()-1]=blockSize+1;
    assert(!verifyAndRemovePadding(badPadLength,blockSize));

    return 0;
}