I will write some kind of security client/server pair:
- The server part provides wrapped AES keys.
- The client part, based on CNG win32 API ( ncrypt.h + bcrypt.h ), will request the server to send some keys (when needed).
Here is my plan:
- On the client side:
I create a persistent RSA key (
NCryptCreatePersistedKey) once for allI export the public part of this key (
NCryptExportKey+BCRYPT_RSAPUBLIC_BLOB)I send this public key to the server (format TBD)
- On the server side:
I generate a random AES key
I wrap it using the received public key
I send back the wrapped AES key to the client (format TBD)
- Back to the client side:
extract the wrapped key and serialize it into a
BCryptcompatible blob.
->how to build a BCrypt blob?import the wrapped AES key as ephemeral (
BCryptImportKey)
-> how to import an ephemeral symmetric key wrapped with a persistant asymmetric key?now I can use this AES key to cipher/decipher data...
I wrote a code that should work, but it still remain some grey areas...
Here is the code:
void get_wrapped_aes_key ( PUCHAR rsa_pub_key_blob , ULONG rsa_pub_key_blob_size ,
PUCHAR wrapped_aes_key_blob , PULONG wrapped_aes_key_blob_size )
{
// send the rsa public key (from buffer rsa_pub_key_blob) to the secu server
// secu server generates a random AES key and wraps it with the rsa public key
// receive the wrapped AES key and serialize it into a BCrypt blob
// mem copy this blob into the buffer wrapped_aes_key_blob)
}
void create_persistent_key ( const wchar_t * key_name )
{
const wchar_t * storage = MS_PLATFORM_CRYPTO_PROVIDER ;
NCRYPT_PROV_HANDLE storage_provider = NULL ;
NCRYPT_KEY_HANDLE rsa_key = NULL ;
NCryptOpenStorageProvider( &storage_provider,storage,0 ) ;
NCryptCreatePersistedKey( storage_provider,&rsa_key,BCRYPT_RSA_ALGORITHM,key_name,0,NCRYPT_OVERWRITE_KEY_FLAG ) ;
NCryptFinalizeKey( rsa_key,0 ) ;
NCryptFreeObject( rsa_key ) ;
NCryptFreeObject( storage_provider ) ;
}
BCRYPT_KEY_HANDLE import_key_using_persistent_key ( const wchar_t * key_name )
{
const wchar_t * storage = MS_PLATFORM_CRYPTO_PROVIDER ;
const wchar_t * blob_type = BCRYPT_RSAPUBLIC_BLOB ;
BCRYPT_ALG_HANDLE algo_provider = NULL;
NCRYPT_PROV_HANDLE storage_provider = NULL;
NCRYPT_KEY_HANDLE rsa_key = NULL;
BCRYPT_KEY_HANDLE bcrypt_rsa_key = NULL;
BCRYPT_KEY_HANDLE imported_aes_key = NULL;
BYTE rsa_pub_key_blob [500] ;
DWORD rsa_pub_key_blob_size = sizeof(rsa_pub_key_blob) ;
BYTE wrapped_aes_key_blob [500] ;
DWORD wrapped_aes_key_blob_size = sizeof(wrapped_aes_key_blob) ;
//------------------- retrieve the persistent key
NCryptOpenStorageProvider( &storage_provider,storage,0 ) ;
NCryptOpenKey( storage_provider,&rsa_key,key_name,0,0 ) ;
NCryptExportKey( rsa_key,NULL,blob_type,NULL,rsa_pub_key_blob,rsa_pub_key_blob_size,&rsa_pub_key_blob_size,0 ) ;
//------------------- get a symmetric key from the security server
get_wrapped_aes_key( rsa_pub_key_blob,rsa_pub_key_blob_size,wrapped_aes_key_blob,&wrapped_aes_key_blob_size ) ;
// mysterious conversion from rsa_key to bcrypt_rsa_key
//------------------- import the security server
BCryptOpenAlgorithmProvider( &algo_provider,BCRYPT_RSA_ALGORITHM,NULL,0 ) ;
BCryptImportKey( algo_provider,bcrypt_rsa_key,BCRYPT_KEY_DATA_BLOB,&imported_aes_key,NULL,0,wrapped_aes_key_blob,wrapped_aes_key_blob_size,0 ) ;
BCryptCloseAlgorithmProvider( algo_provider,0 ) ;
NCryptFreeObject( storage_provider ) ;
NCryptFreeObject( rsa_key ) ;
return imported_aes_key ;
}
Since the server side is not written, the function get_wrapped_aes_key is still empty, but, by the way:
how to build a blob containing a wrapped AES key ?
The function create_persistent_key works fine, but I have a question: how to chose the RSA size ?
(It produces 2048 bits keys, which what I want, but can I change it ?)
In the function import_key_using_persistent_key : BCryptImportKey expects a BCRYPT_KEY_HANDLE as wrapping key, but my persistant key is a NCRYPT_KEY_HANDLE.
I can't figure out what to do...
Thanks in advance