Alex van Rijs
Alex van Rijs

Reputation: 813

Encrypting and Decrypting a byte array/vector using the CryptoPP library

I am trying to encrypt a byte array that has been parsed to a string. This seems to work for all cases, except for the case that the byte array contains 0x00.

int main()
{
    byte cipherTextWithZeroByte[32] = {
        0xD3, 0xFA, 0xD6, 0xEC, 0x84, 0x4E, 0xD3, 0xD8,
        0x2B, 0x76, 0x6C, 0xE8, 0x02, 0xF2, 0xB2, 0x6F,
        0x00, 0xE8, 0x99, 0x8C, 0xEC, 0x4B, 0x3C, 0x7D,         
        0xAC, 0xDE, 0x86, 0x02, 0x51, 0xAB, 0x3F, 0x04
    };

    string cipherText((char *)cipherTextWithZeroByte);
    string plainText = decrypt(cipherText, sizeof(cipherTextWithZeroByte));

    return 1;
}

string decrypt(string cipherText, int size)
{
    string decryptedText;

    CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);

    CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, 
              new CryptoPP::HexEncoder(
                           new CryptoPP::StringSink(decryptedText)));

    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipherText.c_str()), size);
    stfDecryptor.MessageEnd();

    return decryptedText;
}

In this case, the byte array contains 0x00. This causes the cipherText to be cut short leading to an invalid length. An exception is thrown stating: 'StreamTransformationFilter: invalid PKCS #7 block padding found'

So I thought it would be better to use an ArraySource and ArraySink to be sure that a string is not zero terminated.

int main()
{
    byte cipherTextWithZeroByte[32] = {
        0xD3, 0xFA, 0xD6, 0xEC, 0x84, 0x4E, 0xD3, 0xD8,
        0x2B, 0x76, 0x6C, 0xE8, 0x02, 0xF2, 0xB2, 0x6F,
        0x00, 0xE8, 0x99, 0x8C, 0xEC, 0x4B, 0x3C, 0x7D,         
        0xAC, 0xDE, 0x86, 0x02, 0x51, 0xAB, 0x3F, 0x04
    };

    vector<byte> cipherTextData(cipherTextWithZeroByte, cipherTextWithZeroByte + sizeof(cipherTextWithZeroByte) / sizeof(cipherTextWithZeroByte[0]));
    vector<byte> plainTextData = decrypt(cipherTextData);

    return 1;
}

vector<byte> decrypt(vector<byte> cipherText)
{
    vector<byte> plainText;
    plainText.resize(cipherText.size());

    CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor;
    decryptor.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));


    CryptoPP::ArraySource ss(&cipherText[0], cipherText.size(), true,
              new CryptoPP::HexEncoder(
                  new CryptoPP::StreamTransformationFilter(decryptor,
                      new CryptoPP::ArraySink(plainText.data(), plainText.size()))));

    return plainText;
}

In this case, an exception is thrown that the ciphertext is not a multiple of the key length, which clearly is not the case here. (Key = 16 bytes, Ciphertext = 16 bytes). I think that the library casts the byte array to a string leaving out all the data after the 0x00 byte.

What am I doing wrong?

Upvotes: 0

Views: 2255

Answers (1)

zaph
zaph

Reputation: 112865

Encryption is a binary byte not a character operation. As such the encrypted output can not be cast to a string. If you need a string output encode the encrypted data to a string compatible format common formats are Base64 and hexadecimal.

In particular a null byte in a character string by convention in "C" like signals languages the end of the string.

That is on encryption encode the binary data to a string format and on decryption first decode the string representation to binary data by using the inverse of the encoding operation.

Upvotes: 1

Related Questions