重新加密加密的数据文件将生成解密的输出

时间:2019-07-02 20:15:58

标签: c++ aes crypto++

我使用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 

它已经显示了原始数据。不确定这里缺少什么。

1 个答案:

答案 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+0iv+0;第二种加密使用key+16iv+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,因此从密码更改为私钥并不需要太多工作。