AES / GCM解密的结果中的额外数据

时间:2015-06-16 14:54:30

标签: c++ encryption aes crypto++

我有以下代码,基本上是从http://www.cryptopp.com/wiki/AuthenticatedDecryptionFilter

的Crypto ++ wiki中抓取的

问题是,输出我得到“明文:abc1230000000077C8E390”而不是我期望的,只是“明文:abc123”

最后的额外数据是什么?

另外两个基于相同代码库的小问题:

  1. 这个方法是否可以替代使用pdata的实际随机字节数据,或者因为它的字符串实际上必须像普通文本一样?

  2. 我认为adata是以明文形式传输的,所以在存储密文时,我认为iv和adata都是纯文本,而用户只提供密钥(用这些密钥解密密文) 4个元素:密钥(由用户提供),密文(可用),iv(可用)和adata(可用)?

  3. 谢谢!

    AutoSeededRandomPool prng;
    
    byte key[ AES::DEFAULT_KEYLENGTH ];
    prng.GenerateBlock( key, sizeof(key) );
    
    byte iv[ AES::BLOCKSIZE ];
    prng.GenerateBlock( iv, sizeof(iv) );
    
    string adata( 16, (char)0x00 );
    
    string cipherText = encryptData("abc123", adata, key, iv);
    string plainText = decryptData(cipherText, adata, key, iv);
    cout << "plaintext: " << plainText << endl;
    
    //Utilities
    string MainWindow::encryptData(string pdata, string adata, const byte *key, const byte *iv) {
        const int TAG_SIZE = 16;
    
        string cipher;
    
        try
            {
                GCM< AES >::Encryption e;
                e.SetKeyWithIV( key, AES::DEFAULT_KEYLENGTH, iv, AES::BLOCKSIZE );
    
                AuthenticatedEncryptionFilter ef( e,
                    new StringSink( cipher ), false, TAG_SIZE
                ); // AuthenticatedEncryptionFilter
    
                ef.ChannelPut( "AAD", (const byte*)adata.data(), adata.size() );
                ef.ChannelMessageEnd("AAD");
    
                ef.ChannelPut( "", (const byte*)pdata.data(), pdata.size() );
                ef.ChannelMessageEnd("");
            }
            catch( CryptoPP::BufferedTransformation::NoChannelSupport& e )
            {
                cerr << "Caught NoChannelSupport..." << endl;
                cerr << e.what() << endl;
                cerr << endl;
            }
            catch( CryptoPP::AuthenticatedSymmetricCipher::BadState& e )
            {
                cerr << "Caught BadState..." << endl;
                cerr << e.what() << endl;
                cerr << endl;
            }
            catch( CryptoPP::InvalidArgument& e )
            {
                cerr << "Caught InvalidArgument..." << endl;
                cerr << e.what() << endl;
                cerr << endl;
            }
    
        return(cipher);
    }
    
    string MainWindow::decryptData(string cipher, string adata, const byte *key, const byte *iv) {
        const int TAG_SIZE = 16;
        string radata, rpdata;
        try
        {
            GCM< AES >::Decryption d;
            d.SetKeyWithIV( key, AES::DEFAULT_KEYLENGTH, iv, AES::BLOCKSIZE );
    
            string enc = cipher.substr( 0, cipher.length()-TAG_SIZE );
            string mac = cipher.substr( cipher.length()-TAG_SIZE );
    
            assert( cipher.size() == enc.size() + mac.size() );
            assert( enc.size() == pdata.size() );
            assert( TAG_SIZE == mac.size() );
    
            radata = adata;
    
            AuthenticatedDecryptionFilter df( d, NULL,
                AuthenticatedDecryptionFilter::MAC_AT_BEGIN |
                AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE );
    
            df.ChannelPut( "", (const byte*)mac.data(), mac.size() );
            df.ChannelPut( "AAD", (const byte*)adata.data(), adata.size() );
            df.ChannelPut( "", (const byte*)enc.data(), enc.size() );
    
            df.ChannelMessageEnd( "AAD" );
            df.ChannelMessageEnd( "" );
    
            string retrieved;
            size_t n = (size_t)df.MaxRetrievable();
            retrieved.resize( n );
    
            if( n > 0 ) { df.Get( (byte*)retrieved.data(), n ); }
            rpdata = retrieved;
            assert( rpdata == pdata );
    
        }
        catch( CryptoPP::InvalidArgument& e )
        {
            cerr << "Caught InvalidArgument..." << endl;
            cerr << e.what() << endl;
            cerr << endl;
        }
        catch( CryptoPP::AuthenticatedSymmetricCipher::BadState& e )
        {
            cerr << "Caught BadState..." << endl;
            cerr << e.what() << endl;
            cerr << endl;
        }
        catch( CryptoPP::HashVerificationFilter::HashVerificationFailed& e )
        {
            cerr << "Caught HashVerificationFailed..." << endl;
            cerr << e.what() << endl;
            cerr << endl;
        }
    
        return rpdata;    
    }
    

1 个答案:

答案 0 :(得分:0)

  

问题是,我得到的输出&#34;明文:abc1230000000077C8E390&#34;

我的猜测是你重复使用了一个字符串。 Crypto ++将在StringSink中追加而不是覆盖。所以你得到abc123,然后你设法以某种方式附加0000000077C8E390

以下适用于我。它是您程序的温和修改版本。它使adatapdata全局,重命名它们以避免名称隐藏,并通过pdata传递消息。

$ ./cryptopp-test.exe
plaintext: Now is the time for all good men to come to the aide of their country

$ ./cryptopp-test.exe wxyz
plaintext: wxyz

因为您使用的是THROW_EXCEPTION,所以您不需要:

b = df.GetLastResult();
assert( true == b );
  

我认为adata意图以明文转移......

是。它将类似于IP地址,磁盘扇区或计数器(等等)。

更准确地说,它的数据仅通过身份验证。如果被篡改,将被检测到。

  

...我是正确的,iv和adata都是纯文本

IV可以是公共或私人参数。

如果是公共参数,则不需要进行身份验证。它有点不直观,但是因为篡改IV会篡改密码的状态,因此解密将失败,就好像你使用了错误的密钥一样。

  

...用户只提供密钥(用这4个元素解密密文:密钥(由用户提供),密文(可用),iv(可用)和adata(可用)?

pdata获得机密性和真实性保证;并且adata仅获得真实性保证。

钥匙和IV是惯例。像往常一样处理它们(或者应该这样做:)。

using CryptoPP::DEFAULT_CHANNEL;
using CryptoPP::AAD_CHANNEL;

string encryptData(const string& pdata, const string& adata, const byte *key, unsigned int ksize, const byte *iv, unsigned int vsize);
string decryptData(const string& cipher, const string& adata, const byte *key, unsigned int ksize, const byte *iv, unsigned int vsize);

string xadata = "172.16.1.10";
string xpdata = "Now is the time for all good men to come to the aide of their country";

static const unsigned int TAG_SIZE = 16;

int main(int argc, char* argv[])
{
    (void)argc; (void)argv;

    if(argc >= 2)
        xpdata = argv[1];

    try {

        AutoSeededRandomPool prng;

        byte key[ AES::DEFAULT_KEYLENGTH ];
        prng.GenerateBlock( key, sizeof(key) );

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

        string cipherText = encryptData(xpdata, xadata, key, sizeof(key), iv, sizeof(iv));
        string plainText = decryptData(cipherText, xadata, key, sizeof(key), iv, sizeof(iv));

        cout << "plaintext: " << plainText << endl;
    }
    catch(CryptoPP::Exception& ex)
    {
        cerr << ex.what() << endl;
    }

    return 0;
}

//Utilities
string encryptData(const string& pdata, const string& adata, const byte *key, unsigned int ksize, const byte *iv, unsigned int vsize) {

    string cipher;

    GCM< AES >::Encryption e;
    e.SetKeyWithIV( key, ksize, iv, vsize );

    AuthenticatedEncryptionFilter ef( e,
                                     new StringSink( cipher ), false, TAG_SIZE
                                     ); // AuthenticatedEncryptionFilter

    ef.ChannelPut(AAD_CHANNEL, (const byte*)adata.data(), adata.size() );
    ef.ChannelMessageEnd(AAD_CHANNEL);

    ef.ChannelPut(DEFAULT_CHANNEL, (const byte*)pdata.data(), pdata.size() );
    ef.ChannelMessageEnd(DEFAULT_CHANNEL);

    return(cipher);
}

string decryptData(const string& cipher, const string& adata, const byte *key, unsigned int ksize, const byte *iv, unsigned int vsize) {

    string recovered;

    GCM< AES >::Decryption d;
    d.SetKeyWithIV( key, ksize, iv, vsize );

    const string& enc = cipher.substr( 0, cipher.length()-TAG_SIZE );
    const string& mac = cipher.substr( cipher.length()-TAG_SIZE );

    assert( cipher.size() == enc.size() + mac.size() );
    assert( enc.size() == xpdata.size() );
    assert( TAG_SIZE == mac.size() );

    AuthenticatedDecryptionFilter df( d, new StringSink(recovered),
                                     AuthenticatedDecryptionFilter::MAC_AT_BEGIN |
                                     AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE );

    df.ChannelPut(DEFAULT_CHANNEL, (const byte*)mac.data(), mac.size() );
    df.ChannelPut(AAD_CHANNEL, (const byte*)adata.data(), adata.size() );
    df.ChannelPut(DEFAULT_CHANNEL, (const byte*)enc.data(), enc.size() );

    df.ChannelMessageEnd(AAD_CHANNEL);
    df.ChannelMessageEnd(DEFAULT_CHANNEL);

    assert( recovered == xpdata );        
    return(recovered);
}