Шифрование AES с помощью EasyCrypto C# и расшифровка на C++ с использованием Crypto++

Я зашифровал строку с помощью EasyCrypto на С#, используя следующий код

Шифрование С#:

/*
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++, используя следующий код. Я просто получаю сообщение об ошибке «Длина зашифрованного текста не кратна размеру блока», какой части кода не хватает? любая помощь будет весьма ценной.

Расшифровка С++:

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;
      }

Похоже, что в коде Crypto++ отсутствует вывод ключа через PBKDF2. Кроме того, неверно называть метод расшифровки CFBMode_Decrypt(), когда он использует CBC вместо CFB.

Topaco 16.11.2022 16:51

Спасибо, у меня очень мало или совсем нет знаний о шифровании. Я понятия не имею, что такое получение ключа через PBKDF2. Что касается CFB_Mode, когда я использую CBC_Mode, это дает ошибку размера блока, поэтому я использовал CFB_Mode. Я также понятия не имею, какой режим я должен использовать. Не могли бы вы помочь, чтобы получить в правильном направлении! Любая помощь будет весьма ценна.

Abubakar Ikram 16.11.2022 17:29

Я могу показать вам способ: AesEncryption.EncryptWithPassword(...) возвращает результат в кодировке Base64. Этот результат содержит несколько данных, а именно зашифрованный текст, IV (16 байт), соль (32 байта) и (вероятно) MAC (HMACSHA384, 48 байт). Первое, что нужно сделать, это извлечь эти части из результата. В документации EasyCrypto я не могу найти никакой информации о формате/структуре результата, т.е. если вы тоже ничего не найдете, вам придется определять эту информацию анализом кода.

Topaco 17.11.2022 12:07

После того, как вы определили части, 32-байтовый ключ должен быть получен с использованием соли и пароля через PBKDF2. Библиотека использует количество итераций 25000 и (согласно описанию) хэш по умолчанию Rfc2898DeriveBytes (то есть SHA1). Crypto++ поддерживает PBKDF2 с PKCS5_PBKDF2_HMAC. Затем зашифрованный текст можно расшифровать с помощью AES-256 в режиме CBC и заполнения PKCS#7 (с использованием IV и ключа). MAC (если есть) предоставляется для аутентификации.

Topaco 17.11.2022 12:15

Я получил формат в файле CryptoContainer.cs в исходном коде EasyCrypto, позвольте мне добавить к вопросу, и у меня есть ключ, который я использовал для шифрования в C#, я сам сгенерировал ключ.

Abubakar Ikram 17.11.2022 12:22

В соответствии с форматом и вашей полезной информацией я обновил свой код, но получаю сообщение об ошибке «Длина зашифрованного текста не кратна размеру блока».

Abubakar Ikram 17.11.2022 12:29
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
197
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В коде Crypto++ для расшифровки необходимо выполнить следующие шаги:

  • Декодирование Base64 данных EasyCrypto
  • Разделение IV, соли и зашифрованного текста (с использованием информации из файла CryptoContainer.cs)
  • Получение 32-байтового ключа через PBKDF2 с использованием соли и пароля (дайджест: SHA-1, количество итераций: 25000)
  • Расшифровка с помощью AES-256 в режиме CBC и заполнения PKCS#7 (с использованием ключа и IV)

Возможная реализация 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");

Предыдущий раздел был посвящен расшифровке. Обратите внимание, однако, что по соображениям безопасности перед расшифровкой требуется аутентификация, а расшифровка может выполняться только для данных, успешно прошедших аутентификацию.
Для аутентификации также необходимо определить MAC в дополнение к IV, соли и зашифрованному тексту. EasyCrypto применяет HMAC-SHA-384 в качестве 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

который успешно аутентифицирует образцы данных.

Большое спасибо. Я протестирую эту реализацию завтра и дам вам обратную связь еще раз большое спасибо.

Abubakar Ikram 17.11.2022 19:07

Я смешивал ключ с паролем, я думал, что ключ - это пароль. Спасибо за ваше время и усилия.

Abubakar Ikram 18.11.2022 08:13

Другие вопросы по теме