C++调用cryptopp实现 AES-GCM解密

问题:调用 “手把手用C++解密Chrome80版本数据库” 一文中的demo源码,想要实现AES-GCM解密数据,发现得到的cookie值不正确,但他们的特征 长度 等都很近似。

经调试,个人认为是GCM解码出现问题,但看了网上很多C++实现AES-GCM的代码,发现他们的解码方法都是相同的,因此请教论坛师傅,能否看出该文章的代码问题出现在何处。


#include <iostream>
 
#include "cryptlib.h"
#include "rijndael.h"
#include "modes.h"
#include "files.h"
#include "osrng.h"
#include "hex.h"
#include "base64.h"
 
using namespace CryptoPP;
 
// aes ebc 加密(输出 base64)
std::string aes_encrypt_ecb_base64(std::string data , unsigned char* key, int keylen)
{
    std::string encrypt_str;
 
    try 
    {
        CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption ecb_encription(key, keylen);
        CryptoPP::StreamTransformationFilter stf_encription(
            ecb_encription,
            new CryptoPP::Base64Encoder(new CryptoPP::StringSink(encrypt_str)),
            CryptoPP::BlockPaddingSchemeDef::ZEROS_PADDING
        );
        stf_encription.Put(reinterpret_cast<const unsigned char*>(data.c_str()), data.length() + 1);
        stf_encription.MessageEnd();
    }
    catch (std::exception e) {
        std::cout << e.what() << std::endl;
    }
 
    return encrypt_str;
}
 
// aes ebc 加密(输出 hex) 
std::string aes_encrypt_ecb_hex(std::string data , unsigned char* key, int keylen)
{
    std::string encrypt_str;
 
    try 
    {
        CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption ecb_encription(key, keylen);
        CryptoPP::StreamTransformationFilter stf_encription(
            ecb_encription,
            new CryptoPP::HexEncoder(new CryptoPP::StringSink(encrypt_str)),
            CryptoPP::BlockPaddingSchemeDef::ZEROS_PADDING
        );
        stf_encription.Put(reinterpret_cast<const unsigned char*>(data.c_str()), data.length() + 1);
        stf_encription.MessageEnd();
    }
    catch (std::exception e) {
        std::cout << e.what() << std::endl;
    }
 
    return encrypt_str;
}
 
// aes ebc 解密(输出 base64)
std::string aes_decrypt_ecb_base64(std::string base64_data, unsigned char* key, int keylen)
{
    try 
    {
        std::string aes_encrypt_data;
        CryptoPP::Base64Decoder decoder;
        decoder.Attach(new CryptoPP::StringSink(aes_encrypt_data));
        decoder.Put(reinterpret_cast<const unsigned char*>(base64_data.c_str()), base64_data.length());
        decoder.MessageEnd();
 
        std::string decrypt_data;
        CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption ebc_description(key, keylen);
        CryptoPP::StreamTransformationFilter stf_description(
            ebc_description,
            new CryptoPP::StringSink(decrypt_data), 
            CryptoPP::BlockPaddingSchemeDef::ZEROS_PADDING
        );
 
        stf_description.Put(
            reinterpret_cast<const unsigned char*>(aes_encrypt_data.c_str()), 
            aes_encrypt_data.length()
        );
        stf_description.MessageEnd();
 
        return decrypt_data;
    }
    catch (std::exception e) {
        std::cout << e.what() << std::endl;
        return "";
    }
}
 
// aes ebc 解密(输出 hex)
std::string aes_decrypt_ecb_hex(std::string hex_data, unsigned char* key, int keylen)
{
    try
    {
        std::string aes_encrypt_data;
        CryptoPP::HexDecoder decoder;
        decoder.Attach(new CryptoPP::StringSink(aes_encrypt_data));
        decoder.Put(reinterpret_cast<const unsigned char*>(hex_data.c_str()), hex_data.length());
        decoder.MessageEnd();
 
        std::string decrypt_data;
        CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption ebc_description(key, keylen);
        CryptoPP::StreamTransformationFilter stf_description(
            ebc_description,
            new CryptoPP::StringSink(decrypt_data),
            CryptoPP::BlockPaddingSchemeDef::ZEROS_PADDING
        );
 
        stf_description.Put(
            reinterpret_cast<const unsigned char*>(aes_encrypt_data.c_str()),
            aes_encrypt_data.length()
        );
        stf_description.MessageEnd();
 
        return decrypt_data;
    }
    catch (std::exception e) {
        std::cout << e.what() << std::endl;
        return "";
    }
}
 
 
int main()
{
    // ebc base64 
    std::string en_base64 = aes_encrypt_ecb_base64("hello cryptopp",(unsigned char*)"1234567812345678", 16);
    printf("en:%s \n", en_base64.c_str());
    std::string de_base64 = aes_decrypt_ecb_base64(en_base64, (unsigned char*)"1234567812345678", 16);
    printf("de:%s \n", de_base64.c_str());
 
    // ebc hex
    std::string en_hex = aes_encrypt_ecb_hex("hello cryptopp", (unsigned char*)"1234567812345678", 16);
    printf("en:%s \n", en_hex.c_str());
    std::string de_hex = aes_decrypt_ecb_hex(en_hex, (unsigned char*)"1234567812345678", 16);
    printf("de:%s \n", de_hex.c_str());
    
 
 
    (void)getchar();
    return 0;
}

参考GPT和自己的思路,如果您使用了手把手用C++解密Chrome80版本数据库的代码示例,并且您发现解密后的cookie值不正确,可能是以下几个原因导致的:

1.密钥不正确:在解密数据之前,您需要确保使用正确的密钥。请确认您使用的是正确的密钥。

2.参数不正确:AES-GCM解密需要正确的参数才能工作。请检查您是否正确设置了参数,例如初始化向量(IV)和附加数据。

3.数据损坏:如果您尝试解密已经被损坏的数据,则解密后的cookie值可能不正确。请确保您尝试解密正确的数据。

4.解密算法不匹配:如果您的加密数据使用了不同的加密算法(例如AES-CBC),则使用AES-GCM解密算法可能会导致不正确的结果。

为了解决此问题,请尝试检查您的代码并确保上述问题得到了解决。如果问题仍然存在,请提供更多详细信息,例如代码示例和错误消息,以便我可以更好地帮助您。

参考gpt和自己的思路,在使用Crypto++库进行AES-GCM解密时,需要确保正确设置以下参数:

1 密钥和IV:使用正确的密钥和初始化向量(IV)进行解密。在代码中,可以使用CryptoPP::SecByteBlock类型的密钥和IV来表示它们。
2 GCM模式:使用GCM模式进行解密,可以通过创建一个CryptoPP::GCMCryptoPP::AES::Decryption对象来实现。
3 授权数据:在GCM模式下,需要使用授权数据来保证安全性。授权数据是一些附加信息,例如加密数据的长度等。授权数据可以在解密过程中使用。
以下是一个简单的示例,展示了如何使用Crypto++库进行AES-GCM解密:


#include <iostream>
#include <string>
#include <cryptopp/cryptlib.h>
#include <cryptopp/aes.h>
#include <cryptopp/gcm.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>

using namespace CryptoPP;

int main()
{
    // AES key and IV
    byte key[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
    byte iv[12] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b};

    // Encrypted data
    std::string ciphertext_hex = "87ff6c1b0b0d71f8f6ae9eac5e5c5e6d8d6b2e47b04f53e5f6d8d6b2e47b04f5";

    // Convert the ciphertext to bytes
    byte ciphertext[ciphertext_hex.size() / 2];
    HexDecoder decoder;
    decoder.Decode(ciphertext, reinterpret_cast<const byte*>(ciphertext_hex.data()), ciphertext_hex.size());

    // Decrypt the ciphertext
    byte plaintext[ciphertext_hex.size() / 2];
    GCM<AES>::Decryption gcm;
    gcm.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    gcm.SpecifyDataLengths(0, ciphertext_hex.size() / 2, 0);
    gcm.DecryptAndVerify(plaintext, ciphertext, ciphertext_hex.size() / 2, NULL, 0);

    // Print the decrypted plaintext
    std::cout << std::string(reinterpret_cast<const char*>(plaintext), ciphertext_hex.size() / 2) << std::endl;

    return 0;
}


在这个示例中,我们使用了一个16字节的AES密钥和12字节的IV。我们将16进制的密文字符串转换为字节数组,并使用GCM模式解密。最后,我们打印出解密后的明文字符串。

该回答引用ChatGPT

如有疑问,可以回复我!

以下是使用Crypto++库在C++中实现AES-GCM解密的示例代码:


#include <iostream>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>
#include <cryptopp/gcm.h>

int main()
{
    // 从文件或其他来源读取密文、密钥和IV
    std::string ciphertext = "2LgT+PZ32aA8bHdSPynsPw=="; // base64编码的密文
    std::string key = "0123456789ABCDEF"; // 密钥
    std::string iv = "1234567890abcdef"; // 初始化向量

    // 解码密文
    std::string decoded_ciphertext;
    CryptoPP::StringSource(ciphertext, true,
        new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded_ciphertext)));

    // 创建AES-GCM解密器
    CryptoPP::GCM<CryptoPP::AES>::Decryption decryptor;
    decryptor.SetKeyWithIV(reinterpret_cast<const byte*>(key.data()), key.size(),
        reinterpret_cast<const byte*>(iv.data()), iv.size());

    // 解密密文
    std::string plaintext;
    CryptoPP::AuthenticatedDecryptionFilter adf(decryptor,
        new CryptoPP::StringSink(plaintext),
        CryptoPP::AuthenticatedDecryptionFilter::MAC_AT_BEGIN);
    adf.Put(reinterpret_cast<const byte*>(decoded_ciphertext.data()), decoded_ciphertext.size());
    adf.MessageEnd();

    // 输出解密结果
    std::cout << "Plaintext: " << plaintext << std::endl;

    return 0;
}

注意,此代码假定已经读取了密文、密钥和初始化向量,密文已经使用base64编码。在实际应用中,这些值可能需要以其他方式获取。

此代码创建了一个AES-GCM解密器,然后将密文传递给AuthenticatedDecryptionFilter,并在结束后调用MessageEnd来完成解密操作。解密结果将存储在名为plaintext的字符串中,并打印到标准输出中。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
为了更好地帮助您解决问题,我需要您提供更多的上下文和细节。您可以在下面提供更具体的信息:

  1. 你是如何获取到Chrome80版本数据库的cookie值的?
  2. 您当前的代码实现是什么样子的?能否提供当前代码的详细实现和运行情况?
  3. 您有没有查看解码后的数据,是否与原始数据匹配?如果不匹配,有什么不同?

在没有更多信息的情况下,以下是一些可能导致问题的原因:

  1. 执行过程中可能存在错误。在执行AES-GCM解密之前,您必须确保已成功地执行了所有其他步骤。
  2. 您的密钥和IV值是否与加密时使用的值匹配?如果不匹配,您将无法正常解密数据。
  3. 解密后的数据是否进行了正确的处理?您可能需要执行其他步骤,例如解压缩或数据转换。

在这里,我提供一个AES-GCM解密的代码示例,您可以参考这个代码,并根据您的需求进行修改:

#include <iostream>
#include <string>
#include <cryptopp/aes.h>
#include <cryptopp/gcm.h>
#include <cryptopp/hex.h>

using namespace CryptoPP;
using std::string;
using std::cout;
using std::endl;

// 加密后的数据
const string cipher = "CE8E63118145A6A2D1E9ACAF28FC8631F477017D5F139A902F5AA92E2A7204292504AA4A93F9E1A8F5C57A5D5B5A5B5D5E5B5F5F4954F9E9E1F8F6E3E6A3E6A3A6E8";

int main()
{
    // 解密密钥
    const byte key[] = { 0x98, 0x20, 0xEF, 0x1D, 0x68, 0xAC, 0xCA, 0xBA, 0xCE, 0xD1, 0x88, 0xE9, 0xE8, 0x2D, 0x1C, 0xFD };
    // IV值
    const byte iv[] = { 0x7E, 0x04, 0xFC, 0x98, 0xB6, 0x9A, 0x2B, 0x98, 0x5B, 0x50, 0xEC, 0x9F };
    // 使用HexDecoder将字符串形式的加密密文转换为字节形式
    byte decrypted[CryptoPP::AES::BLOCKSIZE];
    HexDecoder decoder;
    decoder.Attach(new ArraySink(reinterpret_cast<byte*>(&decrypted[0]), CryptoPP::AES::BLOCKSIZE));
    decoder.Put(reinterpret_cast<const byte*>(cipher.c_str()), cipher.size());
    decoder.MessageEnd();

    // 使用AES-GCM解密
    GCM<AES>::Decryption decryption;
    decryption.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    string decryptedText;
    try
    {
        DecodingChannel channel(new StringSink(decryptedText));
        ChannelSwitch cs;
        cs.AddDefaultRoute(channel);
        cs.AddRoute("TAGGED", new AuthenticatedDecryptionFilter(decryption, NULL, AuthenticatedDecryptionFilter::MAC_AT_BEGIN));
        StringSource(reinterpret_cast<const byte*>(&decrypted[0]), CryptoPP::AES::BLOCKSIZE, true, new Redirector(cs));
    }
    catch (CryptoPP::Exception& e)
    {
        cout << "Exception: " << e.what() << endl;
        return 1;
    }

    // 输出解密后的结果
    cout << "Decrypted Text: \"" << decryptedText << "\"" << endl;

    return 0;
}

以上代码仅供参考,仍需要根据您的具体情况进行修改。
如果我的回答解决了您的问题,请采纳!

通过执行 “手把手用C++解密Chrome80版本数据库”的代码示例发现执行解密的cookie值虽然错误,但是和正确cookie值的长度以及特征都很近似。执行效果如下图所示,左侧为执行结果,右侧为真正cookie值。

img


(计算机小白,初用csdn,不太熟悉,分成了两次评论,请多担待。)


#include <iostream>
#include <string>
#include <cryptopp/aes.h>
#include <cryptopp/gcm.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>
#include <cryptopp/files.h>

using namespace CryptoPP;

int main()
{
    try
    {
        // 读取密文和密钥
        std::string ciphertext, key;
        FileSource("ciphertext.bin", true, new StringSink(ciphertext));
        FileSource("key.bin", true, new StringSink(key));

        // 解码密钥
        SecByteBlock secKey((const unsigned char*)key.data(), key.size());

        // 解码密文
        byte iv[GCM<>::BLOCKSIZE];
        std::memcpy(iv, ciphertext.data(), GCM<>::BLOCKSIZE);
        std::string ciphertextWithoutIv(ciphertext, GCM<>::BLOCKSIZE);

        // AES-GCM解密
        GCM<AES>::Decryption gcmDecryption;
        gcmDecryption.SetKeyWithIV(secKey, secKey.size(), iv, sizeof(iv));

        std::string decryptedText;
        StringSource(ciphertextWithoutIv, true,
                     new AuthenticatedDecryptionFilter(gcmDecryption,
                                                       new StringSink(decryptedText),
                                                       AuthenticatedDecryptionFilter::DEFAULT_FLAGS,
                                                       GCM<>::TAG_SIZE));

        std::cout << "解密后的文本:" << std::endl;
        std::cout << decryptedText << std::endl;
    }
    catch (const CryptoPP::Exception& e)
    {
        std::cerr << "加密异常:" << e.what() << std::endl;
        return -1;
    }

    return 0;
}

在这个示例中,我们使用FileSource从文件中读取密文和密钥,使用GCM::Decryption进行AES-GCM解密,使用StringSource将密文传递给AuthenticatedDecryptionFilter,并将解密结果保存到StringSink中。

需要注意的是,在解密前需要从密文中提取出IV(Initialization Vector),并将其传递给GCM::Decryption对象的SetKeyWithIV方法。

此外,需要注意密文和密钥的编码方式,一般情况下,建议使用二进制方式保存密文和密钥。