AES with padding pkcs7 c++ code
Solution 1
OpenSSL uses PKCS7 padding by default. This padding means when your data is not a multiple of the block size, you pad n bytes of the value n, where n is however many bytes you need to get to the block size. AES's block size is 16.
Here's an example on how to encrypt a string using AES256-cbc with OpenSSL. The OpenSSL documentation also has examples, although they use different ciphers. This example does no error checking.
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <cassert>
#include <openssl/evp.h>
int main()
{
// ctx holds the state of the encryption algorithm so that it doesn't
// reset back to its initial state while encrypting more than 1 block.
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
unsigned char key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
unsigned char iv[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
assert(sizeof(key) == 32); // AES256 key size
assert(sizeof(iv) == 16); // IV is always the AES block size
// If data isn't a multiple of 16, the default behavior is to pad with
// n bytes of value n, where n is the number of padding bytes required
// to make data a multiple of the block size. This is PKCS7 padding.
// The output then will be a multiple of the block size.
std::string plain("encrypt me");
std::vector<unsigned char> encrypted;
size_t max_output_len = plain.length() + 16 - (plain.length() % 16);
encrypted.resize(max_output_len);
// Enc is 1 to encrypt, 0 to decrypt, or -1 (see documentation).
EVP_CipherInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv, 1);
// EVP_CipherUpdate can encrypt all your data at once, or you can do
// small chunks at a time.
int actual_size = 0;
EVP_CipherUpdate(&ctx,
&encrypted[0], &actual_size,
reinterpret_cast<unsigned char *>(&plain[0]), plain.size());
// EVP_CipherFinal_ex is what applies the padding. If your data is
// a multiple of the block size, you'll get an extra AES block filled
// with nothing but padding.
int final_size;
EVP_CipherFinal_ex(&ctx, &encrypted[actual_size], &final_size);
actual_size += final_size;
encrypted.resize(actual_size);
for( size_t index = 0; index < encrypted.size(); ++index )
{
std::cout << std::hex << std::setw(2) << std::setfill('0') <<
static_cast<unsigned int>(encrypted[index]);
}
std::cout << "\n";
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
Name it encrypt.cpp
and compile with:
g++ encrypt.cpp -o encrypt -lcrypto -lssl -Wall
You'll get this output:
338d2a9e28208cad84c457eb9bd91c81
You can verify correctness by running the OpenSSL command-line utility from the command prompt:
$ echo -n "encrypt me" > to_encrypt
$ openssl enc -in to_encrypt -out encrypted -e -aes-256-cbc \
-K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
-iv 00000000000000000000000000000000
$ hexdump -C encrypted
And the hexdump will show the same bytes as the c++ program.
00000000 33 8d 2a 9e 28 20 8c ad 84 c4 57 eb 9b d9 1c 81 |3.*.( ....W.....|
Solution 2
look also at my answer to this question
I suggest checking out cryptopp. Here's a code sample:
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor;
byte* key;
size_t keylen;
// ... acquire key
encryptor.SetKey( key, keylen );
std::string input;
std::string result;
// read input ...
StringSource( input, true,
new StreamTransformationFilter( encryptor, new StringSink( result ),
StreamTransformationFilter::PKCS_PADDING));
The values for padding mode in StreamTransformationFilter
can be:
BlockPaddingScheme {
NO_PADDING, ZEROS_PADDING, PKCS_PADDING, ONE_AND_ZEROS_PADDING,
DEFAULT_PADDING
}
EDIT: replaced the padding mode in the sample to pkcs
she
Updated on July 18, 2022Comments
-
she almost 2 years
I need an example of string encryption (in C++ -> I'm working on linux-Ubuntu) with aes-cbc256 and a padding: PKCS7 Please help.
For the following code how can I set the IV to 0 and set the key value to a string value? I would also like to add the pkcs7 padding. I'm using the crypto++ lib (in Linux)
// Driver.cpp // #include "stdafx.h" #include "cryptopp/dll.h" #include "cryptopp/default.h" #include "crypto++/osrng.h" using CryptoPP::AutoSeededRandomPool; #include <iostream> using std::cout; using std::cerr; #include <string> using std::string; #include "crypto++/cryptlib.h" using CryptoPP::Exception; #include "crypto++/hex.h" using CryptoPP::HexEncoder; using CryptoPP::HexDecoder; #include "crypto++/filters.h" using CryptoPP::StringSink; using CryptoPP::StringSource; using CryptoPP::StreamTransformationFilter; #include "crypto++/aes.h" using CryptoPP::AES; #include "crypto++/ccm.h" using CryptoPP::CBC_Mode; #include "assert.h" int main(int argc, char* argv[]) { AutoSeededRandomPool prng; byte key[ AES::DEFAULT_KEYLENGTH ]; prng.GenerateBlock( key, sizeof(key) ); byte iv[ AES::BLOCKSIZE]; iv[AES::BLOCKSIZE] = 0; //prng.GenerateBlock(iv, sizeof(iv) ); string plain = "CBC Mode Test"; string cipher, encoded, recovered; // Pretty print key encoded.clear(); StringSource( key, sizeof(key), true, new HexEncoder(new StringSink( encoded )) // HexEncoder ); // StringSource cout << "key: " << encoded << endl; // Pretty print iv encoded.clear(); StringSource( iv, sizeof(iv), true, new HexEncoder(new StringSink( encoded )) // HexEncoder ); // StringSource cout << "iv: " << encoded << endl; /*********************************\ \*********************************/ try { cout << "plain text: " << plain << endl; CBC_Mode< AES >::Encryption e; e.SetKeyWithIV( key, sizeof(key), iv ); // The StreamTransformationFilter adds padding // as required. ECB and CBC Mode must be padded // to the block size of the cipher. StringSource( plain, true, new StreamTransformationFilter( e, new StringSink( cipher ) ) // StreamTransformationFilter ); // StringSource } catch( CryptoPP::Exception& e ) { cerr << "Caught Exception..." << endl; cerr << e.what() << endl; cerr << endl; } /*********************************\ \*********************************/ // Pretty print encoded.clear(); StringSource( cipher, true, new HexEncoder( new StringSink( encoded ) ) // HexEncoder ); // StringSource cout << "cipher text: " << encoded << endl; /*********************************\ \*********************************/ try { CBC_Mode< AES >::Decryption d; d.SetKeyWithIV( key, sizeof(key), iv ); // The StreamTransformationFilter removes // padding as required. StringSource s( cipher, true, new StreamTransformationFilter( d, new StringSink( recovered ) ) // StreamTransformationFilter ); // StringSource cout << "recovered text: " << recovered << endl; } catch( CryptoPP::Exception& e ) { cerr << "Caught Exception..." << endl; cerr << e.what() << endl; cerr << endl; } /*********************************\ \*********************************/ assert( plain == recovered ); return 0; }