【问题标题】:Encrypt/Decrypt byte array Crypto++加密/解密字节数组 Crypto++
【发布时间】:2017-08-06 15:22:34
【问题描述】:

我正在尝试使用 AES 加密字节数组。我已经能够加密字符串和文件没问题,但是字节数组似乎对我不起作用。我传入一个要加密的字节数组,为了便于测试,我只传入由 crypto++ (bArrayToEncrypt) 生成的 AES 密钥。加密似乎有效,但解密确实有效。我还发现加密有大量重复字符很奇怪。我在这里做错了什么??

我看到了一个类似的问题Here,但它与 RSA 有关 以及提供的示例加密我已经运行的字符串。

如何调用函数:

   size_t ksize = CryptoPP::AES::MAX_KEYLENGTH;
   size_t vsize = CryptoPP::AES::BLOCKSIZE;

   byte key[ksize];
   byte testArray[ksize];
   byte encryptedksize];
   byte decrypted[ksize];
   byte iv[vsize];

   //generate key & iv, then generate a random byte array to encrypt/decrypt
   CryptoPP::AutoSeededRandomPool prng;
   prng.GenerateBlock(key, ksize);
   prng.GenerateBlock(iv, vsize);
   prng.GenerateBlock(testArray, ksize);


   encrypt_barray(key, ksize, iv, vsize, testArray, ksize, encrypted);

   //printed results here

   decrypt_barray(key, ksize, iv, vsize, encrypted, ksize, decrypted);

   //printed results here

加密数组

void encrypt_barray(byte* key, 
                    size_t kSize,
                    byte* iv, 
                    size_t ivSize, 
                    byte* bArrayToEncrypt,
                    size_t bArraySize,
                    byte* encrypted) {

   CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption e;
   e.SetKeyWithIV(key, kSize, iv, ivSize);

   CryptoPP::ArraySource(key, true,
      new CryptoPP::StreamTransformationFilter(e, new CryptoPP::ArraySink(encrypted, bArraySize)));
}

解密数组

void decrypt_barray(byte* key,
                    size_t kSize,
                    byte* iv,
                    size_t ivSize,
                    byte* bArrayToDecrypt,
                    size_t bArraySize,
                    byte* decrypted) {

   CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption d;
   d.SetKeyWithIV(keyFromHash, kfhSize, iv1, iv1Size);

   CryptoPP::ArraySource(keyToDecrypt, true,
      new CryptoPP::StreamTransformationFilter(d, new CryptoPP::ArraySink(decrypted, bArraySize)));
}

输出:

 Encrypted: ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠E1A2AFC5D820ADF7
7DB656DEF3245570╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╨Ñ♫

Decrypted: ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠E
1A2AFC5D820ADF77DB656DEF3245570╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╨Ñ♫
Press any key to continue . . .

【问题讨论】:

  • ArraySink 是适合这项工作的错误工具。您无法从加密操作中获取密文的实际大小。然后,在解密过程中,您会失明,因为您不知道ArraySource 使用什么大小。考虑切换到std::stringByteQueue。另请参阅 Crypto++ wiki 上的 SecByteBlockSink
  • 另外,E1A2AFC5D820ADF77DB656DEF3245570E1A2AFC5D820ADF77DB656DEF3245570 在我看来几乎就像一个串联的内存位置(即指针)。您可能应该展示您调用encrypt_barraydecrypt_barray 的方式。
  • @jww 我继续并添加了我如何调用这两个函数。谢谢!
  • 如何将 ByteQueue 合并到这些函数中?
  • 由于操作模式和 PKCS 填充,密文将大于testArray[ksize]ArraySink 将最多存储 ksize 字节,然后停止写入数组。

标签: c++ encryption crypto++


【解决方案1】:

这是使用ArraySourceArraySink 的方法。 Redirector 确保 ArraySink 存在,因此您可以调用 TotalPutLength

#include <iostream>
#include <string>
using namespace std;

#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "modes.h"
#include "hex.h"
#include "aes.h"
using namespace CryptoPP;

int main(int argc, char* argv[])
{
  byte key[AES::MAX_KEYLENGTH];
  byte iv[AES::BLOCKSIZE];
  vector<byte> plain, cipher, recover;
  HexEncoder encoder(new FileSink(cout));

  memset(key, 0x00, sizeof(key));
  memset(iv, 0x00, sizeof(iv));

  string str("Attack at dawn!");
  std::copy(str.begin(), str.end(), std::back_inserter(plain));

  cout << "Plain text: ";
  encoder.Put(plain.data(), plain.size());
  encoder.MessageEnd();
  cout << endl;

  /////////////////////////////////////////////////////////////

  CBC_Mode<AES>::Encryption enc;
  enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

  // Make room for padding
  cipher.resize(plain.size()+AES::BLOCKSIZE);
  ArraySink cs(&cipher[0], cipher.size());

  ArraySource(plain.data(), plain.size(), true,
    new StreamTransformationFilter(enc, new Redirector(cs)));

  // Set cipher text length now that its known
  cipher.resize(cs.TotalPutLength());

  cout << "Cipher text: ";
  encoder.Put(cipher.data(), cipher.size());
  encoder.MessageEnd();
  cout << endl;

  /////////////////////////////////////////////////////////////

  CBC_Mode<AES>::Decryption dec;
  dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

  // Recovered text will be less than cipher text
  recover.resize(cipher.size());
  ArraySink rs(&recover[0], recover.size());

  ArraySource(cipher.data(), cipher.size(), true,
    new StreamTransformationFilter(dec, new Redirector(rs)));

  // Set recovered text length now that its known
  recover.resize(rs.TotalPutLength());

  cout << "Recovered text: ";
  encoder.Put(recover.data(), recover.size());
  encoder.MessageEnd();
  cout << endl;

  return 0;
}

运行程序会导致:

$ ./test.exe
Plain text: 41747461636B206174206461776E21
Cipher text: 85928E5511BFE9E6EE235BCACC4894D4
Recovered text: 41747461636B206174206461776E21

这是使用ByteQueue 的示例。 Redirector 有助于将管道链接在一起,因为 ByteQueueBufferedTransformation

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "modes.h"
#include "queue.h"
#include "hex.h"
#include "aes.h"
using namespace CryptoPP;

int main(int argc, char* argv[])
{
  byte key[AES::MAX_KEYLENGTH];
  byte iv[AES::BLOCKSIZE];
  HexEncoder encoder(new FileSink(cout));

  memset(key, 0x00, sizeof(key));
  memset(iv, 0x00, sizeof(iv));

  ByteQueue plain, cipher, recover;
  string str("Attack at dawn!");
  plain.Put(reinterpret_cast<const byte*>(str.data()), str.size());

  cout << "Plain text: ";
  plain.CopyTo(encoder);
  encoder.MessageEnd();
  cout << endl;

  /////////////////////////////////////////////////////////////

  CBC_Mode<AES>::Encryption enc;
  enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

  StreamTransformationFilter f1(enc, new Redirector(cipher));
  plain.CopyTo(f1);
  f1.MessageEnd();

  cout << "Cipher text: ";
  cipher.CopyTo(encoder);
  encoder.MessageEnd();
  cout << endl;

  /////////////////////////////////////////////////////////////

  CBC_Mode<AES>::Decryption dec;
  dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));

  StreamTransformationFilter f2(dec, new Redirector(recover));
  cipher.CopyTo(f2);
  f2.MessageEnd();

  cout << "Recovered text: ";
  recover.CopyTo(encoder);
  encoder.MessageEnd();
  cout << endl;

  return 0;
}

它还会导致:

skylake:cryptopp$ ./test.exe
Plain text: 41747461636B206174206461776E21
Cipher text: 85928E5511BFE9E6EE235BCACC4894D4
Recovered text: 41747461636B206174206461776E21

【讨论】:

  • 多么棒的答案!真的很感激这个原因,现在我也开始了解为什么它是正确的方法。再次感谢!
猜你喜欢
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
相关资源
最近更新 更多