From 98dab910d774b077d97f25f6613b9ce7489ebff5 Mon Sep 17 00:00:00 2001 From: mingkuang Date: Fri, 17 May 2024 12:39:59 +0800 Subject: [PATCH] =?UTF-8?q?Fea=20#66,=20=E8=AE=A9.NET=208/9=E6=94=AF?= =?UTF-8?q?=E6=8C=81XP=EF=BC=8C=E6=B7=BB=E5=8A=A0BCrypt=E5=AF=B9=E7=A7=B0?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E7=AE=97=E6=B3=95=E6=94=AF=E6=8C=81=20=20=20?= =?UTF-8?q?-=20=E6=B7=BB=E5=8A=A0=20BCryptSetProperty=20=20=20-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20BCryptEncrypt=20=20=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20BCryptDecrypt=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCry?= =?UTF-8?q?ptGenerateSymmetricKey=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptD?= =?UTF-8?q?estroyKey=20=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptExportKey=20?= =?UTF-8?q?=20=20-=20=E6=B7=BB=E5=8A=A0=20BCryptImportKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ThunksList.md | 15 +- .../MinimumRequiredVersionHelper.vcxproj | 2 - src/Thunks/bcrypt.hpp | 1427 +++++++++++++++-- src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp | 969 ++++++++++- src/YY-Thunks.UnitTest/pch.h | 26 + 5 files changed, 2326 insertions(+), 113 deletions(-) diff --git a/ThunksList.md b/ThunksList.md index 86382a2..1d72efa 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -93,16 +93,23 @@ ## bcrypt.dll | 函数 | Fallback | ---- | ----------- -| BCryptOpenAlgorithmProvider | 不存在时,调用CryptAcquireContextW。 +| BCryptOpenAlgorithmProvider | 不存在时,调用CryptAcquireContextW。目前支持的算法有:RC2、RC4、AES、DES、3DES、3DES-112、MD2、MD4、MD5、SHA1、SHA256、SHA384、SHA512、RNG、FIPS186DSARNG、DUALECRNG。 | BCryptCloseAlgorithmProvider | 不存在时,调用CryptReleaseContext。 | BCryptGenRandom | 不存在时,调用RtlGenRandom。 -| BCryptGetProperty | 不存在时,内部实现。 +| BCryptGetProperty | 不存在时,调用CryptGetKeyParam。 +| BCryptSetProperty | 不存在时,调用CryptSetKeyParam。 | BCryptCreateHash | 不存在时,调用CryptCreateHash。 | BCryptDestroyHash | 不存在时,调用CryptDestroyHash。 | BCryptHashData | 不存在时,调用CryptHashData。 | BCryptFinishHash | 不存在时,调用CryptGetHashParam。 -| BCryptDeriveKeyPBKDF2 | 不存在时,调用CryptCreateHash、CryptHashData。 -| BCryptDeriveKeyCapi | 不存在时,调用CryptCreateHash、CryptHashData。 +| BCryptDeriveKeyPBKDF2 | 不存在时,调用BCryptHashData。 +| BCryptDeriveKeyCapi | 不存在时,调用BCryptHashData。 +| BCryptEncrypt | 不存在时,调用CryptEncrypt。 +| BCryptDecrypt | 不存在时,调用CryptDecrypt。 +| BCryptGenerateSymmetricKey | 不存在时,调用CryptImportKey。 +| BCryptDestroyKey | 不存在时,调用CryptDestroyKey。 +| BCryptExportKey | 不存在时,调用CryptExportKey。 +| BCryptImportKey | 不存在时,调用CryptImportKey。 ## bcryptprimitives.dll | 函数 | Fallback diff --git a/src/MinimumRequiredVersionHelper/MinimumRequiredVersionHelper.vcxproj b/src/MinimumRequiredVersionHelper/MinimumRequiredVersionHelper.vcxproj index 085df5d..fffcb98 100644 --- a/src/MinimumRequiredVersionHelper/MinimumRequiredVersionHelper.vcxproj +++ b/src/MinimumRequiredVersionHelper/MinimumRequiredVersionHelper.vcxproj @@ -103,7 +103,6 @@ Level3 - true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -138,7 +137,6 @@ Level3 true true - true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true diff --git a/src/Thunks/bcrypt.hpp b/src/Thunks/bcrypt.hpp index 02234b2..bcd1d78 100644 --- a/src/Thunks/bcrypt.hpp +++ b/src/Thunks/bcrypt.hpp @@ -5,6 +5,10 @@ #pragma comment(lib, "Advapi32.lib") #endif +#if (YY_Thunks_Support_Version < NTDDI_WIN7) && (YY_Thunks_Support_Version >= NTDDI_WIN6) +#pragma comment(lib, "bcrypt.lib") +#endif + namespace YY { namespace Thunks @@ -14,6 +18,7 @@ namespace YY #if defined(YY_Thunks_Implemented) && YY_Thunks_Support_Version < NTDDI_WIN6 struct BCryptHash; struct BCryptAlgorithm; + struct BCryptKey; struct BCryptMapItem; typedef NTSTATUS(__fastcall* OpenAlgorithmProviderType)( _In_ const BCryptMapItem* _pCryptMapItem, @@ -41,6 +46,14 @@ namespace YY } }; + enum class BCryptObjectType + { + None, + Algorithm, + Hash, + Key, + }; + class BCryptObject { static constexpr auto kBCryptObjectMagic = 0x998u; @@ -49,11 +62,11 @@ namespace YY ULONG uRef = 1u; public: - DWORD uAlgId = 0; + BCryptObjectType eType = BCryptObjectType::None; bool bCanFree = true; - BCryptObject(DWORD _uAlgId) - : uAlgId(_uAlgId) + BCryptObject(BCryptObjectType _eType) + : eType(_eType) { } @@ -68,14 +81,24 @@ namespace YY return uMagic == kBCryptObjectMagic; } - DWORD GetClass() const + BCryptObjectType GetClass() const + { + return eType; + } + + bool IsAlgorithm() const { - return GET_ALG_CLASS(uAlgId); + return eType == BCryptObjectType::Algorithm; } - bool IsHash() + bool IsHash() const { - return GetClass() == ALG_CLASS_HASH; + return eType == BCryptObjectType::Hash; + } + + bool IsKey() + { + return eType == BCryptObjectType::Key; } void AddRef() @@ -103,16 +126,31 @@ namespace YY _Out_ ULONG* pcbResult, _In_ ULONG dwFlags ) = 0; + + virtual NTSTATUS WINAPI SetProperty( + _In_z_ LPCWSTR _szProperty, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags) = 0; }; struct BCryptAlgorithm : public BCryptObject { const BCryptMapItem* pMapItem = nullptr; + HCRYPTPROV hProv = NULL; ULONG fOpenAlgorithmFlags = 0; + DWORD uCryptMode = 0; + DWORD uEffectiveKeyBitCount = 0; BCryptAlgorithm() - : BCryptObject(0) + : BCryptObject(BCryptObjectType::Algorithm) + { + } + + ~BCryptAlgorithm() { + if (hProv) + CryptReleaseContext(hProv, 0); } bool IsRng() const @@ -191,6 +229,25 @@ namespace YY } } + static NTSTATUS __fastcall CryptoErrorToNTStatus(LSTATUS _lCryptoError) noexcept + { + switch (_lCryptoError) + { + case NTE_BAD_DATA: + return STATUS_INVALID_BUFFER_SIZE; + case ERROR_INVALID_HANDLE: + case NTE_BAD_HASH: + return STATUS_INVALID_HANDLE; + case NTE_BAD_ALGID: + return STATUS_NOT_SUPPORTED; + case NTE_NO_MEMORY: + return STATUS_NO_MEMORY; + case ERROR_MORE_DATA: + return STATUS_BUFFER_TOO_SMALL; + default: + return STATUS_INVALID_PARAMETER; + } + } NTSTATUS WINAPI GetProperty( _In_z_ LPCWSTR pszProperty, @@ -236,10 +293,16 @@ namespace YY return STATUS_NOT_SUPPORTED; } - virtual - NTSTATUS - WINAPI - CreateHash( + NTSTATUS WINAPI SetProperty( + _In_z_ LPCWSTR _szProperty, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags) override + { + return STATUS_NOT_SUPPORTED; + } + + virtual NTSTATUS WINAPI CreateHash( _Outptr_ BCryptHash** ppHash, _Out_writes_bytes_all_opt_(cbHashObject) PUCHAR pbHashObject, _In_ ULONG cbHashObject, @@ -249,19 +312,36 @@ namespace YY { return STATUS_NOT_SUPPORTED; } - }; - struct BCryptAlgorithmByCryptoAPI : BCryptAlgorithm - { - HCRYPTPROV hProv = NULL; + virtual NTSTATUS WINAPI GenerateSymmetricKey( + _Out_ BCryptKey**_ppKey, + _Out_writes_bytes_all_opt_(_cbKeyObject) PUCHAR _pbKeyObject, + _In_ ULONG _cbKeyObject, + _In_reads_bytes_(_cbSecret) PUCHAR _pbSecret, + _In_ ULONG _cbSecret, + _In_ ULONG _fFlags) + { + return STATUS_NOT_SUPPORTED; + } - ~BCryptAlgorithmByCryptoAPI() + virtual NTSTATUS WINAPI ImportKey( + _In_opt_ BCryptKey* _pImportKey, + _In_z_ LPCWSTR _szBlobType, + _Out_ BCryptKey** _ppKey, + _Out_writes_bytes_all_opt_(_cbKeyObject) PUCHAR _pKeyObject, + _In_ ULONG _cbKeyObject, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags + ) { - if (hProv) - CryptReleaseContext(hProv, 0); + return STATUS_NOT_SUPPORTED; } + }; - template + template + struct BCryptAlgorithmByCryptoAPI : BCryptAlgorithm + { static NTSTATUS __fastcall Create(_In_ const BCryptMapItem* _pMapItem, _In_ ULONG _fOpenAlgorithmFlags, _Outptr_ BCryptAlgorithm** _ppAlgorithm) { *_ppAlgorithm = nullptr; @@ -271,14 +351,14 @@ namespace YY return STATUS_INVALID_PARAMETER; const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; - auto _pBCryptAlgorithm = (BCryptAlgorithmT*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptAlgorithmT)); + auto _pBCryptAlgorithm = (BCryptAlgorithmType*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptAlgorithmType)); if (!_pBCryptAlgorithm) { CryptReleaseContext(_hProv, 0); return STATUS_NO_MEMORY; } - new (_pBCryptAlgorithm) BCryptAlgorithmT(); + new (_pBCryptAlgorithm) BCryptAlgorithmType(); _pBCryptAlgorithm->pMapItem = _pMapItem; _pBCryptAlgorithm->hProv = _hProv; _pBCryptAlgorithm->fOpenAlgorithmFlags = _fOpenAlgorithmFlags; @@ -289,13 +369,13 @@ namespace YY struct BCryptHash : public BCryptObject { - BCryptAlgorithmByCryptoAPI* pAlgorithm = nullptr; + BCryptAlgorithm* pAlgorithm = nullptr; ULONG dwFlags = 0; HCRYPTKEY hPubKey = NULL; HCRYPTHASH hHash = NULL; - BCryptHash(_In_ BCryptAlgorithmByCryptoAPI* _pAlgorithm) - : BCryptObject(_pAlgorithm->pMapItem->uAlgId) + BCryptHash(_In_ BCryptAlgorithm* _pAlgorithm) + : BCryptObject(BCryptObjectType::Hash) , pAlgorithm(_pAlgorithm) { pAlgorithm->AddRef(); @@ -327,7 +407,7 @@ namespace YY BYTE rgbKeyData[2]; }; - const auto _cbKeyBlob = sizeof(_PLAINTEXTKEYBLOB) + _cbSecret; + const DWORD _cbKeyBlob = sizeof(_PLAINTEXTKEYBLOB) + _cbSecret; auto _pKeyBlob = static_cast<_PLAINTEXTKEYBLOB*>(_malloca(_cbKeyBlob)); if (!_pKeyBlob) { @@ -480,9 +560,18 @@ namespace YY return STATUS_NOT_SUPPORTED; } + + NTSTATUS WINAPI SetProperty( + _In_z_ LPCWSTR _szProperty, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags) override + { + return STATUS_NOT_SUPPORTED; + } }; - struct BCryptAlgorithmHash : public BCryptAlgorithmByCryptoAPI + struct BCryptHashAlgorithm : public BCryptAlgorithmByCryptoAPI { NTSTATUS WINAPI GetProperty( _In_z_ LPCWSTR pszProperty, @@ -521,11 +610,796 @@ namespace YY return STATUS_BUFFER_TOO_SMALL; } - *reinterpret_cast(pbOutput) = GetHashLength(); + *reinterpret_cast(pbOutput) = GetHashLength(); + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_HASH_BLOCK_LENGTH, pszProperty, -1) == 0) + { + *pcbResult = sizeof(DWORD); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(DWORD)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pbOutput) = GetHashBlockLength(); + return STATUS_SUCCESS; + } + + return BCryptAlgorithm::GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); + } + + + NTSTATUS + WINAPI + CreateHash( + _Outptr_ BCryptHash** ppHash, + _Out_writes_bytes_all_opt_(cbHashObject) PUCHAR pbHashObject, + _In_ ULONG cbHashObject, + _In_reads_bytes_opt_(cbSecret) PUCHAR pbSecret, // optional + _In_ ULONG cbSecret, // optional + _In_ ULONG dwFlags) + { + BCryptHash* _pBCryptHash = reinterpret_cast(pbHashObject); + if (_pBCryptHash) + { + if (cbHashObject < sizeof(BCryptHash)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + new (_pBCryptHash) BCryptHash(this); + _pBCryptHash->bCanFree = false; + } + else + { + if (cbHashObject != 0) + { + return STATUS_INVALID_PARAMETER; + } + const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + _pBCryptHash = (BCryptHash*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptHash)); + if (!_pBCryptHash) + { + return STATUS_NO_MEMORY; + } + + new (_pBCryptHash) BCryptHash(this); + } + + auto _Status = _pBCryptHash->Init(pbSecret, cbSecret, dwFlags); + if (_Status) + { + _pBCryptHash->Release(); + return _Status; + } + *ppHash = _pBCryptHash; + return STATUS_SUCCESS; + } + }; + + struct BCryptRngAlgorithm : public BCryptAlgorithm + { + static NTSTATUS __fastcall Create(_In_ const BCryptMapItem* _pMapItem, _In_ ULONG _fOpenAlgorithmFlags, _Outptr_ BCryptAlgorithm** _ppAlgorithm) + { + *_ppAlgorithm = nullptr; + + const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; + auto _pBCryptAlgorithm = (BCryptRngAlgorithm*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptRngAlgorithm)); + if (!_pBCryptAlgorithm) + { + return STATUS_NO_MEMORY; + } + + new (_pBCryptAlgorithm) BCryptRngAlgorithm(); + _pBCryptAlgorithm->pMapItem = _pMapItem; + _pBCryptAlgorithm->fOpenAlgorithmFlags = _fOpenAlgorithmFlags; + *_ppAlgorithm = _pBCryptAlgorithm; + return STATUS_SUCCESS; + } + }; + + struct BCryptKey : public BCryptObject + { + static constexpr unsigned kMaxBlockLength = 16'384 / 8; + + BCryptAlgorithm* pAlgorithm = nullptr; + HCRYPTKEY hKey = NULL; + ULONG dwFlags = 0; + + BCryptKey(_In_ BCryptAlgorithm* _pAlgorithm) + : BCryptObject(BCryptObjectType::Key) + , pAlgorithm(_pAlgorithm) + { + pAlgorithm->AddRef(); + } + + ~BCryptKey() + { + if (hKey) + CryptDestroyKey(hKey); + + if (pAlgorithm) + pAlgorithm->Release(); + } + + NTSTATUS WINAPI Init( + _In_reads_bytes_opt_(_cbSecret) PUCHAR _pbSecret, // optional + _In_ ULONG _cbSecret, // optional + _In_ ULONG _fFlags) + { + if (_pbSecret == nullptr || _fFlags) + { + return STATUS_INVALID_PARAMETER; + } + + dwFlags = _fFlags; + // https://learn.microsoft.com/zh-cn/windows/win32/seccrypto/example-c-program--importing-a-plaintext-key + struct _PLAINTEXTKEYBLOB : public BLOBHEADER + { + DWORD dwKeySize; + BYTE rgbKeyData[2048]; + }; + + _PLAINTEXTKEYBLOB _KeyBlob; + _KeyBlob.bType = PLAINTEXTKEYBLOB; + _KeyBlob.bVersion = CUR_BLOB_VERSION; + _KeyBlob.reserved = 0; + if (pAlgorithm->pMapItem->uAlgId == CALG_AES) + { + switch (_cbSecret) + { + case 128 / 8: + _KeyBlob.aiKeyAlg = CALG_AES_128; + break; + case 192 / 8: + _KeyBlob.aiKeyAlg = CALG_AES_192; + break; + case 256 / 8: + _KeyBlob.aiKeyAlg = CALG_AES_256; + break; + default: + return STATUS_INVALID_PARAMETER; + } + } + else if (pAlgorithm->pMapItem->uAlgId == CALG_DES) + { + // DES密钥长度只有64位 + if (_cbSecret >= 64 / 8) + { + _cbSecret = 64 / 8; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + _KeyBlob.aiKeyAlg = CALG_DES; + } + else if (pAlgorithm->pMapItem->uAlgId == CALG_3DES) + { + if (_cbSecret >= 192 / 8) + { + _cbSecret = 192 / 8; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + _KeyBlob.aiKeyAlg = CALG_3DES; + } + else if (pAlgorithm->pMapItem->uAlgId == CALG_3DES_112) + { + if (_cbSecret >= 128 / 8) + { + _cbSecret = 128 / 8; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + _KeyBlob.aiKeyAlg = CALG_3DES_112; + } + else if (pAlgorithm->pMapItem->uAlgId == CALG_RC2) + { + // RC2密钥长度最大128bit + if (_cbSecret < 1) + { + return STATUS_INVALID_PARAMETER; + } + else if (_cbSecret > 16) + { + _cbSecret = 16; + } + + _KeyBlob.aiKeyAlg = CALG_RC2; + } + else if (pAlgorithm->pMapItem->uAlgId == CALG_RC4) + { + if (_cbSecret < 1) + { + return STATUS_INVALID_PARAMETER; + } + else if (_cbSecret > 16) + { + _cbSecret = 16; + } + _KeyBlob.aiKeyAlg = CALG_RC4; + } + else + { + return STATUS_NOT_SUPPORTED; + } + _KeyBlob.dwKeySize = _cbSecret; + memcpy(_KeyBlob.rgbKeyData, _pbSecret, _cbSecret); + + auto _bResult = CryptImportKey(pAlgorithm->hProv, reinterpret_cast(&_KeyBlob), sizeof(BLOBHEADER) + sizeof(DWORD) + _cbSecret, NULL, CRYPT_EXPORTABLE, &hKey); + // 避免密钥泄漏,所以立即将内存值清空!!! + memset(&_KeyBlob, 0, sizeof(_KeyBlob)); + + if (!_bResult) + { + return STATUS_INVALID_PARAMETER; + } + + if (auto _uCryptMode = pAlgorithm->uCryptMode) + { + if (!CryptSetKeyParam(hKey, KP_MODE, (const BYTE*)&_uCryptMode, 0)) + { + return STATUS_INVALID_PARAMETER; + } + } + + if (auto _uEffectiveKeyBitCount = pAlgorithm->uEffectiveKeyBitCount) + { + if (!CryptSetKeyParam(hKey, KP_EFFECTIVE_KEYLEN, (const BYTE*)&_uEffectiveKeyBitCount, 0)) + { + return STATUS_INVALID_PARAMETER; + } + } + + return STATUS_SUCCESS; + } + + + DWORD __fastcall GetBlockLength() const + { + DWORD _cbBlockBitLength = 0; + DWORD _cbData = sizeof(_cbBlockBitLength); + if (!CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&_cbBlockBitLength, &_cbData, 0)) + { + return 0; + } + + return max(_cbBlockBitLength / 8, 1); + } + + NTSTATUS WINAPI GetProperty( + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG* pcbResult, + _In_ ULONG dwFlags + ) override + { + if (__wcsnicmp_ascii(BCRYPT_BLOCK_LENGTH, pszProperty, -1) == 0) + { + *pcbResult = sizeof(DWORD); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(DWORD)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const auto _cbBlockLength = GetBlockLength(); + if (!_cbBlockLength) + { + return STATUS_NOT_SUPPORTED; + } + *reinterpret_cast(pbOutput) = _cbBlockLength; + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_ALGORITHM_NAME, pszProperty, -1) == 0) + { + *pcbResult = pAlgorithm->pMapItem->cbAlgId; + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < pAlgorithm->pMapItem->cbAlgId) + { + return STATUS_BUFFER_TOO_SMALL; + } + + memcpy(pbOutput, pAlgorithm->pMapItem->szAlgName, pAlgorithm->pMapItem->cbAlgId); + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_PROVIDER_HANDLE, pszProperty, -1) == 0) + { + *pcbResult = sizeof(BCRYPT_ALG_HANDLE); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(BCRYPT_ALG_HANDLE)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pbOutput) = pAlgorithm; + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_CHAINING_MODE, pszProperty, -1) == 0) + { + DWORD _uCryptMode = 0; + DWORD _cbResult = sizeof(_uCryptMode); + if (!CryptGetKeyParam(hKey, KP_MODE, (BYTE*)&_uCryptMode, &_cbResult, 0)) + { + return STATUS_NOT_SUPPORTED; + } + + switch (_uCryptMode) + { + case CRYPT_MODE_CBC: + *pcbResult = sizeof(BCRYPT_CHAIN_MODE_CBC); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + if (cbOutput < sizeof(BCRYPT_CHAIN_MODE_CBC)) + { + return STATUS_BUFFER_TOO_SMALL; + } + memcpy(pbOutput, BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC)); + return STATUS_SUCCESS; + case CRYPT_MODE_ECB: + *pcbResult = sizeof(BCRYPT_CHAIN_MODE_ECB); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + if (cbOutput < sizeof(BCRYPT_CHAIN_MODE_ECB)) + { + return STATUS_BUFFER_TOO_SMALL; + } + memcpy(pbOutput, BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB)); + return STATUS_SUCCESS; + case CRYPT_MODE_CFB: + *pcbResult = sizeof(BCRYPT_CHAIN_MODE_CFB); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + if (cbOutput < sizeof(BCRYPT_CHAIN_MODE_CFB)) + { + return STATUS_BUFFER_TOO_SMALL; + } + memcpy(pbOutput, BCRYPT_CHAIN_MODE_CFB, sizeof(BCRYPT_CHAIN_MODE_CFB)); + return STATUS_SUCCESS; + default: + return STATUS_NOT_SUPPORTED; + } + } + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS + WINAPI + SetProperty( + _In_z_ LPCWSTR _szProperty, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags) override + { + if (__wcsnicmp_ascii(BCRYPT_CHAINING_MODE, _szProperty, -1) == 0) + { + DWORD _uCryptMode; + if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_CBC) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_CBC, _countof(BCRYPT_CHAIN_MODE_CBC)) == 0) + { + _uCryptMode = CRYPT_MODE_CBC; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_ECB) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_ECB, _countof(BCRYPT_CHAIN_MODE_ECB)) == 0) + { + _uCryptMode = CRYPT_MODE_ECB; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_CFB) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_CFB, _countof(BCRYPT_CHAIN_MODE_CFB)) == 0) + { + _uCryptMode = CRYPT_MODE_CFB; + } + else + { + /*if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_CCM) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_CCM, _countof(BCRYPT_CHAIN_MODE_CCM)) == 0) + { + _uCryptMode = ; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_GCM) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_GCM, _countof(BCRYPT_CHAIN_MODE_GCM)) == 0) + { + _uCryptMode = ; + }*/ + return STATUS_NOT_SUPPORTED; + } + + if (!CryptSetKeyParam(hKey, KP_MODE, (const BYTE*)&_uCryptMode, 0)) + { + return STATUS_NOT_SUPPORTED; + } + return STATUS_SUCCESS; + } + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS WINAPI Encrypt( + _In_reads_bytes_opt_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_opt_ VOID* _pPaddingInfo, + _Inout_updates_bytes_opt_(_cbIV) PUCHAR _pIV, + _In_ ULONG _cbIV, + _Out_writes_bytes_to_opt_(_cbOutput, *_pcbResult) PUCHAR _pOutput, + _In_ ULONG _cbOutput, + _Out_ ULONG* _pcbResult, + _In_ ULONG _fFlags) + { + BOOL _bFinal = FALSE; + if (_fFlags & BCRYPT_BLOCK_PADDING) + { + _bFinal = TRUE; + } + + // 检测所需的缓冲区 + auto _cbOutputBufferNeed = _cbInput; + if (!CryptEncrypt(hKey, NULL, _bFinal, 0, nullptr, &_cbOutputBufferNeed, 0)) + { + return BCryptAlgorithm::CryptoErrorToNTStatus(GetLastError()); + } + + if (_pOutput) + { + // 检测缓冲区是否充足 + if (_cbOutput < _cbOutputBufferNeed) + { + *_pcbResult = _cbOutputBufferNeed; + return STATUS_BUFFER_TOO_SMALL; + } + + if (!_pInput) + { + return STATUS_INVALID_PARAMETER; + } + + if (_cbIV) + { + if (_pIV == nullptr) + { + return STATUS_INVALID_PARAMETER; + } + + if (GetBlockLength() != _cbIV) + { + return STATUS_INVALID_PARAMETER; + } + + if (!CryptSetKeyParam(hKey, KP_IV, _pIV, 0)) + { + return STATUS_NOT_SUPPORTED; + } + } + + if (_pOutput != _pInput) + { + memcpy(_pOutput, _pInput, _cbInput); + } + + if (!CryptEncrypt(hKey, NULL, _bFinal, 0, _pOutput, &_cbInput, _cbOutput)) + { + return BCryptAlgorithm::CryptoErrorToNTStatus(GetLastError()); + } + *_pcbResult = _cbInput; + } + else + { + // 单纯计算返回块大小 + + *_pcbResult = _cbOutputBufferNeed; + } + + return STATUS_SUCCESS; + } + + NTSTATUS WINAPI Decrypt( + _In_reads_bytes_opt_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_opt_ VOID* _pPaddingInfo, + _Inout_updates_bytes_opt_(_cbIV) PUCHAR _pIV, + _In_ ULONG _cbIV, + _Out_writes_bytes_to_opt_(_cbOutput, *_pcbResult) PUCHAR _pOutput, + _In_ ULONG _cbOutput, + _Out_ ULONG* _pcbResult, + _In_ ULONG _fFlags) + { + BOOL _bFinal = FALSE; + if (_fFlags & BCRYPT_BLOCK_PADDING) + { + _bFinal = TRUE; + } + + // 检测所需的缓冲区 + auto _cbOutputBufferNeed = _cbInput; + if (!CryptDecrypt(hKey, NULL, _bFinal, 0, nullptr, &_cbOutputBufferNeed)) + { + return BCryptAlgorithm::CryptoErrorToNTStatus(GetLastError()); + } + + if (_pOutput) + { + // 检测缓冲区 + if (_cbOutput < _cbOutputBufferNeed) + { + *_pcbResult = _cbOutputBufferNeed; + return STATUS_BUFFER_TOO_SMALL; + } + + if (!_pInput) + { + return STATUS_INVALID_PARAMETER; + } + + const auto _uBlockLength = GetBlockLength(); + if (_uBlockLength == 0) + { + return STATUS_INVALID_PARAMETER; + } + + if (_cbIV) + { + if (_pIV == nullptr) + { + return STATUS_INVALID_PARAMETER; + } + + if (_uBlockLength != _cbIV) + { + return STATUS_INVALID_PARAMETER; + } + + if (!CryptSetKeyParam(hKey, KP_IV, _pIV, 0)) + { + return STATUS_NOT_SUPPORTED; + } + } + + if (_cbInput <= _cbOutput) + { + // 如果现有输出缓冲区足以容纳,那么我们直接干即可 + if (_pInput != _pOutput) + { + memcpy(_pOutput, _pInput, _cbInput); + } + if (!CryptDecrypt(hKey, NULL, _bFinal, 0, _pOutput, &_cbInput)) + { + return BCryptAlgorithm::CryptoErrorToNTStatus(GetLastError()); + } + + *_pcbResult = _cbInput; + return STATUS_SUCCESS; + } + else + { + // 这时一定 _bFinal == TRUE + + // 现有输出缓冲区无法容纳,为了减少中间内存开销,我们分成2步进行 + // 第一步,先把头部的数据先解密 + DWORD _cbResult1 = 0; + if (_cbInput > _uBlockLength) + { + _cbResult1 = _cbInput - _uBlockLength; + memcpy(_pOutput, _pInput, _cbResult1); + _pInput += _cbResult1; + _cbInput = _uBlockLength; + if (!CryptDecrypt(hKey, NULL, FALSE, 0, _pOutput, &_cbResult1)) + { + return BCryptAlgorithm::CryptoErrorToNTStatus(GetLastError()); + } + + _pOutput += _cbResult1; + } + + // 第二步:解密最后一块 + BYTE _TmpOutputBuffer[kMaxBlockLength]; + memcpy(_TmpOutputBuffer, _pInput, _cbInput); + if (!CryptDecrypt(hKey, NULL, _bFinal, 0, _TmpOutputBuffer, &_cbInput)) + { + return BCryptAlgorithm::CryptoErrorToNTStatus(GetLastError()); + } + + memcpy(_pOutput, _TmpOutputBuffer, _cbInput); + *_pcbResult = _cbResult1 + _cbInput; + return STATUS_SUCCESS; + } + } + else + { + // 返回长度 + *_pcbResult = _cbOutputBufferNeed; + return STATUS_SUCCESS; + } + } + + NTSTATUS WINAPI ExportKey( + _In_opt_ BCryptKey* _pExportKey, + _In_z_ LPCWSTR _szBlobType, + _Out_writes_bytes_to_opt_(_cbOutput, *_pcbResult) PUCHAR _pOutput, + _In_ ULONG _cbOutput, + _Out_ ULONG* _pcbResult, + _In_ ULONG _fFlags + ) + { + if (_pExportKey || _fFlags) + { + return STATUS_INVALID_PARAMETER; + } + + if (__wcsnicmp_ascii(_szBlobType, BCRYPT_KEY_DATA_BLOB, -1) == 0 || __wcsnicmp_ascii(_szBlobType, BCRYPT_OPAQUE_KEY_BLOB, -1) == 0) + { + struct _PLAINTEXTKEYBLOB : public BLOBHEADER + { + DWORD dwKeySize; + BYTE rgbKeyData[0]; + }; + + // 内部布局恰好类似,做一些特殊优化 + static_assert(sizeof(_BCRYPT_KEY_DATA_BLOB_HEADER) == sizeof(_PLAINTEXTKEYBLOB), ""); + + if (!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, 0, (BYTE*)_pOutput, &_cbOutput)) + { + auto _lStatus = GetLastError(); + if (_lStatus == ERROR_MORE_DATA) + { + *_pcbResult = _cbOutput; + } + return BCryptAlgorithm::CryptoErrorToNTStatus(_lStatus); + } + + if (_pOutput) + { + auto _pBCryptKeyDataBlobHerder = reinterpret_cast<_BCRYPT_KEY_DATA_BLOB_HEADER*>(_pOutput); + _pBCryptKeyDataBlobHerder->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; + _pBCryptKeyDataBlobHerder->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; + } + + *_pcbResult = _cbOutput; + + return STATUS_SUCCESS; + } + else + { + return STATUS_NOT_SUPPORTED; + } + } + }; + + template + struct BCryptKeyAlgorithm : public BCryptAlgorithmByCryptoAPI + { + BCryptKeyAlgorithm() + { + uCryptMode = kDefaultCryptMode; + } + + NTSTATUS WINAPI GetProperty( + _In_z_ LPCWSTR pszProperty, + _Out_writes_bytes_to_opt_(cbOutput, *pcbResult) PUCHAR pbOutput, + _In_ ULONG cbOutput, + _Out_ ULONG* pcbResult, + _In_ ULONG dwFlags + ) override + { + if (__wcsnicmp_ascii(BCRYPT_OBJECT_LENGTH, pszProperty, -1) == 0) + { + *pcbResult = sizeof(DWORD); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(DWORD)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pbOutput) = sizeof(BCryptKeyType); + return STATUS_SUCCESS; + } + else if (__wcsnicmp_ascii(BCRYPT_CHAINING_MODE, pszProperty, -1) == 0) + { + if (uCryptMode == 0) + { + return STATUS_NOT_SUPPORTED; + } + + switch (uCryptMode) + { + case CRYPT_MODE_CBC: + *pcbResult = sizeof(BCRYPT_CHAIN_MODE_CBC); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + if (cbOutput < sizeof(BCRYPT_CHAIN_MODE_CBC)) + { + return STATUS_BUFFER_TOO_SMALL; + } + memcpy(pbOutput, BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC)); + return STATUS_SUCCESS; + case CRYPT_MODE_ECB: + *pcbResult = sizeof(BCRYPT_CHAIN_MODE_ECB); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + if (cbOutput < sizeof(BCRYPT_CHAIN_MODE_ECB)) + { + return STATUS_BUFFER_TOO_SMALL; + } + memcpy(pbOutput, BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB)); + return STATUS_SUCCESS; + case CRYPT_MODE_CFB: + *pcbResult = sizeof(BCRYPT_CHAIN_MODE_CFB); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + if (cbOutput < sizeof(BCRYPT_CHAIN_MODE_CFB)) + { + return STATUS_BUFFER_TOO_SMALL; + } + memcpy(pbOutput, BCRYPT_CHAIN_MODE_CFB, sizeof(BCRYPT_CHAIN_MODE_CFB)); + return STATUS_SUCCESS; + default: + return STATUS_NOT_SUPPORTED; + } + } + else if(__wcsnicmp_ascii(BCRYPT_BLOCK_SIZE_LIST, pszProperty, -1) == 0) + { + // 我也觉得有点奇怪,为什么AES这样的没有返回一个列表,仅仅返回一个值。 + // 但是实际上微软的BCrypt也是如此。 + if (kDefaultBlockSize == 0) + { + return STATUS_NOT_SUPPORTED; + } + + *pcbResult = sizeof(DWORD); + if (!pbOutput) + { + return STATUS_SUCCESS; + } + + if (cbOutput < sizeof(DWORD)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *reinterpret_cast(pbOutput) = kDefaultBlockSize; return STATUS_SUCCESS; } - else if (__wcsnicmp_ascii(BCRYPT_HASH_BLOCK_LENGTH, pszProperty, -1) == 0) + else if (__wcsnicmp_ascii(BCRYPT_EFFECTIVE_KEY_LENGTH, pszProperty, -1) == 0) { + if (uEffectiveKeyBitCount == 0) + { + return STATUS_NOT_SUPPORTED; + } + *pcbResult = sizeof(DWORD); if (!pbOutput) { @@ -537,83 +1411,166 @@ namespace YY return STATUS_BUFFER_TOO_SMALL; } - *reinterpret_cast(pbOutput) = GetHashBlockLength(); + *reinterpret_cast(pbOutput) = uEffectiveKeyBitCount; return STATUS_SUCCESS; } - - return BCryptAlgorithm::GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); + return BCryptAlgorithmByCryptoAPI::GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); } - NTSTATUS WINAPI - CreateHash( - _Outptr_ BCryptHash** ppHash, - _Out_writes_bytes_all_opt_(cbHashObject) PUCHAR pbHashObject, - _In_ ULONG cbHashObject, - _In_reads_bytes_opt_(cbSecret) PUCHAR pbSecret, // optional - _In_ ULONG cbSecret, // optional - _In_ ULONG dwFlags) + SetProperty( + _In_z_ LPCWSTR _szProperty, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags) override { - BCryptHash* _pBCryptHash = reinterpret_cast(pbHashObject); - if (_pBCryptHash) + if (__wcsnicmp_ascii(BCRYPT_CHAINING_MODE, _szProperty, -1) == 0) { - if (cbHashObject < sizeof(BCryptHash)) + if (uCryptMode == 0) { - return STATUS_BUFFER_TOO_SMALL; + return STATUS_NOT_SUPPORTED; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_CBC) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_CBC, _countof(BCRYPT_CHAIN_MODE_CBC)) == 0) + { + uCryptMode = CRYPT_MODE_CBC; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_ECB) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_ECB, _countof(BCRYPT_CHAIN_MODE_ECB)) == 0) + { + uCryptMode = CRYPT_MODE_ECB; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_CFB) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_CFB, _countof(BCRYPT_CHAIN_MODE_CFB)) == 0) + { + uCryptMode = CRYPT_MODE_CFB; + } + else + { + /*if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_CCM) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_CCM, _countof(BCRYPT_CHAIN_MODE_CCM)) == 0) + { + uCryptMode = ; + } + else if (_cbInput == sizeof(BCRYPT_CHAIN_MODE_GCM) && __wcsnicmp_ascii((const wchar_t*)_pInput, BCRYPT_CHAIN_MODE_GCM, _countof(BCRYPT_CHAIN_MODE_GCM)) == 0) + { + uCryptMode = ; + }*/ + return STATUS_NOT_SUPPORTED; } + + return STATUS_SUCCESS; + } - new (_pBCryptHash) BCryptHash(this); - _pBCryptHash->bCanFree = false; + return BCryptAlgorithmByCryptoAPI::SetProperty(_szProperty, _pInput, _cbInput, _fFlags); + } + + NTSTATUS WINAPI GenerateSymmetricKey( + _Out_ BCryptKey**_ppKey, + _Out_writes_bytes_all_opt_(_cbKeyObject) PUCHAR _pbKeyObject, + _In_ ULONG _cbKeyObject, + _In_reads_bytes_(_cbSecret) PUCHAR _pbSecret, + _In_ ULONG _cbSecret, + _In_ ULONG _fFlags) override + { + *_ppKey = nullptr; + BCryptKeyType* _pKey = nullptr; + if (_cbKeyObject == 0) + { + _pKey = (BCryptKeyType*)internal::Alloc(sizeof(BCryptKeyType)); + new(_pKey) BCryptKeyType(this); } else { - if (cbHashObject != 0) + if (_pbKeyObject == nullptr) { return STATUS_INVALID_PARAMETER; } - const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; - _pBCryptHash = (BCryptHash*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptHash)); - if (!_pBCryptHash) + + if (_cbKeyObject < sizeof(BCryptKeyType)) { - return STATUS_NO_MEMORY; + return STATUS_BUFFER_TOO_SMALL; } - new (_pBCryptHash) BCryptHash(this); + _pKey = reinterpret_cast(_pbKeyObject); + new(_pKey) BCryptKeyType(this); + _pKey->bCanFree = false; } - auto _Status = _pBCryptHash->Init(pbSecret, cbSecret, dwFlags); - if (_Status) + long _Status = _pKey->Init(_pbSecret, _cbSecret, _fFlags); + if (_Status < 0) { - _pBCryptHash->Release(); + _pKey->Release(); return _Status; } - *ppHash = _pBCryptHash; + *_ppKey = _pKey; return STATUS_SUCCESS; } - }; - struct BCryptAlgorithmRng : public BCryptAlgorithm - { - static NTSTATUS __fastcall Create(_In_ const BCryptMapItem* _pMapItem, _In_ ULONG _fOpenAlgorithmFlags, _Outptr_ BCryptAlgorithm** _ppAlgorithm) - { - *_ppAlgorithm = nullptr; - const auto _hProcessHeap = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock->ProcessHeap; - auto _pBCryptAlgorithm = (BCryptAlgorithmRng*)HeapAlloc(_hProcessHeap, 0, sizeof(BCryptAlgorithmRng)); - if (!_pBCryptAlgorithm) + NTSTATUS WINAPI ImportKey( + _In_opt_ BCryptKey* _pImportKey, + _In_z_ LPCWSTR _szBlobType, + _Out_ BCryptKey** _ppKey, + _Out_writes_bytes_all_opt_(_cbKeyObject) PUCHAR _pKeyObject, + _In_ ULONG _cbKeyObject, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags + ) override + { + if (_pImportKey || _fFlags) { - return STATUS_NO_MEMORY; + return STATUS_INVALID_PARAMETER; } + + if (__wcsnicmp_ascii(_szBlobType, BCRYPT_KEY_DATA_BLOB, -1) == 0 || __wcsnicmp_ascii(_szBlobType, BCRYPT_OPAQUE_KEY_BLOB, -1) == 0) + { + auto _pHerder = (_BCRYPT_KEY_DATA_BLOB_HEADER*)_pInput; + if (_pHerder == nullptr || _pHerder->dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC || _pHerder->dwVersion != BCRYPT_KEY_DATA_BLOB_VERSION1) + { + return STATUS_INVALID_PARAMETER; + } - new (_pBCryptAlgorithm) BCryptAlgorithmRng(); - _pBCryptAlgorithm->pMapItem = _pMapItem; - _pBCryptAlgorithm->fOpenAlgorithmFlags = _fOpenAlgorithmFlags; - *_ppAlgorithm = _pBCryptAlgorithm; - return STATUS_SUCCESS; + // _pInput 读取缓冲区溢出 + if (_pHerder->cbKeyData + sizeof(_BCRYPT_KEY_DATA_BLOB_HEADER) > _cbInput) + { + return STATUS_INVALID_PARAMETER; + } + + return GenerateSymmetricKey(_ppKey, _pKeyObject, _cbKeyObject, (PUCHAR)&_pHerder[1], _pHerder->cbKeyData, 0); + } + + return STATUS_NOT_SUPPORTED; + } + }; + + struct BCryptAESAlgorithm : public BCryptKeyAlgorithm + { + }; + + struct BCryptDESAlgorithm : public BCryptKeyAlgorithm + { + }; + + struct BCrypt3DESAlgorithm : public BCryptKeyAlgorithm + { + }; + + struct BCrypt3DES_112Algorithm : public BCryptKeyAlgorithm + { + }; + + struct BCryptRC2Algorithm : public BCryptKeyAlgorithm + { + BCryptRC2Algorithm() + { + // 微软BCrypt的RC2默认为128bits + uEffectiveKeyBitCount = 128; } }; + + struct BCryptRC4Algorithm : public BCryptKeyAlgorithm + { + }; template bool __fastcall Is(void* _pSrc); @@ -621,8 +1578,8 @@ namespace YY template<> bool __fastcall Is(void* _pSrc) { - auto _BCryptObject = reinterpret_cast(_pSrc); - return _BCryptObject != nullptr && _BCryptObject->IsValid(); + auto _pBCryptObject = reinterpret_cast(_pSrc); + return _pBCryptObject != nullptr && _pBCryptObject->IsValid(); } template<> @@ -631,16 +1588,16 @@ namespace YY if (!Is(_pSrc)) return false; - return reinterpret_cast(_pSrc)->GetClass() == 0; + return reinterpret_cast(_pSrc)->IsAlgorithm(); } template<> - bool __fastcall Is(void* _pSrc) + bool __fastcall Is(void* _pSrc) { if (!Is(_pSrc)) return false; - return reinterpret_cast(_pSrc)->IsRng(); + return reinterpret_cast(_pSrc)->IsRng(); } template<> @@ -651,6 +1608,15 @@ namespace YY return reinterpret_cast(_pSrc)->IsHash(); } + + template<> + bool __fastcall Is(void* _pSrc) + { + if (!Is(_pSrc)) + return false; + + return reinterpret_cast(_pSrc)->IsKey(); + } #endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) @@ -683,27 +1649,41 @@ namespace YY static const BCryptMapItem g_Map[] = { - // 加密算法 - // { L"AES", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_AES }, - // { L"DES", MS_DEF_DSS_PROV_W, PROV_DSS, CALG_DES }, - // { L"RC2", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_RC2 }, - // { L"RC4", MS_ENH_RSA_AES_PROV_XP_W, PROV_RSA_AES, CALG_RC4 }, - - // 生成随机数算法 - { BCRYPT_RNG_ALGORITHM, nullptr, 0, 0, &BCryptAlgorithmRng::Create }, - { BCRYPT_RNG_FIPS186_DSA_ALGORITHM, nullptr, 0, 0, &BCryptAlgorithmRng::Create }, - { BCRYPT_RNG_DUAL_EC_ALGORITHM, nullptr, 0, 0, &BCryptAlgorithmRng::Create }, - - // Hash算法 - { L"MD2", nullptr, PROV_RSA_AES, CALG_MD2, &BCryptAlgorithmByCryptoAPI::Create }, - { L"MD4", nullptr, PROV_RSA_AES, CALG_MD4, &BCryptAlgorithmByCryptoAPI::Create }, - { L"MD5", nullptr, PROV_RSA_AES, CALG_MD5, &BCryptAlgorithmByCryptoAPI::Create }, - { L"SHA1", nullptr, PROV_RSA_AES, CALG_SHA1, &BCryptAlgorithmByCryptoAPI::Create }, - { L"SHA256", nullptr, PROV_RSA_AES, CALG_SHA_256, &BCryptAlgorithmByCryptoAPI::Create }, - { L"SHA384", nullptr, PROV_RSA_AES, CALG_SHA_384, &BCryptAlgorithmByCryptoAPI::Create }, - { L"SHA512", nullptr, PROV_RSA_AES, CALG_SHA_512, &BCryptAlgorithmByCryptoAPI::Create }, + // { BCRYPT_RSA_ALGORITHM, nullptr, PROV_RSA_AES, CALG_RC4, &BCryptRSAAlgorithm::Create }, + // BCRYPT_RSA_SIGN_ALGORITHM + // BCRYPT_DH_ALGORITHM + // BCRYPT_DSA_ALGORITHM + { BCRYPT_RC2_ALGORITHM, nullptr, PROV_RSA_AES, CALG_RC2, &BCryptRC2Algorithm::Create }, + { BCRYPT_RC4_ALGORITHM, nullptr, PROV_RSA_AES, CALG_RC4, &BCryptRC4Algorithm::Create }, + { BCRYPT_AES_ALGORITHM, nullptr, PROV_RSA_AES, CALG_AES, &BCryptAESAlgorithm::Create }, + { BCRYPT_DES_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_DES, &BCryptDESAlgorithm::Create }, + // BCRYPT_DESX_ALGORITHM + { BCRYPT_3DES_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_3DES, &BCrypt3DESAlgorithm::Create }, + { BCRYPT_3DES_112_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_3DES_112, &BCrypt3DES_112Algorithm::Create }, + { BCRYPT_MD2_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_MD2, &BCryptHashAlgorithm::Create }, + { BCRYPT_MD4_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_MD4, &BCryptHashAlgorithm::Create }, + { BCRYPT_MD5_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_MD5, &BCryptHashAlgorithm::Create }, + { BCRYPT_SHA1_ALGORITHM, nullptr, PROV_RSA_FULL, CALG_SHA1, &BCryptHashAlgorithm::Create }, + { BCRYPT_SHA256_ALGORITHM, nullptr, PROV_RSA_AES, CALG_SHA_256, &BCryptHashAlgorithm::Create }, + { BCRYPT_SHA384_ALGORITHM, nullptr, PROV_RSA_AES, CALG_SHA_384, &BCryptHashAlgorithm::Create }, + { BCRYPT_SHA512_ALGORITHM, nullptr, PROV_RSA_AES, CALG_SHA_512, &BCryptHashAlgorithm::Create }, + //#define BCRYPT_AES_GMAC_ALGORITHM L"AES-GMAC" + //#define BCRYPT_AES_CMAC_ALGORITHM L"AES-CMAC" + //#define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256" + //#define BCRYPT_ECDSA_P384_ALGORITHM L"ECDSA_P384" + //#define BCRYPT_ECDSA_P521_ALGORITHM L"ECDSA_P521" + //#define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256" + //#define BCRYPT_ECDH_P384_ALGORITHM L"ECDH_P384" + //#define BCRYPT_ECDH_P521_ALGORITHM L"ECDH_P521" + { BCRYPT_RNG_ALGORITHM, nullptr, 0, 0, &BCryptRngAlgorithm::Create }, + { BCRYPT_RNG_FIPS186_DSA_ALGORITHM, nullptr, 0, 0, &BCryptRngAlgorithm::Create }, + { BCRYPT_RNG_DUAL_EC_ALGORITHM, nullptr, 0, 0, &BCryptRngAlgorithm::Create }, }; +#if (YY_Thunks_Support_Version < NTDDI_WINXPSP3) + __WarningMessage__("Windows XP SP3的Crypt开始才支持 CALG_SHA_256、CALG_SHA_384、CALG_SHA_512"); +#endif + for (auto& _Item : g_Map) { if (__wcsnicmp_ascii(_szAlgId, _Item.szAlgName, (size_t)-1) == 0) @@ -778,7 +1758,7 @@ namespace YY } else { - if (!Is(_hAlgorithm)) + if (!Is(_hAlgorithm)) { return STATUS_INVALID_HANDLE; } @@ -834,6 +1814,41 @@ namespace YY return reinterpret_cast(hObject)->GetProperty(pszProperty, pbOutput, cbOutput, pcbResult, dwFlags); } #endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用|UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 20, + NTSTATUS, + WINAPI, + BCryptSetProperty, + _Inout_ BCRYPT_HANDLE _hObject, + _In_z_ LPCWSTR _szProperty, + _In_reads_bytes_(cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags + ) + { + if (const auto _pfnBCryptSetProperty = try_get_BCryptSetProperty()) + { + return _pfnBCryptSetProperty(_hObject, _szProperty, _pInput, _cbInput, _fFlags); + } + + if(_szProperty == nullptr || _fFlags) + return STATUS_INVALID_PARAMETER; + + if (!Is(_hObject)) + { + return STATUS_INVALID_HANDLE; + } + + return reinterpret_cast(_hObject)->SetProperty(_szProperty, _pInput, _cbInput, _fFlags); + } +#endif #if (YY_Thunks_Support_Version < NTDDI_WIN6) @@ -1237,5 +2252,225 @@ namespace YY return _Status; } #endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 40, + NTSTATUS, + WINAPI, + BCryptEncrypt, + _Inout_ BCRYPT_KEY_HANDLE _hKey, + _In_reads_bytes_opt_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_opt_ VOID *_pPaddingInfo, + _Inout_updates_bytes_opt_(_cbIV) PUCHAR _pIV, + _In_ ULONG _cbIV, + _Out_writes_bytes_to_opt_(_cbOutput, *_pcbResult) PUCHAR _pOutput, + _In_ ULONG _cbOutput, + _Out_ ULONG *_pcbResult, + _In_ ULONG _fFlags) + { + if (const auto _pfnBCryptEncrypt = try_get_BCryptEncrypt()) + { + return _pfnBCryptEncrypt(_hKey, _pInput, _cbInput, _pPaddingInfo, _pIV, _cbIV, _pOutput, _cbOutput, _pcbResult, _fFlags); + } + + if (!Is(_hKey)) + { + return STATUS_INVALID_HANDLE; + } + + return reinterpret_cast(_hKey)->Encrypt(_pInput, _cbInput, _pPaddingInfo, _pIV, _cbIV, _pOutput, _cbOutput, _pcbResult, _fFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 40, + NTSTATUS, + WINAPI, + BCryptDecrypt, + _Inout_ BCRYPT_KEY_HANDLE _hKey, + _In_reads_bytes_opt_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_opt_ VOID* _pPaddingInfo, + _Inout_updates_bytes_opt_(_cbIV) PUCHAR _pIV, + _In_ ULONG _cbIV, + _Out_writes_bytes_to_opt_(_cbOutput, *_pcbResult) PUCHAR _pOutput, + _In_ ULONG _cbOutput, + _Out_ ULONG* _pcbResult, + _In_ ULONG _fFlags + ) + { + if (const auto _pfnBCryptDecrypt = try_get_BCryptDecrypt()) + { + return _pfnBCryptDecrypt(_hKey, _pInput, _cbInput, _pPaddingInfo, _pIV, _cbIV, _pOutput, _cbOutput, _pcbResult, _fFlags); + } + + if (!Is(_hKey)) + { + return STATUS_INVALID_HANDLE; + } + + return reinterpret_cast(_hKey)->Decrypt(_pInput, _cbInput, _pPaddingInfo, _pIV, _cbIV, _pOutput, _cbOutput, _pcbResult, _fFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 28, + NTSTATUS, + WINAPI, + BCryptGenerateSymmetricKey, + _Inout_ BCRYPT_ALG_HANDLE _hAlgorithm, + _Out_ BCRYPT_KEY_HANDLE * _phKey, + _Out_writes_bytes_all_opt_(cbKeyObject) PUCHAR _pKeyObject, + _In_ ULONG _cbKeyObject, + _In_reads_bytes_(cbSecret) PUCHAR _pSecret, + _In_ ULONG _cbSecret, + _In_ ULONG _fFlags + ) + { + if (const auto _pfnBCryptGenerateSymmetricKey = try_get_BCryptGenerateSymmetricKey()) + { + return _pfnBCryptGenerateSymmetricKey(_hAlgorithm, _phKey, _pKeyObject, _cbKeyObject, _pSecret, _cbSecret, _fFlags); + } + + if (_fFlags) + { + return STATUS_INVALID_PARAMETER; + } + + + if (!Is(_hAlgorithm)) + { + return STATUS_INVALID_HANDLE; + } + + return reinterpret_cast(_hAlgorithm)->GenerateSymmetricKey(reinterpret_cast(_phKey), _pKeyObject, _cbKeyObject, _pSecret, _cbSecret, _fFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 4, + NTSTATUS, + WINAPI, + BCryptDestroyKey, + _Inout_ BCRYPT_KEY_HANDLE _hKey + ) + { + if (const auto _pfnBCryptDestroyKey = try_get_BCryptDestroyKey()) + { + return _pfnBCryptDestroyKey(_hKey); + } + + if (!Is(_hKey)) + return STATUS_INVALID_HANDLE; + + reinterpret_cast(_hKey)->Release(); + return STATUS_SUCCESS; + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 28, + NTSTATUS, + WINAPI, + BCryptExportKey, + _In_ BCRYPT_KEY_HANDLE _hKey, + _In_opt_ BCRYPT_KEY_HANDLE _hExportKey, + _In_z_ LPCWSTR _szBlobType, + _Out_writes_bytes_to_opt_(_cbOutput, *_pcbResult) PUCHAR _pOutput, + _In_ ULONG _cbOutput, + _Out_ ULONG* _pcbResult, + _In_ ULONG _fFlags + ) + { + if (const auto _pfnBCryptExportKey = try_get_BCryptExportKey()) + { + return _pfnBCryptExportKey(_hKey, _hExportKey, _szBlobType, _pOutput, _cbOutput, _pcbResult, _fFlags); + } + + if (!Is(_hKey)) + return STATUS_INVALID_HANDLE; + + if(_hExportKey && Is(_hExportKey) == false) + return STATUS_INVALID_HANDLE; + + return reinterpret_cast(_hKey)->ExportKey(reinterpret_cast(_hExportKey), _szBlobType, _pOutput, _cbOutput, _pcbResult, _fFlags); + } +#endif + + +#if (YY_Thunks_Support_Version < NTDDI_WIN6) + + // 最低受支持的客户端 Windows Vista [桌面应用 | UWP 应用] + // 最低受支持的服务器 Windows Server 2008[桌面应用 | UWP 应用] + __DEFINE_THUNK( + bcrypt, + 36, + NTSTATUS, + WINAPI, + BCryptImportKey, + _In_ BCRYPT_ALG_HANDLE _hAlgorithm, + _In_opt_ BCRYPT_KEY_HANDLE _hImportKey, + _In_z_ LPCWSTR _szBlobType, + _Out_ BCRYPT_KEY_HANDLE* _phKey, + _Out_writes_bytes_all_opt_(_cbKeyObject) PUCHAR _pKeyObject, + _In_ ULONG _cbKeyObject, + _In_reads_bytes_(_cbInput) PUCHAR _pInput, + _In_ ULONG _cbInput, + _In_ ULONG _fFlags + ) + { + if (const auto _pfnBCryptImportKey = try_get_BCryptImportKey()) + { + return _pfnBCryptImportKey(_hAlgorithm, _hImportKey, _szBlobType, _phKey, _pKeyObject, _cbKeyObject, _pInput, _cbInput, _fFlags); + } + + if (!Is(_hAlgorithm)) + return STATUS_INVALID_HANDLE; + + if(_hImportKey && Is(_hImportKey) == false) + return STATUS_INVALID_HANDLE; + + return reinterpret_cast(_hAlgorithm)->ImportKey( + reinterpret_cast(_hImportKey), + _szBlobType, + reinterpret_cast(_phKey), + _pKeyObject, + _cbKeyObject, + _pInput, + _cbInput, + _fFlags); + } +#endif } } diff --git a/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp b/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp index a4309a4..0b279ae 100644 --- a/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp +++ b/src/YY-Thunks.UnitTest/bcrypt.UnitTest.cpp @@ -1,6 +1,37 @@ #include "pch.h" #include "Thunks/bcrypt.hpp" +#include + +#pragma comment(lib, "bcrypt.lib") + +CStringW GetStringHex(const BYTE* _pData, DWORD _cbData) +{ + CStringW _szResult; + + _szResult += L'{'; + + for (DWORD i = 0; i != _cbData; ++i) + { + if ((i % 8) == 0) + { + _szResult += L'\r'; + _szResult += L'\n'; + _szResult += L' '; + _szResult += L' '; + _szResult += L' '; + _szResult += L' '; + } + _szResult.AppendFormat(L"0x%.2X, ", _pData[i]); + } + + _szResult += L'\r'; + _szResult += L'\n'; + _szResult += L'}'; + + return _szResult; +} + namespace bcrypt { @@ -68,7 +99,7 @@ namespace bcrypt Assert::IsTrue(_Status >= 0); Assert::IsNotNull(_hAlg); BCRYPT_HASH_HANDLE _hHash = nullptr; - _Status = ::BCryptCreateHash(_hAlg, &_hHash, nullptr, 0, (PUCHAR)_szKey, _szKey ? strlen(_szKey) : 0, 0); + _Status = ::BCryptCreateHash(_hAlg, &_hHash, nullptr, 0, (PUCHAR)_szKey, _szKey ? (ULONG)strlen(_szKey) : 0, 0); Assert::IsTrue(_Status >= 0); Assert::IsNotNull(_hHash); @@ -79,7 +110,7 @@ namespace bcrypt _Status = ::BCryptFinishHash(_hHash, _ShaCurrent, sizeof(_ShaCurrent), 0); Assert::IsTrue(_Status >= 0); - Assert::IsTrue(memcmp(_ShaCurrent, _pTargetSha, sizeof(kTargetShaLength)) == 0); + Assert::AreEqual(ToHexString(_ShaCurrent), ToHexString(_pTargetSha)); _Status = ::BCryptDestroyHash(_hHash); Assert::IsTrue(_Status >= 0); @@ -152,8 +183,8 @@ namespace bcrypt Assert::IsTrue(_Status >= 0); static const UCHAR kTargetDerivedKey[] = { 0x04, 0x11, 0xaf, 0x2e, 0x9e, 0x1e, 0xfd, 0x17, 0x7c, 0xc2, 0x06, 0x6a, 0xa0, 0x74, 0xf5, 0x79, 0x44, 0x32, 0x8b, 0x3f }; - static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); - Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + Assert::AreEqual(ToHexString(_DerivedKey), ToHexString(kTargetDerivedKey)); + } { @@ -166,8 +197,7 @@ namespace bcrypt Assert::IsTrue(_Status >= 0); static const UCHAR kTargetDerivedKey[] = { 0x04, 0x11, 0xaf, 0x2e, 0x9e, 0x1e, 0xfd, 0x17, 0x7c, 0xc2, 0x06, 0x6a, 0xa0, 0x74, 0xf5, 0x79, 0x44, 0x32, 0x8b, 0x3f, 0x3e, 0xe7, 0x6a, 0xbd, 0x09, 0x02, 0xd0, 0xed, 0x9c, 0xa0 }; - static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); - Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + Assert::AreEqual(ToHexString(_DerivedKey), ToHexString(kTargetDerivedKey)); } } @@ -191,8 +221,7 @@ namespace bcrypt Assert::IsTrue(_Status >= 0); static const UCHAR kTargetDerivedKey[] = { 0x40, 0xbd, 0x00, 0x15, 0x63, 0x08, 0x5f, 0xc3, 0x51, 0x65, 0x32, 0x9e, 0xa1, 0xff, 0x5c, 0x5e, 0xcb, 0xdb, 0xbe, 0xef }; - static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); - Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + Assert::AreEqual(ToHexString(_DerivedKey), ToHexString(kTargetDerivedKey)); } { @@ -213,8 +242,7 @@ namespace bcrypt Assert::IsTrue(_Status >= 0); static const UCHAR kTargetDerivedKey[22] = { 0xaa, 0x9f, 0x40, 0x19, 0x05, 0xa0, 0x89, 0x0a, 0x1d, 0xdc, 0xe2, 0xcf, 0x2c, 0x7d, 0x98, 0x58, 0x95, 0x50, 0xeb, 0xbd, 0x3d, 0x0a }; - static_assert(sizeof(_DerivedKey) == sizeof(kTargetDerivedKey), ""); - Assert::IsTrue(memcmp(_DerivedKey, kTargetDerivedKey, sizeof(kTargetDerivedKey)) == 0); + Assert::AreEqual(ToHexString(_DerivedKey), ToHexString(kTargetDerivedKey)); } } }; @@ -235,8 +263,11 @@ namespace bcrypt Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyHash; Guard |= YY::Thunks::aways_null_try_get_BCryptHashData; Guard |= YY::Thunks::aways_null_try_get_BCryptFinishHash; + + Guard |= YY::Thunks::aways_null_try_get_BCryptGenerateSymmetricKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyKey; } - + TEST_METHOD(Random) { DWORD _cbGetPropertyResult; @@ -393,5 +424,921 @@ namespace bcrypt _Status = ::BCryptCloseAlgorithmProvider(_hAlg, 0); Assert::IsTrue(_Status >= 0); } + + TEST_METHOD(AES加密算法相关属性) + { + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + { + wchar_t _szModeBuffer[256] = {}; + DWORD _cbMode = sizeof(_szModeBuffer); + _Status = ::BCryptGetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)_szModeBuffer, sizeof(_szModeBuffer), &_cbMode, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(BCRYPT_CHAIN_MODE_CBC, _szModeBuffer); + } + + static constexpr const BYTE kAES128Key[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kAES128Key, + sizeof(kAES128Key), + 0); + Assert::IsTrue(_Status >= 0); + + { + wchar_t _szModeBuffer[256] = {}; + DWORD _cbResult = sizeof(_szModeBuffer); + _Status = ::BCryptGetProperty(hKey, BCRYPT_CHAINING_MODE, (PBYTE)_szModeBuffer, sizeof(_szModeBuffer), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(BCRYPT_CHAIN_MODE_CBC, _szModeBuffer); + } + + { + DWORD _cbBlock; + DWORD _cbResult = sizeof(_cbBlock); + _Status = ::BCryptGetProperty(hKey, BCRYPT_BLOCK_LENGTH, (PBYTE)&_cbBlock, sizeof(_cbBlock), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(_cbBlock, DWORD(128u / 8)); + } + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + }; + + TEST_CLASS(BCryptSetProperty) + { + AwaysNullGuard Guard; + public: + BCryptSetProperty() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptGetProperty; + Guard |= YY::Thunks::aways_null_try_get_BCryptSetProperty; + + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + + Guard |= YY::Thunks::aways_null_try_get_BCryptGenRandom; + + Guard |= YY::Thunks::aways_null_try_get_BCryptCreateHash; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyHash; + Guard |= YY::Thunks::aways_null_try_get_BCryptHashData; + Guard |= YY::Thunks::aways_null_try_get_BCryptFinishHash; + + Guard |= YY::Thunks::aways_null_try_get_BCryptGenerateSymmetricKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyKey; + } + + TEST_METHOD(AES加密算法相关属性) + { + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + { + _Status = ::BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0); + Assert::IsTrue(_Status >= 0); + + wchar_t _szModeBuffer[256] = {}; + DWORD _cbMode = sizeof(_szModeBuffer); + _Status = ::BCryptGetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)_szModeBuffer, sizeof(_szModeBuffer), &_cbMode, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(BCRYPT_CHAIN_MODE_ECB, _szModeBuffer); + } + + static constexpr const BYTE kAES128Key[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kAES128Key, + sizeof(kAES128Key), + 0); + Assert::IsTrue(_Status >= 0); + + { + wchar_t _szModeBuffer[256] = {}; + DWORD _cbResult = sizeof(_szModeBuffer); + _Status = ::BCryptGetProperty(hKey, BCRYPT_CHAINING_MODE, (PBYTE)_szModeBuffer, sizeof(_szModeBuffer), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(BCRYPT_CHAIN_MODE_ECB, _szModeBuffer); + + _Status = ::BCryptSetProperty(hKey, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptGetProperty(hKey, BCRYPT_CHAINING_MODE, (PBYTE)_szModeBuffer, sizeof(_szModeBuffer), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(BCRYPT_CHAIN_MODE_CBC, _szModeBuffer); + } + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + }; + + TEST_CLASS(BCryptEncrypt) + { + AwaysNullGuard Guard; + + public: + BCryptEncrypt() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptEncrypt; + Guard |= YY::Thunks::aways_null_try_get_BCryptGenerateSymmetricKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptSetProperty; + Guard |= YY::Thunks::aways_null_try_get_BCryptGetProperty; + } + + TEST_METHOD(AES加密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BYTE rgbIV[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }; + + static constexpr const BYTE kAES128Key[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kAES128Key, + sizeof(kAES128Key), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + Assert::AreEqual(cbCipherText, (ULONG)vecCipherText.size()); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + static const BYTE kTargetEncryptData[] = + { + 0xC6, 0xA1, 0x3B, 0x37, 0x87, 0x8F, 0x5B, 0x82, + 0x6F, 0x4F, 0x81, 0x62, 0xA1, 0xC8, 0xD8, 0x79, + 0xB1, 0xA2, 0x92, 0x73, 0xBE, 0x2C, 0x42, 0x07, + 0xA5, 0xAC, 0xE3, 0x93, 0x39, 0x8C, 0xB6, 0xFB, + }; + + Assert::AreEqual(ToHexString(kTargetEncryptData), ToHexString(vecCipherText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + + TEST_METHOD(DES加密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BYTE rgbIV[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static constexpr const BYTE kDESKey[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static const BYTE kTargetEncryptData[] = + { + 0xA5, 0x17, 0x3A, 0xD5, 0x95, 0x7B, 0x43, 0x70, + 0x5A, 0x8C, 0xFC, 0x7E, 0xF9, 0x26, 0x6F, 0x57, + 0xD0, 0x69, 0x16, 0x84, 0x0B, 0x48, 0x4C, 0x2A, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_DES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kDESKey, + sizeof(kDESKey), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + + Assert::IsTrue(_Status >= 0); + vecCipherText.resize(cbCipherText); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(kTargetEncryptData), ToHexString(vecCipherText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + + TEST_METHOD(RC2加密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BYTE rgbIV[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static constexpr const BYTE kSecretKey[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static const BYTE kTargetEncryptData[] = + { + 0xD3, 0x3B, 0x1D, 0x1C, 0x25, 0xA6, 0xED, 0x7A, + 0x4F, 0xF3, 0x01, 0xC4, 0x72, 0xB1, 0x6F, 0xA4, + 0x5A, 0xDA, 0x0B, 0xFE, 0x38, 0x33, 0x46, 0xC1, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RC2_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kSecretKey, + sizeof(kSecretKey), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + + Assert::IsTrue(_Status >= 0); + vecCipherText.resize(cbCipherText); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(kTargetEncryptData), ToHexString(vecCipherText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + + TEST_METHOD(RC4加密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + static constexpr const BYTE kSecretKey[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static const BYTE kTargetEncryptData[] = + { + 0xD5, 0xD1, 0xC6, 0xCE, 0xD5, 0xB3, 0xE6, 0x4D, + 0xD1, 0x50, 0xCC, 0x68, 0x39, 0x59, 0xFD, 0xDF, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RC4_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kSecretKey, + sizeof(kSecretKey), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + nullptr, + 0, + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + nullptr, + 0, + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + + Assert::IsTrue(_Status >= 0); + vecCipherText.resize(cbCipherText); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(kTargetEncryptData), ToHexString(vecCipherText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + + TEST_METHOD(_3DES加密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + static constexpr const BYTE kSecretKey[192/8] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static const BYTE kTargetEncryptData[] = + { + 0xE1, 0xB2, 0x46, 0xE5, 0xA7, 0xC7, 0x4C, 0xBC, + 0x27, 0x3B, 0xF0, 0xB4, 0x0E, 0xDB, 0xF8, 0xF5, + 0xCA, 0xDD, 0xCA, 0x87, 0x87, 0x53, 0x6A, 0xD4, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_3DES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + /*{ + wchar_t _cbHashLength[100]; + DWORD _cbResult = 0; + _Status = ::BCryptGetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PUCHAR)&_cbHashLength, sizeof(_cbHashLength), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + }*/ + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kSecretKey, + sizeof(kSecretKey), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + nullptr, + 0, + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + nullptr, + 0, + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + + Assert::IsTrue(_Status >= 0); + vecCipherText.resize(cbCipherText); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(kTargetEncryptData), ToHexString(vecCipherText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + + TEST_METHOD(_3DES_112加密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + static constexpr const BYTE kSecretKey[128/8] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + }; + + static const BYTE kTargetEncryptData[] = + { + 0x33, 0xB2, 0xB0, 0x52, 0x19, 0x73, 0xD0, 0xAC, + 0x13, 0xF5, 0x42, 0x2E, 0x13, 0xC9, 0xE0, 0x68, + 0x04, 0x5A, 0xB4, 0x82, 0x82, 0x24, 0x6B, 0x06, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_3DES_112_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + /*{ + DWORD _cbHashLength[100]; + DWORD _cbResult = 0; + _Status = ::BCryptGetProperty(hAlgorithm, BCRYPT_BLOCK_SIZE_LIST, (PUCHAR)&_cbHashLength, sizeof(_cbHashLength), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + }*/ + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kSecretKey, + sizeof(kSecretKey), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + nullptr, + 0, + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + nullptr, + 0, + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + + Assert::IsTrue(_Status >= 0); + vecCipherText.resize(cbCipherText); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(kTargetEncryptData), ToHexString(vecCipherText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + }; + + TEST_CLASS(BCryptDecrypt) + { + AwaysNullGuard Guard; + + public: + BCryptDecrypt() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptDecrypt; + Guard |= YY::Thunks::aways_null_try_get_BCryptGenerateSymmetricKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptSetProperty; + } + + TEST_METHOD(AES解密测试) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BYTE rgbIV[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }; + + static constexpr const BYTE kAES128Key[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + static const BYTE kEncryptData[] = + { + 0xC6, 0xA1, 0x3B, 0x37, 0x87, 0x8F, 0x5B, 0x82, + 0x6F, 0x4F, 0x81, 0x62, 0xA1, 0xC8, 0xD8, 0x79, + 0xB1, 0xA2, 0x92, 0x73, 0xBE, 0x2C, 0x42, 0x07, + 0xA5, 0xAC, 0xE3, 0x93, 0x39, 0x8C, 0xB6, 0xFB, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kAES128Key, + sizeof(kAES128Key), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbPlainText = 0; + _Status = ::BCryptDecrypt( + hKey, + (PUCHAR)kEncryptData, + sizeof(kEncryptData), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + NULL, + 0, + &cbPlainText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecPlainText; + vecPlainText.resize(cbPlainText); + _Status = ::BCryptDecrypt( + hKey, + (PUCHAR)kEncryptData, + sizeof(kEncryptData), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + vecPlainText.data(), + vecPlainText.size(), + &cbPlainText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + vecPlainText.resize(cbPlainText); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(cbPlainText, (ULONG)sizeof(kPlainText)); + + Assert::AreEqual(ToHexString(kPlainText), ToHexString(vecPlainText)); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + } + }; + + TEST_CLASS(BCryptExportKey) + { + AwaysNullGuard Guard; + + public: + BCryptExportKey() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptExportKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptGenerateSymmetricKey; + } + + TEST_METHOD(AES密钥导出) + { + static constexpr const BYTE kSecret[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + static constexpr const BYTE kKeyDataBlob[] = + { + 0x4B, 0x44, 0x42, 0x4D, + 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptGenerateSymmetricKey( + hAlgorithm, + &hKey, + nullptr, + 0, + (PBYTE)kSecret, + sizeof(kSecret), + 0); + Assert::IsTrue(_Status >= 0); + + ULONG _cbResult; + _Status = ::BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, nullptr, 0, &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + + std::vector _KeyDataBlobBuffer(_cbResult); + _Status = ::BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, _KeyDataBlobBuffer.data(), _KeyDataBlobBuffer.size(), &_cbResult, 0); + Assert::IsTrue(_Status >= 0); + _KeyDataBlobBuffer.resize(_cbResult); + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(_KeyDataBlobBuffer), ToHexString(kKeyDataBlob)); + } + }; + + TEST_CLASS(BCryptImportKey) + { + AwaysNullGuard Guard; + + public: + BCryptImportKey() + { + Guard |= YY::Thunks::aways_null_try_get_BCryptOpenAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptCloseAlgorithmProvider; + Guard |= YY::Thunks::aways_null_try_get_BCryptExportKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptImportKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptGenerateSymmetricKey; + Guard |= YY::Thunks::aways_null_try_get_BCryptSetProperty; + Guard |= YY::Thunks::aways_null_try_get_BCryptEncrypt; + Guard |= YY::Thunks::aways_null_try_get_BCryptDestroyKey; + } + + TEST_METHOD(AES密钥导入) + { + static constexpr const BYTE kPlainText[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + static constexpr const BYTE kKeyDataBlob[] = + { + 0x4B, 0x44, 0x42, 0x4D, + 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + }; + + BYTE rgbIV[] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F + }; + + // 生成的密文如果符合预期那么说明密钥导入成功。 + static const BYTE kTargetEncryptData[] = + { + 0xC6, 0xA1, 0x3B, 0x37, 0x87, 0x8F, 0x5B, 0x82, + 0x6F, 0x4F, 0x81, 0x62, 0xA1, 0xC8, 0xD8, 0x79, + 0xB1, 0xA2, 0x92, 0x73, 0xBE, 0x2C, 0x42, 0x07, + 0xA5, 0xAC, 0xE3, 0x93, 0x39, 0x8C, 0xB6, 0xFB, + }; + + BCRYPT_ALG_HANDLE hAlgorithm; + long _Status = ::BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_AES_ALGORITHM, nullptr, 0); + Assert::IsTrue(_Status >= 0); + + BCRYPT_KEY_HANDLE hKey; + _Status = ::BCryptImportKey( + hAlgorithm, + NULL, + BCRYPT_KEY_DATA_BLOB, + &hKey, + nullptr, + 0, + (PBYTE)kKeyDataBlob, + sizeof(kKeyDataBlob), + 0); + Assert::IsTrue(_Status >= 0); + _Status = ::BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + Assert::IsTrue(_Status >= 0); + + ULONG cbCipherText = 0; + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + NULL, + 0, + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + std::vector vecCipherText; + vecCipherText.resize(cbCipherText); + _Status = ::BCryptEncrypt( + hKey, + (PUCHAR)kPlainText, + sizeof(kPlainText), + NULL, + (PUCHAR)rgbIV, + sizeof(rgbIV), + vecCipherText.data(), + vecCipherText.size(), + &cbCipherText, + BCRYPT_BLOCK_PADDING); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptDestroyKey(hKey); + Assert::IsTrue(_Status >= 0); + + _Status = ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + Assert::IsTrue(_Status >= 0); + + Assert::AreEqual(ToHexString(vecCipherText), ToHexString(kTargetEncryptData)); + } }; } diff --git a/src/YY-Thunks.UnitTest/pch.h b/src/YY-Thunks.UnitTest/pch.h index 6b09773..b0312f5 100644 --- a/src/YY-Thunks.UnitTest/pch.h +++ b/src/YY-Thunks.UnitTest/pch.h @@ -64,5 +64,31 @@ class AwaysNullGuard } }; +inline std::string ToHexString(const void* _pData, size_t _cbData) +{ + std::string _szResult; + _szResult.reserve(_cbData * 2); + constexpr const char kHex[] = "0123456789ABCDEF"; + + for (auto _pItem = reinterpret_cast(_pData); _cbData; --_cbData, ++_pItem) + { + _szResult += kHex[*_pItem >> 4]; + _szResult += kHex[*_pItem & 0xFu]; + } + + return _szResult; +} + +inline std::string ToHexString(const std::vector _Data) +{ + return ToHexString(_Data.data(), _Data.size()); +} + +template +inline std::string ToHexString(const BYTE (&_Data)[kDataLength]) +{ + return ToHexString(_Data, kDataLength); +} + #endif //PCH_H