dimanche 19 avril 2015

Encrypt RSA with a PUBLICKEYBLOB Windows Crypto API

I have a PEM RSA private key stored as a const char* in my code and can decrypt some data which is encrypted by my client software using the associated public key just fine. However, I need to re-encrypt this same data using a different public key and send the data back. You may think there is an easier way to do this, but it has to be done this way. The encrypted data is 128 bytes and 16 bytes decrypted. I keep getting a bad data/Data is Invalid error when I try to run the encryption, I think it is because the format which the public key I'm supposed to use to re-encrypt the data isn't recognized or in the correct format.


All of this is being done using the Windows CAPI by #pragma comment(lib, "crypt32.lib")


Here is my encrypt code:



//Run once to determine size of provided public key and create dynamic BYTE array
if (!CryptStringToBinaryA(PemPubKey, 0, CRYPT_STRING_BASE64HEADER, NULL, &szPubKey, NULL, NULL)){
printf("First Public Key CryptStringToBinaryA failed with error 0x%.8X\n\n", GetLastError());
goto CleanUp;
}
pubBuffer = new BYTE[szPubKey];

//Run a second time with destination buffer to convert from base64
if (!CryptStringToBinaryA(PemPubKey, 0, CRYPT_STRING_BASE64HEADER, pubBuffer, &szPubKey, NULL, NULL)){
printf("Second Public Key CryptStringToBinaryA failed with error 0x%.8X\n\n", GetLastError());
goto CleanUp;
}

//Run once with no destination buffer to determine output KeyBlob size and create dynamic BYTE array
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pubBuffer, szPubKey, 0, NULL, NULL, &szPubBlob)){
printf("Public Key CryptDecodeObjectEx failed with error 0x%.8X\n\n", GetLastError());
goto CleanUp;
}
PubKeyBlob = new BYTE[szPubBlob];

//Run a second time with destination buffer to decode into blob
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pubBuffer, szPubKey, 0, NULL, PubKeyBlob, &szPubBlob)){
printf("Public Key CryptDecodeObjectEx failed with error 0x%.8X\n\n", GetLastError());
goto CleanUp;
}

//Acquire access to a key container in the Cryptographic Service Provider
if (!CryptAcquireContextA(&pProv, NULL, MS_ENHANCED_PROV_A, PROV_RSA_FULL, 0)){
printf("Public Key CryptAcquireContextA failed with error 0x%.8X\n\nTrying to create a new Key Container...\n\n", GetLastError());
//Try to create a new container:
if (!CryptAcquireContextA(&pProv, NULL, MS_ENHANCED_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET))
{
printf("CryptAcquireContextA failed again with error 0x%.8X\n\n", GetLastError());
goto CleanUp;
}

}


//Import Public key into context
if (!CryptImportKey(pProv, PubKeyBlob, szPubBlob, NULL, 0, &pKey)){
printf("CryptImportKey failed with error 0x%.8X\n\n", GetLastError());
goto CleanUp;
}


This particular code errors out with 0x0000000D and here is the public key I'm using:



const char* PemPubKey =
"----- BEGIN RSA PUBLIC KEY-----"
"MIGJAoGBAORzDhBg5vt7ICKGrpj0WSZDao4NtDiVABNLo+18x8e/RjBC7K7hu2sW"
"1dATdS/R8yjbDbaPSE8hRzph8/RimsgPTq9Qwyt3l+EWxsnLPTgzlyDj3FtjZNwp"
"yOstreq+Rj74fLgZVq+lcI/yNKWgXqsry9naFtXMi1jnoNrJuSD3AgMBAAE="
"----- END RSA PUBLIC KEY-----";


The tricky part, is the public key file I'm given to work with actually has what appears to be four keys inside of it and this 'PEM RSA' key I'm using is just openssl's interpretation of it. I think the solution outside of any minor bugs I have in my encrypt code, is simply getting my blob loaded into the Windows CSP properly. This is the unmodified publickey.blob:



unsigned char rawData[592] = {
0x06, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31,
0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xF7, 0x20, 0xB9, 0xC9,
0xDA, 0xA0, 0xE7, 0x58, 0x8B, 0xCC, 0xD5, 0x16, 0xDA, 0xD9, 0xCB, 0x2B,
0xAB, 0x5E, 0xA0, 0xA5, 0x34, 0xF2, 0x8F, 0x70, 0xA5, 0xAF, 0x56, 0x19,
0xB8, 0x7C, 0xF8, 0x3E, 0x46, 0xBE, 0xEA, 0xAD, 0x2D, 0xEB, 0xC8, 0x29,
0xDC, 0x64, 0x63, 0x5B, 0xDC, 0xE3, 0x20, 0x97, 0x33, 0x38, 0x3D, 0xCB,
0xC9, 0xC6, 0x16, 0xE1, 0x97, 0x77, 0x2B, 0xC3, 0x50, 0xAF, 0x4E, 0x0F,
0xC8, 0x9A, 0x62, 0xF4, 0xF3, 0x61, 0x3A, 0x47, 0x21, 0x4F, 0x48, 0x8F,
0xB6, 0x0D, 0xDB, 0x28, 0xF3, 0xD1, 0x2F, 0x75, 0x13, 0xD0, 0xD5, 0x16,
0x6B, 0xBB, 0xE1, 0xAE, 0xEC, 0x42, 0x30, 0x46, 0xBF, 0xC7, 0xC7, 0x7C,
0xED, 0xA3, 0x4B, 0x13, 0x00, 0x95, 0x38, 0xB4, 0x0D, 0x8E, 0x6A, 0x43,
0x26, 0x59, 0xF4, 0x98, 0xAE, 0x86, 0x22, 0x20, 0x7B, 0xFB, 0xE6, 0x60,
0x10, 0x0E, 0x73, 0xE4, 0x06, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00,
0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
0x51, 0x76, 0xC9, 0x4F, 0xDC, 0x29, 0x76, 0xD1, 0x6F, 0xF4, 0x15, 0x6B,
0x4D, 0x55, 0x74, 0x7A, 0x44, 0x3B, 0x5F, 0x67, 0xF7, 0xD0, 0x2E, 0x4B,
0x6E, 0xE7, 0x63, 0xF0, 0xD4, 0x47, 0xAD, 0xE7, 0xC1, 0x20, 0xA2, 0x3B,
0x6E, 0x66, 0x9B, 0x99, 0x84, 0xF1, 0xDC, 0xFA, 0xD1, 0xE9, 0x32, 0x51,
0x81, 0xEB, 0x2A, 0x42, 0x1B, 0x9C, 0x0C, 0x8C, 0x6E, 0x3B, 0x84, 0x9B,
0x42, 0xB2, 0xEC, 0xF7, 0x78, 0xF6, 0x1D, 0xF2, 0xCA, 0x6B, 0x6E, 0x39,
0x90, 0x42, 0x76, 0x6A, 0x0F, 0xC3, 0x5C, 0x00, 0xC9, 0x84, 0xE3, 0xD5,
0x5F, 0x45, 0xCD, 0x6D, 0xE5, 0x17, 0xDB, 0x8D, 0x13, 0x10, 0x6C, 0x27,
0x7D, 0x08, 0x44, 0x6E, 0x02, 0x0E, 0x85, 0x51, 0x38, 0xB0, 0xCB, 0xC2,
0x30, 0x76, 0xF5, 0x03, 0xE7, 0x3A, 0x1E, 0x10, 0x98, 0xB2, 0xB5, 0xD8,
0xAA, 0x61, 0xB3, 0x53, 0x2E, 0x61, 0x95, 0x92, 0x06, 0x02, 0x00, 0x00,
0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x95, 0xEC, 0xA6, 0x05, 0xAE, 0x4B, 0xF2, 0xD3,
0xE2, 0xF2, 0x5B, 0x2A, 0x0B, 0x1E, 0xAB, 0x10, 0x50, 0x46, 0xA4, 0xAF,
0xD1, 0xAA, 0x5E, 0xC8, 0x50, 0xDA, 0x5C, 0xC2, 0xE5, 0x24, 0xBD, 0x66,
0xAD, 0xA1, 0xEE, 0x5B, 0x07, 0x59, 0xB4, 0xD4, 0x5D, 0xF9, 0x81, 0xC4,
0xAA, 0xF8, 0x3D, 0xE8, 0x68, 0x5E, 0xAB, 0x5B, 0x37, 0xBD, 0x75, 0xF7,
0xAB, 0x92, 0xD5, 0xAC, 0x18, 0x91, 0x4D, 0x4A, 0xE7, 0xCF, 0x0C, 0xAD,
0xE9, 0x8D, 0xF9, 0x0C, 0x77, 0xA1, 0x34, 0x67, 0x0E, 0xA4, 0x26, 0x5B,
0x06, 0xEE, 0x34, 0x98, 0x6C, 0x27, 0xAA, 0xA7, 0x34, 0x12, 0xB2, 0x53,
0x83, 0x4F, 0x0F, 0xB6, 0x69, 0x5A, 0xEC, 0x8E, 0x1D, 0xE2, 0x38, 0x0B,
0xC0, 0xB5, 0xA0, 0xAE, 0x41, 0xE4, 0xAF, 0x36, 0xFA, 0x64, 0x79, 0x40,
0x4A, 0x13, 0xE3, 0x01, 0x95, 0x43, 0xC8, 0xBD, 0x1A, 0x9D, 0xCB, 0x98,
0x06, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31,
0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xF3, 0x2A, 0xE0, 0x86,
0x2D, 0x0E, 0x4F, 0x2B, 0xD9, 0x35, 0x20, 0xC8, 0x4F, 0x55, 0xDA, 0x9E,
0x70, 0x88, 0xB8, 0x0A, 0xB7, 0xB3, 0x57, 0xA8, 0xA4, 0x2A, 0xAE, 0xA1,
0x98, 0xE4, 0x7C, 0x32, 0x9C, 0xC5, 0xD1, 0x99, 0x1A, 0x24, 0x94, 0x25,
0x8E, 0x48, 0xF8, 0x04, 0x21, 0x60, 0xF4, 0x99, 0x76, 0x8D, 0x3F, 0x0F,
0x65, 0xA7, 0x20, 0xE0, 0x0B, 0x4D, 0x50, 0x36, 0x23, 0xEE, 0xEE, 0x2C,
0xF8, 0x20, 0x76, 0x98, 0x3A, 0xE2, 0x6D, 0x23, 0x31, 0x2D, 0xEB, 0xF3,
0xAA, 0x75, 0x0D, 0x82, 0x64, 0x60, 0x5E, 0x65, 0xB1, 0x7B, 0xC3, 0xE4,
0x14, 0x54, 0xBB, 0x6A, 0xBF, 0xD0, 0xA5, 0x07, 0xBB, 0x3A, 0x0D, 0x9F,
0x31, 0xD5, 0x01, 0x43, 0x5F, 0x70, 0x80, 0xA4, 0x37, 0xC8, 0xAB, 0x81,
0x42, 0x66, 0x0F, 0x5E, 0x4D, 0xD8, 0xB6, 0x93, 0x81, 0xBB, 0x4A, 0x34,
0x4E, 0xE7, 0x79, 0xAA
};


I've been banging my head on this for a while and I refuse to use any other libraries if I can help it. Please help, let me know anything else you'd like to see, thanks!


EDIT: I don't care what format the public key is in, if there is a way to directly load the publickey.blob directly into the CSP, that is fine with me. It doesn't need to be converted to a PEM/PKCS format first which I'm doing only because I don't know any other way.


Edit2: the error isn't occuring during the encrypt function itself, but rather the prepping of the key. Edit3: the public key shown is the publickey.blob ran through openssl and converted into a pem outpu. It's not valid the way it's shown. The original public okey I'm given I've attached. I need someone who can help me convert it properly so it will import properly.


Aucun commentaire:

Enregistrer un commentaire