1

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:

  1. 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)
  2. 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)
  3. 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...

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

Captain'Flam
  • 479
  • 4
  • 12
  • How exactly is the server sending the symmetric key? I.E., what RSA padding mode does it use, is the encrypted data raw bytes to be used as an AES key or a MS-defined keyblob? – dbush Mar 31 '21 at 17:18
  • I have 2 issues: 1=build a blob ; 2=pass a persistent key handle to BCryptImportKey. When I will know how to build a blob (i.e. what BCryptImportKey wants), I will use the expected padding. – Captain'Flam Mar 31 '21 at 17:32
  • If the server is sending you a key, it will be exporting and encrypting it, not you. You need to know how it did this in order to decrypt and import it. – dbush Mar 31 '21 at 17:35
  • By the way, since the AES key is wrapped with a public key, only the owner of the private key is able to unwrap it. The owner is the NCrypt lib itself. So I won't be able to unwrap it myself. This is the purpose of such a secured key store. – Captain'Flam Mar 31 '21 at 17:40
  • Again, it depends on what the server sent you. It could be an exported `BCRYPT_KEY_HANDLE` which contains both the key data and the algorithm / padding mode, or it could just be 16 or 32 bytes of raw key data where you're expected to know the algorithm / padding mode. So the exact method of importing (including how / if to create a blob) depends on what was exported. – dbush Mar 31 '21 at 17:52
  • Thank you **dbush**, I omitted to say that I will write the code inside the *server*. And since I also write the client side, I have just to agree with myself about the format of the wrapped AES key. What I really need is to know how to build a blob as *BCryptImportKey* wants it. And also, how to use a *NCrypt* asymmetric key as wrapping key of a to-be-imported *BCrypt* symmetric key. – Captain'Flam Apr 01 '21 at 07:30
  • Thanks to **dbush** I understand that my post was not clear so I edited it partially... – Captain'Flam Apr 01 '21 at 08:16
  • Hi @Captain'Flam. I may be able to help you. Where are you at? – manuell Dec 01 '21 at 17:40

0 Answers0