我使用Crypto ++库编写了加密函数,当第一次进行文件加密时,该函数的行为正确。如果再次传递相同的加密文件进行加密,则会生成包含加密和解密数据的输出。
bool EncryptDataFile(const char* inputFile, const char* outputFile)
{
try
{
std::vector<byte> key = HexDecoding(PASSCODE);
std::vector<byte> iv = HexDecoding(INITIALIZATION_VECTOR);
GCM<AES>::Encryption encryptor;
encryptor.SetKeyWithIV(key.data(), key.size(), iv.data(), iv.size());
FileSource fs(inputFile, true,
new AuthenticatedEncryptionFilter(encryptor,
new FileSink(outputFile), false, TAG_SIZE));
}
catch(...)
{
return false;
}
return true;
}
Input.txt:
Privacy and Security
Output1.txt-首次加密输出:
{)ªei ?ñìCzN[hç&Ää€|Ùrñ½…
Ä
输入“ Output1.txt”,输出“ Output2.txt”-第二次加密:
Privacy and Security]®Ÿwþñ úeS„£Fpä40WL ,ÈR¯M
它已经显示了原始数据。不确定这里缺少什么。
答案 0 :(得分:0)
如果再次传递相同的加密文件进行加密,则会生成包含加密和解密数据的输出。
如果我正确解析了内容,则表示您的加密方案中使用的是m ≅ Enc(Enc(m))
而不是c = Enc(Enc(m))
。这就是为什么应该避免设计自己的方案的原因之一。
在几种情况下可能会发生这种情况,例如在重用密钥和iv时以计数器模式使用流密码或分组密码。
对于每个消息或加密操作,您应该使用不同的安全上下文。放弃一些手,这意味着更改每个消息或加密操作的密钥或iv。
std::vector<byte> key = HexDecoding(PASSCODE); std::vector<byte> iv = HexDecoding(INITIALIZATION_VECTOR);
这可能是您的问题。您需要为每个消息或加密操作使用不同的安全上下文。
这是解决问题的方法。您使用密钥派生函数来为每种加密派生不同的安全性参数。在下面的代码中,32字节密钥分为两个16字节密钥。 iv也是如此。第一次加密使用key+0
和iv+0
;第二种加密使用key+16
和iv+16
。
cryptopp$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "aes.h"
#include "gcm.h"
#include "hex.h"
#include "hkdf.h"
#include "sha.h"
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
std::string password = "super secret password";
SecByteBlock key(32), iv(32);
HKDF<SHA256> hkdf;
hkdf.DeriveKey(key, key.size(),
(const byte*)password.data(), password.size(),
NULL, 0, // salt
(const byte*)"key derivation", 14);
hkdf.DeriveKey(iv, iv.size(),
(const byte*)password.data(), password.size(),
NULL, 0, // salt
(const byte*)"iv derivation", 13);
std::string m = "Yoda said, Do or do not. There is no try.";
std::string c1, c2;
GCM<AES>::Encryption encryptor;
encryptor.SetKeyWithIV(key, 16, iv, 16);
StringSource(m, true, new AuthenticatedEncryptionFilter(
encryptor, new StringSink(c1)));
encryptor.SetKeyWithIV(key+16, 16, iv+16, 16);
StringSource(c1, true, new AuthenticatedEncryptionFilter(
encryptor, new StringSink(c2)));
std::cout << "Hex(m):" << std::endl;
StringSource(m, true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
std::cout << "Hex(Enc(m)):" << std::endl;
StringSource(c1, true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
std::cout << "Hex(Enc(Enc(m))):" << std::endl;
StringSource(c2, true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
return 0;
}
这是程序的运行:
cryptopp$ ./test.exe
Hex(m):
596F646120736169642C20446F206F7220646F206E6F742E205468657265206973206E6F20747279
2E
Hex(Enc(m)):
D4A9063DE7400E90627DE90D16346DC5A99740C55F6FEE092A99071F55F1BDB25A72B7422126CCC4
09B5B5C0076E39EBF7256D5DC3151A738D
Hex(Enc(Enc(m))):
83A459F2D4A1627624AF162590465AC705C8AC0F4D915E4A4A9D300156C5F9E042CAA47903353F0A
A1FAE408D5747DD223AC4F9AEF3C320EEF7E79E08AB2C6FBEAE7A3A5B4978C45C7
我认为您的计划还有一些其他问题。例如,如果您多次加密“黎明时袭击!” 消息,则每次运行都会得到相同的密文。它正在泄漏信息,并且缺乏密文的可区分性。
我认为您应该避免使用您的方案,而使用Elliptic Curve Integrated Encryption Scheme (ECIES)。它避免了方案中的大多数潜在问题,并实现了IND-CCA2。
ECIES的缺点是,您必须管理公共/私有密钥对。不过,这并不是一个很大的缺点。您已经在管理密码和iv,因此从密码更改为私钥并不需要太多工作。