Search code examples
c++ccryptographycng

CNG: When to use BCrypt* vs NCrypt* family of functions


In the Microsoft CNG API (Cryptography API: Next Generation), there are two sets of functions that appear to do the same thing.

The following functions start with BCrypt and perform key import/export, encryption/decryption, sign/verify, and Diffie-Hellman key exchange

BCryptExportKey
BCryptImportKey
BCryptEncrypt
BCryptDecrypt
BCryptSignHash
BCryptVerifySignature
BCryptSecretAgreement
BCryptDeriveKey

But the same set of functions exist which start with NCrypt:

NCryptExportKey
NCryptImportKey
NCryptEncrypt
NCryptDecrypt
NCryptSignHash
NCryptVerifySignature
NCryptSecretAgreement
NCryptDeriveKey

What's the difference between these two sets of functions, and when should each one be used?


Solution

  • The BCrypt family of function are classified as Cryptographic Primitives, while the NCrypt family of functions are classified as Key Storage and Retrieval.

    The primary difference is that the BCrypt functions are used when dealing only with ephemeral keys, while the NCrypt functions are used when persistent keys are required.

    In practice, the BCrypt functions are typically used for hashing and symmetric encryption, while the NCrypt functions are used for public/private key encryption and decryption, public/private key signing and verification, and shared secret (e.g. DH and ECDH) negotiation.

    While some public/private key operations can be done with BCrypt functions, they can only be used with ephemeral keys and are therefore of limited use.

    Persistent keys are stored in key containers specific to each user (or to the system). This is a security measure to ensure that users can't view each other's private keys.

    In general, you'll want to use the following functions for the following operations:

    • BCryptHashData: Used for hashing and HMAC (MD5, SHA1, SHA256, SHA384, SHA512)
      • Related: BCryptCreateHash, BCryptFinishHash, BCryptDestroyHash
    • BCryptEncrypt: Symmetric key encryption (DES, 3DES, AES).
      • Related: BCryptGenerateSymmetricKey, BCryptDestroyKey
    • BCryptDecrypt: Symmetric key decryption (DES, 3DES, AES).
      • Related: BCryptGenerateSymmetricKey, BCryptDestroyKey
    • NCryptEncrypt: Asymmetric key encryption (RSA)
    • NCryptDecrypt: Asymmetric key decryption (RSA)
    • NCryptSignHash: Asymetric key signature (RSA, DSA, ECDSA)
    • NCryptVerifySignature: Asymmetric key signature verification (RSA, DSA, ECDSA)
    • NCryptSecretAgreement: Asymmetric key secret sharing (DH, ECDH)
      • Related: NCryptDeriveKey

    Examples are available at MSDN for several of these cases.

    For a real world example, I've implemented all of these in the UFTP source code, specifically the encrypt_cng.c file (there are typedefs in place, defined in encryption.h, to allow the functions in this file to implement a common application level API to allow the use of other crypto libraries such as CryptoAPI and OpenSSL).