重新加密加密数据文件生成解密输出
Re-encrypting the encrypted data file generates a decrypted output
我使用 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
它揭示了原始数据。不确定这里缺少什么。
If the same encrypted file is passed again for encryption, generates the output which includes encrypted and decrypted data.
如果我解析正确,那么您在加密方案中说的是 m ≅ Enc(Enc(m))
而不是 c = Enc(Enc(m))
。这就是为什么你应该避免设计自己的方案的原因之一。
这可能在几种情况下发生,例如当 re-using 密钥和 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
我认为你的方案还有一些问题。例如,如果您多次加密消息 "Attack at dawn!",那么每次 运行 都会得到相同的密文。是泄露信息,缺乏密文不可分辨性
我认为你应该避免你的方案,并使用 Elliptic Curve Integrated Encryption Scheme (ECIES). It avoids most of the latent problems in your scheme, and achieves IND-CCA2.
ECIES 的缺点是,您必须管理 public/private 密钥对。不过,这并不是什么大缺点。您已经在管理密码和 iv,因此从密码更改为私钥并不需要更多工作。
我使用 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
它揭示了原始数据。不确定这里缺少什么。
If the same encrypted file is passed again for encryption, generates the output which includes encrypted and decrypted data.
如果我解析正确,那么您在加密方案中说的是 m ≅ Enc(Enc(m))
而不是 c = Enc(Enc(m))
。这就是为什么你应该避免设计自己的方案的原因之一。
这可能在几种情况下发生,例如当 re-using 密钥和 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
我认为你的方案还有一些问题。例如,如果您多次加密消息 "Attack at dawn!",那么每次 运行 都会得到相同的密文。是泄露信息,缺乏密文不可分辨性
我认为你应该避免你的方案,并使用 Elliptic Curve Integrated Encryption Scheme (ECIES). It avoids most of the latent problems in your scheme, and achieves IND-CCA2.
ECIES 的缺点是,您必须管理 public/private 密钥对。不过,这并不是什么大缺点。您已经在管理密码和 iv,因此从密码更改为私钥并不需要更多工作。