【问题标题】:Encrypting and Decrypting a byte array/vector using the CryptoPP library使用 CryptoPP 库加密和解密字节数组/向量
【发布时间】:2017-12-13 11:10:12
【问题描述】:

我正在尝试加密已解析为字符串的字节数组。这似乎适用于所有情况,除了字节数组包含 0x00 的情况。

int main()
{
    byte cipherTextWithZeroByte[32] = {
        0xD3, 0xFA, 0xD6, 0xEC, 0x84, 0x4E, 0xD3, 0xD8,
        0x2B, 0x76, 0x6C, 0xE8, 0x02, 0xF2, 0xB2, 0x6F,
        0x00, 0xE8, 0x99, 0x8C, 0xEC, 0x4B, 0x3C, 0x7D,         
        0xAC, 0xDE, 0x86, 0x02, 0x51, 0xAB, 0x3F, 0x04
    };

    string cipherText((char *)cipherTextWithZeroByte);
    string plainText = decrypt(cipherText, sizeof(cipherTextWithZeroByte));

    return 1;
}

string decrypt(string cipherText, int size)
{
    string decryptedText;

    CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);

    CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, 
              new CryptoPP::HexEncoder(
                           new CryptoPP::StringSink(decryptedText)));

    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipherText.c_str()), size);
    stfDecryptor.MessageEnd();

    return decryptedText;
}

在这种情况下,字节数组包含 0x00。这会导致密文被缩短,导致长度无效。抛出异常说明:'StreamTransformationFilter: invalid PKCS #7 block padding found'

所以我认为最好使用 ArraySourceArraySink 来确保字符串不以零结尾。

int main()
{
    byte cipherTextWithZeroByte[32] = {
        0xD3, 0xFA, 0xD6, 0xEC, 0x84, 0x4E, 0xD3, 0xD8,
        0x2B, 0x76, 0x6C, 0xE8, 0x02, 0xF2, 0xB2, 0x6F,
        0x00, 0xE8, 0x99, 0x8C, 0xEC, 0x4B, 0x3C, 0x7D,         
        0xAC, 0xDE, 0x86, 0x02, 0x51, 0xAB, 0x3F, 0x04
    };

    vector<byte> cipherTextData(cipherTextWithZeroByte, cipherTextWithZeroByte + sizeof(cipherTextWithZeroByte) / sizeof(cipherTextWithZeroByte[0]));
    vector<byte> plainTextData = decrypt(cipherTextData);

    return 1;
}

vector<byte> decrypt(vector<byte> cipherText)
{
    vector<byte> plainText;
    plainText.resize(cipherText.size());

    CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor;
    decryptor.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));


    CryptoPP::ArraySource ss(&cipherText[0], cipherText.size(), true,
              new CryptoPP::HexEncoder(
                  new CryptoPP::StreamTransformationFilter(decryptor,
                      new CryptoPP::ArraySink(plainText.data(), plainText.size()))));

    return plainText;
}

在这种情况下,会抛出密文不是密钥长度的倍数的异常,这显然不是这里的情况。 (密钥 = 16 字节,密文 = 16 字节)。我认为该库将字节数组转换为字符串,省略了 0x00 字节之后的所有数据。

我做错了什么?

【问题讨论】:

  • “我认为库将字节数组转换为字符串,忽略了 0x00 字节之后的所有数据......” - 不,这不会发生。始终使用字符串的size 成员函数。你的问题出在其他地方。
  • “抛出一个异常,密文不是密钥长度的倍数...” - 这里听起来不太对劲。我不认识这个消息。实际的例外是什么?听起来又像是无效的填充消息(有点)。也许您有一个过时的文件需要在更改后重建。
  • 在第二个示例中,您需要在执行return plainText 之前将plainText 调整为恢复邮件的实际大小。您可能需要调用ArraySink 成员函数TotalPutLength 来获取恢复的消息大小。 Crypto++ wiki 上的 ArraySink 提供了一个示例。

标签: c++ encryption aes crypto++


【解决方案1】:

加密是二进制字节而不是字符操作。因此,加密的输出不能转换为字符串。如果您需要字符串输出,请将加密数据编码为与字符串兼容的格式,常见格式为 Base64 和十六进制。

特别是按照“C”中的约定,字符串中的空字节表示字符串的结尾。

即在加密时将二进制数据编码为字符串格式,在解密时首先使用编码操作的逆操作将字符串表示解码为二进制数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多