0

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?

3
  • "I think that the library casts the byte array to a string leaving out all the data after the 0x00 byte...." - No, that does not happen. The string's size member function is always used. Your problem lies elsewhere. Commented Dec 15, 2017 at 11:49
  • "an exception is thrown that the ciphertext is not a multiple of the key length..." - Something does not sound right here. I don't recognize the message. What is the actual exception? It sounds like the invalid padding message again (sort of). Maybe you have an out-of-date file that needs rebuilding after changes. Commented Dec 15, 2017 at 11:52
  • In your second example you need to resize plainText to the actual size of the recovered message before you perform return plainText. You probably need to call ArraySink member function TotalPutLength to get the recovered message size. An example is available at ArraySink on the Crypto++ wiki. Commented Dec 15, 2017 at 11:57

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.