diff options
Diffstat (limited to 'winpr/libwinpr/crypto')
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; +} |