I'm new to cryptography and I'm working on my first project. I have
written a Java applet to encrypt files with 128bit AES in CBC mode using
PKCS5 padding. The 16 byte random IV is written to the file first, then
the encrypted data. The Java app can decrypt it's own output with no
problems. However, I need my C++ app to be able to decrypt it using
crypto++ and it currently doesn't work.
I get a cyrpto++ exception thrown when 'messageEnd()' is called:
StreamTransformationFilter: invalid PKCS #7 block padding found.
I think this is because the two apps are not using the same block
padding mode but I don't know how to change crypto++ to use the same
mode. It's possible that I've just made a newbie mistake - any help
would be fantastic!
Here's the relevant Java source code:
------------------------------------------------
SecretKeySpec skeySpec = new SecretKeySpec(secret_key, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(
input_text_area_.getText().getBytes() );
FileOutputStream output_stream = new
FileOutputStream(output_file);
output_stream.write( cipher.getIV() ); // write IV first
output_stream.write(encrypted);
output_stream.close();
---------------------------------------------------
Here's the C++:
---------------------------------------------------
std::ifstream licence_file_stream( licence_file_, std::ios::in |
std::ios::binary );
// Key and IV setup
const std::vector<byte> encryption_key =
Base64::Decode(encryption_password);
// read the first 16 byte block of data from the file - this is the
IV...
std::vector<byte> initialisation_vector(16);
licence_file_stream.read( (char*) &initialisation_vector[0],
initialisation_vector.size() );
// read the remaining binary file content - this is the cipher text...
std::vector<byte> cipher_text( file_size - 16 );
licence_file_stream.read( (char*) &cipher_text[0], cipher_text.size() );
licence_file_stream.close();
// Decrypt
CryptoPP::AES::Decryption aesDecryption( &encryption_key[0],
encryption_key.size() );
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(
aesDecryption, &initialisation_vector[0] );
// init string sink...
std::string decrypted_text;
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new
CryptoPP::StringSink( decrypted_text ) );
stfDecryptor.Put( &cipher_text[0], cipher_text.size() );
stfDecryptor.MessageEnd();
----------------------------------------------------
Thanks a lot for your help,
Ian
Thanks for your advice. I just made your recommended change but I now
get an exception from my Java app:
"Cannot find any provider supporting AES/CBC/PKCS7Padding"
Does this mean that I won't be able to encrypt in Java and decrypt using
Crypto++ because they can't use a mutually compatible padding system, or
is there another one I can use that is supported by both systems? Is it
not possible to configure Crypto++ to use "PKCS5Padding"?
Thanks again,
Ian
There is probably something else going wrong. For example not using the same
key or IV on both sides would also produce this error, since the decrypted
padding would be random. I suggest using the debugger and step through the
code to see what is going on.
> const std::vector encryption_key =
> Base64::Decode(encryption_password);
>
> // read the first 16 byte block of data from the file - this is the
> IV...
> std::vector initialisation_vector(16);
> licence_file_stream.read( (char*) &initialisation_vector[0],
> initialisation_vector.size() );
>
> // read the remaining binary file content - this is the cipher text...
> std::vector cipher_text( file_size - 16 );
> licence_file_stream.read( (char*) &cipher_text[0],
> cipher_text.size() );
> licence_file_stream.close();
>
> // Decrypt
> CryptoPP::AES::Decryption aesDecryption( &encryption_key[0],
> encryption_key.size() );
> CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(
> aesDecryption, &initialisation_vector[0] );
>
> // init string sink...
> std::string decrypted_text;
>
> CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new
> CryptoPP::StringSink( decrypted_text ) );
> stfDecryptor.Put( &cipher_text[0], cipher_text.size() );
> stfDecryptor.MessageEnd();
> ----------------------------------------------------
>
> Thanks a lot for your help,
>
> Ian
>
>
>> const std::vector encryption_key =
>> Base64::Decode(encryption_password);
>>
>> // read the first 16 byte block of data from the file - this is the
>> IV...
>> std::vector initialisation_vector(16);
>> licence_file_stream.read( (char*) &initialisation_vector[0],
>> initialisation_vector.size() );
>>
>> // read the remaining binary file content - this is the cipher text...
>> std::vector cipher_text( file_size - 16 );
>> licence_file_stream.read( (char*) &cipher_text[0],
>> cipher_text.size() );
>> licence_file_stream.close();
>>
>> // Decrypt
>> CryptoPP::AES::Decryption aesDecryption( &encryption_key[0],
>> encryption_key.size() );
>> CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(
>> aesDecryption, &initialisation_vector[0] );
>>
>> // init string sink...
>> std::string decrypted_text;
>>
>> CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new
>> CryptoPP::StringSink( decrypted_text ) );
>> stfDecryptor.Put( &cipher_text[0], cipher_text.size() );
>> stfDecryptor.MessageEnd();
>> ----------------------------------------------------
>>
>> Thanks a lot for your help,
>>
>> Ian
>>
>>
>
Thanks for all your comments.
I have just looked at my Java encryption app again and it seems to be
using a block size of 16 bytes. I say that because if I encrypt just one
byte of data, I get a 32 byte output file. Since the file also contains
the 16 byte IV in the first block, this must mean the encrypted data has
been padded to 16 bytes.
I have not explicitly set the block size to be 16 bytes - it is just the
default setting when using the 128bit AES implementation in the Java JCE
module (which comes with the standard SDK from Sun).
If I have understood your last message correctly, what you're saying is
that because I'm using a block size of 16 bytes, the PKCS #5 padding
being used by my Java generator is not compatible with the PKCS #7
padding expected by my crypto++ decryptor. If that is the case, which
padding system is supported by both Java and crypto++? Also, if PKCS #5
is only supposed to support an 8 byte block size, why does the Java
library use it with a 16 byte block size?
I found an interesting article about the Java library here:
http://www.informit.com/guides/content.asp?g=java&seqNum=31&rl=1
It says the padding systems available in the java library are:
- NoPadding: No padding.
- OAEPWith<digest>And<mgf>Padding: Optimal Asymmetric Encryption Padding
scheme defined in PKCS #1, where <digest> should be replaced by the
message digest and <mgf> by the mask generation function. Example:
OAEPWithMD5AndMGF1Padding.
- PKCS5Padding: The padding scheme described in RSA Laboratories, "PKCS
#5: Password-Based Encryption Standard," version 1.5, November 1993.
- SSL3Padding: The padding scheme defined in the SSL Protocol Version
3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher):
Does this help?
Thanks again for all your help,
Ian
Haytham Mohammed wrote:
> Hi Wei
>
> PKCS #5 padding and PKCS #7 padding are similar for block ciphers with
> a block size of 8 bytes only.
>
> PKCS #5 was developed for block ciphers with a block size of 8 bytes
> while PKCS #7 can be used for block sizes up to 255 bytes
>
> Reference "Cryptography with java"
>
> if Lan is using block size greater than 8, then the problem should be
> in the padding scheme.
>
> Regards
> Haytham Mohammed
>
> ------------------------------------------------------------------------
> Everyone is raving about the all-new Yahoo! Mail.
> <http://us.rd.yahoo.com/evt=42297/*http://advision.webevents.yahoo.com/mailbeta>
Hi,
Thanks for all your comments.
I have just looked at my Java encryption app again and it seems to be
using a block size of 16 bytes. I say that because if I encrypt just one
byte of data, I get a 32 byte output file. Since the file also contains
the 16 byte IV in the first block, this must mean the encrypted data has
been padded to 16 bytes.
I have not explicitly set the block size to be 16 bytes - it is just the
default setting when using the 128bit AES implementation in the Java JCE
module (which comes with the standard SDK from Sun).
If I have understood your last message correctly, what you're saying is
that because I'm using a block size of 16 bytes, the PKCS #5 padding
being used by my Java generator is not compatible with the PKCS #7
padding expected by my crypto++ decryptor. If that is the case, which
padding system is supported by both Java and crypto++? Also, if PKCS #5
is only supposed to support an 8 byte block size, why does the Java
library use it with a 16 byte block size?
I found an interesting article about the Java library here:
http://www.informit.com/guides/content.asp?g=java&seqNum=31&rl=1
It says the padding systems available in the java library are:
- NoPadding: No padding.
- OAEPWithAndPadding: Optimal Asymmetric Encryption Padding
scheme defined in PKCS #1, where should be replaced by the
message digest and by the mask generation function. Example:
OAEPWithMD5AndMGF1Padding.
- PKCS5Padding: The padding scheme described in RSA Laboratories, "PKCS
#5: Password-Based Encryption Standard," version 1.5, November 1993.
- SSL3Padding: The padding scheme defined in the SSL Protocol Version
3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher):
Does this help?
Thanks again for all your help,
Ian
Haytham Mohammed wrote:
> Hi Wei
>
> PKCS #5 padding and PKCS #7 padding are similar for block ciphers with
> a block size of 8 bytes only.
>
> PKCS #5 was developed for block ciphers with a block size of 8 bytes
> while PKCS #7 can be used for block sizes up to 255 bytes
>
> Reference "Cryptography with java"
>
> if Lan is using block size greater than 8, then the problem should be
> in the padding scheme.
>
> Regards
> Haytham Mohammed
>