libwinpr-crypto: implement CryptProtectMemory/CryptUnprotectMemory

This commit is contained in:
Marc-André Moreau 2014-02-01 11:52:04 -05:00
parent 6365880f4d
commit 851ace73ff
9 changed files with 322 additions and 8 deletions

View File

@ -23,6 +23,8 @@
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#include <winpr/error.h>
#ifdef _WIN32
#include <wincrypt.h>
@ -492,6 +494,94 @@ DWORD CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType,
#define CertGetNameString CertGetNameStringA
#endif
/**
* Data Protection API (DPAPI)
*/
#define CRYPTPROTECTMEMORY_BLOCK_SIZE 16
#define CRYPTPROTECTMEMORY_SAME_PROCESS 0x00000000
#define CRYPTPROTECTMEMORY_CROSS_PROCESS 0x00000001
#define CRYPTPROTECTMEMORY_SAME_LOGON 0x00000002
#define CRYPTPROTECT_PROMPT_ON_UNPROTECT 0x00000001
#define CRYPTPROTECT_PROMPT_ON_PROTECT 0x00000002
#define CRYPTPROTECT_PROMPT_RESERVED 0x00000004
#define CRYPTPROTECT_PROMPT_STRONG 0x00000008
#define CRYPTPROTECT_PROMPT_REQUIRE_STRONG 0x00000010
#define CRYPTPROTECT_UI_FORBIDDEN 0x1
#define CRYPTPROTECT_LOCAL_MACHINE 0x4
#define CRYPTPROTECT_CRED_SYNC 0x8
#define CRYPTPROTECT_AUDIT 0x10
#define CRYPTPROTECT_NO_RECOVERY 0x20
#define CRYPTPROTECT_VERIFY_PROTECTION 0x40
#define CRYPTPROTECT_CRED_REGENERATE 0x80
#define CRYPTPROTECT_FIRST_RESERVED_FLAGVAL 0x0FFFFFFF
#define CRYPTPROTECT_LAST_RESERVED_FLAGVAL 0xFFFFFFFF
typedef struct _CRYPTPROTECT_PROMPTSTRUCT
{
DWORD cbSize;
DWORD dwPromptFlags;
HWND hwndApp;
LPCWSTR szPrompt;
} CRYPTPROTECT_PROMPTSTRUCT, *PCRYPTPROTECT_PROMPTSTRUCT;
#define CRYPTPROTECT_DEFAULT_PROVIDER { 0xdf9d8cd0, 0x1501, 0x11d1, { 0x8c, 0x7a, 0x00, 0xc0, 0x4f, 0xc2, 0x97, 0xeb } }
#ifdef __cplusplus
extern "C" {
#endif
WINPR_API BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags);
WINPR_API BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags);
WINPR_API BOOL CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, DATA_BLOB* pOptionalEntropy,
PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, DATA_BLOB* pDataOut);
WINPR_API BOOL CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, DATA_BLOB* pOptionalEntropy,
PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, DATA_BLOB* pDataOut);
#ifdef __cplusplus
}
#endif
#define CRYPT_STRING_BASE64HEADER 0x00000000
#define CRYPT_STRING_BASE64 0x00000001
#define CRYPT_STRING_BINARY 0x00000002
#define CRYPT_STRING_BASE64REQUESTHEADER 0x00000003
#define CRYPT_STRING_HEX 0x00000004
#define CRYPT_STRING_HEXASCII 0x00000005
#define CRYPT_STRING_BASE64_ANY 0x00000006
#define CRYPT_STRING_ANY 0x00000007
#define CRYPT_STRING_HEX_ANY 0x00000008
#define CRYPT_STRING_BASE64X509CRLHEADER 0x00000009
#define CRYPT_STRING_HEXADDR 0x0000000A
#define CRYPT_STRING_HEXASCIIADDR 0x0000000B
#define CRYPT_STRING_HEXRAW 0x0000000C
#define CRYPT_STRING_HASHDATA 0x10000000
#define CRYPT_STRING_STRICT 0x20000000
#define CRYPT_STRING_NOCRLF 0x40000000
#define CRYPT_STRING_NOCR 0x80000000
BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags);
BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags);
BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD* pcchString);
BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD* pcchString);
#ifdef UNICODE
#define CryptStringToBinary CryptStringToBinaryW
#define CryptBinaryToString CryptBinaryToStringW
#else
#define CryptStringToBinary CryptStringToBinaryA
#define CryptBinaryToString CryptBinaryToStringA
#endif
#endif
#endif /* WINPR_CRYPTO_H */

View File

@ -35,6 +35,11 @@ if(WIN32)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} credui)
endif()
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
MODULE winpr
MODULES winpr-crt winpr-utils)
if(MONOLITHIC_BUILD)
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
else()

View File

@ -31,8 +31,20 @@ add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
include_directories(${ZLIB_INCLUDE_DIRS})
include_directories(${OPENSSL_INCLUDE_DIR})
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
set(${MODULE_PREFIX}_LIBS
${ZLIB_LIBRARIES}
${OPENSSL_LIBRARIES})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
MODULE winpr
MODULES winpr-crt winpr-utils)
if(WIN32)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} crypt32)
endif()

View File

@ -89,8 +89,6 @@
* CryptMsgUpdate
* CryptMsgVerifyCountersignatureEncoded
* CryptMsgVerifyCountersignatureEncodedEx
* CryptProtectData
* CryptProtectMemory
* CryptQueryObject
* CryptRegisterDefaultOIDFunction
* CryptRegisterOIDFunction
@ -115,11 +113,7 @@
* CryptSIPRetrieveSubjectGuid
* CryptSIPRetrieveSubjectGuidForCatalogFile
* CryptSIPVerifyIndirectData
* CryptStringToBinaryA
* CryptStringToBinaryW
* CryptUninstallDefaultContext
* CryptUnprotectData
* CryptUnprotectMemory
* CryptUnregisterDefaultOIDFunction
* CryptUnregisterOIDFunction
* CryptUnregisterOIDInfo
@ -146,4 +140,140 @@
#include "crypto.h"
#include <winpr/crt.h>
#include <winpr/collections.h>
static wListDictionary* g_ProtectedMemoryBlocks = NULL;
BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
{
BYTE* pCipherText;
int cbOut, cbFinal;
BYTE randomKey[256];
WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock;
if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
return FALSE;
if (!g_ProtectedMemoryBlocks)
g_ProtectedMemoryBlocks = ListDictionary_New(TRUE);
pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) malloc(sizeof(WINPR_PROTECTED_MEMORY_BLOCK));
ZeroMemory(pMemBlock, sizeof(WINPR_PROTECTED_MEMORY_BLOCK));
pMemBlock->pData = pData;
pMemBlock->cbData = cbData;
pMemBlock->dwFlags = dwFlags;
/* AES Initialization */
RAND_bytes(pMemBlock->salt, 8);
RAND_bytes(randomKey, sizeof(randomKey));
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(),
pMemBlock->salt,
randomKey, sizeof(randomKey),
4, pMemBlock->key, pMemBlock->iv);
SecureZeroMemory(randomKey, sizeof(randomKey));
EVP_CIPHER_CTX_init(&(pMemBlock->enc));
EVP_EncryptInit_ex(&(pMemBlock->enc), EVP_aes_256_cbc(), NULL, pMemBlock->key, pMemBlock->iv);
EVP_CIPHER_CTX_init(&(pMemBlock->dec));
EVP_DecryptInit_ex(&(pMemBlock->dec), EVP_aes_256_cbc(), NULL, pMemBlock->key, pMemBlock->iv);
/* AES Encryption */
cbOut = pMemBlock->cbData + AES_BLOCK_SIZE - 1;
pCipherText = (BYTE*) malloc(cbOut);
EVP_EncryptInit_ex(&(pMemBlock->enc), NULL, NULL, NULL, NULL);
EVP_EncryptUpdate(&(pMemBlock->enc), pCipherText, &cbOut, pMemBlock->pData, pMemBlock->cbData);
EVP_EncryptFinal_ex(&(pMemBlock->enc), pCipherText + cbOut, &cbFinal);
CopyMemory(pMemBlock->pData, pCipherText, pMemBlock->cbData);
free(pCipherText);
ListDictionary_Add(g_ProtectedMemoryBlocks, pData, pMemBlock);
return TRUE;
}
BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
{
BYTE* pPlainText;
int cbOut, cbFinal;
WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock;
if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
return FALSE;
if (!g_ProtectedMemoryBlocks)
return FALSE;
pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData);
if (!pMemBlock)
return FALSE;
/* AES Decryption */
cbOut = pMemBlock->cbData + AES_BLOCK_SIZE - 1;
pPlainText = (BYTE*) malloc(cbOut);
EVP_DecryptInit_ex(&(pMemBlock->dec), NULL, NULL, NULL, NULL);
EVP_DecryptUpdate(&(pMemBlock->dec), pPlainText, &cbOut, pMemBlock->pData, pMemBlock->cbData);
EVP_DecryptFinal_ex(&(pMemBlock->dec), pPlainText + cbOut, &cbFinal);
CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData);
SecureZeroMemory(pPlainText, pMemBlock->cbData);
free(pPlainText);
ListDictionary_Remove(g_ProtectedMemoryBlocks, pData);
/* AES Cleanup */
EVP_CIPHER_CTX_cleanup(&(pMemBlock->enc));
EVP_CIPHER_CTX_cleanup(&(pMemBlock->dec));
free(pMemBlock);
return TRUE;
}
BOOL CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, DATA_BLOB* pOptionalEntropy,
PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, DATA_BLOB* pDataOut)
{
return TRUE;
}
BOOL CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, DATA_BLOB* pOptionalEntropy,
PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, DATA_BLOB* pDataOut)
{
return TRUE;
}
BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags)
{
return TRUE;
}
BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags)
{
return TRUE;
}
BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD* pcchString)
{
return TRUE;
}
BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD* pcchString)
{
return TRUE;
}
#endif

View File

@ -22,6 +22,10 @@
#ifndef _WIN32
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
struct _WINPR_CERTSTORE
{
LPCSTR lpszStoreProvider;
@ -29,6 +33,19 @@ struct _WINPR_CERTSTORE
};
typedef struct _WINPR_CERTSTORE WINPR_CERTSTORE;
struct _WINPR_PROTECTED_MEMORY_BLOCK
{
BYTE* pData;
DWORD cbData;
DWORD dwFlags;
BYTE key[32];
BYTE iv[32];
BYTE salt[8];
EVP_CIPHER_CTX enc;
EVP_CIPHER_CTX dec;
};
typedef struct _WINPR_PROTECTED_MEMORY_BLOCK WINPR_PROTECTED_MEMORY_BLOCK;
#endif
#endif /* WINPR_CRYPTO_PRIVATE_H */

View File

@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_CRYPTO")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestCertEnumCertificatesInStore.c)
TestCryptoProtectData.c
TestCryptoProtectMemory.c
TestCryptoCertEnumCertificatesInStore.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}

View File

@ -12,7 +12,7 @@
#include <cryptuiapi.h>
#endif
int TestCertEnumCertificatesInStore(int argc, char* argv[])
int TestCryptoCertEnumCertificatesInStore(int argc, char* argv[])
{
int index;
DWORD status;

View File

@ -0,0 +1,11 @@
#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,47 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
static const char* SECRET_PASSWORD_TEST = "MySecretPassword123!";
int TestCryptoProtectMemory(int argc, char* argv[])
{
int cbPlainText;
int cbCipherText;
char* pPlainText;
BYTE* pCipherText;
pPlainText = (char*) SECRET_PASSWORD_TEST;
cbPlainText = strlen(pPlainText) + 1;
cbCipherText = cbPlainText + (CRYPTPROTECTMEMORY_BLOCK_SIZE - (cbPlainText % CRYPTPROTECTMEMORY_BLOCK_SIZE));
printf("cbPlainText: %d cbCipherText: %d\n", cbPlainText, cbCipherText);
pCipherText = (BYTE*) malloc(cbCipherText);
CopyMemory(pCipherText, pPlainText, cbPlainText);
ZeroMemory(&pCipherText[cbPlainText], (cbCipherText - cbPlainText));
if (!CryptProtectMemory(pCipherText, cbCipherText, CRYPTPROTECTMEMORY_SAME_PROCESS))
{
printf("CryptProtectMemory failure\n");
return -1;
}
printf("PlainText: %s (cbPlainText = %d, cbCipherText = %d)\n", pPlainText, cbPlainText, cbCipherText);
winpr_HexDump(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;
}