我使用CBC_CTS_Mode_ExternalCipher并得到乱码输出

时间:2014-02-21 02:43:32

标签: aes crypto++ cbc-mode

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

我有AES128的部分已知密钥。我构建了一个函数来生成密钥的未知和已知部分的所有可能组合和排列。让我重新说一下......对不起,该函数以我想要的格式创建一个密钥,即16字节的十六进制,但是解密的输出全部搞砸了我只是解密消息和XOR for 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字节十六进制,但解密的输出都搞砸了

1 个答案:

答案 0 :(得分: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

  

string ciphertext =“C7A4123420BF4EFFB815BC0EA8B46D00F440D068CDD9BB28860DC3E9B312710743”

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

string encoded = "FFEEDDCCBBAA99887766554433221100";
string decoded;

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

运行上面的代码后,您将拥有一个可能嵌入NULL的二进制字符串。因此,请务必使用decoded.data()作为指针,decoded.size()作为二进制字符串的长度。


  

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

这可能意味着解密失败了。真正告诉的唯一方法是,您是否通过密文提供类似HMAC的身份验证标记。否则,您将获得这些结果。

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


  

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

如果出现错误,您应该显示该例行程序。我们无法对你置换位的方式发表评论,但我们可以评论它是否像Crypto ++那样产生二进制字符串。


  

我打算手动解密消息并为CBC解除XOR,但我没有时间。

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