summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/crypto
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/crypto
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/crypto')
-rw-r--r--winpr/libwinpr/crypto/CMakeLists.txt59
-rw-r--r--winpr/libwinpr/crypto/ModuleOptions.cmake9
-rw-r--r--winpr/libwinpr/crypto/cert.c223
-rw-r--r--winpr/libwinpr/crypto/cipher.c747
-rw-r--r--winpr/libwinpr/crypto/crypto.c301
-rw-r--r--winpr/libwinpr/crypto/crypto.h43
-rw-r--r--winpr/libwinpr/crypto/hash.c780
-rw-r--r--winpr/libwinpr/crypto/hmac_md5.c57
-rw-r--r--winpr/libwinpr/crypto/hmac_md5.h19
-rw-r--r--winpr/libwinpr/crypto/md4.c275
-rw-r--r--winpr/libwinpr/crypto/md4.h46
-rw-r--r--winpr/libwinpr/crypto/md5.c295
-rw-r--r--winpr/libwinpr/crypto/md5.h48
-rw-r--r--winpr/libwinpr/crypto/rand.c83
-rw-r--r--winpr/libwinpr/crypto/rc4.c88
-rw-r--r--winpr/libwinpr/crypto/rc4.h34
-rw-r--r--winpr/libwinpr/crypto/test/CMakeLists.txt34
-rw-r--r--winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c86
-rw-r--r--winpr/libwinpr/crypto/test/TestCryptoCipher.c232
-rw-r--r--winpr/libwinpr/crypto/test/TestCryptoHash.c316
-rw-r--r--winpr/libwinpr/crypto/test/TestCryptoProtectData.c10
-rw-r--r--winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c55
-rw-r--r--winpr/libwinpr/crypto/test/TestCryptoRand.c26
23 files changed, 3866 insertions, 0 deletions
diff --git a/winpr/libwinpr/crypto/CMakeLists.txt b/winpr/libwinpr/crypto/CMakeLists.txt
new file mode 100644
index 0000000..af8da8a
--- /dev/null
+++ b/winpr/libwinpr/crypto/CMakeLists.txt
@@ -0,0 +1,59 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-crypto cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(SRCS
+ hash.c
+ rand.c
+ cipher.c
+ cert.c
+ crypto.c
+ crypto.h
+)
+if (WITH_INTERNAL_RC4)
+ list(APPEND SRCS rc4.c rc4.h)
+endif()
+
+if (WITH_INTERNAL_MD4)
+ list(APPEND SRCS md4.c md4.h)
+endif()
+
+if (WITH_INTERNAL_MD5)
+ list(APPEND SRCS md5.c md5.h)
+ list(APPEND SRCS hmac_md5.c hmac_md5.h)
+endif()
+
+winpr_module_add(
+ ${SRCS}
+)
+
+if(OPENSSL_FOUND)
+ winpr_include_directory_add(${OPENSSL_INCLUDE_DIR})
+ winpr_library_add_private(${OPENSSL_LIBRARIES})
+endif()
+
+if(MBEDTLS_FOUND)
+ winpr_include_directory_add(${MBEDTLS_INCLUDE_DIR})
+ winpr_library_add_private(${MBEDTLS_LIBRARIES})
+endif()
+
+if(WIN32)
+ winpr_library_add_public(crypt32)
+endif()
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
diff --git a/winpr/libwinpr/crypto/ModuleOptions.cmake b/winpr/libwinpr/crypto/ModuleOptions.cmake
new file mode 100644
index 0000000..39cbfe1
--- /dev/null
+++ b/winpr/libwinpr/crypto/ModuleOptions.cmake
@@ -0,0 +1,9 @@
+
+set(MINWIN_LAYER "1")
+set(MINWIN_GROUP "core")
+set(MINWIN_MAJOR_VERSION "1")
+set(MINWIN_MINOR_VERSION "0")
+set(MINWIN_SHORT_NAME "crypto")
+set(MINWIN_LONG_NAME "Cryptography API (CryptoAPI)")
+set(MODULE_LIBRARY_NAME "crypt32")
+
diff --git a/winpr/libwinpr/crypto/cert.c b/winpr/libwinpr/crypto/cert.c
new file mode 100644
index 0000000..83b7213
--- /dev/null
+++ b/winpr/libwinpr/crypto/cert.c
@@ -0,0 +1,223 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Cryptography API (CryptoAPI)
+ *
+ * Copyright 2012-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crypto.h>
+
+/**
+ * CertOpenStore
+ * CertCloseStore
+ * CertControlStore
+ * CertDuplicateStore
+ * CertSaveStore
+ * CertRegisterPhysicalStore
+ * CertRegisterSystemStore
+ * CertAddStoreToCollection
+ * CertRemoveStoreFromCollection
+ * CertOpenSystemStoreA
+ * CertOpenSystemStoreW
+ * CertEnumPhysicalStore
+ * CertEnumSystemStore
+ * CertEnumSystemStoreLocation
+ * CertSetStoreProperty
+ * CertUnregisterPhysicalStore
+ * CertUnregisterSystemStore
+ *
+ * CertAddCertificateContextToStore
+ * CertAddCertificateLinkToStore
+ * CertAddCRLContextToStore
+ * CertAddCRLLinkToStore
+ * CertAddCTLContextToStore
+ * CertAddCTLLinkToStore
+ * CertAddEncodedCertificateToStore
+ * CertAddEncodedCertificateToSystemStoreA
+ * CertAddEncodedCertificateToSystemStoreW
+ * CertAddEncodedCRLToStore
+ * CertAddEncodedCTLToStore
+ * CertAddSerializedElementToStore
+ * CertDeleteCertificateFromStore
+ * CertDeleteCRLFromStore
+ * CertDeleteCTLFromStore
+ * CertGetCRLFromStore
+ * CertEnumCertificatesInStore
+ * CertEnumCRLsInStore
+ * CertEnumCTLsInStore
+ * CertFindCertificateInStore
+ * CertFindChainInStore
+ * CertFindCRLInStore
+ * CertFindCTLInStore
+ * CertGetIssuerCertificateFromStore
+ * CertGetStoreProperty
+ * CertGetSubjectCertificateFromStore
+ * CertSerializeCertificateStoreElement
+ * CertSerializeCRLStoreElement
+ * CertSerializeCTLStoreElement
+ *
+ * CertAddEnhancedKeyUsageIdentifier
+ * CertAddRefServerOcspResponse
+ * CertAddRefServerOcspResponseContext
+ * CertAlgIdToOID
+ * CertCloseServerOcspResponse
+ * CertCompareCertificate
+ * CertCompareCertificateName
+ * CertCompareIntegerBlob
+ * CertComparePublicKeyInfo
+ * CertCreateCertificateChainEngine
+ * CertCreateCertificateContext
+ * CertCreateContext
+ * CertCreateCRLContext
+ * CertCreateCTLContext
+ * CertCreateCTLEntryFromCertificateContextProperties
+ * CertCreateSelfSignCertificate
+ * CertDuplicateCertificateChain
+ * CertDuplicateCertificateContext
+ * CertDuplicateCRLContext
+ * CertDuplicateCTLContext
+ * CertEnumCertificateContextProperties
+ * CertEnumCRLContextProperties
+ * CertEnumCTLContextProperties
+ * CertEnumSubjectInSortedCTL
+ * CertFindAttribute
+ * CertFindCertificateInCRL
+ * CertFindExtension
+ * CertFindRDNAttr
+ * CertFindSubjectInCTL
+ * CertFindSubjectInSortedCTL
+ * CertFreeCertificateChain
+ * CertFreeCertificateChainEngine
+ * CertFreeCertificateChainList
+ * CertFreeCertificateContext
+ * CertFreeCRLContext
+ * CertFreeCTLContext
+ * CertFreeServerOcspResponseContext
+ * CertGetCertificateChain
+ * CertGetCertificateContextProperty
+ * CertGetCRLContextProperty
+ * CertGetCTLContextProperty
+ * CertGetEnhancedKeyUsage
+ * CertGetIntendedKeyUsage
+ * CertGetNameStringA
+ * CertGetNameStringW
+ * CertGetPublicKeyLength
+ * CertGetServerOcspResponseContext
+ * CertGetValidUsages
+ * CertIsRDNAttrsInCertificateName
+ * CertIsStrongHashToSign
+ * CertIsValidCRLForCertificate
+ * CertNameToStrA
+ * CertNameToStrW
+ * CertOIDToAlgId
+ * CertOpenServerOcspResponse
+ * CertRDNValueToStrA
+ * CertRDNValueToStrW
+ * CertRemoveEnhancedKeyUsageIdentifier
+ * CertResyncCertificateChainEngine
+ * CertRetrieveLogoOrBiometricInfo
+ * CertSelectCertificateChains
+ * CertSetCertificateContextPropertiesFromCTLEntry
+ * CertSetCertificateContextProperty
+ * CertSetCRLContextProperty
+ * CertSetCTLContextProperty
+ * CertSetEnhancedKeyUsage
+ * CertStrToNameA
+ * CertStrToNameW
+ * CertVerifyCertificateChainPolicy
+ * CertVerifyCRLRevocation
+ * CertVerifyCRLTimeValidity
+ * CertVerifyCTLUsage
+ * CertVerifyRevocation
+ * CertVerifySubjectCertificateContext
+ * CertVerifyTimeValidity
+ * CertVerifyValidityNesting
+ */
+
+#include <winpr/crt.h>
+#include <winpr/wincrypt.h>
+
+#ifndef _WIN32
+
+#include "crypto.h"
+
+HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType,
+ HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara)
+{
+ WINPR_CERTSTORE* certstore = NULL;
+
+ certstore = (WINPR_CERTSTORE*)calloc(1, sizeof(WINPR_CERTSTORE));
+
+ if (certstore)
+ {
+ certstore->lpszStoreProvider = lpszStoreProvider;
+ certstore->dwMsgAndCertEncodingType = dwMsgAndCertEncodingType;
+ }
+
+ return (HCERTSTORE)certstore;
+}
+
+HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, LPCWSTR szSubsystemProtocol)
+{
+ HCERTSTORE hCertStore = NULL;
+
+ hCertStore = CertOpenStore(CERT_STORE_PROV_FILE, X509_ASN_ENCODING, hProv, 0, NULL);
+
+ return hCertStore;
+}
+
+HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, LPCSTR szSubsystemProtocol)
+{
+ return CertOpenSystemStoreW(hProv, NULL);
+}
+
+BOOL CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
+{
+ WINPR_CERTSTORE* certstore = NULL;
+
+ certstore = (WINPR_CERTSTORE*)hCertStore;
+
+ free(certstore);
+
+ return TRUE;
+}
+
+PCCERT_CONTEXT CertFindCertificateInStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType,
+ DWORD dwFindFlags, DWORD dwFindType,
+ const void* pvFindPara, PCCERT_CONTEXT pPrevCertContext)
+{
+ return (PCCERT_CONTEXT)1;
+}
+
+PCCERT_CONTEXT CertEnumCertificatesInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext)
+{
+ return (PCCERT_CONTEXT)NULL;
+}
+
+DWORD CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void* pvTypePara,
+ LPWSTR pszNameString, DWORD cchNameString)
+{
+ return 0;
+}
+
+DWORD CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void* pvTypePara,
+ LPSTR pszNameString, DWORD cchNameString)
+{
+ return 0;
+}
+
+#endif
diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c
new file mode 100644
index 0000000..45eca79
--- /dev/null
+++ b/winpr/libwinpr/crypto/cipher.c
@@ -0,0 +1,747 @@
+/**
+ * WinPR: Windows Portable Runtime
+ *
+ * Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/assert.h>
+#include <winpr/crypto.h>
+
+#include "../log.h"
+#define TAG WINPR_TAG("crypto.cipher")
+
+#if defined(WITH_INTERNAL_RC4)
+#include "rc4.h"
+#endif
+
+#ifdef WITH_OPENSSL
+#include <openssl/aes.h>
+#include <openssl/rc4.h>
+#include <openssl/des.h>
+#include <openssl/evp.h>
+#endif
+
+#ifdef WITH_MBEDTLS
+#include <mbedtls/md.h>
+#include <mbedtls/aes.h>
+#include <mbedtls/des.h>
+#include <mbedtls/cipher.h>
+#if MBEDTLS_VERSION_MAJOR < 3
+#define mbedtls_cipher_info_get_iv_size(_info) (_info->iv_size)
+#define mbedtls_cipher_info_get_key_bitlen(_info) (_info->key_bitlen)
+#endif
+#endif
+
+/**
+ * RC4
+ */
+
+struct winpr_rc4_ctx_private_st
+{
+#if defined(WITH_INTERNAL_RC4)
+ winpr_int_RC4_CTX* ictx;
+#else
+#if defined(WITH_OPENSSL)
+ EVP_CIPHER_CTX* ctx;
+#endif
+#endif
+};
+
+static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOOL override_fips)
+{
+ if (!key || (keylen == 0))
+ return NULL;
+
+ WINPR_RC4_CTX* ctx = (WINPR_RC4_CTX*)calloc(1, sizeof(WINPR_RC4_CTX));
+ if (!ctx)
+ return NULL;
+
+#if defined(WITH_INTERNAL_RC4)
+ WINPR_UNUSED(override_fips);
+ ctx->ictx = winpr_int_rc4_new(key, keylen);
+ if (!ctx->ictx)
+ goto fail;
+#elif defined(WITH_OPENSSL)
+ const EVP_CIPHER* evp = NULL;
+
+ if (keylen > INT_MAX)
+ goto fail;
+
+ ctx->ctx = EVP_CIPHER_CTX_new();
+ if (!ctx->ctx)
+ goto fail;
+
+ evp = EVP_rc4();
+
+ if (!evp)
+ goto fail;
+
+ EVP_CIPHER_CTX_reset(ctx->ctx);
+ if (EVP_EncryptInit_ex(ctx->ctx, evp, NULL, NULL, NULL) != 1)
+ goto fail;
+
+ /* EVP_CIPH_FLAG_NON_FIPS_ALLOW does not exist before openssl 1.0.1 */
+#if !(OPENSSL_VERSION_NUMBER < 0x10001000L)
+
+ if (override_fips == TRUE)
+ EVP_CIPHER_CTX_set_flags(ctx->ctx, EVP_CIPH_FLAG_NON_FIPS_ALLOW);
+
+#endif
+ EVP_CIPHER_CTX_set_key_length(ctx->ctx, (int)keylen);
+ if (EVP_EncryptInit_ex(ctx->ctx, NULL, NULL, key, NULL) != 1)
+ goto fail;
+#endif
+ return ctx;
+
+fail:
+ WINPR_PRAGMA_DIAG_PUSH
+ WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
+
+ winpr_RC4_Free(ctx);
+ WINPR_PRAGMA_DIAG_POP
+ return NULL;
+}
+
+WINPR_RC4_CTX* winpr_RC4_New_Allow_FIPS(const void* key, size_t keylen)
+{
+ return winpr_RC4_New_Internal(key, keylen, TRUE);
+}
+
+WINPR_RC4_CTX* winpr_RC4_New(const void* key, size_t keylen)
+{
+ return winpr_RC4_New_Internal(key, keylen, FALSE);
+}
+
+BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const void* input, void* output)
+{
+ WINPR_ASSERT(ctx);
+
+#if defined(WITH_INTERNAL_RC4)
+ return winpr_int_rc4_update(ctx->ictx, length, input, output);
+#elif defined(WITH_OPENSSL)
+ WINPR_ASSERT(ctx->ctx);
+ int outputLength = 0;
+ if (length > INT_MAX)
+ return FALSE;
+
+ WINPR_ASSERT(ctx);
+ if (EVP_CipherUpdate(ctx->ctx, output, &outputLength, input, (int)length) != 1)
+ return FALSE;
+ return TRUE;
+#endif
+ return FALSE;
+}
+
+void winpr_RC4_Free(WINPR_RC4_CTX* ctx)
+{
+ if (!ctx)
+ return;
+
+#if defined(WITH_INTERNAL_RC4)
+ winpr_int_rc4_free(ctx->ictx);
+#elif defined(WITH_OPENSSL)
+ EVP_CIPHER_CTX_free(ctx->ctx);
+#endif
+ free(ctx);
+}
+
+/**
+ * Generic Cipher API
+ */
+
+#ifdef WITH_OPENSSL
+extern const EVP_MD* winpr_openssl_get_evp_md(WINPR_MD_TYPE md);
+#endif
+
+#ifdef WITH_MBEDTLS
+extern mbedtls_md_type_t winpr_mbedtls_get_md_type(int md);
+#endif
+
+#if defined(WITH_OPENSSL)
+static const EVP_CIPHER* winpr_openssl_get_evp_cipher(int cipher)
+{
+ const EVP_CIPHER* evp = NULL;
+
+ switch (cipher)
+ {
+ case WINPR_CIPHER_NULL:
+ evp = EVP_enc_null();
+ break;
+
+ case WINPR_CIPHER_AES_128_ECB:
+ evp = EVP_get_cipherbyname("aes-128-ecb");
+ break;
+
+ case WINPR_CIPHER_AES_192_ECB:
+ evp = EVP_get_cipherbyname("aes-192-ecb");
+ break;
+
+ case WINPR_CIPHER_AES_256_ECB:
+ evp = EVP_get_cipherbyname("aes-256-ecb");
+ break;
+
+ case WINPR_CIPHER_AES_128_CBC:
+ evp = EVP_get_cipherbyname("aes-128-cbc");
+ break;
+
+ case WINPR_CIPHER_AES_192_CBC:
+ evp = EVP_get_cipherbyname("aes-192-cbc");
+ break;
+
+ case WINPR_CIPHER_AES_256_CBC:
+ evp = EVP_get_cipherbyname("aes-256-cbc");
+ break;
+
+ case WINPR_CIPHER_AES_128_CFB128:
+ evp = EVP_get_cipherbyname("aes-128-cfb128");
+ break;
+
+ case WINPR_CIPHER_AES_192_CFB128:
+ evp = EVP_get_cipherbyname("aes-192-cfb128");
+ break;
+
+ case WINPR_CIPHER_AES_256_CFB128:
+ evp = EVP_get_cipherbyname("aes-256-cfb128");
+ break;
+
+ case WINPR_CIPHER_AES_128_CTR:
+ evp = EVP_get_cipherbyname("aes-128-ctr");
+ break;
+
+ case WINPR_CIPHER_AES_192_CTR:
+ evp = EVP_get_cipherbyname("aes-192-ctr");
+ break;
+
+ case WINPR_CIPHER_AES_256_CTR:
+ evp = EVP_get_cipherbyname("aes-256-ctr");
+ break;
+
+ case WINPR_CIPHER_AES_128_GCM:
+ evp = EVP_get_cipherbyname("aes-128-gcm");
+ break;
+
+ case WINPR_CIPHER_AES_192_GCM:
+ evp = EVP_get_cipherbyname("aes-192-gcm");
+ break;
+
+ case WINPR_CIPHER_AES_256_GCM:
+ evp = EVP_get_cipherbyname("aes-256-gcm");
+ break;
+
+ case WINPR_CIPHER_AES_128_CCM:
+ evp = EVP_get_cipherbyname("aes-128-ccm");
+ break;
+
+ case WINPR_CIPHER_AES_192_CCM:
+ evp = EVP_get_cipherbyname("aes-192-ccm");
+ break;
+
+ case WINPR_CIPHER_AES_256_CCM:
+ evp = EVP_get_cipherbyname("aes-256-ccm");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_128_ECB:
+ evp = EVP_get_cipherbyname("camellia-128-ecb");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_192_ECB:
+ evp = EVP_get_cipherbyname("camellia-192-ecb");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_256_ECB:
+ evp = EVP_get_cipherbyname("camellia-256-ecb");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_128_CBC:
+ evp = EVP_get_cipherbyname("camellia-128-cbc");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_192_CBC:
+ evp = EVP_get_cipherbyname("camellia-192-cbc");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_256_CBC:
+ evp = EVP_get_cipherbyname("camellia-256-cbc");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_128_CFB128:
+ evp = EVP_get_cipherbyname("camellia-128-cfb128");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_192_CFB128:
+ evp = EVP_get_cipherbyname("camellia-192-cfb128");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_256_CFB128:
+ evp = EVP_get_cipherbyname("camellia-256-cfb128");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_128_CTR:
+ evp = EVP_get_cipherbyname("camellia-128-ctr");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_192_CTR:
+ evp = EVP_get_cipherbyname("camellia-192-ctr");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_256_CTR:
+ evp = EVP_get_cipherbyname("camellia-256-ctr");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_128_GCM:
+ evp = EVP_get_cipherbyname("camellia-128-gcm");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_192_GCM:
+ evp = EVP_get_cipherbyname("camellia-192-gcm");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_256_GCM:
+ evp = EVP_get_cipherbyname("camellia-256-gcm");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_128_CCM:
+ evp = EVP_get_cipherbyname("camellia-128-ccm");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_192_CCM:
+ evp = EVP_get_cipherbyname("camellia-192-gcm");
+ break;
+
+ case WINPR_CIPHER_CAMELLIA_256_CCM:
+ evp = EVP_get_cipherbyname("camellia-256-gcm");
+ break;
+
+ case WINPR_CIPHER_DES_ECB:
+ evp = EVP_get_cipherbyname("des-ecb");
+ break;
+
+ case WINPR_CIPHER_DES_CBC:
+ evp = EVP_get_cipherbyname("des-cbc");
+ break;
+
+ case WINPR_CIPHER_DES_EDE_ECB:
+ evp = EVP_get_cipherbyname("des-ede-ecb");
+ break;
+
+ case WINPR_CIPHER_DES_EDE_CBC:
+ evp = EVP_get_cipherbyname("des-ede-cbc");
+ break;
+
+ case WINPR_CIPHER_DES_EDE3_ECB:
+ evp = EVP_get_cipherbyname("des-ede3-ecb");
+ break;
+
+ case WINPR_CIPHER_DES_EDE3_CBC:
+ evp = EVP_get_cipherbyname("des-ede3-cbc");
+ break;
+
+ case WINPR_CIPHER_ARC4_128:
+ evp = EVP_get_cipherbyname("rc4");
+ break;
+
+ case WINPR_CIPHER_BLOWFISH_ECB:
+ evp = EVP_get_cipherbyname("blowfish-ecb");
+ break;
+
+ case WINPR_CIPHER_BLOWFISH_CBC:
+ evp = EVP_get_cipherbyname("blowfish-cbc");
+ break;
+
+ case WINPR_CIPHER_BLOWFISH_CFB64:
+ evp = EVP_get_cipherbyname("blowfish-cfb64");
+ break;
+
+ case WINPR_CIPHER_BLOWFISH_CTR:
+ evp = EVP_get_cipherbyname("blowfish-ctr");
+ break;
+ }
+
+ return evp;
+}
+
+#elif defined(WITH_MBEDTLS)
+mbedtls_cipher_type_t winpr_mbedtls_get_cipher_type(int cipher)
+{
+ mbedtls_cipher_type_t type = MBEDTLS_CIPHER_NONE;
+
+ switch (cipher)
+ {
+ case WINPR_CIPHER_NONE:
+ type = MBEDTLS_CIPHER_NONE;
+ break;
+
+ case WINPR_CIPHER_NULL:
+ type = MBEDTLS_CIPHER_NULL;
+ break;
+
+ case WINPR_CIPHER_AES_128_ECB:
+ type = MBEDTLS_CIPHER_AES_128_ECB;
+ break;
+
+ case WINPR_CIPHER_AES_192_ECB:
+ type = MBEDTLS_CIPHER_AES_192_ECB;
+ break;
+
+ case WINPR_CIPHER_AES_256_ECB:
+ type = MBEDTLS_CIPHER_AES_256_ECB;
+ break;
+
+ case WINPR_CIPHER_AES_128_CBC:
+ type = MBEDTLS_CIPHER_AES_128_CBC;
+ break;
+
+ case WINPR_CIPHER_AES_192_CBC:
+ type = MBEDTLS_CIPHER_AES_192_CBC;
+ break;
+
+ case WINPR_CIPHER_AES_256_CBC:
+ type = MBEDTLS_CIPHER_AES_256_CBC;
+ break;
+
+ case WINPR_CIPHER_AES_128_CFB128:
+ type = MBEDTLS_CIPHER_AES_128_CFB128;
+ break;
+
+ case WINPR_CIPHER_AES_192_CFB128:
+ type = MBEDTLS_CIPHER_AES_192_CFB128;
+ break;
+
+ case WINPR_CIPHER_AES_256_CFB128:
+ type = MBEDTLS_CIPHER_AES_256_CFB128;
+ break;
+
+ case WINPR_CIPHER_AES_128_CTR:
+ type = MBEDTLS_CIPHER_AES_128_CTR;
+ break;
+
+ case WINPR_CIPHER_AES_192_CTR:
+ type = MBEDTLS_CIPHER_AES_192_CTR;
+ break;
+
+ case WINPR_CIPHER_AES_256_CTR:
+ type = MBEDTLS_CIPHER_AES_256_CTR;
+ break;
+
+ case WINPR_CIPHER_AES_128_GCM:
+ type = MBEDTLS_CIPHER_AES_128_GCM;
+ break;
+
+ case WINPR_CIPHER_AES_192_GCM:
+ type = MBEDTLS_CIPHER_AES_192_GCM;
+ break;
+
+ case WINPR_CIPHER_AES_256_GCM:
+ type = MBEDTLS_CIPHER_AES_256_GCM;
+ break;
+
+ case WINPR_CIPHER_AES_128_CCM:
+ type = MBEDTLS_CIPHER_AES_128_CCM;
+ break;
+
+ case WINPR_CIPHER_AES_192_CCM:
+ type = MBEDTLS_CIPHER_AES_192_CCM;
+ break;
+
+ case WINPR_CIPHER_AES_256_CCM:
+ type = MBEDTLS_CIPHER_AES_256_CCM;
+ break;
+ }
+
+ return type;
+}
+#endif
+
+WINPR_CIPHER_CTX* winpr_Cipher_New(int cipher, int op, const void* key, const void* iv)
+{
+ WINPR_CIPHER_CTX* ctx = NULL;
+#if defined(WITH_OPENSSL)
+ int operation = 0;
+ const EVP_CIPHER* evp = NULL;
+ EVP_CIPHER_CTX* octx = NULL;
+
+ if (!(evp = winpr_openssl_get_evp_cipher(cipher)))
+ return NULL;
+
+ if (!(octx = EVP_CIPHER_CTX_new()))
+ return NULL;
+
+ operation = (op == WINPR_ENCRYPT) ? 1 : 0;
+
+ if (EVP_CipherInit_ex(octx, evp, NULL, key, iv, operation) != 1)
+ {
+ EVP_CIPHER_CTX_free(octx);
+ return NULL;
+ }
+
+ EVP_CIPHER_CTX_set_padding(octx, 0);
+ ctx = (WINPR_CIPHER_CTX*)octx;
+#elif defined(WITH_MBEDTLS)
+ int key_bitlen;
+ mbedtls_operation_t operation;
+ mbedtls_cipher_context_t* mctx;
+ mbedtls_cipher_type_t cipher_type = winpr_mbedtls_get_cipher_type(cipher);
+ const mbedtls_cipher_info_t* cipher_info = mbedtls_cipher_info_from_type(cipher_type);
+
+ if (!cipher_info)
+ return NULL;
+
+ if (!(mctx = (mbedtls_cipher_context_t*)calloc(1, sizeof(mbedtls_cipher_context_t))))
+ return NULL;
+
+ operation = (op == WINPR_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT;
+ mbedtls_cipher_init(mctx);
+
+ if (mbedtls_cipher_setup(mctx, cipher_info) != 0)
+ {
+ free(mctx);
+ return NULL;
+ }
+
+ key_bitlen = mbedtls_cipher_get_key_bitlen(mctx);
+
+ if (mbedtls_cipher_setkey(mctx, key, key_bitlen, operation) != 0)
+ {
+ mbedtls_cipher_free(mctx);
+ free(mctx);
+ return NULL;
+ }
+
+ if (mbedtls_cipher_set_padding_mode(mctx, MBEDTLS_PADDING_NONE) != 0)
+ {
+ mbedtls_cipher_free(mctx);
+ free(mctx);
+ return NULL;
+ }
+
+ ctx = (WINPR_CIPHER_CTX*)mctx;
+#endif
+ return ctx;
+}
+
+BOOL winpr_Cipher_SetPadding(WINPR_CIPHER_CTX* ctx, BOOL enabled)
+{
+ WINPR_ASSERT(ctx);
+
+#if defined(WITH_OPENSSL)
+ EVP_CIPHER_CTX_set_padding((EVP_CIPHER_CTX*)ctx, enabled);
+#elif defined(WITH_MBEDTLS)
+ mbedtls_cipher_padding_t option = enabled ? MBEDTLS_PADDING_PKCS7 : MBEDTLS_PADDING_NONE;
+ if (mbedtls_cipher_set_padding_mode((mbedtls_cipher_context_t*)ctx, option) != 0)
+ return FALSE;
+#else
+ return FALSE;
+#endif
+ return TRUE;
+}
+
+BOOL winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const void* input, size_t ilen, void* output,
+ size_t* olen)
+{
+#if defined(WITH_OPENSSL)
+ int outl = (int)*olen;
+
+ if (ilen > INT_MAX)
+ {
+ WLog_ERR(TAG, "input length %" PRIuz " > %d, abort", ilen, INT_MAX);
+ return FALSE;
+ }
+
+ WINPR_ASSERT(ctx);
+ if (EVP_CipherUpdate((EVP_CIPHER_CTX*)ctx, output, &outl, input, (int)ilen) == 1)
+ {
+ *olen = (size_t)outl;
+ return TRUE;
+ }
+
+#elif defined(WITH_MBEDTLS)
+
+ if (mbedtls_cipher_update((mbedtls_cipher_context_t*)ctx, input, ilen, output, olen) == 0)
+ return TRUE;
+
+#endif
+
+ WLog_ERR(TAG, "Failed to update the data");
+ return FALSE;
+}
+
+BOOL winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, void* output, size_t* olen)
+{
+#if defined(WITH_OPENSSL)
+ int outl = (int)*olen;
+
+ if (EVP_CipherFinal_ex((EVP_CIPHER_CTX*)ctx, output, &outl) == 1)
+ {
+ *olen = (size_t)outl;
+ return TRUE;
+ }
+
+#elif defined(WITH_MBEDTLS)
+
+ if (mbedtls_cipher_finish((mbedtls_cipher_context_t*)ctx, output, olen) == 0)
+ return TRUE;
+
+#endif
+ return FALSE;
+}
+
+void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx)
+{
+ if (!ctx)
+ return;
+
+#if defined(WITH_OPENSSL)
+ EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)ctx);
+#elif defined(WITH_MBEDTLS)
+ mbedtls_cipher_free((mbedtls_cipher_context_t*)ctx);
+ free(ctx);
+#endif
+}
+
+/**
+ * Key Generation
+ */
+
+int winpr_Cipher_BytesToKey(int cipher, WINPR_MD_TYPE md, const void* salt, const void* data,
+ size_t datal, size_t count, void* key, void* iv)
+{
+ /**
+ * Key and IV generation compatible with OpenSSL EVP_BytesToKey():
+ * https://www.openssl.org/docs/manmaster/crypto/EVP_BytesToKey.html
+ */
+#if defined(WITH_OPENSSL)
+ const EVP_MD* evp_md = NULL;
+ const EVP_CIPHER* evp_cipher = NULL;
+ evp_md = winpr_openssl_get_evp_md((WINPR_MD_TYPE)md);
+ evp_cipher = winpr_openssl_get_evp_cipher(cipher);
+ return EVP_BytesToKey(evp_cipher, evp_md, salt, data, datal, count, key, iv);
+#elif defined(WITH_MBEDTLS)
+ int rv = 0;
+ BYTE md_buf[64];
+ int niv, nkey, addmd = 0;
+ unsigned int mds = 0;
+ mbedtls_md_context_t ctx;
+ const mbedtls_md_info_t* md_info;
+ mbedtls_cipher_type_t cipher_type;
+ const mbedtls_cipher_info_t* cipher_info;
+ mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
+ md_info = mbedtls_md_info_from_type(md_type);
+ cipher_type = winpr_mbedtls_get_cipher_type(cipher);
+ cipher_info = mbedtls_cipher_info_from_type(cipher_type);
+ nkey = mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
+ niv = mbedtls_cipher_info_get_iv_size(cipher_info);
+
+ if ((nkey > 64) || (niv > 64))
+ return 0;
+
+ if (!data)
+ return nkey;
+
+ mbedtls_md_init(&ctx);
+
+ if (mbedtls_md_setup(&ctx, md_info, 0) != 0)
+ goto err;
+
+ while (1)
+ {
+ if (mbedtls_md_starts(&ctx) != 0)
+ goto err;
+
+ if (addmd++)
+ {
+ if (mbedtls_md_update(&ctx, md_buf, mds) != 0)
+ goto err;
+ }
+
+ if (mbedtls_md_update(&ctx, data, datal) != 0)
+ goto err;
+
+ if (salt)
+ {
+ if (mbedtls_md_update(&ctx, salt, 8) != 0)
+ goto err;
+ }
+
+ if (mbedtls_md_finish(&ctx, md_buf) != 0)
+ goto err;
+
+ mds = mbedtls_md_get_size(md_info);
+
+ for (unsigned int i = 1; i < (unsigned int)count; i++)
+ {
+ if (mbedtls_md_starts(&ctx) != 0)
+ goto err;
+
+ if (mbedtls_md_update(&ctx, md_buf, mds) != 0)
+ goto err;
+
+ if (mbedtls_md_finish(&ctx, md_buf) != 0)
+ goto err;
+ }
+
+ i = 0;
+
+ if (nkey)
+ {
+ while (1)
+ {
+ if (nkey == 0)
+ break;
+
+ if (i == mds)
+ break;
+
+ if (key)
+ *(BYTE*)(key++) = md_buf[i];
+
+ nkey--;
+ i++;
+ }
+ }
+
+ if (niv && (i != mds))
+ {
+ while (1)
+ {
+ if (niv == 0)
+ break;
+
+ if (i == mds)
+ break;
+
+ if (iv)
+ *(BYTE*)(iv++) = md_buf[i];
+
+ niv--;
+ i++;
+ }
+ }
+
+ if ((nkey == 0) && (niv == 0))
+ break;
+ }
+
+ rv = mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
+err:
+ mbedtls_md_free(&ctx);
+ SecureZeroMemory(md_buf, 64);
+ return rv;
+#else
+ return 0;
+#endif
+}
diff --git a/winpr/libwinpr/crypto/crypto.c b/winpr/libwinpr/crypto/crypto.c
new file mode 100644
index 0000000..26d371f
--- /dev/null
+++ b/winpr/libwinpr/crypto/crypto.c
@@ -0,0 +1,301 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Cryptography API (CryptoAPI)
+ *
+ * Copyright 2012-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crypto.h>
+
+/**
+ * CryptAcquireCertificatePrivateKey
+ * CryptBinaryToStringA
+ * CryptBinaryToStringW
+ * CryptCloseAsyncHandle
+ * CryptCreateAsyncHandle
+ * CryptCreateKeyIdentifierFromCSP
+ * CryptDecodeMessage
+ * CryptDecodeObject
+ * CryptDecodeObjectEx
+ * CryptDecryptAndVerifyMessageSignature
+ * CryptDecryptMessage
+ * CryptEncodeObject
+ * CryptEncodeObjectEx
+ * CryptEncryptMessage
+ * CryptEnumKeyIdentifierProperties
+ * CryptEnumOIDFunction
+ * CryptEnumOIDInfo
+ * CryptExportPKCS8
+ * CryptExportPublicKeyInfo
+ * CryptExportPublicKeyInfoEx
+ * CryptExportPublicKeyInfoFromBCryptKeyHandle
+ * CryptFindCertificateKeyProvInfo
+ * CryptFindLocalizedName
+ * CryptFindOIDInfo
+ * CryptFormatObject
+ * CryptFreeOIDFunctionAddress
+ * CryptGetAsyncParam
+ * CryptGetDefaultOIDDllList
+ * CryptGetDefaultOIDFunctionAddress
+ * CryptGetKeyIdentifierProperty
+ * CryptGetMessageCertificates
+ * CryptGetMessageSignerCount
+ * CryptGetOIDFunctionAddress
+ * CryptGetOIDFunctionValue
+ * CryptHashCertificate
+ * CryptHashCertificate2
+ * CryptHashMessage
+ * CryptHashPublicKeyInfo
+ * CryptHashToBeSigned
+ * CryptImportPKCS8
+ * CryptImportPublicKeyInfo
+ * CryptImportPublicKeyInfoEx
+ * CryptImportPublicKeyInfoEx2
+ * CryptInitOIDFunctionSet
+ * CryptInstallDefaultContext
+ * CryptInstallOIDFunctionAddress
+ * CryptLoadSip
+ * CryptMemAlloc
+ * CryptMemFree
+ * CryptMemRealloc
+ * CryptMsgCalculateEncodedLength
+ * CryptMsgClose
+ * CryptMsgControl
+ * CryptMsgCountersign
+ * CryptMsgCountersignEncoded
+ * CryptMsgDuplicate
+ * CryptMsgEncodeAndSignCTL
+ * CryptMsgGetAndVerifySigner
+ * CryptMsgGetParam
+ * CryptMsgOpenToDecode
+ * CryptMsgOpenToEncode
+ * CryptMsgSignCTL
+ * CryptMsgUpdate
+ * CryptMsgVerifyCountersignatureEncoded
+ * CryptMsgVerifyCountersignatureEncodedEx
+ * CryptQueryObject
+ * CryptRegisterDefaultOIDFunction
+ * CryptRegisterOIDFunction
+ * CryptRegisterOIDInfo
+ * CryptRetrieveTimeStamp
+ * CryptSetAsyncParam
+ * CryptSetKeyIdentifierProperty
+ * CryptSetOIDFunctionValue
+ * CryptSignAndEncodeCertificate
+ * CryptSignAndEncryptMessage
+ * CryptSignCertificate
+ * CryptSignMessage
+ * CryptSignMessageWithKey
+ * CryptSIPAddProvider
+ * CryptSIPCreateIndirectData
+ * CryptSIPGetCaps
+ * CryptSIPGetSignedDataMsg
+ * CryptSIPLoad
+ * CryptSIPPutSignedDataMsg
+ * CryptSIPRemoveProvider
+ * CryptSIPRemoveSignedDataMsg
+ * CryptSIPRetrieveSubjectGuid
+ * CryptSIPRetrieveSubjectGuidForCatalogFile
+ * CryptSIPVerifyIndirectData
+ * CryptUninstallDefaultContext
+ * CryptUnregisterDefaultOIDFunction
+ * CryptUnregisterOIDFunction
+ * CryptUnregisterOIDInfo
+ * CryptUpdateProtectedState
+ * CryptVerifyCertificateSignature
+ * CryptVerifyCertificateSignatureEx
+ * CryptVerifyDetachedMessageHash
+ * CryptVerifyDetachedMessageSignature
+ * CryptVerifyMessageHash
+ * CryptVerifyMessageSignature
+ * CryptVerifyMessageSignatureWithKey
+ * CryptVerifyTimeStampSignature
+ * DbgInitOSS
+ * DbgPrintf
+ * PFXExportCertStore
+ * PFXExportCertStore2
+ * PFXExportCertStoreEx
+ * PFXImportCertStore
+ * PFXIsPFXBlob
+ * PFXVerifyPassword
+ */
+
+#ifndef _WIN32
+
+#include "crypto.h"
+
+#include <winpr/crt.h>
+#include <winpr/collections.h>
+
+static wListDictionary* g_ProtectedMemoryBlocks = NULL;
+
+BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
+{
+ BYTE* pCipherText = NULL;
+ size_t cbOut = 0;
+ size_t cbFinal = 0;
+ WINPR_CIPHER_CTX* enc = NULL;
+ BYTE randomKey[256] = { 0 };
+ WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = NULL;
+
+ if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
+ return FALSE;
+
+ if (!g_ProtectedMemoryBlocks)
+ {
+ g_ProtectedMemoryBlocks = ListDictionary_New(TRUE);
+
+ if (!g_ProtectedMemoryBlocks)
+ return FALSE;
+ }
+
+ pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*)calloc(1, sizeof(WINPR_PROTECTED_MEMORY_BLOCK));
+
+ if (!pMemBlock)
+ return FALSE;
+
+ pMemBlock->pData = pData;
+ pMemBlock->cbData = cbData;
+ pMemBlock->dwFlags = dwFlags;
+
+ winpr_RAND(pMemBlock->salt, 8);
+ winpr_RAND(randomKey, sizeof(randomKey));
+
+ winpr_Cipher_BytesToKey(WINPR_CIPHER_AES_256_CBC, WINPR_MD_SHA1, pMemBlock->salt, randomKey,
+ sizeof(randomKey), 4, pMemBlock->key, pMemBlock->iv);
+
+ SecureZeroMemory(randomKey, sizeof(randomKey));
+
+ cbOut = pMemBlock->cbData + 16 - 1;
+ pCipherText = (BYTE*)calloc(1, cbOut);
+
+ if (!pCipherText)
+ goto out;
+
+ if ((enc = winpr_Cipher_New(WINPR_CIPHER_AES_256_CBC, WINPR_ENCRYPT, pMemBlock->key,
+ pMemBlock->iv)) == NULL)
+ goto out;
+ if (!winpr_Cipher_Update(enc, pMemBlock->pData, pMemBlock->cbData, pCipherText, &cbOut))
+ goto out;
+ if (!winpr_Cipher_Final(enc, pCipherText + cbOut, &cbFinal))
+ goto out;
+ winpr_Cipher_Free(enc);
+
+ CopyMemory(pMemBlock->pData, pCipherText, pMemBlock->cbData);
+ free(pCipherText);
+
+ return ListDictionary_Add(g_ProtectedMemoryBlocks, pData, pMemBlock);
+out:
+ free(pMemBlock);
+ free(pCipherText);
+ winpr_Cipher_Free(enc);
+
+ return FALSE;
+}
+
+BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
+{
+ BYTE* pPlainText = NULL;
+ size_t cbOut = 0;
+ size_t cbFinal = 0;
+ WINPR_CIPHER_CTX* dec = NULL;
+ WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = NULL;
+
+ if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
+ return FALSE;
+
+ if (!g_ProtectedMemoryBlocks)
+ return FALSE;
+
+ pMemBlock =
+ (WINPR_PROTECTED_MEMORY_BLOCK*)ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData);
+
+ if (!pMemBlock)
+ goto out;
+
+ cbOut = pMemBlock->cbData + 16 - 1;
+
+ pPlainText = (BYTE*)malloc(cbOut);
+
+ if (!pPlainText)
+ goto out;
+
+ if ((dec = winpr_Cipher_New(WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT, pMemBlock->key,
+ pMemBlock->iv)) == NULL)
+ goto out;
+ if (!winpr_Cipher_Update(dec, pMemBlock->pData, pMemBlock->cbData, pPlainText, &cbOut))
+ goto out;
+ if (!winpr_Cipher_Final(dec, pPlainText + cbOut, &cbFinal))
+ goto out;
+ winpr_Cipher_Free(dec);
+
+ CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData);
+ SecureZeroMemory(pPlainText, pMemBlock->cbData);
+ free(pPlainText);
+
+ ListDictionary_Remove(g_ProtectedMemoryBlocks, pData);
+
+ free(pMemBlock);
+
+ return TRUE;
+
+out:
+ free(pPlainText);
+ free(pMemBlock);
+ winpr_Cipher_Free(dec);
+ return FALSE;
+}
+
+BOOL CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, DATA_BLOB* pOptionalEntropy,
+ PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags,
+ DATA_BLOB* pDataOut)
+{
+ return TRUE;
+}
+
+BOOL CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, DATA_BLOB* pOptionalEntropy,
+ PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags,
+ DATA_BLOB* pDataOut)
+{
+ return TRUE;
+}
+
+BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
+ DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags)
+{
+ return TRUE;
+}
+
+BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
+ DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags)
+{
+ return TRUE;
+}
+
+BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPWSTR pszString,
+ DWORD* pcchString)
+{
+ return TRUE;
+}
+
+BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString,
+ DWORD* pcchString)
+{
+ return TRUE;
+}
+
+#endif
diff --git a/winpr/libwinpr/crypto/crypto.h b/winpr/libwinpr/crypto/crypto.h
new file mode 100644
index 0000000..c5ec0dd
--- /dev/null
+++ b/winpr/libwinpr/crypto/crypto.h
@@ -0,0 +1,43 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Cryptography API (CryptoAPI)
+ *
+ * Copyright 2012-2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WINPR_CRYPTO_PRIVATE_H
+#define WINPR_CRYPTO_PRIVATE_H
+
+#ifndef _WIN32
+
+typedef struct
+{
+ BYTE* pData;
+ DWORD cbData;
+ DWORD dwFlags;
+ BYTE key[32];
+ BYTE iv[32];
+ BYTE salt[8];
+} WINPR_PROTECTED_MEMORY_BLOCK;
+
+typedef struct
+{
+ LPCSTR lpszStoreProvider;
+ DWORD dwMsgAndCertEncodingType;
+} WINPR_CERTSTORE;
+
+#endif
+
+#endif /* WINPR_CRYPTO_PRIVATE_H */
diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c
new file mode 100644
index 0000000..92ece48
--- /dev/null
+++ b/winpr/libwinpr/crypto/hash.c
@@ -0,0 +1,780 @@
+/**
+ * WinPR: Windows Portable Runtime
+ *
+ * Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/assert.h>
+#include <winpr/crypto.h>
+
+#ifdef WITH_OPENSSL
+#include <openssl/md4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#endif
+#endif
+
+#ifdef WITH_MBEDTLS
+#ifdef MBEDTLS_MD5_C
+#include <mbedtls/md5.h>
+#endif
+#include <mbedtls/sha1.h>
+#include <mbedtls/md.h>
+#if MBEDTLS_VERSION_MAJOR < 3
+#define mbedtls_md_info_from_ctx(_ctx) (_ctx->md_info)
+#endif
+#endif
+
+#if defined(WITH_INTERNAL_MD4)
+#include "md4.h"
+#endif
+
+#if defined(WITH_INTERNAL_MD5)
+#include "md5.h"
+#include "hmac_md5.h"
+#endif
+
+#include "../log.h"
+#define TAG WINPR_TAG("crypto.hash")
+
+/**
+ * HMAC
+ */
+
+#ifdef WITH_OPENSSL
+extern const EVP_MD* winpr_openssl_get_evp_md(WINPR_MD_TYPE md);
+#endif
+
+#ifdef WITH_OPENSSL
+const EVP_MD* winpr_openssl_get_evp_md(WINPR_MD_TYPE md)
+{
+ const char* name = winpr_md_type_to_string(md);
+ if (!name)
+ return NULL;
+ return EVP_get_digestbyname(name);
+}
+#endif
+
+#ifdef WITH_MBEDTLS
+mbedtls_md_type_t winpr_mbedtls_get_md_type(int md)
+{
+ mbedtls_md_type_t type = MBEDTLS_MD_NONE;
+
+ switch (md)
+ {
+ case WINPR_MD_MD5:
+ type = MBEDTLS_MD_MD5;
+ break;
+
+ case WINPR_MD_SHA1:
+ type = MBEDTLS_MD_SHA1;
+ break;
+
+ case WINPR_MD_SHA224:
+ type = MBEDTLS_MD_SHA224;
+ break;
+
+ case WINPR_MD_SHA256:
+ type = MBEDTLS_MD_SHA256;
+ break;
+
+ case WINPR_MD_SHA384:
+ type = MBEDTLS_MD_SHA384;
+ break;
+
+ case WINPR_MD_SHA512:
+ type = MBEDTLS_MD_SHA512;
+ break;
+ }
+
+ return type;
+}
+#endif
+
+struct hash_map
+{
+ const char* name;
+ WINPR_MD_TYPE md;
+};
+static const struct hash_map hashes[] = { { "md2", WINPR_MD_MD2 },
+ { "md4", WINPR_MD_MD4 },
+ { "md5", WINPR_MD_MD5 },
+ { "sha1", WINPR_MD_SHA1 },
+ { "sha224", WINPR_MD_SHA224 },
+ { "sha256", WINPR_MD_SHA256 },
+ { "sha384", WINPR_MD_SHA384 },
+ { "sha512", WINPR_MD_SHA512 },
+ { "sha3_224", WINPR_MD_SHA3_224 },
+ { "sha3_256", WINPR_MD_SHA3_256 },
+ { "sha3_384", WINPR_MD_SHA3_384 },
+ { "sha3_512", WINPR_MD_SHA3_512 },
+ { "shake128", WINPR_MD_SHAKE128 },
+ { "shake256", WINPR_MD_SHAKE256 },
+ { NULL, WINPR_MD_NONE } };
+
+WINPR_MD_TYPE winpr_md_type_from_string(const char* name)
+{
+ const struct hash_map* cur = hashes;
+ while (cur->name)
+ {
+ if (_stricmp(cur->name, name) == 0)
+ return cur->md;
+ cur++;
+ }
+ return WINPR_MD_NONE;
+}
+
+const char* winpr_md_type_to_string(WINPR_MD_TYPE md)
+{
+ const struct hash_map* cur = hashes;
+ while (cur->name)
+ {
+ if (cur->md == md)
+ return cur->name;
+ cur++;
+ }
+ return NULL;
+}
+
+struct winpr_hmac_ctx_private_st
+{
+ WINPR_MD_TYPE md;
+
+#if defined(WITH_INTERNAL_MD5)
+ WINPR_HMAC_MD5_CTX hmac_md5;
+#endif
+#if defined(WITH_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX* xhmac;
+#else
+ HMAC_CTX* hmac;
+#endif
+#endif
+#if defined(WITH_MBEDTLS)
+ mbedtls_md_context_t hmac;
+#endif
+};
+
+WINPR_HMAC_CTX* winpr_HMAC_New(void)
+{
+ WINPR_HMAC_CTX* ctx = (WINPR_HMAC_CTX*)calloc(1, sizeof(WINPR_HMAC_CTX));
+ if (!ctx)
+ return NULL;
+#if defined(WITH_OPENSSL)
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+
+ if (!(ctx->hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX))))
+ goto fail;
+
+ HMAC_CTX_init(ctx->hmac);
+#elif OPENSSL_VERSION_NUMBER < 0x30000000L
+ if (!(ctx->hmac = HMAC_CTX_new()))
+ goto fail;
+#else
+ EVP_MAC* emac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!emac)
+ goto fail;
+ ctx->xhmac = EVP_MAC_CTX_new(emac);
+ EVP_MAC_free(emac);
+ if (!ctx->xhmac)
+ goto fail;
+#endif
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_init(&ctx->hmac);
+#endif
+ return ctx;
+
+fail:
+ WINPR_PRAGMA_DIAG_PUSH
+ WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
+ winpr_HMAC_Free(ctx);
+ WINPR_PRAGMA_DIAG_POP
+ return NULL;
+}
+
+BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const void* key, size_t keylen)
+{
+ WINPR_ASSERT(ctx);
+
+ ctx->md = md;
+ switch (ctx->md)
+ {
+#if defined(WITH_INTERNAL_MD5)
+ case WINPR_MD_MD5:
+ hmac_md5_init(&ctx->hmac_md5, key, keylen);
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+#if defined(WITH_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ const char* hash = winpr_md_type_to_string(md);
+
+ if (!ctx->xhmac)
+ return FALSE;
+
+ const char* param_name = OSSL_MAC_PARAM_DIGEST;
+ const OSSL_PARAM param[] = { OSSL_PARAM_construct_utf8_string(param_name, hash, 0),
+ OSSL_PARAM_construct_end() };
+
+ if (EVP_MAC_init(ctx->xhmac, key, keylen, param) == 1)
+ return TRUE;
+#else
+ HMAC_CTX* hmac = ctx->hmac;
+ const EVP_MD* evp = winpr_openssl_get_evp_md(md);
+
+ if (!evp || !hmac)
+ return FALSE;
+
+ if (keylen > INT_MAX)
+ return FALSE;
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ HMAC_Init_ex(hmac, key, (int)keylen, evp, NULL); /* no return value on OpenSSL 0.9.x */
+ return TRUE;
+#else
+
+ if (HMAC_Init_ex(hmac, key, (int)keylen, evp, NULL) == 1)
+ return TRUE;
+
+#endif
+#endif
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* hmac = &ctx->hmac;
+ mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
+ const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
+
+ if (!md_info || !hmac)
+ return FALSE;
+
+ if (mbedtls_md_info_from_ctx(hmac) != md_info)
+ {
+ mbedtls_md_free(hmac); /* can be called at any time after mbedtls_md_init */
+
+ if (mbedtls_md_setup(hmac, md_info, 1) != 0)
+ return FALSE;
+ }
+
+ if (mbedtls_md_hmac_starts(hmac, key, keylen) == 0)
+ return TRUE;
+
+#endif
+ return FALSE;
+}
+
+BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const void* input, size_t ilen)
+{
+ WINPR_ASSERT(ctx);
+
+ switch (ctx->md)
+ {
+#if defined(WITH_INTERNAL_MD5)
+ case WINPR_MD_MD5:
+ hmac_md5_update(&ctx->hmac_md5, input, ilen);
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+#if defined(WITH_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (EVP_MAC_update(ctx->xhmac, input, ilen) == 1)
+ return TRUE;
+#else
+ HMAC_CTX* hmac = ctx->hmac;
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */
+ return TRUE;
+#else
+
+ if (HMAC_Update(hmac, input, ilen) == 1)
+ return TRUE;
+#endif
+#endif
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* mdctx = &ctx->hmac;
+
+ if (mbedtls_md_hmac_update(mdctx, input, ilen) == 0)
+ return TRUE;
+
+#endif
+ return FALSE;
+}
+
+BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, void* output, size_t olen)
+{
+ WINPR_ASSERT(ctx);
+
+ switch (ctx->md)
+ {
+#if defined(WITH_INTERNAL_MD5)
+ case WINPR_MD_MD5:
+ if (olen < WINPR_MD5_DIGEST_LENGTH)
+ return FALSE;
+ hmac_md5_finalize(&ctx->hmac_md5, output);
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+#if defined(WITH_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ const int rc = EVP_MAC_final(ctx->xhmac, output, NULL, olen);
+ if (rc == 1)
+ return TRUE;
+#else
+ HMAC_CTX* hmac = ctx->hmac;
+#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ HMAC_Final(hmac, output, NULL); /* no return value on OpenSSL 0.9.x */
+ return TRUE;
+#else
+
+ if (HMAC_Final(hmac, output, NULL) == 1)
+ return TRUE;
+
+#endif
+#endif
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* mdctx = &ctx->hmac;
+
+ if (mbedtls_md_hmac_finish(mdctx, output) == 0)
+ return TRUE;
+
+#endif
+ return FALSE;
+}
+
+void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx)
+{
+ if (!ctx)
+ return;
+
+#if defined(WITH_OPENSSL)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX_free(ctx->xhmac);
+#else
+ HMAC_CTX* hmac = ctx->hmac;
+
+ if (hmac)
+ {
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ HMAC_CTX_cleanup(hmac);
+ free(hmac);
+#else
+ HMAC_CTX_free(hmac);
+#endif
+ }
+#endif
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* hmac = &ctx->hmac;
+
+ if (hmac)
+ mbedtls_md_free(hmac);
+
+#endif
+
+ free(ctx);
+}
+
+BOOL winpr_HMAC(WINPR_MD_TYPE md, const void* key, size_t keylen, const void* input, size_t ilen,
+ void* output, size_t olen)
+{
+ BOOL result = FALSE;
+ WINPR_HMAC_CTX* ctx = winpr_HMAC_New();
+
+ if (!ctx)
+ return FALSE;
+
+ if (!winpr_HMAC_Init(ctx, md, key, keylen))
+ goto out;
+
+ if (!winpr_HMAC_Update(ctx, input, ilen))
+ goto out;
+
+ if (!winpr_HMAC_Final(ctx, output, olen))
+ goto out;
+
+ result = TRUE;
+out:
+ winpr_HMAC_Free(ctx);
+ return result;
+}
+
+/**
+ * Generic Digest API
+ */
+
+struct winpr_digest_ctx_private_st
+{
+ WINPR_MD_TYPE md;
+
+#if defined(WITH_INTERNAL_MD4)
+ WINPR_MD4_CTX md4;
+#endif
+#if defined(WITH_INTERNAL_MD5)
+ WINPR_MD5_CTX md5;
+#endif
+#if defined(WITH_OPENSSL)
+ EVP_MD_CTX* mdctx;
+#endif
+#if defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* mdctx;
+#endif
+};
+
+WINPR_DIGEST_CTX* winpr_Digest_New(void)
+{
+ WINPR_DIGEST_CTX* ctx = calloc(1, sizeof(WINPR_DIGEST_CTX));
+ if (!ctx)
+ return NULL;
+
+#if defined(WITH_OPENSSL)
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ ctx->mdctx = EVP_MD_CTX_create();
+#else
+ ctx->mdctx = EVP_MD_CTX_new();
+#endif
+ if (!ctx->mdctx)
+ goto fail;
+
+#elif defined(WITH_MBEDTLS)
+ ctx->mdctx = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t));
+
+ if (!ctx->mdctx)
+ goto fail;
+
+ mbedtls_md_init(ctx->mdctx);
+#endif
+ return ctx;
+
+fail:
+ WINPR_PRAGMA_DIAG_PUSH
+ WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
+ winpr_Digest_Free(ctx);
+ WINPR_PRAGMA_DIAG_POP
+ return NULL;
+}
+
+#if defined(WITH_OPENSSL)
+static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, const EVP_MD* evp)
+{
+ WINPR_ASSERT(ctx);
+ EVP_MD_CTX* mdctx = ctx->mdctx;
+
+ if (!mdctx || !evp)
+ return FALSE;
+
+ if (EVP_DigestInit_ex(mdctx, evp, NULL) != 1)
+ {
+ WLog_ERR(TAG, "Failed to initialize digest %s", winpr_md_type_to_string(ctx->md));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#elif defined(WITH_MBEDTLS)
+static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
+{
+ WINPR_ASSERT(ctx);
+ mbedtls_md_context_t* mdctx = ctx->mdctx;
+ mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md);
+ const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
+
+ if (!md_info)
+ return FALSE;
+
+ if (mbedtls_md_info_from_ctx(mdctx) != md_info)
+ {
+ mbedtls_md_free(mdctx); /* can be called at any time after mbedtls_md_init */
+
+ if (mbedtls_md_setup(mdctx, md_info, 0) != 0)
+ return FALSE;
+ }
+
+ if (mbedtls_md_starts(mdctx) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+#endif
+
+BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
+{
+ WINPR_ASSERT(ctx);
+
+ ctx->md = md;
+ switch (md)
+ {
+ case WINPR_MD_MD5:
+#if defined(WITH_INTERNAL_MD5)
+ winpr_MD5_Init(&ctx->md5);
+ return TRUE;
+#endif
+ break;
+ default:
+ WLog_ERR(TAG, "Invalid FIPS digest %s requested", winpr_md_type_to_string(md));
+ return FALSE;
+ }
+
+#if defined(WITH_OPENSSL)
+ const EVP_MD* evp = winpr_openssl_get_evp_md(md);
+ EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ return winpr_Digest_Init_Internal(ctx, evp);
+#elif defined(WITH_MBEDTLS)
+ return winpr_Digest_Init_Internal(ctx, md);
+#endif
+}
+
+BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md)
+{
+ WINPR_ASSERT(ctx);
+
+ ctx->md = md;
+ switch (md)
+ {
+#if defined(WITH_INTERNAL_MD4)
+ case WINPR_MD_MD4:
+ winpr_MD4_Init(&ctx->md4);
+ return TRUE;
+#endif
+#if defined(WITH_INTERNAL_MD5)
+ case WINPR_MD_MD5:
+ winpr_MD5_Init(&ctx->md5);
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+#if defined(WITH_OPENSSL)
+ const EVP_MD* evp = winpr_openssl_get_evp_md(md);
+ return winpr_Digest_Init_Internal(ctx, evp);
+#else
+ return winpr_Digest_Init_Internal(ctx, md);
+#endif
+}
+
+BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const void* input, size_t ilen)
+{
+ WINPR_ASSERT(ctx);
+
+ switch (ctx->md)
+ {
+#if defined(WITH_INTERNAL_MD4)
+ case WINPR_MD_MD4:
+ winpr_MD4_Update(&ctx->md4, input, ilen);
+ return TRUE;
+#endif
+#if defined(WITH_INTERNAL_MD5)
+ case WINPR_MD_MD5:
+ winpr_MD5_Update(&ctx->md5, input, ilen);
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+#if defined(WITH_OPENSSL)
+ EVP_MD_CTX* mdctx = ctx->mdctx;
+
+ if (EVP_DigestUpdate(mdctx, input, ilen) != 1)
+ return FALSE;
+
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* mdctx = ctx->mdctx;
+
+ if (mbedtls_md_update(mdctx, input, ilen) != 0)
+ return FALSE;
+
+#endif
+ return TRUE;
+}
+
+BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, void* output, size_t olen)
+{
+ WINPR_ASSERT(ctx);
+
+ switch (ctx->md)
+ {
+#if defined(WITH_INTERNAL_MD4)
+ case WINPR_MD_MD4:
+ if (olen < WINPR_MD4_DIGEST_LENGTH)
+ return FALSE;
+ winpr_MD4_Final(output, &ctx->md4);
+ return TRUE;
+#endif
+#if defined(WITH_INTERNAL_MD5)
+ case WINPR_MD_MD5:
+ if (olen < WINPR_MD5_DIGEST_LENGTH)
+ return FALSE;
+ winpr_MD5_Final(output, &ctx->md5);
+ return TRUE;
+#endif
+
+ default:
+ break;
+ }
+
+#if defined(WITH_OPENSSL)
+ EVP_MD_CTX* mdctx = ctx->mdctx;
+
+ if (EVP_DigestFinal_ex(mdctx, output, NULL) == 1)
+ return TRUE;
+
+#elif defined(WITH_MBEDTLS)
+ mbedtls_md_context_t* mdctx = ctx->mdctx;
+
+ if (mbedtls_md_finish(mdctx, output) == 0)
+ return TRUE;
+
+#endif
+ return FALSE;
+}
+
+BOOL winpr_DigestSign_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE digest, void* key)
+{
+ WINPR_ASSERT(ctx);
+
+#if defined(WITH_OPENSSL)
+ const EVP_MD* evp = winpr_openssl_get_evp_md(digest);
+ if (!evp)
+ return FALSE;
+
+ const int rdsi = EVP_DigestSignInit(ctx->mdctx, NULL, evp, NULL, key);
+ if (rdsi <= 0)
+ return FALSE;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+BOOL winpr_DigestSign_Update(WINPR_DIGEST_CTX* ctx, const void* input, size_t ilen)
+{
+ WINPR_ASSERT(ctx);
+
+#if defined(WITH_OPENSSL)
+ EVP_MD_CTX* mdctx = ctx->mdctx;
+
+ if (EVP_DigestSignUpdate(mdctx, input, ilen) != 1)
+ return FALSE;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+BOOL winpr_DigestSign_Final(WINPR_DIGEST_CTX* ctx, void* output, size_t* piolen)
+{
+ WINPR_ASSERT(ctx);
+
+#if defined(WITH_OPENSSL)
+ EVP_MD_CTX* mdctx = ctx->mdctx;
+
+ return EVP_DigestSignFinal(mdctx, output, piolen) == 1;
+#else
+ return FALSE;
+#endif
+}
+
+void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx)
+{
+ if (!ctx)
+ return;
+#if defined(WITH_OPENSSL)
+ if (ctx->mdctx)
+ {
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ EVP_MD_CTX_destroy(ctx->mdctx);
+#else
+ EVP_MD_CTX_free(ctx->mdctx);
+#endif
+ }
+
+#elif defined(WITH_MBEDTLS)
+ if (ctx->mdctx)
+ {
+ mbedtls_md_free(ctx->mdctx);
+ free(ctx->mdctx);
+ }
+
+#endif
+ free(ctx);
+}
+
+BOOL winpr_Digest_Allow_FIPS(WINPR_MD_TYPE md, const void* input, size_t ilen, void* output,
+ size_t olen)
+{
+ BOOL result = FALSE;
+ WINPR_DIGEST_CTX* ctx = winpr_Digest_New();
+
+ if (!ctx)
+ return FALSE;
+
+ if (!winpr_Digest_Init_Allow_FIPS(ctx, md))
+ goto out;
+
+ if (!winpr_Digest_Update(ctx, input, ilen))
+ goto out;
+
+ if (!winpr_Digest_Final(ctx, output, olen))
+ goto out;
+
+ result = TRUE;
+out:
+ winpr_Digest_Free(ctx);
+ return result;
+}
+
+BOOL winpr_Digest(WINPR_MD_TYPE md, const void* input, size_t ilen, void* output, size_t olen)
+{
+ BOOL result = FALSE;
+ WINPR_DIGEST_CTX* ctx = winpr_Digest_New();
+
+ if (!ctx)
+ return FALSE;
+
+ if (!winpr_Digest_Init(ctx, md))
+ goto out;
+
+ if (!winpr_Digest_Update(ctx, input, ilen))
+ goto out;
+
+ if (!winpr_Digest_Final(ctx, output, olen))
+ goto out;
+
+ result = TRUE;
+out:
+ winpr_Digest_Free(ctx);
+ return result;
+}
diff --git a/winpr/libwinpr/crypto/hmac_md5.c b/winpr/libwinpr/crypto/hmac_md5.c
new file mode 100644
index 0000000..5550bbd
--- /dev/null
+++ b/winpr/libwinpr/crypto/hmac_md5.c
@@ -0,0 +1,57 @@
+#include <assert.h>
+#include <string.h>
+
+#include "hmac_md5.h"
+#include "md5.h"
+#include <string.h>
+
+void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* key, size_t key_len)
+{
+ const WINPR_HMAC_MD5_CTX empty = { 0 };
+ unsigned char k_ipad[KEY_IOPAD_SIZE] = { 0 };
+ unsigned char k_opad[KEY_IOPAD_SIZE] = { 0 };
+
+ assert(ctx);
+ *ctx = empty;
+
+ if (key_len <= KEY_IOPAD_SIZE)
+ {
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+ }
+ else
+ {
+ WINPR_MD5_CTX lctx = { 0 };
+
+ winpr_MD5_Init(&lctx);
+ winpr_MD5_Update(&lctx, key, key_len);
+ winpr_MD5_Final(k_ipad, &lctx);
+ memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE);
+ }
+ for (size_t i = 0; i < KEY_IOPAD_SIZE; i++)
+ {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ winpr_MD5_Init(&ctx->icontext);
+ winpr_MD5_Update(&ctx->icontext, k_ipad, KEY_IOPAD_SIZE);
+
+ winpr_MD5_Init(&ctx->ocontext);
+ winpr_MD5_Update(&ctx->ocontext, k_opad, KEY_IOPAD_SIZE);
+}
+
+void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* text, size_t text_len)
+{
+ assert(ctx);
+ winpr_MD5_Update(&ctx->icontext, text, text_len);
+}
+
+void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac)
+{
+ assert(ctx);
+ winpr_MD5_Final(hmac, &ctx->icontext);
+
+ winpr_MD5_Update(&ctx->ocontext, hmac, 16);
+ winpr_MD5_Final(hmac, &ctx->ocontext);
+}
diff --git a/winpr/libwinpr/crypto/hmac_md5.h b/winpr/libwinpr/crypto/hmac_md5.h
new file mode 100644
index 0000000..8ade3e4
--- /dev/null
+++ b/winpr/libwinpr/crypto/hmac_md5.h
@@ -0,0 +1,19 @@
+#ifndef WINPR_HMAC_MD5
+#define WINPR_HMAC_MD5
+
+#include <stddef.h>
+
+#include "md5.h"
+
+#define KEY_IOPAD_SIZE 64
+typedef struct
+{
+ WINPR_MD5_CTX icontext;
+ WINPR_MD5_CTX ocontext;
+} WINPR_HMAC_MD5_CTX;
+
+void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* key, size_t key_len);
+void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* text, size_t text_len);
+void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac);
+
+#endif
diff --git a/winpr/libwinpr/crypto/md4.c b/winpr/libwinpr/crypto/md4.c
new file mode 100644
index 0000000..0743805
--- /dev/null
+++ b/winpr/libwinpr/crypto/md4.c
@@ -0,0 +1,275 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD4 Message-Digest Algorithm (RFC 1320).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible. Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#include <string.h>
+
+#include "md4.h"
+
+/*
+ * The basic MD4 functions.
+ *
+ * F and G are optimized compared to their RFC 1320 definitions, with the
+ * optimization for F borrowed from Colin Plumb's MD5 implementation.
+ */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The MD4 transformation for all three rounds.
+ */
+#define STEP(f, a, b, c, d, x, s) \
+ (a) += f((b), (c), (d)) + (x); \
+ (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s))));
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them in a
+ * properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned memory
+ * accesses is just an optimization. Nothing will break if it fails to detect
+ * a suitable architecture.
+ *
+ * Unfortunately, this optimization may be a C strict aliasing rules violation
+ * if the caller's data buffer has effective type that cannot be aliased by
+ * winpr_MD4_u32plus. In practice, this problem may occur if these MD4 routines are
+ * inlined into a calling function, or with future and dangerously advanced
+ * link-time optimizations. For the time being, keeping these MD4 routines in
+ * their own translation unit avoids the problem.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) (*(const winpr_MD4_u32plus*)&ptr[(n)*4])
+#define GET(n) SET(n)
+#else
+#define SET(n) \
+ (ctx->block[(n)] = (winpr_MD4_u32plus)ptr[(n)*4] | ((winpr_MD4_u32plus)ptr[(n)*4 + 1] << 8) | \
+ ((winpr_MD4_u32plus)ptr[(n)*4 + 2] << 16) | \
+ ((winpr_MD4_u32plus)ptr[(n)*4 + 3] << 24))
+#define GET(n) (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update the bit
+ * counters. There are no alignment requirements.
+ */
+static const void* body(WINPR_MD4_CTX* ctx, const void* data, unsigned long size)
+{
+ const unsigned char* ptr = NULL;
+ winpr_MD4_u32plus a = 0;
+ winpr_MD4_u32plus b = 0;
+ winpr_MD4_u32plus c = 0;
+ winpr_MD4_u32plus d = 0;
+ winpr_MD4_u32plus saved_a = 0;
+ winpr_MD4_u32plus saved_b = 0;
+ winpr_MD4_u32plus saved_c = 0;
+ winpr_MD4_u32plus saved_d = 0;
+ const winpr_MD4_u32plus ac1 = 0x5a827999;
+ const winpr_MD4_u32plus ac2 = 0x6ed9eba1;
+
+ ptr = (const unsigned char*)data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do
+ {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ /* Round 1 */
+ STEP(F, a, b, c, d, SET(0), 3)
+ STEP(F, d, a, b, c, SET(1), 7)
+ STEP(F, c, d, a, b, SET(2), 11)
+ STEP(F, b, c, d, a, SET(3), 19)
+ STEP(F, a, b, c, d, SET(4), 3)
+ STEP(F, d, a, b, c, SET(5), 7)
+ STEP(F, c, d, a, b, SET(6), 11)
+ STEP(F, b, c, d, a, SET(7), 19)
+ STEP(F, a, b, c, d, SET(8), 3)
+ STEP(F, d, a, b, c, SET(9), 7)
+ STEP(F, c, d, a, b, SET(10), 11)
+ STEP(F, b, c, d, a, SET(11), 19)
+ STEP(F, a, b, c, d, SET(12), 3)
+ STEP(F, d, a, b, c, SET(13), 7)
+ STEP(F, c, d, a, b, SET(14), 11)
+ STEP(F, b, c, d, a, SET(15), 19)
+
+ /* Round 2 */
+ STEP(G, a, b, c, d, GET(0) + ac1, 3)
+ STEP(G, d, a, b, c, GET(4) + ac1, 5)
+ STEP(G, c, d, a, b, GET(8) + ac1, 9)
+ STEP(G, b, c, d, a, GET(12) + ac1, 13)
+ STEP(G, a, b, c, d, GET(1) + ac1, 3)
+ STEP(G, d, a, b, c, GET(5) + ac1, 5)
+ STEP(G, c, d, a, b, GET(9) + ac1, 9)
+ STEP(G, b, c, d, a, GET(13) + ac1, 13)
+ STEP(G, a, b, c, d, GET(2) + ac1, 3)
+ STEP(G, d, a, b, c, GET(6) + ac1, 5)
+ STEP(G, c, d, a, b, GET(10) + ac1, 9)
+ STEP(G, b, c, d, a, GET(14) + ac1, 13)
+ STEP(G, a, b, c, d, GET(3) + ac1, 3)
+ STEP(G, d, a, b, c, GET(7) + ac1, 5)
+ STEP(G, c, d, a, b, GET(11) + ac1, 9)
+ STEP(G, b, c, d, a, GET(15) + ac1, 13)
+
+ /* Round 3 */
+ STEP(H, a, b, c, d, GET(0) + ac2, 3)
+ STEP(H, d, a, b, c, GET(8) + ac2, 9)
+ STEP(H, c, d, a, b, GET(4) + ac2, 11)
+ STEP(H, b, c, d, a, GET(12) + ac2, 15)
+ STEP(H, a, b, c, d, GET(2) + ac2, 3)
+ STEP(H, d, a, b, c, GET(10) + ac2, 9)
+ STEP(H, c, d, a, b, GET(6) + ac2, 11)
+ STEP(H, b, c, d, a, GET(14) + ac2, 15)
+ STEP(H, a, b, c, d, GET(1) + ac2, 3)
+ STEP(H, d, a, b, c, GET(9) + ac2, 9)
+ STEP(H, c, d, a, b, GET(5) + ac2, 11)
+ STEP(H, b, c, d, a, GET(13) + ac2, 15)
+ STEP(H, a, b, c, d, GET(3) + ac2, 3)
+ STEP(H, d, a, b, c, GET(11) + ac2, 9)
+ STEP(H, c, d, a, b, GET(7) + ac2, 11)
+ STEP(H, b, c, d, a, GET(15) + ac2, 15)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return ptr;
+}
+
+void winpr_MD4_Init(WINPR_MD4_CTX* ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->lo = 0;
+ ctx->hi = 0;
+}
+
+void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, unsigned long size)
+{
+ winpr_MD4_u32plus saved_lo = 0;
+ unsigned long used = 0;
+ unsigned long available = 0;
+
+ saved_lo = ctx->lo;
+ if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+ ctx->hi++;
+ ctx->hi += size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if (used)
+ {
+ available = 64 - used;
+
+ if (size < available)
+ {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, available);
+ data = (const unsigned char*)data + available;
+ size -= available;
+ body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64)
+ {
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+#define OUT(dst, src) \
+ (dst)[0] = (unsigned char)(src); \
+ (dst)[1] = (unsigned char)((src) >> 8); \
+ (dst)[2] = (unsigned char)((src) >> 16); \
+ (dst)[3] = (unsigned char)((src) >> 24);
+
+void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx)
+{
+ unsigned long used = 0;
+ unsigned long available = 0;
+
+ used = ctx->lo & 0x3f;
+
+ ctx->buffer[used++] = 0x80;
+
+ available = 64 - used;
+
+ if (available < 8)
+ {
+ memset(&ctx->buffer[used], 0, available);
+ body(ctx, ctx->buffer, 64);
+ used = 0;
+ available = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, available - 8);
+
+ ctx->lo <<= 3;
+ OUT(&ctx->buffer[56], ctx->lo)
+ OUT(&ctx->buffer[60], ctx->hi)
+
+ body(ctx, ctx->buffer, 64);
+
+ OUT(&result[0], ctx->a)
+ OUT(&result[4], ctx->b)
+ OUT(&result[8], ctx->c)
+ OUT(&result[12], ctx->d)
+
+ memset(ctx, 0, sizeof(*ctx));
+}
diff --git a/winpr/libwinpr/crypto/md4.h b/winpr/libwinpr/crypto/md4.h
new file mode 100644
index 0000000..1ea008e
--- /dev/null
+++ b/winpr/libwinpr/crypto/md4.h
@@ -0,0 +1,46 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD4 Message-Digest Algorithm (RFC 1320).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md4.c for more information.
+ */
+
+#if !defined(WINPR_MD4_H)
+#define WINPR_MD4_H
+
+#include <winpr/wtypes.h>
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef UINT32 winpr_MD4_u32plus;
+
+typedef struct
+{
+ winpr_MD4_u32plus lo, hi;
+ winpr_MD4_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ winpr_MD4_u32plus block[16];
+} WINPR_MD4_CTX;
+
+extern void winpr_MD4_Init(WINPR_MD4_CTX* ctx);
+extern void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, unsigned long size);
+extern void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx);
+
+#endif
diff --git a/winpr/libwinpr/crypto/md5.c b/winpr/libwinpr/crypto/md5.c
new file mode 100644
index 0000000..f98a542
--- /dev/null
+++ b/winpr/libwinpr/crypto/md5.c
@@ -0,0 +1,295 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible. Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#include <string.h>
+
+#include "md5.h"
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) (((x) ^ (y)) ^ (z))
+#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them in a
+ * properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned memory
+ * accesses is just an optimization. Nothing will break if it fails to detect
+ * a suitable architecture.
+ *
+ * Unfortunately, this optimization may be a C strict aliasing rules violation
+ * if the caller's data buffer has effective type that cannot be aliased by
+ * MD5_u32plus. In practice, this problem may occur if these MD5 routines are
+ * inlined into a calling function, or with future and dangerously advanced
+ * link-time optimizations. For the time being, keeping these MD5 routines in
+ * their own translation unit avoids the problem.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) (*(const winpr_MD5_u32plus*)&ptr[(n)*4])
+#define GET(n) SET(n)
+#else
+#define SET(n) \
+ (ctx->block[(n)] = (winpr_MD5_u32plus)ptr[(n)*4] | ((winpr_MD5_u32plus)ptr[(n)*4 + 1] << 8) | \
+ ((winpr_MD5_u32plus)ptr[(n)*4 + 2] << 16) | \
+ ((winpr_MD5_u32plus)ptr[(n)*4 + 3] << 24))
+#define GET(n) (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update the bit
+ * counters. There are no alignment requirements.
+ */
+static const void* body(WINPR_MD5_CTX* ctx, const void* data, unsigned long size)
+{
+ const unsigned char* ptr = NULL;
+ winpr_MD5_u32plus a = 0;
+ winpr_MD5_u32plus b = 0;
+ winpr_MD5_u32plus c = 0;
+ winpr_MD5_u32plus d = 0;
+ winpr_MD5_u32plus saved_a = 0;
+ winpr_MD5_u32plus saved_b = 0;
+ winpr_MD5_u32plus saved_c = 0;
+ winpr_MD5_u32plus saved_d = 0;
+
+ ptr = (const unsigned char*)data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do
+ {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ /* Round 1 */
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+ /* Round 2 */
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+ /* Round 3 */
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+ /* Round 4 */
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return ptr;
+}
+
+void winpr_MD5_Init(WINPR_MD5_CTX* ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->lo = 0;
+ ctx->hi = 0;
+}
+
+void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, unsigned long size)
+{
+ winpr_MD5_u32plus saved_lo = 0;
+ unsigned long used = 0;
+ unsigned long available = 0;
+
+ saved_lo = ctx->lo;
+ if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+ ctx->hi++;
+ ctx->hi += size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if (used)
+ {
+ available = 64 - used;
+
+ if (size < available)
+ {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, available);
+ data = (const unsigned char*)data + available;
+ size -= available;
+ body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64)
+ {
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+#define OUT(dst, src) \
+ (dst)[0] = (unsigned char)(src); \
+ (dst)[1] = (unsigned char)((src) >> 8); \
+ (dst)[2] = (unsigned char)((src) >> 16); \
+ (dst)[3] = (unsigned char)((src) >> 24);
+
+void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx)
+{
+ unsigned long used = 0;
+ unsigned long available = 0;
+
+ used = ctx->lo & 0x3f;
+
+ ctx->buffer[used++] = 0x80;
+
+ available = 64 - used;
+
+ if (available < 8)
+ {
+ memset(&ctx->buffer[used], 0, available);
+ body(ctx, ctx->buffer, 64);
+ used = 0;
+ available = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, available - 8);
+
+ ctx->lo <<= 3;
+ OUT(&ctx->buffer[56], ctx->lo)
+ OUT(&ctx->buffer[60], ctx->hi)
+
+ body(ctx, ctx->buffer, 64);
+
+ OUT(&result[0], ctx->a)
+ OUT(&result[4], ctx->b)
+ OUT(&result[8], ctx->c)
+ OUT(&result[12], ctx->d)
+
+ memset(ctx, 0, sizeof(*ctx));
+}
diff --git a/winpr/libwinpr/crypto/md5.h b/winpr/libwinpr/crypto/md5.h
new file mode 100644
index 0000000..2056b9a
--- /dev/null
+++ b/winpr/libwinpr/crypto/md5.h
@@ -0,0 +1,48 @@
+
+
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
+ */
+
+#if !defined(WINPR_MD5_H)
+#define WINPR_MD5_H
+
+#include <winpr/wtypes.h>
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef UINT32 winpr_MD5_u32plus;
+
+typedef struct
+{
+ winpr_MD5_u32plus lo, hi;
+ winpr_MD5_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ winpr_MD5_u32plus block[16];
+} WINPR_MD5_CTX;
+
+extern void winpr_MD5_Init(WINPR_MD5_CTX* ctx);
+extern void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, unsigned long size);
+extern void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx);
+
+#endif
diff --git a/winpr/libwinpr/crypto/rand.c b/winpr/libwinpr/crypto/rand.c
new file mode 100644
index 0000000..41fe06f
--- /dev/null
+++ b/winpr/libwinpr/crypto/rand.c
@@ -0,0 +1,83 @@
+/**
+ * WinPR: Windows Portable Runtime
+ *
+ * Copyright 2015 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+
+#include <winpr/crypto.h>
+
+#ifdef WITH_OPENSSL
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+#endif
+
+#ifdef WITH_MBEDTLS
+#include <mbedtls/md.h>
+#include <mbedtls/entropy.h>
+#ifdef MBEDTLS_HAVEGE_C
+#include <mbedtls/havege.h>
+#endif
+#include <mbedtls/hmac_drbg.h>
+#endif
+
+int winpr_RAND(void* output, size_t len)
+{
+#if defined(WITH_OPENSSL)
+ if (len > INT_MAX)
+ return -1;
+ if (RAND_bytes(output, (int)len) != 1)
+ return -1;
+#elif defined(WITH_MBEDTLS)
+#if defined(MBEDTLS_HAVEGE_C)
+ mbedtls_havege_state hs;
+ mbedtls_havege_init(&hs);
+
+ if (mbedtls_havege_random(&hs, output, len) != 0)
+ return -1;
+
+ mbedtls_havege_free(&hs);
+#else
+ int status;
+ mbedtls_entropy_context entropy;
+ mbedtls_hmac_drbg_context hmac_drbg;
+ const mbedtls_md_info_t* md_info;
+
+ mbedtls_entropy_init(&entropy);
+ mbedtls_hmac_drbg_init(&hmac_drbg);
+
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+ if ((status = mbedtls_hmac_drbg_seed(&hmac_drbg, md_info, mbedtls_entropy_func, &entropy, NULL,
+ 0)) != 0)
+ return -1;
+
+ status = mbedtls_hmac_drbg_random(&hmac_drbg, output, len);
+ mbedtls_hmac_drbg_free(&hmac_drbg);
+ mbedtls_entropy_free(&entropy);
+
+ if (status != 0)
+ return -1;
+#endif
+#endif
+ return 0;
+}
+
+int winpr_RAND_pseudo(void* output, size_t len)
+{
+ return winpr_RAND(output, len);
+}
diff --git a/winpr/libwinpr/crypto/rc4.c b/winpr/libwinpr/crypto/rc4.c
new file mode 100644
index 0000000..e170785
--- /dev/null
+++ b/winpr/libwinpr/crypto/rc4.c
@@ -0,0 +1,88 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * RC4 implementation for RDP
+ *
+ * Copyright 2023 Armin Novak <anovak@thincast.com>
+ * Copyright 2023 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <winpr/assert.h>
+
+#include "rc4.h"
+
+#define CTX_SIZE 256
+
+struct winpr_int_rc4_ctx
+{
+ size_t i;
+ size_t j;
+ BYTE s[CTX_SIZE];
+ BYTE t[CTX_SIZE];
+};
+
+static void swap(BYTE* p1, BYTE* p2)
+{
+ BYTE t = *p1;
+ *p1 = *p2;
+ *p2 = t;
+}
+
+winpr_int_RC4_CTX* winpr_int_rc4_new(const BYTE* key, size_t keylength)
+{
+ winpr_int_RC4_CTX* ctx = calloc(1, sizeof(winpr_int_RC4_CTX));
+ if (!ctx)
+ return NULL;
+
+ for (size_t i = 0; i < CTX_SIZE; i++)
+ {
+ ctx->s[i] = i;
+ ctx->t[i] = key[i % keylength];
+ }
+
+ size_t j = 0;
+ for (size_t i = 0; i < CTX_SIZE; i++)
+ {
+ j = (j + ctx->s[i] + ctx->t[i]) % CTX_SIZE;
+ swap(&ctx->s[i], &ctx->s[j]);
+ }
+ return ctx;
+}
+
+void winpr_int_rc4_free(winpr_int_RC4_CTX* ctx)
+{
+ free(ctx);
+}
+
+BOOL winpr_int_rc4_update(winpr_int_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output)
+{
+ WINPR_ASSERT(ctx);
+
+ UINT32 t1 = ctx->i;
+ UINT32 t2 = ctx->j;
+ for (size_t i = 0; i < length; i++)
+ {
+ t1 = (t1 + 1) % CTX_SIZE;
+ t2 = (t2 + ctx->s[t1]) % CTX_SIZE;
+ swap(&ctx->s[t1], &ctx->s[t2]);
+
+ const size_t idx = ((size_t)ctx->s[t1] + ctx->s[t2]) % CTX_SIZE;
+ const BYTE val = ctx->s[idx];
+ const BYTE out = *input++ ^ val;
+ *output++ = out;
+ }
+
+ ctx->i = t1;
+ ctx->j = t2;
+ return TRUE;
+}
diff --git a/winpr/libwinpr/crypto/rc4.h b/winpr/libwinpr/crypto/rc4.h
new file mode 100644
index 0000000..63c9954
--- /dev/null
+++ b/winpr/libwinpr/crypto/rc4.h
@@ -0,0 +1,34 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * RC4 implementation for RDP
+ *
+ * Copyright 2023 Armin Novak <anovak@thincast.com>
+ * Copyright 2023 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef WINPR_RC4_H
+#define WINPR_RC4_H
+
+#include <winpr/wtypes.h>
+#include <winpr/winpr.h>
+
+typedef struct winpr_int_rc4_ctx winpr_int_RC4_CTX;
+
+void winpr_int_rc4_free(winpr_int_RC4_CTX* ctx);
+
+WINPR_ATTR_MALLOC(winpr_int_rc4_free, 1)
+winpr_int_RC4_CTX* winpr_int_rc4_new(const BYTE* key, size_t keylength);
+BOOL winpr_int_rc4_update(winpr_int_RC4_CTX* ctx, size_t length, const BYTE* input, BYTE* output);
+
+#endif
diff --git a/winpr/libwinpr/crypto/test/CMakeLists.txt b/winpr/libwinpr/crypto/test/CMakeLists.txt
new file mode 100644
index 0000000..4fb9aa0
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/CMakeLists.txt
@@ -0,0 +1,34 @@
+
+set(MODULE_NAME "TestCrypto")
+set(MODULE_PREFIX "TEST_CRYPTO")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestCryptoHash.c
+ TestCryptoRand.c
+ TestCryptoCipher.c
+ TestCryptoProtectData.c
+ TestCryptoProtectMemory.c
+ TestCryptoCertEnumCertificatesInStore.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+if(WIN32)
+ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} secur32 crypt32 cryptui)
+endif()
+
+target_link_libraries(${MODULE_NAME} winpr)
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
diff --git a/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c b/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c
new file mode 100644
index 0000000..6b40c8d
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c
@@ -0,0 +1,86 @@
+
+
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/crypto.h>
+
+#ifdef _WIN32
+//#define WITH_CRYPTUI 1
+#endif
+
+#ifdef WITH_CRYPTUI
+#include <cryptuiapi.h>
+#endif
+
+int TestCryptoCertEnumCertificatesInStore(int argc, char* argv[])
+{
+ int index = 0;
+ DWORD status = 0;
+ LPTSTR pszNameString = NULL;
+ HCERTSTORE hCertStore = NULL;
+ PCCERT_CONTEXT pCertContext = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ /**
+ * System Store Locations:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa388136/
+ */
+
+ /**
+ * Requires elevated rights:
+ * hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, (HCRYPTPROV_LEGACY) NULL,
+ * CERT_SYSTEM_STORE_LOCAL_MACHINE, _T("Remote Desktop"));
+ */
+
+ hCertStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL, _T("MY"));
+ // hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, (HCRYPTPROV_LEGACY) NULL,
+ // CERT_SYSTEM_STORE_CURRENT_USER, _T("MY"));
+
+ if (!hCertStore)
+ {
+ printf("Failed to open system store\n");
+ return -1;
+ }
+
+ index = 0;
+
+ while ((pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext)))
+ {
+ status = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0);
+ if (status == 0)
+ return -1;
+
+ pszNameString = (LPTSTR)calloc(status, sizeof(TCHAR));
+ if (!pszNameString)
+ {
+ printf("Unable to allocate memory\n");
+ return -1;
+ }
+
+ status = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL,
+ pszNameString, status);
+ if (status == 0)
+ {
+ free(pszNameString);
+ return -1;
+ }
+
+ _tprintf(_T("Certificate #%d: %s\n"), index++, pszNameString);
+
+ free(pszNameString);
+
+#ifdef WITH_CRYPTUI
+ CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT, pCertContext, NULL, NULL, 0, NULL);
+#endif
+ }
+
+ if (!CertCloseStore(hCertStore, 0))
+ {
+ printf("Failed to close system store\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/winpr/libwinpr/crypto/test/TestCryptoCipher.c b/winpr/libwinpr/crypto/test/TestCryptoCipher.c
new file mode 100644
index 0000000..518b443
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/TestCryptoCipher.c
@@ -0,0 +1,232 @@
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/crypto.h>
+#include <winpr/ssl.h>
+
+static BOOL test_crypto_cipher_aes_128_cbc(void)
+{
+ WINPR_CIPHER_CTX* ctx = NULL;
+ BOOL result = FALSE;
+ BYTE key[] = "0123456789abcdeF";
+ BYTE iv[] = "1234567887654321";
+ BYTE ibuf[1024] = { 0 };
+ BYTE obuf[1024] = { 0 };
+ size_t ilen = 0;
+ size_t olen = 0;
+ size_t xlen = 0;
+ const char plaintext[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua.";
+
+ /* encrypt */
+
+ if (!(ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, iv)))
+ {
+ fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __func__);
+ return FALSE;
+ }
+
+ ilen = strnlen(plaintext, sizeof(plaintext)) + 1;
+ memcpy(ibuf, plaintext, ilen);
+
+ ilen = ((ilen + 15) / 16) * 16;
+ olen = 0;
+ xlen = 0;
+
+ if (!winpr_Cipher_Update(ctx, ibuf, ilen, obuf, &olen))
+ {
+ fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __func__);
+ goto out;
+ }
+ xlen += olen;
+
+ if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
+ {
+ fprintf(stderr, "%s: winpr_Cipher_Final (encrypt) failed\n", __func__);
+ goto out;
+ }
+ xlen += olen;
+
+ if (xlen != ilen)
+ {
+ fprintf(stderr, "%s: error, xlen (%" PRIuz ") != ilen (%" PRIuz ") (encrypt)\n", __func__,
+ xlen, ilen);
+ goto out;
+ }
+
+ winpr_Cipher_Free(ctx);
+
+ /* decrypt */
+
+ if (!(ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, key, iv)))
+ {
+ fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __func__);
+ return FALSE;
+ }
+
+ memset(ibuf, 0, sizeof(ibuf));
+ memcpy(ibuf, obuf, xlen);
+ memset(obuf, 0, sizeof(obuf));
+
+ ilen = xlen;
+ olen = 0;
+ xlen = 0;
+
+ if (!winpr_Cipher_Update(ctx, ibuf, ilen, obuf, &olen))
+ {
+ fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __func__);
+ goto out;
+ }
+ xlen += olen;
+
+ if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
+ {
+ fprintf(stderr, "%s: winpr_Cipher_Final (decrypt) failed\n", __func__);
+ goto out;
+ }
+ xlen += olen;
+
+ if (xlen != ilen)
+ {
+ fprintf(stderr, "%s: error, xlen (%" PRIuz ") != ilen (%" PRIuz ") (decrypt)\n", __func__,
+ xlen, ilen);
+ goto out;
+ }
+
+ if (strcmp((const char*)obuf, plaintext))
+ {
+ fprintf(stderr, "%s: error, decrypted data does not match plaintext\n", __func__);
+ goto out;
+ }
+
+ result = TRUE;
+
+out:
+ winpr_Cipher_Free(ctx);
+ return result;
+}
+
+static const BYTE* TEST_RC4_KEY = (BYTE*)"Key";
+static const char* TEST_RC4_PLAINTEXT = "Plaintext";
+static const BYTE* TEST_RC4_CIPHERTEXT = (BYTE*)"\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3";
+
+static BOOL test_crypto_cipher_rc4(void)
+{
+ size_t len = 0;
+ BOOL rc = FALSE;
+ BYTE* text = NULL;
+ WINPR_RC4_CTX* ctx = NULL;
+
+ len = strnlen(TEST_RC4_PLAINTEXT, sizeof(TEST_RC4_PLAINTEXT));
+
+ if (!(text = (BYTE*)calloc(1, len)))
+ {
+ fprintf(stderr, "%s: failed to allocate text buffer (len=%" PRIuz ")\n", __func__, len);
+ goto out;
+ }
+
+ if ((ctx = winpr_RC4_New(TEST_RC4_KEY,
+ strnlen((const char*)TEST_RC4_KEY, sizeof(TEST_RC4_KEY)))) == NULL)
+ {
+ fprintf(stderr, "%s: winpr_RC4_New failed\n", __func__);
+ goto out;
+ }
+ rc = winpr_RC4_Update(ctx, len, (const BYTE*)TEST_RC4_PLAINTEXT, text);
+ winpr_RC4_Free(ctx);
+ if (!rc)
+ {
+ fprintf(stderr, "%s: winpr_RC4_Update failed\n", __func__);
+ goto out;
+ }
+
+ if (memcmp(text, TEST_RC4_CIPHERTEXT, len) != 0)
+ {
+ char* actual = NULL;
+ char* expected = NULL;
+
+ actual = winpr_BinToHexString(text, len, FALSE);
+ expected = winpr_BinToHexString(TEST_RC4_CIPHERTEXT, len, FALSE);
+
+ fprintf(stderr, "%s: unexpected RC4 ciphertext: Actual: %s Expected: %s\n", __func__,
+ actual, expected);
+
+ free(actual);
+ free(expected);
+ goto out;
+ }
+
+ rc = TRUE;
+
+out:
+ free(text);
+ return rc;
+}
+
+static const BYTE* TEST_RAND_DATA =
+ (BYTE*)"\x1F\xC2\xEE\x4C\xA3\x66\x80\xA2\xCE\xFE\x56\xB4\x9E\x08\x30\x96"
+ "\x33\x6A\xA9\x6D\x36\xFD\x3C\xB7\x83\x04\x4E\x5E\xDC\x22\xCD\xF3"
+ "\x48\xDF\x3A\x2A\x61\xF1\xA8\xFA\x1F\xC6\xC7\x1B\x81\xB4\xE1\x0E"
+ "\xCB\xA2\xEF\xA1\x12\x4A\x83\xE5\x1D\x72\x1D\x2D\x26\xA8\x6B\xC0";
+
+static const BYTE* TEST_CIPHER_KEY =
+ (BYTE*)"\x9D\x7C\xC0\xA1\x94\x3B\x07\x67\x2F\xD3\x83\x10\x51\x83\x38\x0E"
+ "\x1C\x74\x8C\x4E\x15\x79\xD6\xFF\xE2\xF0\x37\x7F\x8C\xD7\xD2\x13";
+
+static const BYTE* TEST_CIPHER_IV =
+ (BYTE*)"\xFE\xE3\x9F\xF0\xD1\x5E\x37\x0C\xAB\xAB\x9B\x04\xF3\xDB\x99\x15";
+
+static BOOL test_crypto_cipher_key(void)
+{
+ int status = 0;
+ BYTE key[32] = { 0 };
+ BYTE iv[16] = { 0 };
+ BYTE salt[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
+
+ status = winpr_Cipher_BytesToKey(WINPR_CIPHER_AES_256_CBC, WINPR_MD_SHA1, salt, TEST_RAND_DATA,
+ 64, 4, key, iv);
+
+ if (status != 32 || memcmp(key, TEST_CIPHER_KEY, 32) || memcmp(iv, TEST_CIPHER_IV, 16))
+ {
+ char* akstr = NULL;
+ char* ekstr = NULL;
+ char* aivstr = NULL;
+ char* eivstr = NULL;
+
+ akstr = winpr_BinToHexString(key, 32, 0);
+ ekstr = winpr_BinToHexString(TEST_CIPHER_KEY, 32, 0);
+
+ aivstr = winpr_BinToHexString(iv, 16, 0);
+ eivstr = winpr_BinToHexString(TEST_CIPHER_IV, 16, 0);
+
+ fprintf(stderr, "Unexpected EVP_BytesToKey Key: Actual: %s, Expected: %s\n", akstr, ekstr);
+ fprintf(stderr, "Unexpected EVP_BytesToKey IV : Actual: %s, Expected: %s\n", aivstr,
+ eivstr);
+
+ free(akstr);
+ free(ekstr);
+ free(aivstr);
+ free(eivstr);
+ }
+
+ return TRUE;
+}
+
+int TestCryptoCipher(int argc, char* argv[])
+{
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
+
+ if (!test_crypto_cipher_aes_128_cbc())
+ return -1;
+
+ if (!test_crypto_cipher_rc4())
+ return -1;
+
+ if (!test_crypto_cipher_key())
+ return -1;
+
+ return 0;
+}
diff --git a/winpr/libwinpr/crypto/test/TestCryptoHash.c b/winpr/libwinpr/crypto/test/TestCryptoHash.c
new file mode 100644
index 0000000..3057b9f
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/TestCryptoHash.c
@@ -0,0 +1,316 @@
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/crypto.h>
+#include <winpr/ssl.h>
+
+static const char TEST_MD5_DATA[] = "test";
+static const BYTE TEST_MD5_HASH[] =
+ "\x09\x8f\x6b\xcd\x46\x21\xd3\x73\xca\xde\x4e\x83\x26\x27\xb4\xf6";
+
+static BOOL test_crypto_hash_md5(void)
+{
+ BOOL result = FALSE;
+ BYTE hash[WINPR_MD5_DIGEST_LENGTH] = { 0 };
+ WINPR_DIGEST_CTX* ctx = NULL;
+
+ if (!(ctx = winpr_Digest_New()))
+ {
+ fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
+ return FALSE;
+ }
+ if (!winpr_Digest_Init(ctx, WINPR_MD_MD5))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Init failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_Digest_Update(ctx, (const BYTE*)TEST_MD5_DATA,
+ strnlen(TEST_MD5_DATA, sizeof(TEST_MD5_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
+ goto out;
+ }
+ if (memcmp(hash, TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
+ {
+ char* actual = NULL;
+ char* expected = NULL;
+
+ actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE);
+ expected = winpr_BinToHexString(TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE);
+
+ fprintf(stderr, "unexpected MD5 hash: Actual: %s Expected: %s\n", actual, expected);
+
+ free(actual);
+ free(expected);
+
+ goto out;
+ }
+
+ result = TRUE;
+out:
+ winpr_Digest_Free(ctx);
+ return result;
+}
+
+static const char TEST_MD4_DATA[] = "test";
+static const BYTE TEST_MD4_HASH[] =
+ "\xdb\x34\x6d\x69\x1d\x7a\xcc\x4d\xc2\x62\x5d\xb1\x9f\x9e\x3f\x52";
+
+static BOOL test_crypto_hash_md4(void)
+{
+ BOOL result = FALSE;
+ BYTE hash[WINPR_MD4_DIGEST_LENGTH] = { 0 };
+ WINPR_DIGEST_CTX* ctx = NULL;
+
+ if (!(ctx = winpr_Digest_New()))
+ {
+ fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
+ return FALSE;
+ }
+ if (!winpr_Digest_Init(ctx, WINPR_MD_MD4))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Init failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_Digest_Update(ctx, (const BYTE*)TEST_MD4_DATA,
+ strnlen(TEST_MD4_DATA, sizeof(TEST_MD4_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
+ goto out;
+ }
+ if (memcmp(hash, TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH) != 0)
+ {
+ char* actual = NULL;
+ char* expected = NULL;
+
+ actual = winpr_BinToHexString(hash, WINPR_MD4_DIGEST_LENGTH, FALSE);
+ expected = winpr_BinToHexString(TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH, FALSE);
+
+ fprintf(stderr, "unexpected MD4 hash: Actual: %s Expected: %s\n", actual, expected);
+
+ free(actual);
+ free(expected);
+
+ goto out;
+ }
+
+ result = TRUE;
+out:
+ winpr_Digest_Free(ctx);
+ return result;
+}
+
+static const char TEST_SHA1_DATA[] = "test";
+static const BYTE TEST_SHA1_HASH[] =
+ "\xa9\x4a\x8f\xe5\xcc\xb1\x9b\xa6\x1c\x4c\x08\x73\xd3\x91\xe9\x87\x98\x2f\xbb\xd3";
+
+static BOOL test_crypto_hash_sha1(void)
+{
+ BOOL result = FALSE;
+ BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = { 0 };
+ WINPR_DIGEST_CTX* ctx = NULL;
+
+ if (!(ctx = winpr_Digest_New()))
+ {
+ fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
+ return FALSE;
+ }
+ if (!winpr_Digest_Init(ctx, WINPR_MD_SHA1))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Init failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_Digest_Update(ctx, (const BYTE*)TEST_SHA1_DATA,
+ strnlen(TEST_SHA1_DATA, sizeof(TEST_SHA1_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
+ {
+ fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
+ goto out;
+ }
+
+ if (memcmp(hash, TEST_SHA1_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
+ {
+ char* actual = NULL;
+ char* expected = NULL;
+
+ actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE);
+ expected = winpr_BinToHexString(TEST_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE);
+
+ fprintf(stderr, "unexpected SHA1 hash: Actual: %s Expected: %s\n", actual, expected);
+
+ free(actual);
+ free(expected);
+
+ goto out;
+ }
+
+ result = TRUE;
+out:
+ winpr_Digest_Free(ctx);
+ return result;
+}
+
+static const char TEST_HMAC_MD5_DATA[] = "Hi There";
+static const BYTE TEST_HMAC_MD5_KEY[] =
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
+static const BYTE TEST_HMAC_MD5_HASH[] =
+ "\xb5\x79\x91\xa2\x20\x3d\x49\x2d\x73\xfb\x71\x43\xdf\xc5\x08\x28";
+
+static BOOL test_crypto_hash_hmac_md5(void)
+{
+ BYTE hash[WINPR_MD5_DIGEST_LENGTH] = { 0 };
+ WINPR_HMAC_CTX* ctx = NULL;
+ BOOL result = FALSE;
+
+ if (!(ctx = winpr_HMAC_New()))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_New failed\n", __func__);
+ return FALSE;
+ }
+
+ if (!winpr_HMAC_Init(ctx, WINPR_MD_MD5, TEST_HMAC_MD5_KEY, WINPR_MD5_DIGEST_LENGTH))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Init failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_MD5_DATA,
+ strnlen(TEST_HMAC_MD5_DATA, sizeof(TEST_HMAC_MD5_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_MD5_DATA,
+ strnlen(TEST_HMAC_MD5_DATA, sizeof(TEST_HMAC_MD5_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_HMAC_Final(ctx, hash, sizeof(hash)))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __func__);
+ goto out;
+ }
+
+ if (memcmp(hash, TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
+ {
+ char* actual = NULL;
+ char* expected = NULL;
+
+ actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE);
+ expected = winpr_BinToHexString(TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE);
+
+ fprintf(stderr, "unexpected HMAC-MD5 hash: Actual: %s Expected: %s\n", actual, expected);
+
+ free(actual);
+ free(expected);
+
+ goto out;
+ }
+
+ result = TRUE;
+out:
+ winpr_HMAC_Free(ctx);
+ return result;
+}
+
+static const char TEST_HMAC_SHA1_DATA[] = "Hi There";
+static const BYTE TEST_HMAC_SHA1_KEY[] =
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";
+static const BYTE TEST_HMAC_SHA1_HASH[] =
+ "\xab\x23\x08\x2d\xca\x0c\x75\xea\xca\x60\x09\xc0\xb8\x8c\x2d\xf4\xf4\xbf\x88\xee";
+
+static BOOL test_crypto_hash_hmac_sha1(void)
+{
+ BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = { 0 };
+ WINPR_HMAC_CTX* ctx = NULL;
+ BOOL result = FALSE;
+
+ if (!(ctx = winpr_HMAC_New()))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_New failed\n", __func__);
+ return FALSE;
+ }
+
+ if (!winpr_HMAC_Init(ctx, WINPR_MD_SHA1, TEST_HMAC_SHA1_KEY, WINPR_SHA1_DIGEST_LENGTH))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Init failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_SHA1_DATA,
+ strnlen(TEST_HMAC_SHA1_DATA, sizeof(TEST_HMAC_SHA1_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_SHA1_DATA,
+ strnlen(TEST_HMAC_SHA1_DATA, sizeof(TEST_HMAC_SHA1_DATA))))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
+ goto out;
+ }
+ if (!winpr_HMAC_Final(ctx, hash, sizeof(hash)))
+ {
+ fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __func__);
+ goto out;
+ }
+
+ if (memcmp(hash, TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH) != 0)
+ {
+ char* actual = NULL;
+ char* expected = NULL;
+
+ actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE);
+ expected = winpr_BinToHexString(TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE);
+
+ fprintf(stderr, "unexpected HMAC-SHA1 hash: Actual: %s Expected: %s\n", actual, expected);
+
+ free(actual);
+ free(expected);
+
+ goto out;
+ }
+
+ result = TRUE;
+out:
+ winpr_HMAC_Free(ctx);
+ return result;
+}
+
+int TestCryptoHash(int argc, char* argv[])
+{
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
+
+ if (!test_crypto_hash_md5())
+ return -1;
+
+ if (!test_crypto_hash_md4())
+ return -1;
+
+ if (!test_crypto_hash_sha1())
+ return -1;
+
+ if (!test_crypto_hash_hmac_md5())
+ return -1;
+
+ if (!test_crypto_hash_hmac_sha1())
+ return -1;
+
+ return 0;
+}
diff --git a/winpr/libwinpr/crypto/test/TestCryptoProtectData.c b/winpr/libwinpr/crypto/test/TestCryptoProtectData.c
new file mode 100644
index 0000000..45ef3e0
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/TestCryptoProtectData.c
@@ -0,0 +1,10 @@
+
+
+#include <winpr/crt.h>
+#include <winpr/tchar.h>
+#include <winpr/crypto.h>
+
+int TestCryptoProtectData(int argc, char* argv[])
+{
+ return 0;
+}
diff --git a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c
new file mode 100644
index 0000000..d904c7f
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c
@@ -0,0 +1,55 @@
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/crypto.h>
+#include <winpr/ssl.h>
+#include <winpr/wlog.h>
+
+static const char* SECRET_PASSWORD_TEST = "MySecretPassword123!";
+
+int TestCryptoProtectMemory(int argc, char* argv[])
+{
+ UINT32 cbPlainText = 0;
+ UINT32 cbCipherText = 0;
+ const char* pPlainText = NULL;
+ BYTE* pCipherText = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ pPlainText = SECRET_PASSWORD_TEST;
+ cbPlainText = strlen(pPlainText) + 1;
+ cbCipherText = cbPlainText +
+ (CRYPTPROTECTMEMORY_BLOCK_SIZE - (cbPlainText % CRYPTPROTECTMEMORY_BLOCK_SIZE));
+ printf("cbPlainText: %" PRIu32 " cbCipherText: %" PRIu32 "\n", cbPlainText, cbCipherText);
+ pCipherText = (BYTE*)malloc(cbCipherText);
+ if (!pCipherText)
+ {
+ printf("Unable to allocate memory\n");
+ return -1;
+ }
+ CopyMemory(pCipherText, pPlainText, cbPlainText);
+ ZeroMemory(&pCipherText[cbPlainText], (cbCipherText - cbPlainText));
+ winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
+
+ if (!CryptProtectMemory(pCipherText, cbCipherText, CRYPTPROTECTMEMORY_SAME_PROCESS))
+ {
+ printf("CryptProtectMemory failure\n");
+ return -1;
+ }
+
+ printf("PlainText: %s (cbPlainText = %" PRIu32 ", cbCipherText = %" PRIu32 ")\n", pPlainText,
+ cbPlainText, cbCipherText);
+ winpr_HexDump("crypto.test", WLOG_DEBUG, pCipherText, cbCipherText);
+
+ if (!CryptUnprotectMemory(pCipherText, cbCipherText, CRYPTPROTECTMEMORY_SAME_PROCESS))
+ {
+ printf("CryptUnprotectMemory failure\n");
+ return -1;
+ }
+
+ printf("Decrypted CipherText: %s\n", pCipherText);
+ SecureZeroMemory(pCipherText, cbCipherText);
+ free(pCipherText);
+ return 0;
+}
diff --git a/winpr/libwinpr/crypto/test/TestCryptoRand.c b/winpr/libwinpr/crypto/test/TestCryptoRand.c
new file mode 100644
index 0000000..7dde55e
--- /dev/null
+++ b/winpr/libwinpr/crypto/test/TestCryptoRand.c
@@ -0,0 +1,26 @@
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/crypto.h>
+
+int TestCryptoRand(int argc, char* argv[])
+{
+ char* str = NULL;
+ BYTE rnd[16] = { 0 };
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ winpr_RAND(rnd, sizeof(rnd));
+
+ str = winpr_BinToHexString(rnd, sizeof(rnd), FALSE);
+ // fprintf(stderr, "Rand: %s\n", str);
+ free(str);
+
+ if (memcmp(rnd, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}