0

好的,我讨厌这样做,但我很沮丧,因为 CBC_CTS_Mode_ExternalCipher 上几乎没有文档。

我有一个部分已知的 AES128 密钥。我构建了一个函数来生成密钥未知和已知部分的所有可能组合和排列。让我换个说法……对不起,该函数以我想要的格式创建一个密钥,即 16 个字节的十六进制,但是解密的输出都搞砸了,我打算只解密消息和 XOR CBC手动,但我没有时间。

当解密输出时,我得到各种符号、数字、字母和疯狂。

string ciphertext = "C7A4123420BF4EFFB815BC0EA8B46D00F440D068CDD9BB28860DC3E9B312710743";
string plaintext;

CryptoPP::AES::Decryption aesDecryption(tmp, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_CTS_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );

CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new 
    CryptoPP::StringSink( plaintext ) );

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

当您已经拥有用于密码分析的密文时,有更多知识的人可以帮助解释为什么这不起作用或解释在 CBC 模式下解密密文字符串的更好方法吗?

谢谢

编辑:替换“密钥有效,但解密无效”,让我改述一下......对不起,该函数以我想要的格式创建一个密钥,即 16 个字节的十六进制,但解密的输出是一切都搞砸了

4

1 回答 1

1

当您已经拥有用于密码分析的密文时,在 CBC 模式下解密密文字符串的更好方法

您使用的是 CTS 模式,而不是 CBC 模式。所以第一步是使用正确的模式;)

这是来自 Crypto++ wiki CBC Mode的 CBC 加密和解密示例:

AutoSeededRandomPool prng;

SecByteBlock key(AES::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );

byte iv[ AES::BLOCKSIZE ];
prng.GenerateBlock( iv, sizeof(iv) );

string plain = "CBC Mode Test";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
    cout << "plain text: " << plain << endl;

    CBC_Mode< AES >::Encryption e;
    e.SetKeyWithIV( key, key.size(), iv );

    // The StreamTransformationFilter adds padding
    //  as required. ECB and CBC Mode must be padded
    //  to the block size of the cipher.
    StringSource ss( plain, true, 
        new StreamTransformationFilter( e,
            new StringSink( cipher )
        ) // StreamTransformationFilter      
    ); // StringSource
}
catch( const CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss( cipher, true,
    new HexEncoder(
        new StringSink( encoded )
    ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
    CBC_Mode< AES >::Decryption d;
    d.SetKeyWithIV( key, key.size(), iv );

    // The StreamTransformationFilter removes
    //  padding as required.
    StringSource ss( cipher, true, 
        new StreamTransformationFilter( d,
            new StringSink( recovered )
        ) // StreamTransformationFilter
    ); // StringSource

    cout << "recovered text: " << recovered << endl;
}
catch( const CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

这是一个典型的输出:

$ ./driver.exe 
key: B00DDF9D93E199EFEAE967805E0A5228
iv: CA8A8878F145C9B9B3C31A1F15C34A6D
plain text: CBC Mode Test
cipher text: D6AF39534926C21CFF3E7477A7146FF3
recovered text: CBC Mode Test

字符串密文 = "C7A4123420BF4EFFB815BC0EA8B46D00F440D068CDD9BB28860DC3E9B312710743"

您可能想要做的第二件事是将字符串从十六进制编码更改为二进制。这在HexDecoder下的 Crypto++ wiki 中有介绍:

string encoded = "FFEEDDCCBBAA99887766554433221100";
string decoded;

StringSource ss(encoded,
    new HexDecoder(
        new StringSink(decoded)
    ) // HexDecoder
); // StringSource

上面的代码运行后,你会得到一个可能嵌入了NULLs 的二进制字符串。所以一定要使用decoded.data()指针,以及decoded.size()二进制字符串的长度。


当解密输出时,我得到各种符号、数字、字母和疯狂。

这可能意味着解密失败。真正判断的唯一方法是您是否在密文上提供了像 HMAC 这样的身份验证标签。否则,您将得到这些结果。

如果您使用需要填充的模式(如 CBC 模式),那么当填充恰好正确时,您仍然会得到虚假命中。唯一明确的方式是提供身份验证标签。


我构建了一个函数来生成密钥未知和已知部分的所有可能组合和排列。

您也应该显示该例程,以防它出现错误。我们无法评论您排列位的方式,但我们可以评论它是否看起来像 Crypto++ 使用的那样生成二进制字符串。


我打算手动解密消息和 CBC 的 XOR,但我没有时间。

我真的不知道该怎么做......你想在ECB模式下操作AES然后自己执行XOR吗?如果是这样,您可能会考虑使用ArrayXorSink

于 2014-02-21T17:29:53.890 回答