用EasyCrypto C#实现AES加密,用Crypto++实现C++中的解密

cdmah0mi  于 2022-11-19  发布在  C#
关注(0)|答案(1)|浏览(201)

我 使用 C # 中 的 EasyCrypto 加密 了 一 个 字符 串 , 代码 如下
加密 C # :

/*
EasyCrypto encrypted key format from CryptoContainer.cs file from the EasyCrypto source on GitHub.

         *      Format:
         *          04 bytes    00  - MagicNumber
         *          02 bytes    04  - DataVersionNumber
         *          02 bytes    06  - MinCompatibleDataVersionNumber
         *          16 bytes    08  - IV
         *          32 bytes    24  - Salt
         *          19 bytes    56  - Key check value
         *          48 bytes    75  - MAC
         *          04 bytes   123  - Additional header data length
         *          xx bytes   127  - Additional data
         *          ----- end of header ----- (sum: 127)
         *          xx bytes     - additional header data (0 for version 1)
         *          xx bytes     - data
         */

AesEncryption.EncryptWithPassword("data to encrypt", "password string");

/*
Method Description:
Encrypts string and returns string. Salt and IV will be embedded to encrypted string. Can later be decrypted with 
EasyCrypto.AesEncryption.DecryptWithPassword(System.String,System.String,EasyCrypto.ReportAndCancellationToken) 
IV and salt are generated by EasyCrypto.CryptoRandom which is using System.Security.Cryptography.Rfc2898DeriveBytes.
IV size is 16 bytes (128 bits) and key size will be 32 bytes (256 bits).
/*

中 的 每 一 个
我 正在 尝试 使用 Crypto + + 在 C + + 中 解密 , 使用 以下 代码 。 我 刚刚 得到 错误 " 密 文 长度 不 是 块 大小 的 倍数 " , 代码 中 缺少 的 部分 是 什么 ? 任何 帮助 都 将 是 非常 值得 赞赏 的 。
解密 C + + :

string Decrypt() {
    
// getting CryptoPP::byte array from passowrd
    string destination;
    CryptoPP::StringSource ss(<hex of password string>, true, new CryptoPP::HexDecoder(new CryptoPP::StringSink(destination)));
    CryptoPP::byte* keyByteArray = (CryptoPP::byte*)destination.data();

// getting CryptoPP::byte array from encoded data
    string pkDst;
    CryptoPP::StringSource ss2(<hex of encoded data>, true, new CryptoPP::HexDecoder(new CryptoPP::StringSink(pkDst)));
    CryptoPP::byte* pkByteArray = (CryptoPP::byte*)pkDst.data();

// getting initialization vector from encoded data
    CryptoPP::byte iv[16]; 
    for (int i = 8; i < 24; i++) {
        iv[i] = pkByteArray[i];
    }

    string result = CBCMode_Decrypt(keyByteArray, 32, iv);

    return result;
}

string CBCMode_Decrypt(CryptoPP::byte key[], int keySize, CryptoPP::byte iv[]) {
          string recovered = "";
          //Decryption
          try
          {
              CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption d;

              d.SetKeyWithIV(key, keySize, iv);
              // The StreamTransformationFilter removes
              //  padding as required.
              CryptoPP::StringSource s("encoded string", true, new CryptoPP::StreamTransformationFilter(d, new CryptoPP::StringSink(recovered))); // StringSource
          }
          catch (const CryptoPP::Exception& e)
          {
              cerr << e.what() << endl;
              exit(1);
          }
          return recovered;
      }

格式

j8ag8udp

j8ag8udp1#

在Crypto++代码中,必须执行以下步骤进行解密:

  • EasyCrypto数据的Base64解码
  • 分离IV、salt和密文(使用CryptoContainer.cs文件中的信息)
  • 通过PBKDF 2使用salt和密码(摘要:SHA-1,迭代计数:25000个)
  • 在CBC模式和PKCS#7填充(使用密钥和IV)下使用AES-256解密

一种可能的Crypto++实现是:

#include "aes.h"
#include "modes.h"
#include "pwdbased.h"
#include "sha.h"
#include "base64.h"

using namespace CryptoPP;
using namespace std;

...

// Base64 decode data from EasyCrypto
string encoded = "bqCrDAQABABtXsh2DxqYdpZc6M6+kGALOsKUHzxoMR6WAVg5Qtj3zWbr4MiEBdqt9nPIiIZAynFAZmweHQPa/PhEItR6M8Jg1bHAYeQ8Cm5eUlKNzPXFNfuUw0+qtds29S0L4wAWY0xfuiBJTUeTJuSLWqoirm/rHGOWAAAAAKtBivUDvxta1d0QXE6J9x5VdSpAw2LIlXARKzmz+JRDtJcaj4KmGmXW/1GjZlMiUA==";
string decoded;
StringSource ssB64(
    encoded, 
    true,
    new Base64Decoder(
        new StringSink(decoded)
    ) 
); 

// Separate IV, salt and ciphertext
string ivStr = decoded.substr(8, 16);
string saltStr = decoded.substr(24, 32);
string ciphertextStr = decoded.substr(127);

// Derive 32 bytes key using PBKDF2
char password[] = "my passphrase";
unsigned int iterations = 25000;
byte key[32];
size_t keyLen = sizeof(key);
PKCS5_PBKDF2_HMAC<SHA1> pbkdf;
pbkdf.DeriveKey(key, keyLen, 0, (byte*)password, sizeof(password), (byte*)saltStr.c_str(), saltStr.length(), iterations, 0.0f);

// Decrypt with AES-256, CBC, PKCS#7 padding
string decrypted;
CBC_Mode<AES>::Decryption decryption(key, keyLen, (byte*)ivStr.c_str());
StringSource ssDec(
    ciphertextStr,
    true,
    new StreamTransformationFilter(
        decryption,
        new StringSink(decrypted),
        BlockPaddingSchemeDef::BlockPaddingScheme::PKCS_PADDING
    )
);

// Output
cout << "Decrypted: " << decrypted << "\n";

输出为:

Decrypted: The quick brown fox jumps over the lazy dog

密文是用EasyCrypto生成的:

AesEncryption.EncryptWithPassword("The quick brown fox jumps over the lazy dog", "my passphrase");

上一节重点介绍了解密。但是,请注意,出于安全原因,解密 * 之前 * 需要进行身份验证,并且只能对成功验证的数据执行解密。
为了验证,除了IV、salt和密文之外,还必须确定MAC。EasyCrypto应用HMAC-SHA-384作为MAC。仅使用密文来确定MAC,用于验证的密钥与用于加密的密钥相同。
认证时,必须将计算出的MAC和发送的MAC进行比较,如果两者相同,则认证成功(可以进行解密)。
用于身份验证的一种可能的Crypto++实现是:

// Get the sent MAC
string macSentStr = decoded.substr(75, 48);

// Calculate the MAC using ciphertext and encryption key
string macCalcStr;
HMAC<SHA384> hmac(key, keyLen);
StringSource ssMac(
    ciphertextStr, 
    true,
    new HashFilter(hmac,
        new StringSink(macCalcStr)
    )  
); 

// Compare both MACs
cout << (!macSentStr.compare(macCalcStr) ? "Authentication successful" : "Authentication failed") << endl; // compare returns 0 if both strings match

其成功地认证了样本数据。

相关问题