Decrypt using a non-exportable private key with CryptoAPI - c++

I created RSA key pair in windows key store.
I encrypted data (a symmetric key) successfully:
HCERTSTORE hstore = ::CertOpenSystemStore(NULL, L"TestStore");
PCCERT_CONTEXT pctxt = ::CertFindCertificateInStore(hstore, X509_ASN_ENCODING, NULL,
CERT_FIND_SUBJECT_STR, L"My Test Keys", NULL);
HCRYPTPROV hprovider = NULL;
if(!::CryptAcquireContext(&hprovider,
NULL,
MS_ENHANCED_PROV,
PROV_RSA_FULL,
NULL/*CRYPT_NEWKEYSET*/))
{
DWORD err = ::GetLastError();
return 0;
}
HCRYPTKEY hkey = NULL;
if(!::CryptImportPublicKeyInfo(hprovider,
X509_ASN_ENCODING,
&pctxt->pCertInfo->SubjectPublicKeyInfo,
&hkey
))
{
return 0;
}
Now I used CryptEncrypt() with HCRYPTKEY.
Next I want to decrypt the data with the private key, but it is not exportable. All the examples I've seen include importing of the keys.
How can I decrypt the data without exporting the key?

Well, I'm not an expert in RSA/Microsoft store, but I think I get what you're trying to do here. You're doing it a bit backwards. You're using the public key to encrypt and the private do decrypt. So the assumption is that you'd have the private key since that is what you used to generate the public key.
So, let's see... to decrypt the data you need a key, right? So you can (a) encrypt the data with the public key and then find a way to export the private key, but then you'd be using something akin to private key encryption and you'd be better off using blowfish anyway, or (b) encrypt the data using your private key so that you can share the public key to decrypt. Remember CryptImportPublicKeyInfo returns a handle to it: http://msdn.microsoft.com/en-us/library/windows/desktop/aa380209(v=vs.85).aspx
So what I'm saying is that you already have your answer. It's there when you say you have a symmetric key. Either you'll use the same public key to decrypt or it will be a simple transformation: http://en.wikipedia.org/wiki/Symmetric-key_algorithm

Related

Store a private key and a certificate in C++/OpenSSL

I need to store certificates and their private key in memory.
Certificates can be in the 4 following formats : PEM, PKCS12, PKCS7, DER.
I'ill need to write them back as PEM later.
All the snippets i see are storing only the public certificate in a X509 struct.
What about the private part ??
I've found a way using X509_INFO, but i got a major problem with it :
I haven't find a way to get a X509_INFO from DER/PKCS7/PKCS12 files
For the moment i got the following code :
QList<X509_INFO*>* Certificat::stringPEMToX509_INFO(QString stringPem)
{
QList <X509_INFO*>* liste_certificats = new QList<X509_INFO*>;
STACK_OF(X509_INFO)* pile_certificats = NULL;
X509_INFO* certificat;
BIO* bio = BIO_new(BIO_s_mem());
const char* pem = stringPem.toAscii().constData();
BIO_puts(bio, pem);
//https://github.com/openssl/openssl/blob/master/crypto/pem/pem_info.c
pile_certificats = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
for (int i = 0; i < sk_X509_INFO_num(pile_certificats); i++)
{
certificat = sk_X509_INFO_value(pile_certificats, i);
liste_certificats->push_back(certificat);
}
sk_X509_INFO_pop_free(pile_certificats, X509_INFO_free);
BIO_free_all(bio);
return liste_certificats;
}
My goal would be to have the same function but for DER, PKCS12 and PKCS7.
I tried to get a X509_INFO from a DER like this :
p12 = d2i_PKCS12_bio(bio, NULL);
certificat = X509_INFO_new();
certificat->x509 = cert;
certificat->x_pkey = pkey;
But x_pkey is a X509_PKEY and pkey an EVP_PKEY...
If there is no way to store it as a single struct, would it be possible to store my certificates as X509 + a EVP_PKEY for the private key, and still output both private and public part in a PEM ?
PKCS7 is only meant for public keys. DER and PEM are simply ways of encoding a PKCS (and many other) objects. Since you want to store everything into a single structure, you would probably most benefit from PKCS12. OpenSSL provides functions to parse PKCS12 data and get both the cert and key out of it.

RSA encryption between c++ and node.js

I have to send some encrypted data throught the network (websocket)
I generated a key pair with the the following node.js module :
https://github.com/juliangruber/keypair
My public key looks like this:
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAlUiMDQsBgj5P/T86w/eg9MXUj8M4WMVihP8YzmDxMqCFb7D+w4N/1XcxWxQT
....
Wo+SRCsr6npfp1ctDhMtkXIeNT4lKf3qUGhP5tbx/TreaNF/d8zCeinGR/KeBGadMwIDAQAB
-----END RSA PUBLIC KEY-----
In the C++ code, I generated a RSA class with read the public key via a char*
const char rsaKey1[] = "-----BEGIN RSA PUBLIC KEY-----\n"
"MIIBCgKCAQEAlUiMDQsBgj5P/T86w/eg9MXUj8M4WMVihP8YzmDxMqCFb7D+w4N/1XcxWxQT\n"
....
"Wo+SRCsr6npfp1ctDhMtkXIeNT4lKf3qUGhP5tbx/TreaNF/d8zCeinGR/KeBGadMwIDAQAB\n"
"-----END RSA PUBLIC KEY-----\n";
BIO* bio = BIO_new_mem_buf( rsaKey1, strlen(rsaKey1));
m_rsaPubKey = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
usigned the m_rsaPubKey , I have able to generate a std::vector of unsigned char with encrypted data
std::vector<u8> Rsa::encrypt(std::string & msg)
{
std::vector<u8> encryptedData;
char *encrypt = new char[RSA_size(m_rsaPubKey)];
int encryptLen;
if (encryptLen = RSA_public_encrypt(msg.size() + 1, (unsigned
char*)msg.c_str(), (unsigned char*)encrypt, m_rsaPubKey,
RSA_PKCS1_OAEP_PADDING) == -1)
{
LogOutSys("error encoding string");
}
for (u32 i = 0; i < strlen(encrypt); i++)
{
encryptedData.push_back(encrypt[i]);
}
delete encrypt;
return encryptedData;
}
I don't get any errors while reading the public key or encrypting my data so I assume the encryption went ok.
then the data went throught a websocket and is received with node.js
the private key is read like this:
var rsa = new RSA(fs.readFileSync("./rsa-keys/sj_private_1.pem"),
{encryptionScheme :'pkcs8'})
and decoding
var decrypted = rsa.decrypt(data)
where data is a buffer of same length and content (no corruption while sending via the websocket)
c++ side:
encrypted len 256, first bytes 117 125 58 109
node size :
Buffer(256) [117, 125, 58, 109, 38, 229, 7, 189, …]
the rsa.decrypt generated an exception :
TypeError: Cannot read property 'length' of null
I tried several encryptionScheme option (including the default , but always getting the same error or Incorrect key or data
Because of the random padding in OAEP, troubleshooting encryption issues with it can sometimes be a bit tricky.
For further troubleshooting use the following checklist to shoot down potential issues:
Make sure you use the same crypto mechanism on both ends. In your C++ code you are using RSA_PKCS1_OAEP_PADDING but the JavaScript lines in your question does not tell what mechanism you use there.
Make sure that the mechanisms are implemented the same ways in both C++ and Node libraries. It is crucial you have the same hashing method and MGF1 (mask generation function) in both implementations. This is one of the most typical failing points that I've seen in my career.
Since you are working with byte arrays, make sure you are not having any issues in the byte order. In other words, make sure both ends talks the same language in regard of endianness (For self-study: https://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/endian.html).

Import a persistent key in to Windows key storage using CNG storage functions

I'm trying to import a persistent RSA public key into the key storage. I read on the CNG help page that it's possible for private keys and I wonder if I can also apply is to public keys (specifically the BCRYPT_RSAPUBLIC_BLOB). I've tried with the following code, but in the import section, when I call NCryptSetProperty to set the public blob as a property, I get "Error 0x80090029" which is NTE Bad Data. Having trouble debugging why this function is failing.
NCRYPT_PROV_HANDLE providerHandle = NULL;
NCRYPT_KEY_HANDLE keyHandle = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PBYTE blob = NULL;
DWORD blob_len = 0;
///////////////////Export Test (extract key from storage)///////////////////////////
// Open handle to the Key Storage Provider
if(FAILED(status = NCryptOpenStorageProvider(
&providerHandle, //OUT: provider handle
MS_KEY_STORAGE_PROVIDER, //IN: Microsoft key storage provider
0))) //IN: dwFlags (unused)
{
//report fail
}
// Open key in the Key Storage Provider
if (FAILED(status = NCryptOpenKey(
providerHandle,
&keyHandle,
keyName.c_str(),
0,
0)))
{
//report fail
}
// (2 step key extraction process) 1. Get size of key
if (FAILED(status = NCryptExportKey(
keyHandle, //IN: Handle of the key to export
NULL, //IN(opt): key used to encrypt exported BLOB data <-- potentially an safer way for key extraction, encrypt it with a key during extraction (decrypt with NCryptDecrypt)
BCRYPT_RSAPUBLIC_BLOB, //IN: BLOB type (https://msdn.microsoft.com/en-us/library/windows/desktop/aa376263%28v=vs.85%29.aspx)
NULL, //IN(opt): List of paramters for the key
NULL, //OUT(opt): Output byte buffer
0, //IN: Size of the output buffer
&blob_len, //OUT: Amount of bytes copied to the output buffer
0))) //IN: Flag to modify function behaviour (0 means no flag set)
{
//report fail
}
// Allocate data blob to store key in
blob = (PBYTE)malloc(blob_len);
if (NULL == blob) {
//report fail
}
// (2 step key extraction process) 2. Get key and store in byte array (Extracted key is in form of BCRYPT_RSAKEY_BLOB)
if (FAILED(status = NCryptExportKey(
keyHandle,
NULL,
BCRYPT_RSAPUBLIC_BLOB,
NULL,
blob,
blob_len,
&blob_len,
0)))
{
//report fail
}
///////////////Import Test (Store into storage)//////////////////////////////////////////////
// Create a persisted key
if(FAILED(status = NCryptCreatePersistedKey(
providerHandle, //IN: provider handle
&keyHandle, //OUT: Handle to key
NCRYPT_RSA_ALGORITHM, //IN: CNG Algorithm Identifiers. NCRYPT_RSA_ALGORITHM creates public key
keyName.c_str(), //IN: Key name. If NULL, the key does not persist
0, //IN: Key type
NCRYPT_OVERWRITE_KEY_FLAG)))//IN: Behaviour: 0 - apply to current user only, NCRYPT_MACHINE_KEY_FLAG - apply to local comp only, NCRYPT_OVERWRITE_KEY_FLAG - overwrite existing key
{
//report fail
}
// Set the size of the key
if(FAILED(status = NCryptSetProperty(
keyHandle, //IN: Handle to key
BCRYPT_RSAPUBLIC_BLOB, //IN: CNG Algorithm Identifiers. BCRYPT_RSAPUBLIC_BLOB allows me to use set this blob as the new key's blob
blob, //IN: Key name. If NULL, the key does not persist
blob_len, //IN: Key Length
0))) //IN: Bahaviour: 0 - apply to current user only, NCRYPT_MACHINE_KEY_FLAG - apply to local comp only, NCRYPT_OVERWRITE_KEY_FLAG - overwrite existing key
{
//report fail <<-------------------------- Fail here
}
// Finalize key generation (Key is now usable, but uneditable)
if(FAILED(status = NCryptFinalizeKey(keyHandle, 0))) {
//report fail
}
////////////////////////////////////////////////////////////////////////
On creation of an asymmetric key, one of the properties that can be set is the NCRYPT_EXPORT_POLICY_PROPERTY. I used this to control whether the private could be read or not.
//... after NCryptCreatePersistedKey()
DWORD export_policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
if(FAILED(status = NCryptSetProperty(
keyHandle,
NCRYPT_EXPORT_POLICY_PROPERTY,
(PBYTE)&export_policy,
static_cast<DWORD>(sizeof(DWORD)),
NCRYPT_PERSIST_FLAG | NCRYPT_SILENT_FLAG)))
{
//report error
}
//... before NCryptFinalizeKey()
The properties are defined here.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa376242(v=vs.85).aspx

Get CryptoAPI public key via PKCS#11

In my C++ program I created a public/private key pair using CryptoAPI.
CryptGenKey(eTokenProv,ENCRYPT_ALGORITHM,CRYPT_EXPORTABLE,&k1)
Keys are stored in a eToken.
Is it possible to get the public key using PKCS#11? The private key previously created is found after a search using the following search-template:
CK_ATTRIBUTE private_search[] = {
{CKA_PRIVATE, CK_TRUE, sizeof(CK_BBOOL)}
};
If I set CKA_PRIVATE to CK_FALSE, I can't get the public key. I also tried with other attributes.
Is there a way to do it?
EDIT
As owlstead suggests, I tried to create a public key starting from the modulus and public exponent of a key created in a previous session (in CAPI or, just for this test, in PKCS11). I got the modulus and public exponent from a private key in these buffers:
CK_BYTE modulus[128]; //if 1024bit
CK_BYTE publicExponent[4]; //4 Byte, according to public key blob
But when I try to create a new public with key with the following instructions:
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_TOKEN, &yes, sizeof(true)},
{CKA_WRAP, &yes, sizeof(true)},
{CKA_ENCRYPT, &yes, sizeof(true)},
{CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
{CKA_MODULUS, &modulus, sizeof(modulus)},
{CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
rv = (*functions->C_GenerateKeyPair) (session, &mechanism, publicKeyTemplate, 6, privateKeyTemplate, 6, &hPublicKey, &hPrivateKey);
I get the error "Invalid template". The probles is the modulus, because, without it, I can create a key pair. I use the function C_GenerateKeyPair, but I'm only interested in the public key. I omitted the private template.
What is the wrong here?
CKA_PRIVATE does not indicate a private key at all.
When the CKA_PRIVATE attribute is TRUE, a user may not access the object until the user
has been authenticated to the token
Instead you should look for an attribute such as CKA_CLASS with a value CKO_PUBLIC_KEY or CKO_PRIVATE_KEY, possibly using other attributes to filter your results further.
If you cannot find any CKO_PUBLIC_KEY then I presume it was either not generated in the token (key was imported, check if CKA_LOCAL is set). Alternatively, it may have only been created as a session object. Finally it may have been removed.
Note that RSA private keys commonly do contain the public exponent, so you can still construct a public key from just the private key object (using the modulus and public exponent, of course).
Remove the reference symbol in CK_ATTRIBUTE when setting a pointer to a CK_BYTE array - in your case modulus.
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_TOKEN, &yes, sizeof(true)},
{CKA_WRAP, &yes, sizeof(true)},
{CKA_ENCRYPT, &yes, sizeof(true)},
{CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
{CKA_MODULUS, modulus, sizeof(modulus)},
{CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
I haven't tested your code, but I am able to successfully obtain modulus of an CK_OBJECT_HANDLE (private key / public key) by setting following template and making a call to C_GetAttributeValue:
CK_BYTE modulus[128];
CK_ATTRIBUTE Modulus = { CKA_MODULUS, modulus, sizeof(modulus) };
if ((rv = (*p11FunctionList->C_GetAttributeValue)(hSession, hPrivKey /*hPubKey*/, &Modulus, 1)) == CKR_OK)
{
// do something with obtained modulus
}
The generated private-public key pair was generated as follow:
CK_OBJECT_HANDLE hPrivKey, hPubKey;
CK_BBOOL bTrue = TRUE;
CK_ULONG mod_bits = 1024;
CK_MECHANISM GenMechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
CK_ATTRIBUTE GenPubTemplate[] = {
{ CKA_MODULUS_BITS, &mod_bits, sizeof(CK_ULONG) },
{ CKA_PUBLIC_EXPONENT, "\x01\x00\x01", 3 },
{ CKA_TOKEN, &bTrue, sizeof(CK_BBOOL) },
{ CKA_ID, (CK_CHAR_PTR)szKeyID, strlen(szKeyID) } }; // szKeyID is a const char *
CK_ATTRIBUTE GenPrivTemplate[] = {
{ CKA_TOKEN, &bTrue, sizeof(CK_BBOOL) },
{ CKA_PRIVATE, &bTrue, sizeof(CK_BBOOL) },
{ CKA_SENSITIVE, &bTrue, sizeof(CK_BBOOL) },
{ CKA_ID, (CK_CHAR_PTR)szKeyID, strlen(szKeyID) } }; // szKeyID is a const char *
// hSession is a CK_SESSION_HANDLE of an opened & logged in session
if ((rv = (*p11FunctionList->C_GenerateKeyPair)(hSession, &GenMechanism, GenPubTemplate, 4, GenPrivTemplate, 4, &hPubKey, &hPrivKey)) == CKR_OK)
{
// Now get the modulus of a the private / public key as described above
}
Though this has already been answered for others who want to do this we have created a PKCS#11 based wrapper for CryptoAPI, you can find it here:
https://github.com/PeculiarVentures/pvpkcs11
With this you can access keys stored in CryptoAPI as well as certificates using the native PKCS#11 interfaces.

How to read RSA public and private keys into single RSA struct?

What I'm trying to do is generate random RSA keys and then store them before my program terminates. This part is working just fine using RSA_generate_key, PEM_write_bio_RSAPrivateKey and PEM_write_bio_RSA_PUBKEY. I can also encrypt/decrypt just find using the RSA structure returned by RSA_generate_key.
However, my problem comes when my program restarts and I want to read back in the keys that I stored previously. I can use PEM_read_bio_RSAPrivateKey and PEM_read_bio_RSA_PUBKEY to pull the keys in, but I need to get them into the same RSA structure, similar to how they are stored by RSA_generate_key.
My code is shown below. I have the keys stored in memory along with a small header that tell me how large the keys are. The private key start right after the header and the public key is stored right after the private key.
privateKey = (uint8_t *) ( buffer + rsaStruct->hdrSize );
publicKey = (uint8_t *) ( privateKey + rsaStruct->privateKeyLength );
bioPrivate = BIO_new_mem_buf( (void *) privateKey, rsaStruct->privateKeyLength );
bioPublic = BIO_new_mem_buf( (void *) publicKey, rsaStruct->publicKeyLength );
bioPrivate = BIO_new_mem_buf( (void *) privateKey, rsaStruct->privateKeyLength + rsaStruct->publicKeyLength );
if( bioPrivate == NULL || bioPublic == NULL ) {
fprintf( stderr, "%s: BIO_new_mem_buf failed!\n", __FUNCTION__ );
return ECE_RSA_ERROR_BIO_CREATION_FAILED;
}
PEM_read_bio_RSAPrivateKey( bioPrivate, &keyPair, NULL, NULL );
PEM_read_bio_RSA_PUBKEY( bioPublic, &keyPair, NULL, NULL );
BIO_free( bioPrivate );
BIO_free( bioPublic );
If I try to just send in the same RSA structure, it doesn't seem to work. I'm able to encrypt just fine, but my decryption fails. This could likely be due to the fact that the public key is the last key retrieve and the one used for encryption. If the second call over-writes the address of my RSA struct, I would end up with an RSA structure that has nothing but the public key.
Anyway, if anyone could tell me how to get both the public and private key into the same RSA structure, that would be great!
Comparing to RSA private key, public key additionaly contains only the public exponent. So just copy it from public key to private key structure, and everything should work.