I read in this question about Importing a public key from native components. I tried doing the same for private key based on the BLOB documentation, but I'm getting a NTE_BAD_DATA error.
Is my idea feasible? If so, Can you help?
My Try:
void old_RSA_decrypt(PBYTE blob, DWORD blobSize)
{
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
DWORD dwDecryptedLen = 0;
DWORD length;
std::ifstream f;
f.open("c:\\Programming\\encrypted.txt", std::ios::binary);
if (!f.is_open())
{
std::cout << "Error on open file: " << GetLastError() << std::endl;
return;
}
f.seekg(0, f.end);
length = f.tellg();
f.seekg(0, f.beg);
char * buffer = new char[length];
f.read(buffer, length);
if (!f)
std::cout << "error: only " << f.gcount() << " could be read" << std::endl;
f.close();
PBYTE bBuffer = (PBYTE)buffer;
//now to get the decryption thing going
if (!CryptAcquireContext(
&hCryptProv,
NULL,
MS_STRONG_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
std::cout << "Error on CryptAcquireContext " << GetLastError() << std::endl;
return;
}
if (!CryptImportKey(
hCryptProv,
blob,
blobSize,
NULL,
0,
&hKey))
{
std::cout << "Error on CryptImportKey " << GetLastError() << std::endl;
return;
}
if (!CryptDecrypt(hKey, NULL, TRUE, 0, NULL, &dwDecryptedLen))
{
std::cout << "Error on CryptDecrypt (First Pass) " << GetLastError() << std::endl;
return;
}
PBYTE decBuffer = new BYTE[dwDecryptedLen];
for(int i = 0; i < length ; ++i)
decBuffer[i] = bBuffer[i];
if (!CryptDecrypt(hKey, NULL, TRUE, 0, decBuffer, &length))
{
std::cout << "Error on CryptDecrypt (Second Pass) " << GetLastError() << std::endl;
return;
}
std::cout << "Yurika2!" << std::endl;
std::ofstream of;
of.open("c:\\Programming\\decrypted.txt", std::ios::binary);
if (!of.is_open())
{
std::cout << "Error on open write file: " << GetLastError() << std::endl;
return;
}
string sDecMsg = string(reinterpret_cast<char*>(decBuffer), length);
of << sDecMsg << std::endl;
of.close();
cleanup:
delete[] buffer;
delete[] decBuffer;
}
void do_decrypt()
{
string modStr = "yVUndgQFuB5Z5FgC0/WgWCg6Y8VuB582avGjQDdeoJDa1+RBKCyXo700sAMSGjM/bVakOlFqvCsVFNBysx1CH731CDb2DR1a0bsmYmDQ9d0ZHX+AOohVDIx9mc7bkDQZoEFpe9NqFsu95Y9yktpl1JKPmKyLOFgufGJYYvQyoOM=";
string expStr = "AQAB";
string PStr = "/JydNn89lSWjgWOG1XRJm1qTWDekzzoLfTQU+GK+h8DGQ6gkUbgqGosLGo+eAxbO/ETZV3ibbBuIdvL4UxC5Qw==";
string QStr = "zAh23Gc8Oqz/Uh2wh+yt8DqUesVLwMn2koc9CbyF9/Z5Qe8OIR4yygJtuYruRC1x/KYj85l6DGzstUZOtYmv4Q==";
string DPStr ="+1INj1SUPjjOLUKJuQAS4z7/7PqfO5RyLcSNQHltOb5vAozcZXkmWnYPPAO6nzQoBg+xdDcH2kyiPkWJDYtL5Q==";
string DQStr = "cbYh8HJEufrijTRox0hcJG+xgr7kmjy1BDMFDKEaFPkz2VBPEpwO+FDkMC1C35JoXcOGc+RMhhJK1jip8zkaYQ==";
string InverseQStr = "3PAXzlAXgvLVrbOEygjA2zhJEYALBEi6VTKqfDKlnv8/D9QUkC39bEDIRLG0wMFFxN8NlLx5zTiiVswxnMy8Mw==";
string DStr = "KKBSyKkyID+bowyxcWUAuJlRgv19YPNbL0RYTWZ+5UalqmfoT/uDk+pjndrYxcmulFkl5ZC1SYgmBl+zrXoLc/Ei86BtNiuwfcqHlUDp0fdP+fyYN45wh/251HQ3UM1zBpMP8XeYB6zjpCU/s3/wCBE6WpJWN9fKcG0W5PLq8eE=";
//FROM STRINGS TO BYTE VECTORS!
vector<BYTE> modBinMSB = base64_decode(modStr);
vector<BYTE> expBinMSB = base64_decode(expStr);
vector<BYTE> PBinMSB = base64_decode(PStr);
vector<BYTE> QBinMSB = base64_decode(QStr);
vector<BYTE> DPBinMSB = base64_decode(DPStr);
vector<BYTE> DQBinMSB = base64_decode(DQStr);
vector<BYTE> InverseQBinMSB = base64_decode(InverseQStr);
vector<BYTE> DBinMSB = base64_decode(DStr);
//TURN MSB TO LSB
DWORD offset = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); // to keep track of things
const DWORD modulusLengthInBytes = 128;
DWORD keyBlobLength = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (modulusLengthInBytes * 4) + (modulusLengthInBytes / 2);
BYTE* keyBlob = (PBYTE)malloc(keyBlobLength);
BLOBHEADER* blobheader = (BLOBHEADER*)keyBlob;
blobheader->bType = PRIVATEKEYBLOB;
blobheader->bVersion = CUR_BLOB_VERSION;
blobheader->reserved = 0;
blobheader->aiKeyAlg = CALG_RSA_KEYX;
RSAPUBKEY* rsapubkey = (RSAPUBKEY*)(keyBlob + sizeof(BLOBHEADER));
rsapubkey->magic = 0x31415352;
rsapubkey->bitlen = modulusLengthInBytes * 8 *4 + modulusLengthInBytes*4;
rsapubkey->pubexp = MSBByteVectorToDword(expBinMSB);
BYTE* modulus = keyBlob + offset;
copyReversed(modBinMSB, modulus);
offset += modulusLengthInBytes;
BYTE* prime1 = keyBlob + offset ;
copyReversed(PBinMSB, prime1);
offset += modulusLengthInBytes / 2;
BYTE* prime2 = keyBlob + offset;
copyReversed(QBinMSB, prime2);
offset += (modulusLengthInBytes / 2);
BYTE* exponent1 = keyBlob + offset;
copyReversed(DPBinMSB, exponent1);
offset += (modulusLengthInBytes / 2);
BYTE* exponent2 = keyBlob + offset;
copyReversed(DQBinMSB, exponent2);
offset += (modulusLengthInBytes / 2);
BYTE* coefficient = keyBlob + offset;
copyReversed(InverseQBinMSB, coefficient);
offset += modulusLengthInBytes / 2;
BYTE* privateExponent = keyBlob + offset;
copyReversed(DBinMSB, privateExponent);
old_RSA_decrypt(keyBlob, keyBlobLength);
}
It's certainly possible to do so. You mentioned both Windows crypto stacks, and there are some differences:
I see one obvious error in your code:
rsapubkey->bitlen = modulusLengthInBytes * 8 *4 + modulusLengthInBytes*4;
Per the documentation:
bitlen
Number of bits in the modulus. In practice, this must always be a multiple of eight.
So just
rsapubkey->bitlen = modulusLengthInBytes * 8;
Your setting of the dwMagic value seems to be incorrect, too.
rsapubkey->magic = 0x31415352;
0x31415352 is RSA_PUB_MAGIC, so you are calling yourself a public key. You want RSA_PRIV_MAGIC (and to use the constant).
rsapubkey->magic = RSA_PRIV_MAGIC;
Compare to http://source.dot.net/#System.Security.Cryptography.Csp/System/Security/Cryptography/CapiHelper.Shared.cs,b7bc764e6deb34f5, which is a working blob writer in C#.