Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,50 @@
# 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_system_include_directory_add(${OPENSSL_INCLUDE_DIR})
winpr_library_add_private(${OPENSSL_LIBRARIES})
endif()
if(MBEDTLS_FOUND)
winpr_system_include_directory_add(${MBEDTLS_INCLUDE_DIR})
winpr_library_add_private(${MBEDTLS_LIBRARIES})
endif()
if(WIN32)
winpr_library_add_public(crypt32)
endif()
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,7 @@
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")

View File

@@ -0,0 +1,239 @@
/**
* 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/wlog.h>
#include <winpr/wincrypt.h>
#ifndef _WIN32
#include "crypto.h"
HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType,
WINPR_ATTR_UNUSED HCRYPTPROV_LEGACY hCryptProv,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED const void* pvPara)
{
WINPR_CERTSTORE* certstore = nullptr;
certstore = (WINPR_CERTSTORE*)calloc(1, sizeof(WINPR_CERTSTORE));
if (certstore)
{
certstore->lpszStoreProvider = lpszStoreProvider;
certstore->dwMsgAndCertEncodingType = dwMsgAndCertEncodingType;
}
return (HCERTSTORE)certstore;
}
HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
WINPR_ATTR_UNUSED LPCWSTR szSubsystemProtocol)
{
HCERTSTORE hCertStore = nullptr;
hCertStore = CertOpenStore(CERT_STORE_PROV_FILE, X509_ASN_ENCODING, hProv, 0, nullptr);
return hCertStore;
}
HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
WINPR_ATTR_UNUSED LPCSTR szSubsystemProtocol)
{
return CertOpenSystemStoreW(hProv, nullptr);
}
BOOL CertCloseStore(HCERTSTORE hCertStore, WINPR_ATTR_UNUSED DWORD dwFlags)
{
WINPR_CERTSTORE* certstore = nullptr;
certstore = (WINPR_CERTSTORE*)hCertStore;
free(certstore);
return TRUE;
}
PCCERT_CONTEXT CertFindCertificateInStore(WINPR_ATTR_UNUSED HCERTSTORE hCertStore,
WINPR_ATTR_UNUSED DWORD dwCertEncodingType,
WINPR_ATTR_UNUSED DWORD dwFindFlags,
WINPR_ATTR_UNUSED DWORD dwFindType,
WINPR_ATTR_UNUSED const void* pvFindPara,
WINPR_ATTR_UNUSED PCCERT_CONTEXT pPrevCertContext)
{
WLog_ERR("TODO", "TODO: Implement");
return (PCCERT_CONTEXT)1;
}
PCCERT_CONTEXT CertEnumCertificatesInStore(WINPR_ATTR_UNUSED HCERTSTORE hCertStore,
WINPR_ATTR_UNUSED PCCERT_CONTEXT pPrevCertContext)
{
WLog_ERR("TODO", "TODO: Implement");
return (PCCERT_CONTEXT) nullptr;
}
DWORD CertGetNameStringW(WINPR_ATTR_UNUSED PCCERT_CONTEXT pCertContext,
WINPR_ATTR_UNUSED DWORD dwType, WINPR_ATTR_UNUSED DWORD dwFlags,
WINPR_ATTR_UNUSED void* pvTypePara, WINPR_ATTR_UNUSED LPWSTR pszNameString,
WINPR_ATTR_UNUSED DWORD cchNameString)
{
WLog_ERR("TODO", "TODO: Implement");
return 0;
}
DWORD CertGetNameStringA(WINPR_ATTR_UNUSED PCCERT_CONTEXT pCertContext,
WINPR_ATTR_UNUSED DWORD dwType, WINPR_ATTR_UNUSED DWORD dwFlags,
WINPR_ATTR_UNUSED void* pvTypePara, WINPR_ATTR_UNUSED LPSTR pszNameString,
WINPR_ATTR_UNUSED DWORD cchNameString)
{
WLog_ERR("TODO", "TODO: Implement");
return 0;
}
#endif

View File

@@ -0,0 +1,881 @@
/**
* 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
struct winpr_cipher_ctx_private_st
{
WINPR_CIPHER_TYPE cipher;
WINPR_CRYPTO_OPERATION op;
#ifdef WITH_OPENSSL
EVP_CIPHER_CTX* ectx;
#endif
#ifdef WITH_MBEDTLS
mbedtls_cipher_context_t* mctx;
#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 nullptr;
WINPR_RC4_CTX* ctx = (WINPR_RC4_CTX*)calloc(1, sizeof(WINPR_RC4_CTX));
if (!ctx)
return nullptr;
#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 = nullptr;
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, nullptr, nullptr, nullptr) != 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, nullptr, nullptr, key, nullptr) != 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 nullptr;
}
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
struct cipher_map
{
WINPR_CIPHER_TYPE md;
const char* name;
};
static const struct cipher_map s_cipher_map[] = {
{ WINPR_CIPHER_NONE, "none" },
{ WINPR_CIPHER_NULL, "null" },
{ WINPR_CIPHER_AES_128_ECB, "aes-128-ecb" },
{ WINPR_CIPHER_AES_192_ECB, "aes-192-ecb" },
{ WINPR_CIPHER_AES_256_ECB, "aes-256-ecb" },
{ WINPR_CIPHER_AES_128_CBC, "aes-128-cbc" },
{ WINPR_CIPHER_AES_192_CBC, "aes-192-cbc" },
{ WINPR_CIPHER_AES_256_CBC, "aes-256-cbc" },
{ WINPR_CIPHER_AES_128_CFB128, "aes-128-cfb128" },
{ WINPR_CIPHER_AES_192_CFB128, "aes-192-cfb128" },
{ WINPR_CIPHER_AES_256_CFB128, "aes-256-cfb128" },
{ WINPR_CIPHER_AES_128_CTR, "aes-128-ctr" },
{ WINPR_CIPHER_AES_192_CTR, "aes-192-ctr" },
{ WINPR_CIPHER_AES_256_CTR, "aes-256-ctr" },
{ WINPR_CIPHER_AES_128_GCM, "aes-128-gcm" },
{ WINPR_CIPHER_AES_192_GCM, "aes-192-gcm" },
{ WINPR_CIPHER_AES_256_GCM, "aes-256-gcm" },
{ WINPR_CIPHER_CAMELLIA_128_ECB, "camellia-128-ecb" },
{ WINPR_CIPHER_CAMELLIA_192_ECB, "camellia-192-ecb" },
{ WINPR_CIPHER_CAMELLIA_256_ECB, "camellia-256-ecb" },
{ WINPR_CIPHER_CAMELLIA_128_CBC, "camellia-128-cbc" },
{ WINPR_CIPHER_CAMELLIA_192_CBC, "camellia-192-cbc" },
{ WINPR_CIPHER_CAMELLIA_256_CBC, "camellia-256-cbc" },
{ WINPR_CIPHER_CAMELLIA_128_CFB128, "camellia-128-cfb128" },
{ WINPR_CIPHER_CAMELLIA_192_CFB128, "camellia-192-cfb128" },
{ WINPR_CIPHER_CAMELLIA_256_CFB128, "camellia-256-cfb128" },
{ WINPR_CIPHER_CAMELLIA_128_CTR, "camellia-128-ctr" },
{ WINPR_CIPHER_CAMELLIA_192_CTR, "camellia-192-ctr" },
{ WINPR_CIPHER_CAMELLIA_256_CTR, "camellia-256-ctr" },
{ WINPR_CIPHER_CAMELLIA_128_GCM, "camellia-128-gcm" },
{ WINPR_CIPHER_CAMELLIA_192_GCM, "camellia-192-gcm" },
{ WINPR_CIPHER_CAMELLIA_256_GCM, "camellia-256-gcm" },
{ WINPR_CIPHER_DES_ECB, "des-ecb" },
{ WINPR_CIPHER_DES_CBC, "des-cbc" },
{ WINPR_CIPHER_DES_EDE_ECB, "des-ede-ecb" },
{ WINPR_CIPHER_DES_EDE_CBC, "des-ede-cbc" },
{ WINPR_CIPHER_DES_EDE3_ECB, "des-ede3-ecb" },
{ WINPR_CIPHER_DES_EDE3_CBC, "des-ede3-cbc" },
{ WINPR_CIPHER_BLOWFISH_ECB, "blowfish-ecb" },
{ WINPR_CIPHER_BLOWFISH_CBC, "blowfish-cbc" },
{ WINPR_CIPHER_BLOWFISH_CFB64, "blowfish-cfb64" },
{ WINPR_CIPHER_BLOWFISH_CTR, "blowfish-ctr" },
{ WINPR_CIPHER_ARC4_128, "rc4" },
{ WINPR_CIPHER_AES_128_CCM, "aes-128-ccm" },
{ WINPR_CIPHER_AES_192_CCM, "aes-192-ccm" },
{ WINPR_CIPHER_AES_256_CCM, "aes-256-ccm" },
{ WINPR_CIPHER_CAMELLIA_128_CCM, "camellia-128-ccm" },
{ WINPR_CIPHER_CAMELLIA_192_CCM, "camellia-192-ccm" },
{ WINPR_CIPHER_CAMELLIA_256_CCM, "camellia-256-ccm" },
};
static int cipher_compare(const void* a, const void* b)
{
const WINPR_CIPHER_TYPE* cipher = a;
const struct cipher_map* map = b;
if (*cipher == map->md)
return 0;
return *cipher > map->md ? 1 : -1;
}
const char* winpr_cipher_type_to_string(WINPR_CIPHER_TYPE md)
{
WINPR_CIPHER_TYPE lc = md;
const struct cipher_map* ret = bsearch(&lc, s_cipher_map, ARRAYSIZE(s_cipher_map),
sizeof(struct cipher_map), cipher_compare);
if (!ret)
return "unknown";
return ret->name;
}
static int cipher_string_compare(const void* a, const void* b)
{
const char* cipher = a;
const struct cipher_map* map = b;
return strcmp(cipher, map->name);
}
WINPR_CIPHER_TYPE winpr_cipher_type_from_string(const char* name)
{
const struct cipher_map* ret = bsearch(name, s_cipher_map, ARRAYSIZE(s_cipher_map),
sizeof(struct cipher_map), cipher_string_compare);
if (!ret)
return WINPR_CIPHER_NONE;
return ret->md;
}
#if defined(WITH_OPENSSL)
static const EVP_CIPHER* winpr_openssl_get_evp_cipher(WINPR_CIPHER_TYPE cipher)
{
const EVP_CIPHER* evp = nullptr;
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-ccm");
break;
case WINPR_CIPHER_CAMELLIA_256_CCM:
evp = EVP_get_cipherbyname("camellia-256-ccm");
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;
default:
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
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
WINPR_CIPHER_CTX* winpr_Cipher_New(WINPR_CIPHER_TYPE cipher, WINPR_CRYPTO_OPERATION op,
const void* key, const void* iv)
{
return winpr_Cipher_NewEx(cipher, op, key, 0, iv, 0);
}
#endif
WINPR_API WINPR_CIPHER_CTX* winpr_Cipher_NewEx(WINPR_CIPHER_TYPE cipher, WINPR_CRYPTO_OPERATION op,
const void* key, WINPR_ATTR_UNUSED size_t keylen,
const void* iv, WINPR_ATTR_UNUSED size_t ivlen)
{
if (cipher == WINPR_CIPHER_ARC4_128)
{
WLog_ERR(TAG,
"WINPR_CIPHER_ARC4_128 (RC4) cipher not supported, use winpr_RC4_new instead");
return nullptr;
}
WINPR_CIPHER_CTX* ctx = calloc(1, sizeof(WINPR_CIPHER_CTX));
if (!ctx)
return nullptr;
ctx->cipher = cipher;
ctx->op = op;
#if defined(WITH_OPENSSL)
const EVP_CIPHER* evp = winpr_openssl_get_evp_cipher(cipher);
if (!evp)
goto fail;
ctx->ectx = EVP_CIPHER_CTX_new();
if (!ctx->ectx)
goto fail;
{
const int operation = (op == WINPR_ENCRYPT) ? 1 : 0;
if (EVP_CipherInit_ex(ctx->ectx, evp, nullptr, key, iv, operation) != 1)
goto fail;
}
EVP_CIPHER_CTX_set_padding(ctx->ectx, 0);
#elif defined(WITH_MBEDTLS)
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)
goto fail;
ctx->mctx = calloc(1, sizeof(mbedtls_cipher_context_t));
if (!ctx->mctx)
goto fail;
const mbedtls_operation_t operation = (op == WINPR_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT;
mbedtls_cipher_init(ctx->mctx);
if (mbedtls_cipher_setup(ctx->mctx, cipher_info) != 0)
goto fail;
const int key_bitlen = mbedtls_cipher_get_key_bitlen(ctx->mctx);
if (mbedtls_cipher_setkey(ctx->mctx, key, key_bitlen, operation) != 0)
goto fail;
if (mbedtls_cipher_set_padding_mode(ctx->mctx, MBEDTLS_PADDING_NONE) != 0)
goto fail;
#endif
return ctx;
fail:
winpr_Cipher_Free(ctx);
return nullptr;
}
BOOL winpr_Cipher_SetPadding(WINPR_CIPHER_CTX* ctx, BOOL enabled)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
if (!ctx->ectx)
return FALSE;
EVP_CIPHER_CTX_set_padding(ctx->ectx, 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)
{
WINPR_ASSERT(ctx);
WINPR_ASSERT(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->ectx);
if (EVP_CipherUpdate(ctx->ectx, output, &outl, input, (int)ilen) == 1)
{
*olen = (size_t)outl;
return TRUE;
}
#elif defined(WITH_MBEDTLS)
WINPR_ASSERT(ctx->mctx);
if (mbedtls_cipher_update(ctx->mctx, 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)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
int outl = (int)*olen;
WINPR_ASSERT(ctx->ectx);
if (EVP_CipherFinal_ex(ctx->ectx, output, &outl) == 1)
{
*olen = (size_t)outl;
return TRUE;
}
#elif defined(WITH_MBEDTLS)
WINPR_ASSERT(ctx->mctx);
if (mbedtls_cipher_finish(ctx->mctx, output, olen) == 0)
return TRUE;
#endif
return FALSE;
}
void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx)
{
if (!ctx)
return;
#if defined(WITH_OPENSSL)
if (ctx->ectx)
EVP_CIPHER_CTX_free(ctx->ectx);
#elif defined(WITH_MBEDTLS)
if (ctx->mctx)
{
mbedtls_cipher_free(ctx->mctx);
free(ctx->mctx);
}
#endif
free(ctx);
}
/**
* 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 = nullptr;
const EVP_CIPHER* evp_cipher = nullptr;
evp_md = winpr_openssl_get_evp_md(md);
evp_cipher = winpr_openssl_get_evp_cipher(WINPR_ASSERTING_INT_CAST(WINPR_CIPHER_TYPE, cipher));
WINPR_ASSERT(datal <= INT_MAX);
WINPR_ASSERT(count <= INT_MAX);
return EVP_BytesToKey(evp_cipher, evp_md, salt, data, (int)datal, (int)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;
}
unsigned int 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
}

View File

@@ -0,0 +1,324 @@
/**
* 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/wlog.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 = nullptr;
BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
{
BYTE* pCipherText = nullptr;
size_t cbOut = 0;
size_t cbFinal = 0;
WINPR_CIPHER_CTX* enc = nullptr;
BYTE randomKey[256] = WINPR_C_ARRAY_INIT;
WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = nullptr;
if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
return FALSE;
if (winpr_RAND(randomKey, sizeof(randomKey)) < 0)
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;
if (winpr_RAND(pMemBlock->salt, 8) < 0)
goto out;
if (winpr_Cipher_BytesToKey(WINPR_CIPHER_AES_256_CBC, WINPR_MD_SHA1, pMemBlock->salt, randomKey,
sizeof(randomKey), 4, pMemBlock->key, pMemBlock->iv) <= 0)
goto out;
SecureZeroMemory(randomKey, sizeof(randomKey));
cbOut = pMemBlock->cbData + 16 - 1;
pCipherText = (BYTE*)calloc(1, cbOut);
if (!pCipherText)
goto out;
if ((enc = winpr_Cipher_NewEx(WINPR_CIPHER_AES_256_CBC, WINPR_ENCRYPT, pMemBlock->key,
sizeof(pMemBlock->key), pMemBlock->iv, sizeof(pMemBlock->iv))) ==
nullptr)
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, WINPR_ATTR_UNUSED DWORD cbData, DWORD dwFlags)
{
BYTE* pPlainText = nullptr;
size_t cbOut = 0;
size_t cbFinal = 0;
WINPR_CIPHER_CTX* dec = nullptr;
WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = nullptr;
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_NewEx(WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT, pMemBlock->key,
sizeof(pMemBlock->key), pMemBlock->iv, sizeof(pMemBlock->iv))) ==
nullptr)
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(WINPR_ATTR_UNUSED DATA_BLOB* pDataIn, WINPR_ATTR_UNUSED LPCWSTR szDataDescr,
WINPR_ATTR_UNUSED DATA_BLOB* pOptionalEntropy,
WINPR_ATTR_UNUSED PVOID pvReserved,
WINPR_ATTR_UNUSED CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED DATA_BLOB* pDataOut)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptUnprotectData(WINPR_ATTR_UNUSED DATA_BLOB* pDataIn,
WINPR_ATTR_UNUSED LPWSTR* ppszDataDescr,
WINPR_ATTR_UNUSED DATA_BLOB* pOptionalEntropy,
WINPR_ATTR_UNUSED PVOID pvReserved,
WINPR_ATTR_UNUSED CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED DATA_BLOB* pDataOut)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptStringToBinaryW(WINPR_ATTR_UNUSED LPCWSTR pszString, WINPR_ATTR_UNUSED DWORD cchString,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED BYTE* pbBinary,
WINPR_ATTR_UNUSED DWORD* pcbBinary, WINPR_ATTR_UNUSED DWORD* pdwSkip,
WINPR_ATTR_UNUSED DWORD* pdwFlags)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptStringToBinaryA(WINPR_ATTR_UNUSED LPCSTR pszString, WINPR_ATTR_UNUSED DWORD cchString,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED BYTE* pbBinary,
WINPR_ATTR_UNUSED DWORD* pcbBinary, WINPR_ATTR_UNUSED DWORD* pdwSkip,
WINPR_ATTR_UNUSED DWORD* pdwFlags)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptBinaryToStringW(WINPR_ATTR_UNUSED CONST BYTE* pbBinary, WINPR_ATTR_UNUSED DWORD cbBinary,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED LPWSTR pszString,
WINPR_ATTR_UNUSED DWORD* pcchString)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
BOOL CryptBinaryToStringA(WINPR_ATTR_UNUSED CONST BYTE* pbBinary, WINPR_ATTR_UNUSED DWORD cbBinary,
WINPR_ATTR_UNUSED DWORD dwFlags, WINPR_ATTR_UNUSED LPSTR pszString,
WINPR_ATTR_UNUSED DWORD* pcchString)
{
WLog_ERR("TODO", "TODO: Implement");
return TRUE;
}
#endif

View File

@@ -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 */

View File

@@ -0,0 +1,776 @@
/**
* 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 nullptr;
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 },
{ nullptr, 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 nullptr;
}
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 nullptr;
#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(nullptr, "HMAC", nullptr);
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 nullptr;
}
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
char* hash = WINPR_CAST_CONST_PTR_AWAY(winpr_md_type_to_string(md), char*);
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() };
return EVP_MAC_init(ctx->xhmac, key, keylen, param) == 1;
#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, nullptr); /* no return value on OpenSSL 0.9.x */
return TRUE;
#else
if (HMAC_Init_ex(hmac, key, (int)keylen, evp, nullptr) == 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
return EVP_MAC_update(ctx->xhmac, input, ilen) == 1;
#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, nullptr, olen);
return (rc == 1);
#else
HMAC_CTX* hmac = ctx->hmac;
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
HMAC_Final(hmac, output, nullptr); /* no return value on OpenSSL 0.9.x */
return TRUE;
#else
if (HMAC_Final(hmac, output, nullptr) == 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 nullptr;
#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 nullptr;
}
#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, nullptr) != 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;
#elif defined(WITH_OPENSSL)
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#if !defined(WITH_INTERNAL_MD5)
if (md == WINPR_MD_MD5)
{
EVP_MD* md5 = EVP_MD_fetch(nullptr, "MD5", "fips=no");
BOOL rc = winpr_Digest_Init_Internal(ctx, md5);
EVP_MD_free(md5);
return rc;
}
#endif
#endif
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
}
default:
WLog_ERR(TAG, "Invalid FIPS digest %s requested", winpr_md_type_to_string(md));
return FALSE;
}
}
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;
return EVP_DigestUpdate(mdctx, input, ilen) == 1;
#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, WINPR_ATTR_UNUSED 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;
return EVP_DigestFinal_ex(mdctx, output, nullptr) == 1;
#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 md, void* key)
{
WINPR_ASSERT(ctx);
#if defined(WITH_OPENSSL)
const EVP_MD* evp = winpr_openssl_get_evp_md(md);
if (!evp)
return FALSE;
const int rdsi = EVP_DigestSignInit(ctx->mdctx, nullptr, evp, nullptr, key);
return (rdsi > 0);
#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;
return (EVP_DigestSignUpdate(mdctx, input, ilen) == 1);
#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;
}

View File

@@ -0,0 +1,56 @@
#include <assert.h>
#include <string.h>
#include "hmac_md5.h"
#include "md5.h"
void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, const unsigned char* key, size_t key_len)
{
const WINPR_HMAC_MD5_CTX empty = WINPR_C_ARRAY_INIT;
unsigned char k_ipad[KEY_IOPAD_SIZE] = WINPR_C_ARRAY_INIT;
unsigned char k_opad[KEY_IOPAD_SIZE] = WINPR_C_ARRAY_INIT;
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 = WINPR_C_ARRAY_INIT;
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);
}

View File

@@ -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

View File

@@ -0,0 +1,271 @@
/*
* 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.
*/
static inline winpr_MD4_u32plus F(winpr_MD4_u32plus x, winpr_MD4_u32plus y, winpr_MD4_u32plus z)
{
return ((z) ^ ((x) & ((y) ^ (z))));
}
static inline winpr_MD4_u32plus G(winpr_MD4_u32plus x, winpr_MD4_u32plus y, winpr_MD4_u32plus z)
{
return (((x) & ((y) | (z))) | ((y) & (z)));
}
static inline winpr_MD4_u32plus H(winpr_MD4_u32plus x, winpr_MD4_u32plus y, winpr_MD4_u32plus z)
{
return ((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[4ULL * (n)])
#define GET(n) SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = (winpr_MD4_u32plus)ptr[4ULL * (n)] | \
((winpr_MD4_u32plus)ptr[4ULL * (n) + 1] << 8) | \
((winpr_MD4_u32plus)ptr[4ULL * (n) + 2] << 16) | \
((winpr_MD4_u32plus)ptr[4ULL * (n) + 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, size_t size)
{
const winpr_MD4_u32plus ac1 = 0x5a827999;
const winpr_MD4_u32plus ac2 = 0x6ed9eba1;
const unsigned char* ptr = (const unsigned char*)data;
winpr_MD4_u32plus a = ctx->a;
winpr_MD4_u32plus b = ctx->b;
winpr_MD4_u32plus c = ctx->c;
winpr_MD4_u32plus d = ctx->d;
do
{
const winpr_MD4_u32plus saved_a = a;
const winpr_MD4_u32plus saved_b = b;
const winpr_MD4_u32plus saved_c = c;
const winpr_MD4_u32plus 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, size_t size)
{
winpr_MD4_u32plus saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
size_t used = saved_lo & 0x3f;
if (used)
{
size_t 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 & ~(size_t)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
static inline void mdOUT(unsigned char* dst, winpr_MD4_u32plus 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)
{
size_t used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
size_t 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;
mdOUT(&ctx->buffer[56], ctx->lo);
mdOUT(&ctx->buffer[60], ctx->hi);
body(ctx, ctx->buffer, 64);
mdOUT(&result[0], ctx->a);
mdOUT(&result[4], ctx->b);
mdOUT(&result[8], ctx->c);
mdOUT(&result[12], ctx->d);
memset(ctx, 0, sizeof(*ctx));
}

View File

@@ -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, size_t size);
extern void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx);
#endif

View File

@@ -0,0 +1,296 @@
/*
* 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.
*/
static inline winpr_MD5_u32plus F(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((z) ^ ((x) & ((y) ^ (z))));
}
static inline winpr_MD5_u32plus G(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((y) ^ ((z) & ((x) ^ (y))));
}
static inline winpr_MD5_u32plus H(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return (((x) ^ (y)) ^ (z));
}
static inline winpr_MD5_u32plus H2(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((x) ^ ((y) ^ (z)));
}
static inline winpr_MD5_u32plus I(winpr_MD5_u32plus x, winpr_MD5_u32plus y, winpr_MD5_u32plus z)
{
return ((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[4ULL * (n)])
#define GET(n) SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = (winpr_MD5_u32plus)ptr[4ULL * (n)] | \
((winpr_MD5_u32plus)ptr[4ULL * (n) + 1] << 8) | \
((winpr_MD5_u32plus)ptr[4ULL * (n) + 2] << 16) | \
((winpr_MD5_u32plus)ptr[4ULL * (n) + 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, size_t size)
{
const unsigned char* ptr = (const unsigned char*)data;
winpr_MD5_u32plus a = ctx->a;
winpr_MD5_u32plus b = ctx->b;
winpr_MD5_u32plus c = ctx->c;
winpr_MD5_u32plus d = ctx->d;
do
{
const winpr_MD5_u32plus saved_a = a;
const winpr_MD5_u32plus saved_b = b;
const winpr_MD5_u32plus saved_c = c;
const winpr_MD5_u32plus 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, size_t size)
{
winpr_MD5_u32plus saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
size_t used = saved_lo & 0x3f;
if (used)
{
size_t 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 & ~(size_t)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
static inline void mdOUT(unsigned char* dst, winpr_MD5_u32plus 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)
{
size_t used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
size_t 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;
mdOUT(&ctx->buffer[56], ctx->lo);
mdOUT(&ctx->buffer[60], ctx->hi);
body(ctx, ctx->buffer, 64);
mdOUT(&result[0], ctx->a);
mdOUT(&result[4], ctx->b);
mdOUT(&result[8], ctx->c);
mdOUT(&result[12], ctx->d);
memset(ctx, 0, sizeof(*ctx));
}

View File

@@ -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, size_t size);
extern void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx);
#endif

View File

@@ -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,
nullptr, 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);
}

View File

@@ -0,0 +1,89 @@
/**
* 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 <winpr/cast.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 nullptr;
for (size_t i = 0; i < CTX_SIZE; i++)
{
ctx->s[i] = WINPR_ASSERTING_INT_CAST(BYTE, 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);
size_t t1 = ctx->i;
size_t 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;
}

View File

@@ -0,0 +1,35 @@
/**
* 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_ATTR_NODISCARD
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

View File

@@ -0,0 +1,29 @@
set(MODULE_NAME "TestCrypto")
set(MODULE_PREFIX "TEST_CRYPTO")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
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")

View File

@@ -0,0 +1,88 @@
#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 = nullptr;
HCERTSTORE hCertStore = nullptr;
PCCERT_CONTEXT pCertContext = nullptr;
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, 0,
* CERT_SYSTEM_STORE_LOCAL_MACHINE, _T("Remote Desktop"));
*/
hCertStore = CertOpenSystemStore(0, _T("MY"));
// hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
// 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, nullptr, nullptr, 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, nullptr,
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, nullptr, nullptr, 0,
nullptr);
#endif
}
if (!CertCloseStore(hCertStore, 0))
{
printf("Failed to close system store\n");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,251 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
#include <winpr/ssl.h>
static BOOL test_crypto_cipher_aes_128_cbc(BOOL ex)
{
BOOL result = FALSE;
BYTE key[16] = "0123456789abcdeF";
BYTE iv[16] = "1234567887654321";
BYTE ibuf[1024] = WINPR_C_ARRAY_INIT;
BYTE obuf[1024] = WINPR_C_ARRAY_INIT;
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 */
WINPR_CIPHER_CTX* ctx = nullptr;
if (ex)
ctx = winpr_Cipher_NewEx(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, sizeof(key), iv,
sizeof(iv));
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
else
ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, iv);
#endif
if (!ctx)
{
(void)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))
{
(void)fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
{
(void)fprintf(stderr, "%s: winpr_Cipher_Final (encrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (xlen != ilen)
{
(void)fprintf(stderr, "%s: error, xlen (%" PRIuz ") != ilen (%" PRIuz ") (encrypt)\n",
__func__, xlen, ilen);
goto out;
}
winpr_Cipher_Free(ctx);
ctx = nullptr;
/* decrypt */
if (ex)
ctx = winpr_Cipher_NewEx(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, key, sizeof(key), iv,
sizeof(iv));
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
else
ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, key, iv);
#endif
if (!ctx)
{
(void)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))
{
(void)fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
{
(void)fprintf(stderr, "%s: winpr_Cipher_Final (decrypt) failed\n", __func__);
goto out;
}
xlen += olen;
if (xlen != ilen)
{
(void)fprintf(stderr, "%s: error, xlen (%" PRIuz ") != ilen (%" PRIuz ") (decrypt)\n",
__func__, xlen, ilen);
goto out;
}
if (strcmp((const char*)obuf, plaintext) != 0)
{
(void)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 char TEST_RC4_KEY[] = "Key";
static const char TEST_RC4_PLAINTEXT[] = "Plaintext";
static const char TEST_RC4_CIPHERTEXT[] = "\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3";
static BOOL test_crypto_cipher_rc4(void)
{
BOOL rc = FALSE;
WINPR_RC4_CTX* ctx = nullptr;
const size_t len = strnlen(TEST_RC4_PLAINTEXT, sizeof(TEST_RC4_PLAINTEXT));
BYTE* text = (BYTE*)calloc(1, len);
if (!text)
{
(void)fprintf(stderr, "%s: failed to allocate text buffer (len=%" PRIuz ")\n", __func__,
len);
goto out;
}
if ((ctx = winpr_RC4_New(TEST_RC4_KEY, strnlen(TEST_RC4_KEY, sizeof(TEST_RC4_KEY)))) == nullptr)
{
(void)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)
{
(void)fprintf(stderr, "%s: winpr_RC4_Update failed\n", __func__);
goto out;
}
if (memcmp(text, TEST_RC4_CIPHERTEXT, len) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(text, len, FALSE);
expected = winpr_BinToHexString(TEST_RC4_CIPHERTEXT, len, FALSE);
(void)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] = WINPR_C_ARRAY_INIT;
BYTE iv[16] = WINPR_C_ARRAY_INIT;
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) != 0 ||
memcmp(iv, TEST_CIPHER_IV, 16) != 0)
{
char* akstr = nullptr;
char* ekstr = nullptr;
char* aivstr = nullptr;
char* eivstr = nullptr;
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);
(void)fprintf(stderr, "Unexpected EVP_BytesToKey Key: Actual: %s, Expected: %s\n", akstr,
ekstr);
(void)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(TRUE))
return -1;
if (!test_crypto_cipher_aes_128_cbc(FALSE))
return -1;
if (!test_crypto_cipher_rc4())
return -1;
if (!test_crypto_cipher_key())
return -1;
return 0;
}

View File

@@ -0,0 +1,318 @@
#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] = WINPR_C_ARRAY_INIT;
WINPR_DIGEST_CTX* ctx = nullptr;
if (!(ctx = winpr_Digest_New()))
{
(void)fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
return FALSE;
}
if (!winpr_Digest_Init(ctx, WINPR_MD_MD5))
{
(void)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))))
{
(void)fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
goto out;
}
if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE);
(void)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] = WINPR_C_ARRAY_INIT;
WINPR_DIGEST_CTX* ctx = nullptr;
if (!(ctx = winpr_Digest_New()))
{
(void)fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
return FALSE;
}
if (!winpr_Digest_Init(ctx, WINPR_MD_MD4))
{
(void)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))))
{
(void)fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
goto out;
}
if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_MD4_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_MD4_HASH, WINPR_MD4_DIGEST_LENGTH, FALSE);
(void)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] = WINPR_C_ARRAY_INIT;
WINPR_DIGEST_CTX* ctx = nullptr;
if (!(ctx = winpr_Digest_New()))
{
(void)fprintf(stderr, "%s: winpr_Digest_New failed\n", __func__);
return FALSE;
}
if (!winpr_Digest_Init(ctx, WINPR_MD_SHA1))
{
(void)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))))
{
(void)fprintf(stderr, "%s: winpr_Digest_Update failed\n", __func__);
goto out;
}
if (!winpr_Digest_Final(ctx, hash, sizeof(hash)))
{
(void)fprintf(stderr, "%s: winpr_Digest_Final failed\n", __func__);
goto out;
}
if (memcmp(hash, TEST_SHA1_HASH, WINPR_MD5_DIGEST_LENGTH) != 0)
{
char* actual = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE);
(void)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] = WINPR_C_ARRAY_INIT;
WINPR_HMAC_CTX* ctx = nullptr;
BOOL result = FALSE;
if (!(ctx = winpr_HMAC_New()))
{
(void)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))
{
(void)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))))
{
(void)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))))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Final(ctx, hash, sizeof(hash)))
{
(void)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 = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_MD5_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_HMAC_MD5_HASH, WINPR_MD5_DIGEST_LENGTH, FALSE);
(void)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] = WINPR_C_ARRAY_INIT;
WINPR_HMAC_CTX* ctx = nullptr;
BOOL result = FALSE;
if (!(ctx = winpr_HMAC_New()))
{
(void)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))
{
(void)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))))
{
(void)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))))
{
(void)fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __func__);
goto out;
}
if (!winpr_HMAC_Final(ctx, hash, sizeof(hash)))
{
(void)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 = nullptr;
char* expected = nullptr;
actual = winpr_BinToHexString(hash, WINPR_SHA1_DIGEST_LENGTH, FALSE);
expected = winpr_BinToHexString(TEST_HMAC_SHA1_HASH, WINPR_SHA1_DIGEST_LENGTH, FALSE);
(void)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;
}

View File

@@ -0,0 +1,10 @@
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/crypto.h>
int TestCryptoProtectData(int argc, char* argv[])
{
return 0;
}

View File

@@ -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 = nullptr;
BYTE* pCipherText = nullptr;
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;
}

View File

@@ -0,0 +1,27 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
int TestCryptoRand(int argc, char* argv[])
{
char* str = nullptr;
BYTE rnd[16] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (winpr_RAND(rnd, sizeof(rnd)) < 0)
return -1;
str = winpr_BinToHexString(rnd, sizeof(rnd), FALSE);
// (void)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;
}