AES/GCM 解密结果中的额外数据
Extra data in result for AES/GCM decryption
我有以下代码,基本上是从 http://www.cryptopp.com/wiki/AuthenticatedDecryptionFilter
的 Crypto++ wiki 上抓取的
问题是,我得到的输出是 "plaintext: abc1230000000077C8E390" 而不是我所期望的,只是 "plaintext: abc123"
最后的额外数据是什么?
还有两个基于相同代码库的小问题:
此方法是否可以作为对 pdata 使用实际随机字节数据的直接替代方法 - 或者因为它是字符串,所以它实际上必须像普通文本一样吗?
我假设adata是明文传输的,所以在存储密文时,我正确的是iv和adata都是明文的,用户只提供密钥(解密包含这 4 个元素的密文:key(由用户提供)、ciphertext(可用)、iv(可用)和 adata(可用)?
谢谢!
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;
}
The problem is, with the output I get "plaintext: abc1230000000077C8E390"
我猜你重复使用了一个字符串。 Crypto++ 将在 StringSink
中附加,而不是覆盖。所以你得到了 abc123
,然后你设法以某种方式附加了 0000000077C8E390
。
以下适合我。它是您的程序的轻微修改版本。它使 adata
和 pdata
全局化,重命名它们以避免名称隐藏,并通过 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 );
I assume adata is meant to be transferred in plaintext...
是的。它将类似于 IP 地址、磁盘扇区或计数器(以及其他)。
更准确地说,它的数据仅经过身份验证。如果它被篡改,它会被检测到。
... am I correct that both the iv and adata are in plaintext
IV 可以是 public 或私有参数。
如果是public参数,则不需要认证。它有点不直观,但那是因为篡改IV会篡改密码的状态,所以解密会失败,就像你使用了错误的密钥一样。
... the user only provides the key (to decrypt the ciphertext with those 4 elements: key (provided by user), ciphertext (made available), iv (made available), and adata (made available)?
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);
}
我有以下代码,基本上是从 http://www.cryptopp.com/wiki/AuthenticatedDecryptionFilter
的 Crypto++ wiki 上抓取的问题是,我得到的输出是 "plaintext: abc1230000000077C8E390" 而不是我所期望的,只是 "plaintext: abc123"
最后的额外数据是什么?
还有两个基于相同代码库的小问题:
此方法是否可以作为对 pdata 使用实际随机字节数据的直接替代方法 - 或者因为它是字符串,所以它实际上必须像普通文本一样吗?
我假设adata是明文传输的,所以在存储密文时,我正确的是iv和adata都是明文的,用户只提供密钥(解密包含这 4 个元素的密文:key(由用户提供)、ciphertext(可用)、iv(可用)和 adata(可用)?
谢谢!
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;
}
The problem is, with the output I get "plaintext: abc1230000000077C8E390"
我猜你重复使用了一个字符串。 Crypto++ 将在 StringSink
中附加,而不是覆盖。所以你得到了 abc123
,然后你设法以某种方式附加了 0000000077C8E390
。
以下适合我。它是您的程序的轻微修改版本。它使 adata
和 pdata
全局化,重命名它们以避免名称隐藏,并通过 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 );
I assume adata is meant to be transferred in plaintext...
是的。它将类似于 IP 地址、磁盘扇区或计数器(以及其他)。
更准确地说,它的数据仅经过身份验证。如果它被篡改,它会被检测到。
... am I correct that both the iv and adata are in plaintext
IV 可以是 public 或私有参数。
如果是public参数,则不需要认证。它有点不直观,但那是因为篡改IV会篡改密码的状态,所以解密会失败,就像你使用了错误的密钥一样。
... the user only provides the key (to decrypt the ciphertext with those 4 elements: key (provided by user), ciphertext (made available), iv (made available), and adata (made available)?
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);
}