diff options
| author | Stefan Boberg <[email protected]> | 2023-11-08 14:05:28 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-08 14:05:28 +0100 |
| commit | 9e20e6c9f46420c88969236fa0cb64b31109d967 (patch) | |
| tree | 0ca61a578c143bfb39d3c922519e727256d71b26 /src/zencore/crypto.cpp | |
| parent | changed logic around sponsor process monitoring (#522) (diff) | |
| download | zen-9e20e6c9f46420c88969236fa0cb64b31109d967.tar.xz zen-9e20e6c9f46420c88969236fa0cb64b31109d967.zip | |
implemented openssl-free encryption for Windows (#520)
trims 40% off the (Windows) executable size
Diffstat (limited to 'src/zencore/crypto.cpp')
| -rw-r--r-- | src/zencore/crypto.cpp | 204 |
1 files changed, 191 insertions, 13 deletions
diff --git a/src/zencore/crypto.cpp b/src/zencore/crypto.cpp index 553dafafc..8403a35f4 100644 --- a/src/zencore/crypto.cpp +++ b/src/zencore/crypto.cpp @@ -2,16 +2,33 @@ #include <zencore/crypto.h> #include <zencore/intmath.h> +#include <zencore/scopeguard.h> #include <zencore/testing.h> #include <string> #include <string_view> +#ifndef ZEN_USE_OPENSSL +# if ZEN_PLATFORM_WINDOWS +# define ZEN_USE_OPENSSL 0 +# else +# define ZEN_USE_OPENSSL 1 +# endif +#endif + ZEN_THIRD_PARTY_INCLUDES_START #include <fmt/format.h> -#include <openssl/conf.h> -#include <openssl/err.h> -#include <openssl/evp.h> + +#if ZEN_USE_OPENSSL +# include <openssl/conf.h> +# include <openssl/err.h> +# include <openssl/evp.h> +#else +# include <zencore/windows.h> +# include <bcrypt.h> +# define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +# define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#endif ZEN_THIRD_PARTY_INCLUDES_END namespace zen { @@ -19,6 +36,13 @@ namespace zen { using namespace std::literals; namespace crypto { + enum class TransformMode : uint32_t + { + Decrypt, + Encrypt + }; + +#if ZEN_USE_OPENSSL class EvpContext { @@ -32,20 +56,15 @@ namespace crypto { EVP_CIPHER_CTX* m_Ctx; }; - enum class TransformMode : uint32_t - { - Decrypt, - Encrypt - }; - - MemoryView Transform(const EVP_CIPHER* Cipher, - TransformMode Mode, + MemoryView Transform(TransformMode Mode, MemoryView Key, MemoryView IV, MemoryView In, MutableMemoryView Out, std::optional<std::string>& Reason) { + const EVP_CIPHER* Cipher = EVP_aes_256_cbc(); + ZEN_ASSERT(Cipher != nullptr); EvpContext Ctx; @@ -98,6 +117,165 @@ namespace crypto { return Out.Left(TotalEncryptedBytes); } +#else + MemoryView Transform(TransformMode Mode, + MemoryView Key, + MemoryView IV, + MemoryView In, + MutableMemoryView Out, + std::optional<std::string>& Reason) + { + BCRYPT_ALG_HANDLE hAesAlg = NULL; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + // Open an algorithm handle. + if (!NT_SUCCESS(Status = BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))) + { + Reason = fmt::format("Error 0x{:08x} returned by BCryptGetProperty"sv, Status); + return {}; + } + + auto _ = MakeGuard([hAesAlg] { BCryptCloseAlgorithmProvider(hAesAlg, 0); }); + + DWORD cbData = 0; + + DWORD cbBlockLen = 0; + if (!NT_SUCCESS(Status = BCryptGetProperty(hAesAlg, BCRYPT_BLOCK_LENGTH, (PBYTE)&cbBlockLen, sizeof(DWORD), &cbData, 0))) + { + Reason = fmt::format("Error 0x{:08x} returned by BCryptGetProperty"sv, Status); + return {}; + } + + if (cbBlockLen > IV.GetSize()) + { + Reason = "block length is longer than the provided IV length"sv; + + return {}; + } + + AesIV128Bit MutableIV = AesIV128Bit::FromMemoryView(IV); + + if (!NT_SUCCESS( + Status = BCryptSetProperty(hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) + { + Reason = fmt::format("Error 0x{:08x} returned by BCryptSetProperty"sv, Status); + return {}; + } + + DWORD cbKeyObject = 0; + if (!NT_SUCCESS(Status = BCryptGetProperty(hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbData, 0))) + { + Reason = fmt::format("Error 0x{:08x} returned by BCryptGetProperty"sv, Status); + return {}; + } + + PBYTE pbKeyObject = (PBYTE)Memory::Alloc(cbKeyObject); + if (NULL == pbKeyObject) + { + Reason = fmt::format("memory allocation failed"); + return {}; + } + + auto __ = MakeGuard([pbKeyObject] { Memory::Free(pbKeyObject); }); + + BCRYPT_KEY_HANDLE hKey = NULL; + + if (!NT_SUCCESS(Status = BCryptGenerateSymmetricKey(hAesAlg, + &hKey, + pbKeyObject, + cbKeyObject, + (PBYTE)Key.GetData(), + (ULONG)Key.GetSize(), + /* flags */ 0))) + { + Reason = fmt::format("Error 0x{:08x} returned by BCryptGenerateSymmetricKey"sv, Status); + return {}; + } + + auto ___ = MakeGuard([hKey] { BCryptDestroyKey(hKey); }); + + if (Mode == TransformMode::Encrypt) + { + DWORD CipherTextByteCount = 0; + if (NT_SUCCESS(Status = BCryptEncrypt(hKey, + (PUCHAR)In.GetData(), + (ULONG)In.GetSize(), + NULL, + (PUCHAR)MutableIV.GetView().GetData(), + cbBlockLen, + NULL, + 0, + &CipherTextByteCount, + BCRYPT_BLOCK_PADDING))) + { + if (Out.GetSize() < CipherTextByteCount) + { + Reason = "invalid output buffer size"; + return {}; + } + + if (NT_SUCCESS(Status = BCryptEncrypt(hKey, + (PUCHAR)In.GetData(), + (ULONG)In.GetSize(), + NULL, + (PUCHAR)MutableIV.GetView().GetData(), + cbBlockLen, + (PUCHAR)Out.GetData(), + (ULONG)Out.GetSize(), + &CipherTextByteCount, + BCRYPT_BLOCK_PADDING))) + { + return Out.Left(CipherTextByteCount); + } + } + + Reason = fmt::format("Error 0x{:08x} returned by BCryptEncrypt", Status); + return {}; + } + else + { + DWORD PlainTextByteCount = 0; + + // + // Get the output buffer size. + // + if (NT_SUCCESS(Status = BCryptDecrypt(hKey, + (PUCHAR)In.GetData(), + (ULONG)In.GetSize(), + NULL, + (PUCHAR)MutableIV.GetView().GetData(), + cbBlockLen, + NULL, + 0, + &PlainTextByteCount, + BCRYPT_BLOCK_PADDING))) + { + if (Out.GetSize() < PlainTextByteCount) + { + Reason = "invalid output buffer size"sv; + return {}; + } + + if (NT_SUCCESS(Status = BCryptDecrypt(hKey, + (PUCHAR)In.GetData(), + (ULONG)In.GetSize(), + NULL, + (PUCHAR)MutableIV.GetView().GetData(), + cbBlockLen, + (PUCHAR)Out.GetData(), + (ULONG)Out.GetSize(), + &PlainTextByteCount, + BCRYPT_BLOCK_PADDING))) + { + return Out.Left(PlainTextByteCount); + } + } + + Reason = fmt::format("Error 0x{:08x} returned by BCryptDecrypt"sv, Status); + return {}; + } + } +#endif bool ValidateKeyAndIV(const AesKey256Bit& Key, const AesIV128Bit& IV, std::optional<std::string>& Reason) { @@ -128,7 +306,7 @@ Aes::Encrypt(const AesKey256Bit& Key, const AesIV128Bit& IV, MemoryView In, Muta return MemoryView(); } - return crypto::Transform(EVP_aes_256_cbc(), crypto::TransformMode::Encrypt, Key.GetView(), IV.GetView(), In, Out, Reason); + return crypto::Transform(crypto::TransformMode::Encrypt, Key.GetView(), IV.GetView(), In, Out, Reason); } MemoryView @@ -139,7 +317,7 @@ Aes::Decrypt(const AesKey256Bit& Key, const AesIV128Bit& IV, MemoryView In, Muta return MemoryView(); } - return crypto::Transform(EVP_aes_256_cbc(), crypto::TransformMode::Decrypt, Key.GetView(), IV.GetView(), In, Out, Reason); + return crypto::Transform(crypto::TransformMode::Decrypt, Key.GetView(), IV.GetView(), In, Out, Reason); } #if ZEN_WITH_TESTS |