Hcrypt
C++ helper library for Windows bcrypt, ncrypt and credman
Install / Use
/learn @vladp72/HcryptREADME
C++ Helper Classes for Windows Cryptography API Next Generation (CNG), that includes BCRYPT and NCRYPT.
This is a header only library for Windows CNG API that includes functions from ncrypt.h and bcrypt.h.
MSDN documentation for bcrypt.h
CNG Bcrypt algorithm providers
CNG Bcrypt cryptography primitive property identifiers
MSDN documentation for ncrypt.h
CNG Ncrypt storage property identifiers
CNG Ncrypt key storage architecture
StackOverflow threads with cng tag
Note: CNG bcrypt does not implement Blowfish algorithm. CNG bcrypt originated from BestCrypt. See this discussion for more details
Also check test and samples that come with this library
This post by dbush provides a good summary when to use NCrypt API versus BCrypt API.
Credential Manager Helpers documents helpers for credman APIs located in credman.h and credman_ui.h.
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
Helper classes consists of several namespaces:
Note: In all classes you will find each crypto function wrapperd twice. One wrapper will have "try_" prefix and will be noexcept. It will communicate failure by returning std::error_code. The other wrapper will not have 'try' prefix and will communicate most failures using an exception. For example:
class storage_provider {
public:
//
// This wrapped would not throw exception.
// It communicates failure using std::error_code
//
[[nodiscard]] std::error_code try_open(wchar_t const *provider) noexcept;
//
// This wrapper communicates failures using exception
//
void open(wchar_t const *provider)
};
Use try_ wrappers in the performance critical code when failures are expected to happen often and can affect performance. It is also a good fit when you need to use wrappers in an exception unsafe code base.
- hcrypt helper function and error category definitions. These helpers are shared between bcrypt and ncrypt.
- String Formatting
- v_make_string estimates string size using _vscprintf, resizes buffer and prints string using _vsnprintf_s
- make_string calls v_make_string
- v_make_wstring estimates string size using _vscwprintf, resizes buffer and prints string using _vsnwprintf_s
- make_wstring calls v_make_wstring
- try_resize family of functions that can be used in noexcept context to convert std::bad_alloc to an error code
- Convertion between character encodings
- a_to_u Converts multibype string to Unicode string
- u_to_a Converts Unicode string to multibype string
- Error handling helpers for NTSTATUS and WIn32 error
- enum class status : long Enumeration type used for NTSTATUS
- enum class win32_error : unsigned long Enumeration type used for WIN32 erors domain
- is_success Family of functions that return true if error code is success
- is_failure Family of functions that return true if error code is a failure
- error_category_t error category for NTSTATUS
- get_error_category returns instance of errror_category_t
- make_error_code creates error_code with matching error category for the given enumeration type.
- Bitfield anumeration
- set_flag Sets bits
- is_flag_on Checks if bits are set
- clear_flag Clears bits
- consume_flag Clears bits and returns if they were set
- Conversion between bag of bytes and hexidecimal string
- to_hex
- from_hex
- Conversion between bag of bytes and base64 encoding string
- to_base64
- from_base64
- Time helper function
- systemtime_to_filetime
- filetime_to_systemtime
- systemtime_to_string
- systemtime_to_wstring
- filetime_to_string
- filetime_to_wstring
- GUID helper function
- guid_to_string
- guid_to_wstring
- Other
- round_to_block rounds up size to number of blocks of specified size.
- String Formatting
- bcrypt helpers for functions in bcrypt.h
- algorith_provider instance of algorithm provider. You can enumerate providers using try_enum_registered_providers, enum_registered_providers, try_resolve_providers, resolve_providers, try_enum_algorithms or enum_algorithms. To navigate result of enumeration prefer to use bcrypt::for_each or bcrypt::find_first family of functions.
- key implementation of shared/private/public key algorithm by a provider
- hash particular implementation of hash algorithm by a provider
- secret helper class for derivation of a key from a secret agreement. To create secret you can use bcrypt::create_secret helper function
- ncrypt helpers for functions in ncrypt.h
- storate_provider instance of storage provider. You can enumerate providers using try_enum_providers or enum_providers. To navigate result of enumeration prefer to use ncrypt::for_each or ncrypt::find_first family of functions.
- storage_provider::key_iterator enumeration of keys in the storage
- key implementation of shared/private/public key algorithm by a provider
- secret helper class for derivation of a key from a secret agreement. To create secret you can use ncrypt::create_secret helper function
Note: ncrypt::property_impl and bcrypt::property_impl implement query/set property interfaces for all obects in each namespace. Often times it is hard to tell from the MSDN documentation what property is applicable to what object type (key/hash/particular provide/secret). You can use useprint_bcrypt_object_properties and print_ncrypt_object_properties to create a test program that attempts to print every property for a passed object, and see what queries are supported for the given object.
For example following snippet
bcrypt::algorithm_provider ap{BCRYPT_AES_ALGORITHM};
print_bcrypt_object_properties(2, ap, true);
will print
name: AES
block length: 16
chaining mode: ChainingModeCBC
block[00] size: 16
block[01] size: 4261281277
keys length: min 128, max 256, increment 64
key object length: 654
message block length: 16
object length: 654
After changing mode to CCM
ap.set_chaining_mode(BCRYPT_CHAIN_MODE_CCM);
print_bcrypt_object_properties(2, ap, true);
you will get
name: AES
block length: 16
chaining mode: ChainingModeCCM
block[00] size: 16
block[01] size: 4261281277
keys length: min 128, max 256, increment 64
key object length: 654
auth tag length: min 4, max 16, increment 2
message block length: 1
object length: 654
Create keys and print its propertie
