BCrypt: Add

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-01-24 15:07:14 +01:00
parent ba13a57897
commit 289aab2354

309
include/WinStd/BCrypt.h Normal file
View File

@ -0,0 +1,309 @@
/*
SPDX-License-Identifier: MIT
Copyright © 1991-2025 Amebis
Copyright © 2016 GÉANT
*/
/// \defgroup WinStdBCryptAPI Cryptography API
#pragma once
#include "Common.h"
#include "Win.h"
#include <assert.h>
#include <bcrypt.h>
#include <string>
#include <vector>
/// \addtogroup WinStdBCryptAPI
/// @{
///
/// Implements default constructors and operators to prevent their auto-generation by compiler.
///
#define WINSTD_BCRYPT_HWO_IMPL(C, T) \
public: \
C ( ) noexcept {} \
C (_In_ const C &h) { if (h.m_h != invalid) duplicate_internal(h); } \
C (_Inout_ C &&h) noexcept : bcrypt_handle_with_object<T>(std::move(h)) {} \
C& operator=(_In_ const C &h) { bcrypt_handle_with_object<T>::operator=( h ); return *this; } \
C& operator=(_Inout_ C &&h) noexcept { bcrypt_handle_with_object<T>::operator=(std::move(h)); return *this; } \
private:
template<class _Ty, class _Ax>
static _Must_inspect_result_ NTSTATUS BCryptSignHash(_In_ BCRYPT_KEY_HANDLE hKey, _In_opt_ VOID *pPaddingInfo, _In_reads_bytes_(cbInput) PUCHAR pbInput, _In_ ULONG cbInput, _Out_ std::vector<_Ty, _Ax> &aOutput, _In_ ULONG dwFlags)
{
ULONG cbSignature = 0;
NTSTATUS status = BCryptSignHash(hKey, pPaddingInfo, pbInput, cbInput, NULL, 0, &cbSignature, dwFlags);
if (!status) {
aOutput.resize((cbSignature + sizeof(_Ty) - 1) / sizeof(_Ty));
status = BCryptSignHash(hKey, NULL, pbInput, cbInput, aOutput.data(), cbSignature, &cbSignature, dwFlags);
if (!status)
aOutput.resize((cbSignature + sizeof(_Ty) - 1) / sizeof(_Ty));
}
return status;
}
template<class _Ty, class _Ax>
static _Must_inspect_result_ NTSTATUS BCryptExportKey(_In_ BCRYPT_KEY_HANDLE hKey, _In_opt_ BCRYPT_KEY_HANDLE hExportKey, _In_z_ LPCWSTR pszBlobType, _Out_ std::vector<_Ty, _Ax> &aOutput, _In_ ULONG dwFlags)
{
DWORD cbBlob = 0;
NTSTATUS status = BCryptExportKey(hKey, hExportKey, pszBlobType, NULL, 0, &cbBlob, dwFlags);
if (!status) {
aOutput.resize((cbBlob + sizeof(_Ty) - 1) / sizeof(_Ty));
status = BCryptExportKey(hKey, hExportKey, pszBlobType, aOutput.data(), cbBlob, &cbBlob, dwFlags);
if (!status)
aOutput.resize((cbBlob + sizeof(_Ty) - 1) / sizeof(_Ty));
}
return status;
}
/// @}
namespace winstd
{
/// \addtogroup WinStdBCryptAPI
/// @{
///
/// BCRYPT_ALG_HANDLE wrapper class
///
/// \sa [BCryptOpenAlgorithmProvider function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider)
///
class bcrypt_algorithm_provider : public handle<BCRYPT_ALG_HANDLE, NULL>
{
WINSTD_HANDLE_IMPL(bcrypt_algorithm_provider, BCRYPT_ALG_HANDLE, NULL)
public:
///
/// Releases the algorithm provider.
///
/// \sa [BCryptCloseAlgorithmProvider function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptclosealgorithmprovider)
///
virtual ~bcrypt_algorithm_provider()
{
if (m_h != invalid)
free_internal();
}
protected:
///
/// Releases the algorithm provider.
///
/// \sa [BCryptCloseAlgorithmProvider function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptclosealgorithmprovider)
///
void free_internal() noexcept override
{
BCryptCloseAlgorithmProvider(m_h, 0);
}
};
template <class T>
class bcrypt_handle_with_object : public handle<T, NULL>
{
public:
bcrypt_handle_with_object<T>() noexcept {}
///
/// Move constructor
///
/// \param[inout] h A rvalue reference of another object
///
bcrypt_handle_with_object<T>(_Inout_ bcrypt_handle_with_object<T>&& h) noexcept :
handle<T, NULL>(std::move(h)),
m_hash_object(std::move(h.m_hash_object))
{
}
///
/// Duplicates the object.
///
/// \param[in] h Object
///
bcrypt_handle_with_object<T>& operator=(_In_ const bcrypt_handle_with_object<T>& h)
{
if (this != std::addressof(h)) {
if (m_h != invalid)
free_internal();
if (h)
duplicate_internal(h);
else
m_h = invalid;
}
return *this;
}
///
/// Move assignment
///
/// \param[inout] h A rvalue reference of another object
///
bcrypt_handle_with_object<T>& operator=(_Inout_ bcrypt_handle_with_object<T>&& h) noexcept
{
if (this != std::addressof(h)) {
handle<T, NULL>::operator=(std::move(h));
m_hash_object = std::move(h.m_hash_object);
}
return *this;
}
protected:
///
/// Abstract member function that must be implemented by child classes to do the actual object duplication.
///
/// \param[inout] h A reference of another object
///
virtual void duplicate_internal(_In_ const bcrypt_handle_with_object<T>& h) = 0;
protected:
std::vector<UCHAR> m_hash_object;
};
///
/// BCRYPT_HASH_HANDLE wrapper class
///
class bcrypt_hash : public bcrypt_handle_with_object<BCRYPT_HASH_HANDLE>
{
WINSTD_BCRYPT_HWO_IMPL(bcrypt_hash, BCRYPT_HASH_HANDLE)
public:
///
/// Creates a hash.
///
/// \sa [BCryptCreateHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379908.aspx)
///
bcrypt_hash(_In_ BCRYPT_ALG_HANDLE hAlgorithm, _In_reads_bytes_opt_(cbSecret) PUCHAR pbSecret, _In_ ULONG cbSecret, _In_ ULONG dwFlags)
{
ULONG hashObjectSize, bytesRead;
NTSTATUS status = BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, reinterpret_cast<PUCHAR>(&hashObjectSize), sizeof(hashObjectSize), &bytesRead, 0);
if (status || bytesRead != sizeof(hashObjectSize))
throw ntstatus_error(status, "Failed to get hash object size");
m_hash_object.resize(hashObjectSize);
status = BCryptCreateHash(hAlgorithm, &m_h, m_hash_object.data(), static_cast<DWORD>(m_hash_object.size()), pbSecret, cbSecret, dwFlags);
if (status)
throw ntstatus_error(status, "Failed to create hash");
}
///
/// Destroys the hash.
///
/// \sa [BCryptDestroyHash function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroyhash)
///
virtual ~bcrypt_hash()
{
if (m_h != invalid)
free_internal();
}
protected:
///
/// Destroys the hash.
///
/// \sa [BCryptDestroyHash function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroyhash)
///
void free_internal() noexcept override
{
BCryptDestroyHash(m_h);
}
///
/// Duplicates an existing hash or Message Authentication Code (MAC) object.
///
/// \sa [BCryptDuplicateHash function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptduplicatehash)
///
void duplicate_internal(_In_ const bcrypt_handle_with_object<BCRYPT_HASH_HANDLE>& h) override
{
auto h2 = reinterpret_cast<const bcrypt_hash*>(&h);
m_hash_object.resize(h2->m_hash_object.size());
assert(m_hash_object.size() < ULONG_MAX);
NTSTATUS status = BCryptDuplicateHash(h2->m_h, &m_h, m_hash_object.data(), static_cast<ULONG>(m_hash_object.size()), 0);
if (status)
throw ntstatus_error(status, "Failed to duplicate hash");
}
};
///
/// BCRYPT_KEY_HANDLE wrapper class for symetrical keys
///
class bcrypt_key : public bcrypt_handle_with_object<BCRYPT_KEY_HANDLE>
{
WINSTD_BCRYPT_HWO_IMPL(bcrypt_key, BCRYPT_KEY_HANDLE)
public:
///
/// Destroys the key.
///
/// \sa [BCryptDestroyKey function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey)
///
virtual ~bcrypt_key()
{
if (m_h != invalid)
free_internal();
}
protected:
///
/// Destroys the key.
///
/// \sa [BCryptDestroyKey function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey)
///
void free_internal() noexcept override
{
BCryptDestroyKey(m_h);
}
///
/// Creates a duplicate of a symmetric key.
///
/// \sa [BCryptDuplicateKey function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptduplicatekey)
///
void duplicate_internal(_In_ const bcrypt_handle_with_object<BCRYPT_KEY_HANDLE>& h) override
{
auto h2 = reinterpret_cast<const bcrypt_key*>(&h);
m_key_object.resize(h2->m_key_object.size());
assert(m_key_object.size() < ULONG_MAX);
NTSTATUS status = BCryptDuplicateKey(h2->m_h, &m_h, m_key_object.data(), static_cast<ULONG>(m_key_object.size()), 0);
if (status)
throw ntstatus_error(status, "Failed to duplicate key");
}
protected:
std::vector<UCHAR> m_key_object;
};
///
/// BCRYPT_KEY_HANDLE wrapper class for keypairs
///
/// \sa [BCryptImportKeyPair function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptimportkeypair)
/// \sa [BCryptGenerateKeyPair function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgeneratekeypair)
///
class bcrypt_keypair : public handle<BCRYPT_KEY_HANDLE, NULL>
{
WINSTD_HANDLE_IMPL(bcrypt_keypair, BCRYPT_KEY_HANDLE, NULL)
public:
///
/// Releases the algorithm provider.
///
/// \sa [BCryptCloseAlgorithmProvider function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptclosealgorithmprovider)
///
virtual ~bcrypt_keypair()
{
if (m_h != invalid)
free_internal();
}
protected:
///
/// Releases the algorithm provider.
///
/// \sa [BCryptCloseAlgorithmProvider function](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptclosealgorithmprovider)
///
void free_internal() noexcept override
{
BCryptCloseAlgorithmProvider(m_h, 0);
}
};
/// @}
}