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 all - I export the public part of this key (
NCryptExportKey
+BCRYPT_RSAPUBLIC_BLOB
) - I send this public key to the server (format TBD)
- I create a persistent RSA key (
- 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
BCrypt
compatible 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...
- extract the wrapped key and serialize it into a
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