Как передать сессионный ключ для дешифровки в cryptoapi
Необходимо шифровать строки в файле при помощи CryptoAPI, а потом расшифровывать его и читать данные.
Начальный ключ генерирую так:
HCRYPTPROV hProv;
HCRYPTKEY hSessionKey;
if(!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){
cout << "Error, getting encryption context" << endl;
return 1;
}
cout << "Cryptographic provider successfully initialized!" << endl;
if(!CryptGenKey(hProv, CALG_RC4, CRYPT_EXPORTABLE, &hSessionKey)){
cout << "Error, generating session key for encryption!" << endl;
return 1;
}
cout << "Session key successfully generated!" << endl;
После этого передаю в функцию сохранения файла, которая для каждой строки вызывает функцию шифрования:
Crypto* CWEncrypt(const char* toEncode, HCRYPTKEY hSessionKey) {
char *tempString;
tempString = new char[strlen(toEncode)];
strcpy_s(tempString, strlen(tempString), toEncode);
DWORD count = strlen(tempString);
if(!CryptEncrypt(hSessionKey, NULL, true, NULL, reinterpret_cast<BYTE*>(tempString), &count, count)){
cout << "Error, encrypting provided data" << endl;
return nullptr;
}
auto response = new Crypto(tempString, hSessionKey); //Crypto is a struct with fields with types string and HCRYPTKEY
return response;
}
После сохранения hSessionKey выводится пользователю на экран. Потом при попытке загрузиться из файла у человека спрашивают hSessionKey, который он вводит через cin. Этот же ключ отправляется в функцию дешифрования:
char* CWDecrypt(const char* toDecode, HCRYPTKEY hSessionKey) {
char *tempString;
tempString = new char[strlen(toDecode)];
strcpy_s(tempString, strlen(tempString), toDecode);
DWORD count = strlen(tempString);
if(!CryptDecrypt(hSessionKey, NULL, true, NULL, reinterpret_cast<BYTE*>(tempString), &count)){
cout << "Error, decrypting provided data" << endl;
return nullptr;
}
return tempString;
}
И вот тут уже возникает ошибка - отрабатывает if и выдаёт Error, decrypting provided data.
При этом сами функции рабочие, и такой код в мэйне работает:
string ss = "String to encrypt and decrypt";
Crypto cr = *CWEncrypt(ss.c_str());
ss = cr.getValue();
cout << ss << endl;
cout << CWDecrypt(ss.c_str(), cr.getSessionKey()) << endl;
Судя по всему, просто передать ключ не достаточно, и его нужно заново сгенерировать по какому-то другому ключу. hPov для этого не подходит, так как hSessionKey генерируется другой и расшифровать данные не получается. Среди функций нашёл CryptExportKey, но он в качестве параметра принимает ещё какой-то ключ, который я без понятия где взять.
И очень большая просьба знатокам, даже если вопрос кажется глупым и простым, не молча минусить его, а хотя бы перед выставлением минуса ответить, как это реализовать, раз уж это так просто, а я дурак не догадался. Спасибо.
UPD: Попытка сохранить hSessionKey в файл тоже успехом не увенчалась.
UPD 2: Нашёл хоть какую-то информацию о CryptExportKey. В некоторых источниках написано, что второй ключ, который туда нужно передавать - это открытый ключ, который потом при дешифровании нужно будет ввести, но если он не нужен, то можно ввести NULL. При этом изначально нужно получать длину итогового экспортируемого ключа, и для этого нужно запустить CryptExportKey, и в качестве адреса, куда ключ записывать, передавать NULL:
DWORD dwPublicKeyLen;
if (!CryptExportKey( hSessionKey, hUserKey,
SIMPLEBLOB, NULL, NULL /* Also I tried to use nullptr here, and it didn't help */, &dwPublicKeyLen)) {
cout << "Error, exporting key for encryption!" << endl;
return 1;
}
BYTE* hPublicKey = static_cast<BYTE*>(malloc(dwPublicKeyLen));
if (!CryptExportKey( hSessionKey, NULL,
SIMPLEBLOB, NULL, hPublicKey, &dwPublicKeyLen)){
cout << "Error, exporting key for encryption!" << endl;
return 1;
}
И на этом моменте отрабатывает первый if и выдаёт ошибку. Подумал, что, может, там ошиблись, и без открытого ключа экспортировать сессионный ключ нельзя, так что стал пробовать перед этим генерировать его, опять же по примерам, которые смог найти:
HCRYPTKEY hUserKey;
if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hUserKey)) {
cout << "Error, generating user key!" << endl;
return 1;
}
Здесь ошибка (отработка if) начинает возникать уже при генерации этого ключа. Я в ещё большем замешательстве...