#include "wincrypt.h" #include "common.h" #include "context.h" #include "errors.h" #include "md5.h" #define SHA1_IMPLEMENTATION #include "sha1.h" #include #include namespace { struct HashObject { ALG_ID algid = 0; unsigned char digest[20]{}; union { MD5_CTX md5{}; sha1_context sha1; }; }; bool computeDigest(HashObject &hash) { switch (hash.algid) { case CALG_MD5: MD5_Final(hash.digest, &hash.md5); return true; case CALG_SHA1: sha1_finalize(&hash.sha1, hash.digest); return true; default: return false; } } HashObject *hashObjectFromHandle(HCRYPTHASH hHash) { if (hHash == 0) { return nullptr; } return reinterpret_cast(static_cast(hHash)); } HCRYPTHASH hashHandleFromObject(HashObject *hash) { return static_cast(reinterpret_cast(hash)); } DWORD hashSizeForAlgid(ALG_ID algid) { switch (algid) { case CALG_MD5: return 16; case CALG_SHA1: return 20; default: return 0; } } } // namespace namespace advapi32 { BOOL WIN_FUNC CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: CryptReleaseContext(%p, %u)\n", reinterpret_cast(static_cast(hProv)), dwFlags); (void)hProv; (void)dwFlags; return TRUE; } BOOL WIN_FUNC CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType, DWORD dwFlags) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: CryptAcquireContextW(%p, %p, %p, %u, %u)\n", phProv, pszContainer, pszProvider, dwProvType, dwFlags); // to quote the guy above me: screw them for now static int dummyProvider = 42; if (!phProv) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } *phProv = static_cast(reinterpret_cast(&dummyProvider)); return TRUE; } BOOL WIN_FUNC CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CryptGenRandom(%p)\n", reinterpret_cast(static_cast(hProv))); (void)hProv; if (!pbBuffer || dwLen == 0) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } ssize_t ret = getrandom(pbBuffer, dwLen, 0); if (ret < 0 || static_cast(ret) != dwLen) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } return TRUE; } BOOL WIN_FUNC CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CryptCreateHash(%p, %u, %p, %u, %p)\n", reinterpret_cast(static_cast(hProv)), Algid, reinterpret_cast(static_cast(hKey)), dwFlags, phHash); (void)hProv; if (!phHash) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } if (dwFlags != 0) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } if (hKey != 0) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } if (Algid != CALG_MD5 && Algid != CALG_SHA1) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } auto *hash = new HashObject; hash->algid = Algid; if (Algid == CALG_MD5) { MD5_Init(&hash->md5); } else if (Algid == CALG_SHA1) { sha1_init(&hash->sha1); } *phHash = hashHandleFromObject(hash); return TRUE; } BOOL WIN_FUNC CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CryptHashData(%p, %p, %u, %u)\n", reinterpret_cast(static_cast(hHash)), pbData, dwDataLen, dwFlags); if (dwFlags != 0) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } auto *hash = hashObjectFromHandle(hHash); if (!hash || (dwDataLen != 0 && !pbData)) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } if (pbData && dwDataLen) { if (hash->algid == CALG_MD5) { MD5_Update(&hash->md5, pbData, dwDataLen); } else if (hash->algid == CALG_SHA1) { sha1_update(&hash->sha1, pbData, dwDataLen); } } return TRUE; } BOOL WIN_FUNC CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CryptGetHashParam(%p, %u, %p, %p, %u)\n", reinterpret_cast(static_cast(hHash)), dwParam, pbData, pdwDataLen, dwFlags); if (dwFlags != 0 || !pdwDataLen) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } auto *hash = hashObjectFromHandle(hHash); if (!hash) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } switch (dwParam) { case HP_ALGID: { DWORD required = sizeof(ALG_ID); if (!pbData) { *pdwDataLen = required; return TRUE; } if (*pdwDataLen < required) { *pdwDataLen = required; wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return FALSE; } memcpy(pbData, &hash->algid, required); *pdwDataLen = required; return TRUE; } case HP_HASHSIZE: { DWORD required = sizeof(DWORD); if (!pbData) { *pdwDataLen = required; return TRUE; } if (*pdwDataLen < required) { *pdwDataLen = required; wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return FALSE; } DWORD size = hashSizeForAlgid(hash->algid); if (size == 0) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } memcpy(pbData, &size, required); *pdwDataLen = required; return TRUE; } case HP_HASHVAL: { if (!computeDigest(*hash)) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } DWORD size = hashSizeForAlgid(hash->algid); if (size == 0) { wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } if (!pbData) { *pdwDataLen = size; return TRUE; } if (*pdwDataLen < size) { *pdwDataLen = size; wibo::lastError = ERROR_INSUFFICIENT_BUFFER; return FALSE; } memcpy(pbData, hash->digest, size); *pdwDataLen = size; return TRUE; } default: wibo::lastError = ERROR_NOT_SUPPORTED; return FALSE; } } BOOL WIN_FUNC CryptDestroyHash(HCRYPTHASH hHash) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CryptDestroyHash(%p)\n", reinterpret_cast(static_cast(hHash))); auto *hash = hashObjectFromHandle(hHash); if (!hash) { wibo::lastError = ERROR_INVALID_PARAMETER; return FALSE; } delete hash; return TRUE; } } // namespace advapi32