Я зашифровал строку с помощью 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;
}
Спасибо, у меня очень мало или совсем нет знаний о шифровании. Я понятия не имею, что такое получение ключа через PBKDF2. Что касается CFB_Mode, когда я использую CBC_Mode, это дает ошибку размера блока, поэтому я использовал CFB_Mode. Я также понятия не имею, какой режим я должен использовать. Не могли бы вы помочь, чтобы получить в правильном направлении! Любая помощь будет весьма ценна.
Я могу показать вам способ: AesEncryption.EncryptWithPassword(...)
возвращает результат в кодировке Base64. Этот результат содержит несколько данных, а именно зашифрованный текст, IV (16 байт), соль (32 байта) и (вероятно) MAC (HMACSHA384, 48 байт). Первое, что нужно сделать, это извлечь эти части из результата. В документации EasyCrypto я не могу найти никакой информации о формате/структуре результата, т.е. если вы тоже ничего не найдете, вам придется определять эту информацию анализом кода.
После того, как вы определили части, 32-байтовый ключ должен быть получен с использованием соли и пароля через PBKDF2. Библиотека использует количество итераций 25000 и (согласно описанию) хэш по умолчанию Rfc2898DeriveBytes
(то есть SHA1). Crypto++ поддерживает PBKDF2 с PKCS5_PBKDF2_HMAC. Затем зашифрованный текст можно расшифровать с помощью AES-256 в режиме CBC и заполнения PKCS#7 (с использованием IV и ключа). MAC (если есть) предоставляется для аутентификации.
Я получил формат в файле CryptoContainer.cs в исходном коде EasyCrypto, позвольте мне добавить к вопросу, и у меня есть ключ, который я использовал для шифрования в C#, я сам сгенерировал ключ.
В соответствии с форматом и вашей полезной информацией я обновил свой код, но получаю сообщение об ошибке «Длина зашифрованного текста не кратна размеру блока».
В коде Crypto++ для расшифровки необходимо выполнить следующие шаги:
Возможная реализация 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
который успешно аутентифицирует образцы данных.
Большое спасибо. Я протестирую эту реализацию завтра и дам вам обратную связь еще раз большое спасибо.
Я смешивал ключ с паролем, я думал, что ключ - это пароль. Спасибо за ваше время и усилия.
Похоже, что в коде Crypto++ отсутствует вывод ключа через PBKDF2. Кроме того, неверно называть метод расшифровки
CFBMode_Decrypt()
, когда он использует CBC вместо CFB.