带有填充 pkcs7 C++ 代码的 AES
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4508749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AES with padding pkcs7 c++ code
提问by she
I need an example of string encryption (in C++ -> I'm working on linux-Ubuntu) with aes-cbc256 and a padding: PKCS7 Please help.
我需要一个带有 aes-cbc256 和填充的字符串加密示例(在 C++ 中 -> 我正在使用 linux-Ubuntu):PKCS7 请帮忙。
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)
对于以下代码,如何将 IV 设置为 0 并将键值设置为字符串值?我还想添加 pkcs7 填充。我正在使用 crypto++ lib(在 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;
}
回答by indiv
OpenSSL uses PKCS7 padding by default. This padding means when your data is not a multiple of the block size, you pad nbytes of the value n, where nis however many bytes you need to get to the block size. AES's block size is 16.
OpenSSL 默认使用 PKCS7 填充。这种填充意味着当您的数据不是块大小的倍数时,您可以填充值n 的n个字节,其中n是达到块大小所需的字节数。AES 的块大小为 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.
这是一个关于如何使用 AES256-cbc 和 OpenSSL 加密字符串的示例。OpenSSL 文档也有示例,尽管它们使用不同的密码。此示例不进行错误检查。
#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:
命名encrypt.cpp
并编译:
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:
您可以通过从命令提示符运行 OpenSSL 命令行实用程序来验证正确性:
$ 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.
hexdump 将显示与 c++ 程序相同的字节。
00000000 33 8d 2a 9e 28 20 8c ad 84 c4 57 eb 9b d9 1c 81 |3.*.( ....W.....|
回答by davka
look also at my answer to this question
也看看我对这个问题的回答
I suggest checking out cryptopp. Here's a code sample:
我建议检查cryptopp。这是一个代码示例:
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:
填充模式 in 的值StreamTransformationFilter
可以是:
BlockPaddingScheme {
NO_PADDING, ZEROS_PADDING, PKCS_PADDING, ONE_AND_ZEROS_PADDING,
DEFAULT_PADDING
}
EDIT: replaced the padding mode in the sample to pkcs
编辑:将示例中的填充模式替换为 pkcs