解密图像与原始图像不同
Decrypted image is not same as original image
我刚开始研究 cryptopp 库。我有一个图像缓冲区,我想用一些密钥加密,然后稍后解密,但面临问题,解密图像和原始图像不一样。
我不确定加密中的天气问题是否有人可以帮助我解决这个问题。
使用 qt creator
代码:
AutoSeededRandomPool prng;
SecByteBlock key(AES::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );
byte ctr[ AES::BLOCKSIZE ];
prng.GenerateBlock( ctr, sizeof(ctr) );
string cipher, encoded, recovered;
QFile file("original.png");
if(!file.open(QIODevice::ReadOnly)){
cout << "could not open the file"<< endl;
}
QByteArray buffer = file.readAll();
qDebug()<<"buffer length"<<buffer.length();
file.close();
try
{
CTR_Mode< AES >::Encryption e;
e.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
StringSource ss1( buffer, true,
new StreamTransformationFilter( e,
new StringSink( cipher )
)
);
}
catch( CryptoPP::Exception& e )
{
cerr << e.what() << endl;
exit(1);
}
qDebug()<<"cipher length "<<cipher.length();
try
{
CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
StringSource ss3( cipher, true,
new StreamTransformationFilter( d,
new StringSink( recovered )
)
);
}
catch( CryptoPP::Exception& e )
{
cerr << e.what() << endl;
exit(1);
}
qDebug()<<"recovered length "<<recovered.length();
QFile ouput("recovered.png");
if(ouput.open(QIODevice::WriteOnly)){
ouput.write(recovered.data(), recovered.size());
ouput.close();
}
回复:
buffer length 538770
cipher length 8
recovered length 8
为什么我的密码长度只有8位
在您的代码中,您将文件内容转换为 Base64,
对其进行加密、解密并将其保存到文件中(从而将 png 文件保存为 Base64)
您应该加密原始文件数据(而不是 Base64 编码的数据)。
编辑: 编辑后我不知道什么地方失败了。请尝试以下对我有用的功能。使用 FileSource
和 FileSink
,但应相应地使用 StringSource 和 StringSink。
bool encryptdecrypt(const std::string& filename)
{
std::string key = "7D9BB722DA2DC8674E08C3D44AAE976F";
byte ctr[ CryptoPP::AES::BLOCKSIZE ];
std::string cipher;
try
{
CryptoPP::CTR_Mode< CryptoPP::AES >::Encryption e;
e.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
CryptoPP::FileSource( filename.c_str(), true,
new CryptoPP::StreamTransformationFilter( e,
new CryptoPP::StringSink( cipher )
)
);
}
catch( CryptoPP::Exception& e )
{
std::cerr << e.what() << std::endl;
return false;
}
try
{
CryptoPP::CTR_Mode< CryptoPP::AES >::Decryption d;
d.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
CryptoPP::StringSource( cipher, true,
new CryptoPP::StreamTransformationFilter( d,
new CryptoPP::FileSink( ( "decrypted_" + filename ).c_str() )
)
);
}
catch( CryptoPP::Exception& e )
{
std::cerr << e.what() << std::endl;
return false;
}
return true;
}
QFile ouput("recovered.png");
if(ouput.open(QIODevice::WriteOnly)){
ouput.write(recovered.c_str());
ouput.close();
}
让我把我的扔进锅里....您将二进制数据视为 C-String,这意味着 reading/writing 在第一个 NULL 字符处停止。您应该使用带有指针和大小的重载。也许是这样的:
ouput.write(recovered.data(), recovered.size());
(代码编辑后)
QByteArray buffer = file.readAll();
...
StringSource ss1( buffer, true, ...);
这可能不会产生预期的结果。也许你应该试试:
QByteArray buffer = file.readAll();
...
StringSource ss1( buffer.data(), buffer.size(), true, ...);
上面的StringSource
重载,带有一个指针 和 size 是您在这种情况下应该更喜欢的那个。这是它设计的确切案例,它保存了 buffer
.
的额外副本
您甚至可以使用 FileSource
和 FileSink` 与 Crypto++::
集成
FileSource ifile("original.png", true,
new StreamTransformationFilter(e,
new StringSink( cipher )
)
);
另外,Barmak 是正确的:
In your case you call it ctr but it seems to be uninitialized...
虽然没有初始化,但是加密和解密使用的是同一个[unknown]值,所以问题没有暴露出来。它稍后会出现,例如当您在一台机器上加密并在另一台机器上解密时。
您应该按照 Barmak 的建议对其进行初始化。也许是这样的:
byte ctr[16];
OS_GenerateRandomBlock(false, ctr, sizeof(ctr));
OS_GenerateRandomBlock is discussed on Crypto++ wiki at RandomNumberGenerator.
您通常可以在消息中以明文形式发送计数器,因为它通常被认为是一个 public 值。但这实际上取决于您的安全模型。
请务必永不在计数器模式下重用安全上下文。每条消息都必须在唯一的安全上下文中加密。安全上下文是 {key,ctr}
对。
您还可以打印计数器:
byte ctr[16];
OS_GenerateRandomBlock(false, ctr, sizeof(ctr));
HexEncoder encoder(new FileSink(cout));
cout << "Counter: ";
encoder.Put(ctr, sizeof(ctr));
encoder.MessageEnd();
cout << endl;
上面的代码只是 hex-encodes 原始字节数组,然后将其打印到 stdout
.
(comment) string key = "7D9BB722DA2DC8674E08C3D44AAE976F";
- You probably want a binary string; not an ASCII string. For Crypto++, see HexDecoder on the Crypto++ wiki. I'm not sure what QT offers for the service.
因为这里有更多 space...这是您可以做的事情之一:
string key, encodedKey = "7D9BB722DA2DC8674E08C3D44AAE976F";
StringSource ss(encodedKey, true, new HexDecoder(key));
语句执行后,字符串key
将是二进制数据
我发现了 QByteArray 缓冲区的问题。我刚刚转换为 std::string 它的工作。
QByteArray buffer = file.readAll();
// string
std::string stdString(buffer.data(), buffer.length());
//used stdString instead of buffer in pipeline
StringSource ss1(stdString, true,
new StreamTransformationFilter( e,
new StringSink( cipher )
)
);
我刚开始研究 cryptopp 库。我有一个图像缓冲区,我想用一些密钥加密,然后稍后解密,但面临问题,解密图像和原始图像不一样。 我不确定加密中的天气问题是否有人可以帮助我解决这个问题。
使用 qt creator
代码:
AutoSeededRandomPool prng;
SecByteBlock key(AES::DEFAULT_KEYLENGTH);
prng.GenerateBlock( key, key.size() );
byte ctr[ AES::BLOCKSIZE ];
prng.GenerateBlock( ctr, sizeof(ctr) );
string cipher, encoded, recovered;
QFile file("original.png");
if(!file.open(QIODevice::ReadOnly)){
cout << "could not open the file"<< endl;
}
QByteArray buffer = file.readAll();
qDebug()<<"buffer length"<<buffer.length();
file.close();
try
{
CTR_Mode< AES >::Encryption e;
e.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
StringSource ss1( buffer, true,
new StreamTransformationFilter( e,
new StringSink( cipher )
)
);
}
catch( CryptoPP::Exception& e )
{
cerr << e.what() << endl;
exit(1);
}
qDebug()<<"cipher length "<<cipher.length();
try
{
CTR_Mode< AES >::Decryption d;
d.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
StringSource ss3( cipher, true,
new StreamTransformationFilter( d,
new StringSink( recovered )
)
);
}
catch( CryptoPP::Exception& e )
{
cerr << e.what() << endl;
exit(1);
}
qDebug()<<"recovered length "<<recovered.length();
QFile ouput("recovered.png");
if(ouput.open(QIODevice::WriteOnly)){
ouput.write(recovered.data(), recovered.size());
ouput.close();
}
回复:
buffer length 538770
cipher length 8
recovered length 8
为什么我的密码长度只有8位
在您的代码中,您将文件内容转换为 Base64, 对其进行加密、解密并将其保存到文件中(从而将 png 文件保存为 Base64)
您应该加密原始文件数据(而不是 Base64 编码的数据)。
编辑: 编辑后我不知道什么地方失败了。请尝试以下对我有用的功能。使用 FileSource
和 FileSink
,但应相应地使用 StringSource 和 StringSink。
bool encryptdecrypt(const std::string& filename)
{
std::string key = "7D9BB722DA2DC8674E08C3D44AAE976F";
byte ctr[ CryptoPP::AES::BLOCKSIZE ];
std::string cipher;
try
{
CryptoPP::CTR_Mode< CryptoPP::AES >::Encryption e;
e.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
CryptoPP::FileSource( filename.c_str(), true,
new CryptoPP::StreamTransformationFilter( e,
new CryptoPP::StringSink( cipher )
)
);
}
catch( CryptoPP::Exception& e )
{
std::cerr << e.what() << std::endl;
return false;
}
try
{
CryptoPP::CTR_Mode< CryptoPP::AES >::Decryption d;
d.SetKeyWithIV( (byte*)key.data(), key.size(), ctr );
CryptoPP::StringSource( cipher, true,
new CryptoPP::StreamTransformationFilter( d,
new CryptoPP::FileSink( ( "decrypted_" + filename ).c_str() )
)
);
}
catch( CryptoPP::Exception& e )
{
std::cerr << e.what() << std::endl;
return false;
}
return true;
}
QFile ouput("recovered.png"); if(ouput.open(QIODevice::WriteOnly)){ ouput.write(recovered.c_str()); ouput.close(); }
让我把我的扔进锅里....您将二进制数据视为 C-String,这意味着 reading/writing 在第一个 NULL 字符处停止。您应该使用带有指针和大小的重载。也许是这样的:
ouput.write(recovered.data(), recovered.size());
(代码编辑后)
QByteArray buffer = file.readAll();
...
StringSource ss1( buffer, true, ...);
这可能不会产生预期的结果。也许你应该试试:
QByteArray buffer = file.readAll();
...
StringSource ss1( buffer.data(), buffer.size(), true, ...);
上面的StringSource
重载,带有一个指针 和 size 是您在这种情况下应该更喜欢的那个。这是它设计的确切案例,它保存了 buffer
.
您甚至可以使用 FileSource
和 FileSink` 与 Crypto++::
FileSource ifile("original.png", true,
new StreamTransformationFilter(e,
new StringSink( cipher )
)
);
另外,Barmak 是正确的:
In your case you call it ctr but it seems to be uninitialized...
虽然没有初始化,但是加密和解密使用的是同一个[unknown]值,所以问题没有暴露出来。它稍后会出现,例如当您在一台机器上加密并在另一台机器上解密时。
您应该按照 Barmak 的建议对其进行初始化。也许是这样的:
byte ctr[16];
OS_GenerateRandomBlock(false, ctr, sizeof(ctr));
OS_GenerateRandomBlock is discussed on Crypto++ wiki at RandomNumberGenerator.
您通常可以在消息中以明文形式发送计数器,因为它通常被认为是一个 public 值。但这实际上取决于您的安全模型。
请务必永不在计数器模式下重用安全上下文。每条消息都必须在唯一的安全上下文中加密。安全上下文是 {key,ctr}
对。
您还可以打印计数器:
byte ctr[16];
OS_GenerateRandomBlock(false, ctr, sizeof(ctr));
HexEncoder encoder(new FileSink(cout));
cout << "Counter: ";
encoder.Put(ctr, sizeof(ctr));
encoder.MessageEnd();
cout << endl;
上面的代码只是 hex-encodes 原始字节数组,然后将其打印到 stdout
.
(comment)
string key = "7D9BB722DA2DC8674E08C3D44AAE976F";
- You probably want a binary string; not an ASCII string. For Crypto++, see HexDecoder on the Crypto++ wiki. I'm not sure what QT offers for the service.
因为这里有更多 space...这是您可以做的事情之一:
string key, encodedKey = "7D9BB722DA2DC8674E08C3D44AAE976F";
StringSource ss(encodedKey, true, new HexDecoder(key));
语句执行后,字符串key
将是二进制数据
我发现了 QByteArray 缓冲区的问题。我刚刚转换为 std::string 它的工作。
QByteArray buffer = file.readAll();
// string
std::string stdString(buffer.data(), buffer.length());
//used stdString instead of buffer in pipeline
StringSource ss1(stdString, true,
new StreamTransformationFilter( e,
new StringSink( cipher )
)
);