带有填充的 AES pkcs7 c++代码

发布于 2024-10-08 15:45:29 字数 4139 浏览 2 评论 0原文

我需要一个使用 aes-cbc256 和填充的字符串加密示例(在 C++ 中 -> 我正在 linux-Ubuntu 上工作):PKCS7 请帮忙。


对于以下代码,如何将 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;    
}

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;    
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

慢慢从新开始 2024-10-15 15:45:29

OpenSSL 默认使用 PKCS7 填充。此填充意味着当您的数据不是块大小的倍数时,您将填充值 nn 个字节,其中 n 是多少达到块大小所需的字节数。 AES 的块大小为 16。

以下示例介绍了如何使用 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;
}

将其命名为 encrypt.cpp 并使用以下内容进行编译:

g++ encrypt.cpp -o encrypt -lcrypto -lssl -Wall

您将得到以下输出:

338d2a9e28208cad84c457eb9bd91c81

您可以通过从命令提示符运行 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

十六进制转储将显示与c++ 程序。

00000000  33 8d 2a 9e 28 20 8c ad  84 c4 57 eb 9b d9 1c 81  |3.*.( ....W.....|

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.....|
故事未完 2024-10-15 15:45:29

另请查看我对这个问题的回答,

我建议查看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));

StreamTransformationFilter 中填充模式的值可以是:

BlockPaddingScheme { 
  NO_PADDING, ZEROS_PADDING, PKCS_PADDING, ONE_AND_ZEROS_PADDING, 
  DEFAULT_PADDING 
}

编辑:将示例中的填充模式替换为 pkcs

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文