Index: trunk/src/advapi32/crypt.c
===================================================================
--- trunk/src/advapi32/crypt.c	(revision 21326)
+++ trunk/src/advapi32/crypt.c	(revision 21326)
@@ -0,0 +1,2368 @@
+/*
+ * Copyright 1999 Ian Schmidt
+ * Copyright 2001 Travis Michielsen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/***********************************************************************
+ *
+ *  TODO:
+ *  - Reference counting
+ *  - Thread-safing
+ */
+
+#include <os2win.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <odinwrap.h>
+#include <misc.h>
+#include "wincrypt.h"
+
+ODINDEBUGCHANNEL(ADVAPI32-CRYPT)
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <time.h>
+//#include <stdlib.h>
+#include <stdio.h>
+//#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "crypt.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "rpc.h"
+#include "debugtools.h"
+#include "wine/unicode.h"
+//#include "winternl.h"
+
+static HWND crypt_hWindow;
+
+#define CRYPT_Alloc(size) (LocalAlloc(LMEM_ZEROINIT, size))
+#define CRYPT_Free(buffer) (LocalFree((HLOCAL)buffer))
+
+static inline PWSTR CRYPT_GetProvKeyName(PCWSTR pProvName)
+{
+	static const WCHAR KEYSTR[] = {
+                'S','o','f','t','w','a','r','e','\\',
+                'M','i','c','r','o','s','o','f','t','\\',
+                'C','r','y','p','t','o','g','r','a','p','h','y','\\',
+                'D','e','f','a','u','l','t','s','\\',
+                'P','r','o','v','i','d','e','r','\\',0
+	};
+	PWSTR keyname;
+
+	keyname = (PWSTR)CRYPT_Alloc((strlenW(KEYSTR) + strlenW(pProvName) +1)*sizeof(WCHAR));
+	if (keyname)
+	{
+		strcpyW(keyname, KEYSTR);
+		strcpyW(keyname + strlenW(KEYSTR), pProvName);
+	} else
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+	return keyname;
+}
+
+static inline PWSTR CRYPT_GetTypeKeyName(DWORD dwType, BOOL user)
+{
+	static const WCHAR MACHINESTR[] = {
+                'S','o','f','t','w','a','r','e','\\',
+                'M','i','c','r','o','s','o','f','t','\\',
+                'C','r','y','p','t','o','g','r','a','p','h','y','\\',
+                'D','e','f','a','u','l','t','s','\\',
+                'P','r','o','v','i','d','e','r',' ','T','y','p','e','s','\\',
+                'T','y','p','e',' ','X','X','X',0
+	};
+	static const WCHAR USERSTR[] = {
+                'S','o','f','t','w','a','r','e','\\',
+                'M','i','c','r','o','s','o','f','t','\\',
+                'C','r','y','p','t','o','g','r','a','p','h','y','\\',
+                'P','r','o','v','i','d','e','r',' ','T','y','p','e',' ','X','X','X',0
+	};
+	PWSTR keyname;
+	PWSTR ptr;
+
+	keyname = (PWSTR)CRYPT_Alloc( ((user ? strlenW(USERSTR) : strlenW(MACHINESTR)) +1)*sizeof(WCHAR));
+	if (keyname)
+	{
+		user ? strcpyW(keyname, USERSTR) : strcpyW(keyname, MACHINESTR);
+		ptr = keyname + strlenW(keyname);
+		*(--ptr) = (dwType % 10) + '0';
+		*(--ptr) = ((dwType / 10) % 10) + '0';
+		*(--ptr) = (dwType / 100) + '0';
+	} else
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+	return keyname;
+}
+
+/* CRYPT_UnicodeTOANSI
+ * wstr - unicode string
+ * str - pointer to ANSI string
+ * strsize - size of buffer pointed to by str or -1 if we have to do the allocation
+ *
+ * returns TRUE if unsuccessful, FALSE otherwise.
+ * if wstr is NULL, returns TRUE and sets str to NULL! Value of str should be checked after call
+ */
+static inline BOOL CRYPT_UnicodeToANSI(LPCWSTR wstr, LPSTR* str, int strsize)
+{
+	int count;
+
+	if (!wstr)
+	{
+		*str = NULL;
+		return TRUE;
+	}
+	count = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
+	if (strsize == -1)
+		*str = (LPSTR)CRYPT_Alloc(count * sizeof(CHAR));
+	else
+		count = min( count, strsize );
+	if (*str)
+	{
+		WideCharToMultiByte(CP_ACP, 0, wstr, -1, *str, count, NULL, NULL);
+		return TRUE;
+	}
+	SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+	return FALSE;
+}
+
+/* CRYPT_ANSITOUnicode
+ * str - ANSI string
+ * wstr - pointer to unicode string
+ * wstrsize - size of buffer pointed to by wstr or -1 if we have to do the allocation
+ */
+static inline BOOL CRYPT_ANSIToUnicode(LPCSTR str, LPWSTR* wstr, int wstrsize)
+{
+	unsigned int wcount;
+
+	if (!str)
+	{
+		*wstr = NULL;
+		return TRUE;
+	}
+	wcount = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+	if (wstrsize == -1)
+		*wstr = (PWSTR)CRYPT_Alloc(wcount * sizeof(WCHAR));
+	else
+		wcount = min( wcount, wstrsize/sizeof(WCHAR) );
+	if (*wstr)
+	{
+		MultiByteToWideChar(CP_ACP, 0, str, -1, *wstr, wcount);
+		return TRUE;
+	}
+	SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+	return FALSE;
+}
+
+/* These next 2 functions are used by the VTableProvStruc structure */
+static BOOL CALLBACK CRYPT_VerifyImage(LPCSTR lpszImage, BYTE* pData)
+{
+	if (!lpszImage || !pData)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	FIXME("(%s, %p): not verifying image\n", lpszImage, pData);
+
+	return TRUE;
+}
+
+static BOOL CALLBACK CRYPT_ReturnhWnd(HWND *phWnd)
+{
+	if (!phWnd)
+		return FALSE;
+	*phWnd = crypt_hWindow;
+	return TRUE;
+}
+
+#define CRYPT_GetProvFunc(name) \
+	if ( !(provider->pFuncs->p##name = (void*)GetProcAddress(provider->hModule, #name)) ) goto error
+#define CRYPT_GetProvFuncOpt(name) \
+	provider->pFuncs->p##name = (void*)GetProcAddress(provider->hModule, #name)
+static PCRYPTPROV CRYPT_LoadProvider(PCWSTR pImage)
+{
+	PCRYPTPROV provider;
+	DWORD errorcode = ERROR_NOT_ENOUGH_MEMORY;
+
+	if ( !(provider = CRYPT_Alloc(sizeof(CRYPTPROV))) ) goto error;
+	if ( !(provider->pFuncs = CRYPT_Alloc(sizeof(PROVFUNCS))) ) goto error;
+	if ( !(provider->pVTable = CRYPT_Alloc(sizeof(VTableProvStruc))) ) goto error;
+	if ( !(provider->hModule = LoadLibraryW(pImage)) )
+	{
+		errorcode = (GetLastError() == ERROR_FILE_NOT_FOUND) ? NTE_PROV_DLL_NOT_FOUND : NTE_PROVIDER_DLL_FAIL;
+		FIXME("Failed to load dll %s\n", debugstr_w(pImage));
+		goto error;
+	}
+	provider->dwMagic = MAGIC_CRYPTPROV;
+	provider->refcount = 1;
+
+	errorcode = NTE_PROVIDER_DLL_FAIL;
+	CRYPT_GetProvFunc(CPAcquireContext);
+	CRYPT_GetProvFunc(CPCreateHash);
+	CRYPT_GetProvFunc(CPDecrypt);
+	CRYPT_GetProvFunc(CPDeriveKey);
+	CRYPT_GetProvFunc(CPDestroyHash);
+	CRYPT_GetProvFunc(CPDestroyKey);
+	CRYPT_GetProvFuncOpt(CPDuplicateHash);
+	CRYPT_GetProvFuncOpt(CPDuplicateKey);
+	CRYPT_GetProvFunc(CPEncrypt);
+	CRYPT_GetProvFunc(CPExportKey);
+	CRYPT_GetProvFunc(CPGenKey);
+	CRYPT_GetProvFunc(CPGenRandom);
+	CRYPT_GetProvFunc(CPGetHashParam);
+	CRYPT_GetProvFunc(CPGetKeyParam);
+	CRYPT_GetProvFunc(CPGetProvParam);
+	CRYPT_GetProvFunc(CPGetUserKey);
+	CRYPT_GetProvFunc(CPHashData);
+	CRYPT_GetProvFunc(CPHashSessionKey);
+	CRYPT_GetProvFunc(CPImportKey);
+	CRYPT_GetProvFunc(CPReleaseContext);
+	CRYPT_GetProvFunc(CPSetHashParam);
+	CRYPT_GetProvFunc(CPSetKeyParam);
+	CRYPT_GetProvFunc(CPSetProvParam);
+	CRYPT_GetProvFunc(CPSignHash);
+	CRYPT_GetProvFunc(CPVerifySignature);
+
+	/* FIXME: Not sure what the pbContextInfo field is for.
+	 *        Does it need memory allocation?
+         */
+	provider->pVTable->Version = 3;
+	provider->pVTable->pFuncVerifyImage = (FARPROC)CRYPT_VerifyImage;
+	provider->pVTable->pFuncReturnhWnd = (FARPROC)CRYPT_ReturnhWnd;
+	provider->pVTable->dwProvType = 0;
+	provider->pVTable->pbContextInfo = NULL;
+	provider->pVTable->cbContextInfo = 0;
+	provider->pVTable->pszProvName = NULL;
+	return provider;
+
+error:
+	SetLastError(errorcode);
+	if (provider)
+	{
+		provider->dwMagic = 0;
+		if (provider->hModule)
+			FreeLibrary(provider->hModule);
+		CRYPT_Free(provider->pVTable);
+		CRYPT_Free(provider->pFuncs);
+		CRYPT_Free(provider);
+	}
+	return NULL;
+}
+#undef CRYPT_GetProvFunc
+#undef CRYPT_GetProvFuncOpt
+
+
+static void CRYPT_CreateMachineGuid(void)
+{
+	static const WCHAR cryptographyW[] = {
+                'S','o','f','t','w','a','r','e','\\',
+                'M','i','c','r','o','s','o','f','t','\\',
+                'C','r','y','p','t','o','g','r','a','p','h','y',0 };
+	static const WCHAR machineGuidW[] = {
+		'M','a','c','h','i','n','e','G','u','i','d',0 };
+	LONG r;
+	HKEY key;
+
+	r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, cryptographyW, 0, KEY_ALL_ACCESS,
+			  &key);
+	if (!r)
+	{
+		DWORD size;
+
+		r = RegQueryValueExW(key, machineGuidW, NULL, NULL, NULL, &size);
+		if (r == ERROR_FILE_NOT_FOUND)
+		{
+			static const WCHAR rpcrt4[] = {
+				'r','p','c','r','t','4',0 };
+			HMODULE lib = LoadLibraryW(rpcrt4);
+
+			if (lib)
+			{
+				RPC_STATUS (*RPC_ENTRY pUuidCreate)(UUID *);
+				UUID uuid;
+                                WCHAR buf[37];
+                                RPC_STATUS rs;
+                                static const WCHAR uuidFmt[] = {
+                                    '%','0','8','x','-','%','0','4','x','-',
+                                    '%','0','4','x','-','%','0','2','x',
+                                    '%','0','2','x','-','%','0','2','x',
+                                    '%','0','2','x','%','0','2','x',
+                                    '%','0','2','x','%','0','2','x',
+                                    '%','0','2','x',0 };
+
+				pUuidCreate = GetProcAddress(lib, "UuidCreate");
+                                rs = pUuidCreate(&uuid);
+                                if (rs == S_OK)
+                                {
+                                    sprintfW(buf, uuidFmt,
+                                             uuid.Data1, uuid.Data2, uuid.Data3,
+                                             uuid.Data4[0], uuid.Data4[1],
+                                             uuid.Data4[2], uuid.Data4[3],
+                                             uuid.Data4[4], uuid.Data4[5],
+                                             uuid.Data4[6], uuid.Data4[7] );
+                                    RegSetValueExW(key, machineGuidW, 0, REG_SZ,
+                                                   (const BYTE *)buf,
+                                                   (lstrlenW(buf)+1)*sizeof(WCHAR));
+                                }
+				FreeLibrary(lib);
+			}
+		}
+		RegCloseKey(key);
+	}
+}
+
+/******************************************************************************
+ * CryptAcquireContextW (ADVAPI32.@)
+ *
+ * Acquire a crypto provider context handle.
+ *
+ * PARAMS
+ *  phProv       [O] Pointer to HCRYPTPROV for the output.
+ *  pszContainer [I] Key Container Name
+ *  pszProvider  [I] Cryptographic Service Provider Name
+ *  dwProvType   [I] Crypto provider type to get a handle.
+ *  dwFlags      [I] flags for the operation
+ *
+ * RETURNS 
+ *  TRUE on success, FALSE on failure.
+ */
+BOOL WINAPI CryptAcquireContextW (HCRYPTPROV *phProv, LPCWSTR pszContainer,
+		LPCWSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
+{
+	PCRYPTPROV pProv = NULL;
+	HKEY key;
+	PWSTR imagepath = NULL, keyname = NULL, provname = NULL, temp = NULL;
+	PSTR provnameA = NULL, pszContainerA = NULL;
+	DWORD keytype, type, len;
+	ULONG r;
+	static const WCHAR nameW[] = {'N','a','m','e',0};
+	static const WCHAR typeW[] = {'T','y','p','e',0};
+	static const WCHAR imagepathW[] = {'I','m','a','g','e',' ','P','a','t','h',0};
+
+	TRACE("(%p, %s, %s, %d, %08x)\n", phProv, debugstr_w(pszContainer),
+		debugstr_w(pszProvider), dwProvType, dwFlags);
+
+	if (dwProvType < 1 || dwProvType > MAXPROVTYPES)
+	{
+		SetLastError(NTE_BAD_PROV_TYPE);
+		return FALSE;
+	}
+	
+	if (!phProv)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	/* Make sure the MachineGuid value exists */
+	CRYPT_CreateMachineGuid();
+
+	if (!pszProvider || !*pszProvider)
+	{
+		/* No CSP name specified so try the user default CSP first
+		 * then try the machine default CSP
+		 */
+		if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, TRUE)) ) {
+			TRACE("No provider registered for crypto provider type %d.\n", dwProvType);
+			SetLastError(NTE_PROV_TYPE_NOT_DEF);
+			return FALSE;
+		}
+		if (RegOpenKeyW(HKEY_CURRENT_USER, keyname, &key))
+		{
+			CRYPT_Free(keyname);
+			if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, FALSE)) ) {
+				TRACE("No type registered for crypto provider type %d.\n", dwProvType);
+				RegCloseKey(key);
+				SetLastError(NTE_PROV_TYPE_NOT_DEF);
+				goto error;
+			}
+			if (RegOpenKeyW(HKEY_LOCAL_MACHINE, keyname, &key)) {
+				TRACE("Did not find registry entry of crypto provider for %s.\n", debugstr_w(keyname));
+				CRYPT_Free(keyname);
+				RegCloseKey(key);
+				SetLastError(NTE_PROV_TYPE_NOT_DEF);
+				goto error;
+			}
+		}
+		CRYPT_Free(keyname);
+		r = RegQueryValueExW(key, nameW, NULL, &keytype, NULL, &len);
+		if( r != ERROR_SUCCESS || !len || keytype != REG_SZ)
+		{
+			TRACE("error %d reading size of 'Name' from registry\n", r );
+			RegCloseKey(key);
+			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+			goto error;
+		}
+		if(!(provname = CRYPT_Alloc(len)))
+		{
+			RegCloseKey(key);
+			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+			goto error;
+		}
+		r = RegQueryValueExW(key, nameW, NULL, NULL, (LPBYTE)provname, &len);
+		if( r != ERROR_SUCCESS )
+		{
+			TRACE("error %d reading 'Name' from registry\n", r );
+			RegCloseKey(key);
+			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+			goto error;
+		}
+		RegCloseKey(key);
+	} else {
+		if ( !(provname = CRYPT_Alloc((strlenW(pszProvider) +1)*sizeof(WCHAR))) )
+		{
+			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+			goto error;
+		}
+		strcpyW(provname, pszProvider);
+	}
+
+	keyname = CRYPT_GetProvKeyName(provname);
+	r = RegOpenKeyW(HKEY_LOCAL_MACHINE, keyname, &key);
+	CRYPT_Free(keyname);
+	if (r != ERROR_SUCCESS)
+	{
+		SetLastError(NTE_KEYSET_NOT_DEF);
+		goto error;
+	}
+	len = sizeof(DWORD);
+	r = RegQueryValueExW(key, typeW, NULL, NULL, (BYTE*)&type, &len);
+	if (r != ERROR_SUCCESS)
+	{
+		SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+		goto error;
+	}
+	if (type != dwProvType)
+	{
+		TRACE("Crypto provider has wrong type (%d vs expected %d).\n", type, dwProvType);
+		SetLastError(NTE_PROV_TYPE_NO_MATCH);
+		goto error;
+	}
+
+	r = RegQueryValueExW(key, imagepathW, NULL, &keytype, NULL, &len);
+	if ( r != ERROR_SUCCESS || keytype != REG_SZ)
+	{
+		TRACE("error %d reading size of 'Image Path' from registry\n", r );
+		RegCloseKey(key);
+		SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+		goto error;
+	}
+	if (!(temp = CRYPT_Alloc(len)))
+	{
+		RegCloseKey(key);
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		goto error;
+	}
+	r = RegQueryValueExW(key, imagepathW, NULL, NULL, (LPBYTE)temp, &len);
+	if( r != ERROR_SUCCESS )
+	{
+		TRACE("error %d reading 'Image Path' from registry\n", r );
+		RegCloseKey(key);
+		SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+		goto error;
+	}
+	RegCloseKey(key);
+	len = ExpandEnvironmentStringsW(temp, NULL, 0);
+	if ( !(imagepath = CRYPT_Alloc(len*sizeof(WCHAR))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		goto error;
+	}
+	if (!ExpandEnvironmentStringsW(temp, imagepath, len))
+	{
+		/* ExpandEnvironmentStrings will call SetLastError */
+		goto error;
+	}
+	pProv = CRYPT_LoadProvider(imagepath);
+	if (!pProv) {
+		/* CRYPT_LoadProvider calls SetLastError */
+		goto error;
+	}
+	pProv->pVTable->dwProvType = dwProvType;
+	if(!CRYPT_UnicodeToANSI(provname, &provnameA, -1))
+	{
+		/* CRYPT_UnicodeToANSI calls SetLastError */
+		goto error;
+	}
+	pProv->pVTable->pszProvName = provnameA;
+	if(!CRYPT_UnicodeToANSI(pszContainer, &pszContainerA, -1))
+	{
+		/* CRYPT_UnicodeToANSI calls SetLastError */
+		goto error;
+	}
+	if (pProv->pFuncs->pCPAcquireContext(&pProv->hPrivate, pszContainerA, dwFlags, pProv->pVTable))
+	{
+		/* MSDN: When this flag is set, the value returned in phProv is undefined,
+		 *       and thus, the CryptReleaseContext function need not be called afterwards.
+		 *       Therefore, we must clean up everything now.
+		 */
+		if (dwFlags & CRYPT_DELETEKEYSET)
+		{
+			pProv->dwMagic = 0;
+			FreeLibrary(pProv->hModule);
+			CRYPT_Free(provnameA);
+			CRYPT_Free(pProv->pVTable);
+			CRYPT_Free(pProv->pFuncs);
+			CRYPT_Free(pProv);
+		} else {
+			*phProv = (HCRYPTPROV)pProv;
+		}
+		CRYPT_Free(pszContainerA);
+		CRYPT_Free(provname);
+		CRYPT_Free(temp);
+		CRYPT_Free(imagepath);
+		return TRUE;
+	}
+	/* FALLTHROUGH TO ERROR IF FALSE - CSP internal error! */
+error:
+	if (pProv)
+	{
+		pProv->dwMagic = 0;
+		if (pProv->hModule)
+			FreeLibrary(pProv->hModule);
+		CRYPT_Free(pProv->pVTable);
+		CRYPT_Free(pProv->pFuncs);
+		CRYPT_Free(pProv);
+	}
+	CRYPT_Free(pszContainerA);
+	CRYPT_Free(provnameA);
+	CRYPT_Free(provname);
+	CRYPT_Free(temp);
+	CRYPT_Free(imagepath);
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptAcquireContextA (ADVAPI32.@)
+ *
+ * See CryptAcquireContextW.
+ */
+BOOL WINAPI CryptAcquireContextA (HCRYPTPROV *phProv, LPCSTR pszContainer,
+		LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
+{
+	PWSTR pProvider = NULL, pContainer = NULL;
+	BOOL ret = FALSE;
+
+	TRACE("(%p, %s, %s, %d, %08x)\n", phProv, pszContainer,
+		pszProvider, dwProvType, dwFlags);
+
+	if ( !CRYPT_ANSIToUnicode(pszContainer, &pContainer, -1) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	if ( !CRYPT_ANSIToUnicode(pszProvider, &pProvider, -1) )
+	{
+		CRYPT_Free(pContainer);
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	ret = CryptAcquireContextW(phProv, pContainer, pProvider, dwProvType, dwFlags);
+
+	CRYPT_Free(pContainer);
+	CRYPT_Free(pProvider);
+
+	return ret;
+}
+
+/******************************************************************************
+ * CryptContextAddRef (ADVAPI32.@)
+ *
+ * Increases reference count of a cryptographic service provider handle
+ * by one.
+ *
+ * PARAMS
+ *  hProv       [I] Handle to the CSP whose reference is being incremented.
+ *  pdwReserved [IN] Reserved for future use and must be NULL.
+ *  dwFlags     [I] Reserved for future use and must be NULL.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptContextAddRef (HCRYPTPROV hProv, DWORD *pdwReserved, DWORD dwFlags)
+{
+	PCRYPTPROV pProv = (PCRYPTPROV)hProv;	
+
+	TRACE("(0x%lx, %p, %08x)\n", hProv, pdwReserved, dwFlags);
+
+	if (!pProv)
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	if (pProv->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	pProv->refcount++;
+	return TRUE;
+}
+
+/******************************************************************************
+ * CryptReleaseContext (ADVAPI32.@)
+ *
+ * Releases the handle of a CSP.  Reference count is decreased.
+ *
+ * PARAMS
+ *  hProv   [I] Handle of a CSP.
+ *  dwFlags [I] Reserved for future use and must be NULL.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptReleaseContext (HCRYPTPROV hProv, ULONG_PTR dwFlags)
+{
+	PCRYPTPROV pProv = (PCRYPTPROV)hProv;
+	BOOL ret = TRUE;
+
+	TRACE("(0x%lx, %08lx)\n", hProv, dwFlags);
+
+	if (!pProv)
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	if (pProv->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	pProv->refcount--;
+	if (pProv->refcount <= 0) 
+	{
+		ret = pProv->pFuncs->pCPReleaseContext(pProv->hPrivate, dwFlags);
+		pProv->dwMagic = 0;
+		FreeLibrary(pProv->hModule);
+#if 0
+		CRYPT_Free(pProv->pVTable->pContextInfo);
+#endif
+		CRYPT_Free(pProv->pVTable->pszProvName);
+		CRYPT_Free(pProv->pVTable);
+		CRYPT_Free(pProv->pFuncs);
+		CRYPT_Free(pProv);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ * CryptGenRandom (ADVAPI32.@)
+ *
+ * Fills a buffer with cryptographically random bytes.
+ *
+ * PARAMS
+ *  hProv    [I] Handle of a CSP.
+ *  dwLen    [I] Number of bytes to generate.
+ *  pbBuffer [I/O] Buffer to contain random bytes.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  pdBuffer must be at least dwLen bytes long.
+ */
+BOOL WINAPI CryptGenRandom (HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+
+	TRACE("(0x%lx, %d, %p)\n", hProv, dwLen, pbBuffer);
+
+	if (!hProv)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+
+	if (prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	return prov->pFuncs->pCPGenRandom(prov->hPrivate, dwLen, pbBuffer);
+}
+
+/******************************************************************************
+ * CryptCreateHash (ADVAPI32.@)
+ *
+ * Initiates the hashing of a stream of data.
+ *
+ * PARAMS
+ *  hProv   [I] Handle of a CSP.
+ *  Algid   [I] Identifies the hash algorithm to use.
+ *  hKey    [I] Key for the hash (if required).
+ *  dwFlags [I] Reserved for future use and must be NULL.
+ *  phHash  [O] Address of the future handle to the new hash object.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  If the algorithm is a keyed hash, hKey is the key.
+ */
+BOOL WINAPI CryptCreateHash (HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey,
+		DWORD dwFlags, HCRYPTHASH *phHash)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+	PCRYPTHASH hash;
+
+	TRACE("(0x%lx, 0x%x, 0x%lx, %08x, %p)\n", hProv, Algid, hKey, dwFlags, phHash);
+
+	if (!prov)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (!phHash || prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if (dwFlags)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+	if ( !(hash = CRYPT_Alloc(sizeof(CRYPTHASH))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	hash->pProvider = prov;
+
+	if (prov->pFuncs->pCPCreateHash(prov->hPrivate, Algid,
+			key ? key->hPrivate : 0, 0, &hash->hPrivate))
+        {
+            *phHash = (HCRYPTHASH)hash;
+            return TRUE;
+        }
+
+	/* CSP error! */
+	CRYPT_Free(hash);
+	*phHash = 0;
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptDecrypt (ADVAPI32.@)
+ *
+ * Decrypts data encrypted by CryptEncrypt.
+ *
+ * PARAMS
+ *  hKey       [I] Handle to the decryption key.
+ *  hHash      [I] Handle to a hash object.
+ *  Final      [I] TRUE if this is the last section to be decrypted.
+ *  dwFlags    [I] Reserved for future use. Can be CRYPT_OAEP.
+ *  pbData     [I/O] Buffer that holds the encrypted data. Holds decrypted
+ *                   data on return
+ *  pdwDataLen [I/O] Length of pbData before and after the call.
+ *
+ *  RETURNS
+ *   Success: TRUE
+ *   Failure: FALSE
+ */
+BOOL WINAPI CryptDecrypt (HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final,
+		DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
+{
+	PCRYPTPROV prov;
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+
+	TRACE("(0x%lx, 0x%lx, %d, %08x, %p, %p)\n", hKey, hHash, Final, dwFlags, pbData, pdwDataLen);
+
+	if (!key || !pbData || !pdwDataLen || !key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = key->pProvider;
+	return prov->pFuncs->pCPDecrypt(prov->hPrivate, key->hPrivate, hash ? hash->hPrivate : 0,
+			Final, dwFlags, pbData, pdwDataLen);
+}
+
+/******************************************************************************
+ * CryptDeriveKey (ADVAPI32.@)
+ *
+ * Generates session keys derived from a base data value.
+ *
+ * PARAMS
+ *  hProv     [I] Handle to a CSP.
+ *  Algid     [I] Identifies the symmetric encryption algorithm to use.
+ *  hBaseData [I] Handle to a hash object.
+ *  dwFlags   [I] Type of key to generate.
+ *  phKey     [I/O] Address of the newly generated key.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptDeriveKey (HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData,
+		DWORD dwFlags, HCRYPTKEY *phKey)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+	PCRYPTHASH hash = (PCRYPTHASH)hBaseData;
+	PCRYPTKEY key;
+
+	TRACE("(0x%lx, 0x%08x, 0x%lx, 0x%08x, %p)\n", hProv, Algid, hBaseData, dwFlags, phKey);
+
+	if (!prov || !hash)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (!phKey || prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if ( !(key = CRYPT_Alloc(sizeof(CRYPTKEY))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	key->pProvider = prov;
+	if (prov->pFuncs->pCPDeriveKey(prov->hPrivate, Algid, hash->hPrivate, dwFlags, &key->hPrivate))
+        {
+            *phKey = (HCRYPTKEY)key;
+            return TRUE;
+        }
+
+	/* CSP error! */
+	CRYPT_Free(key);
+	*phKey = 0;
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptDestroyHash (ADVAPI32.@)
+ *
+ * Destroys the hash object referenced by hHash.
+ *
+ * PARAMS
+ *  hHash [I] Handle of the hash object to be destroyed.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptDestroyHash (HCRYPTHASH hHash)
+{
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+	PCRYPTPROV prov;
+	BOOL ret;
+
+	TRACE("(0x%lx)\n", hHash);
+
+	if (!hash)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+
+	if (!hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = hash->pProvider;
+	ret = prov->pFuncs->pCPDestroyHash(prov->hPrivate, hash->hPrivate);
+	CRYPT_Free(hash);
+	return ret;
+}
+
+/******************************************************************************
+ * CryptDestroyKey (ADVAPI32.@)
+ *
+ * Releases the handle referenced by hKey.
+ *
+ * PARAMS
+ *  hKey [I] Handle of the key to be destroyed.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptDestroyKey (HCRYPTKEY hKey)
+{
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+	PCRYPTPROV prov;
+	BOOL ret;
+
+	TRACE("(0x%lx)\n", hKey);
+
+	if (!key)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+
+	if (!key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = key->pProvider;
+	ret = prov->pFuncs->pCPDestroyKey(prov->hPrivate, key->hPrivate);
+	CRYPT_Free(key);
+	return ret;
+}
+
+/******************************************************************************
+ * CryptDuplicateHash (ADVAPI32.@)
+ *
+ * Duplicates a hash.
+ *
+ * PARAMS
+ *  hHash       [I] Handle to the hash to be copied.
+ *  pdwReserved [I] Reserved for future use and must be zero.
+ *  dwFlags     [I] Reserved for future use and must be zero.
+ *  phHash      [O] Address of the handle to receive the copy.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptDuplicateHash (HCRYPTHASH hHash, DWORD *pdwReserved,
+		DWORD dwFlags, HCRYPTHASH *phHash)
+{
+	PCRYPTPROV prov;
+	PCRYPTHASH orghash, newhash;
+
+	TRACE("(0x%lx, %p, %08x, %p)\n", hHash, pdwReserved, dwFlags, phHash);
+
+	orghash = (PCRYPTHASH)hHash;
+	if (!orghash || pdwReserved || !phHash || !orghash->pProvider || 
+		orghash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = orghash->pProvider;
+	if (!prov->pFuncs->pCPDuplicateHash)
+	{
+		SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+		return FALSE;
+	}
+
+	if ( !(newhash = CRYPT_Alloc(sizeof(CRYPTHASH))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	newhash->pProvider = prov;
+	if (prov->pFuncs->pCPDuplicateHash(prov->hPrivate, orghash->hPrivate, pdwReserved, dwFlags, &newhash->hPrivate))
+	{
+		*phHash = (HCRYPTHASH)newhash;
+		return TRUE;
+	}
+	CRYPT_Free(newhash);
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptDuplicateKey (ADVAPI32.@)
+ *
+ * Duplicate a key and the key's state.
+ *
+ * PARAMS
+ *  hKey        [I] Handle of the key to copy.
+ *  pdwReserved [I] Reserved for future use and must be NULL.
+ *  dwFlags     [I] Reserved for future use and must be zero.
+ *  phKey       [I] Address of the handle to the duplicated key.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptDuplicateKey (HCRYPTKEY hKey, DWORD *pdwReserved, DWORD dwFlags, HCRYPTKEY *phKey)
+{
+	PCRYPTPROV prov;
+	PCRYPTKEY orgkey, newkey;
+
+	TRACE("(0x%lx, %p, %08x, %p)\n", hKey, pdwReserved, dwFlags, phKey);
+
+	orgkey = (PCRYPTKEY)hKey;
+	if (!orgkey || pdwReserved || !phKey || !orgkey->pProvider || 
+		orgkey->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = orgkey->pProvider;
+	if (!prov->pFuncs->pCPDuplicateKey)
+	{
+		SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+		return FALSE;
+	}
+
+	if ( !(newkey = CRYPT_Alloc(sizeof(CRYPTKEY))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	newkey->pProvider = prov;
+	if (prov->pFuncs->pCPDuplicateKey(prov->hPrivate, orgkey->hPrivate, pdwReserved, dwFlags, &newkey->hPrivate))
+	{
+		*phKey = (HCRYPTKEY)newkey;
+		return TRUE;
+	}
+	CRYPT_Free(newkey);
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptEncrypt (ADVAPI32.@)
+ *
+ * Encrypts data.
+ *
+ * PARAMS
+ *  hKey       [I] Handle to the encryption key.
+ *  hHash      [I] Handle to a hash object.
+ *  Final      [I] TRUE if this is the last section to encrypt.
+ *  dwFlags    [I] Can be CRYPT_OAEP.
+ *  pbData     [I/O] Data to be encrypted. Contains encrypted data after call.
+ *  pdwDataLen [I/O] Length of the data to encrypt. Contains the length of the
+ *                   encrypted data after call.
+ *  dwBufLen   [I] Length of the input pbData buffer.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ *  NOTES
+ *   If pbData is NULL, CryptEncrypt determines stores the number of bytes
+ *   required for the returned data in pdwDataLen.
+ */
+BOOL WINAPI CryptEncrypt (HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final,
+		DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen)
+{
+	PCRYPTPROV prov;
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+
+	TRACE("(0x%lx, 0x%lx, %d, %08x, %p, %p, %d)\n", hKey, hHash, Final, dwFlags, pbData, pdwDataLen, dwBufLen);
+
+	if (!key || !pdwDataLen || !key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = key->pProvider;
+	return prov->pFuncs->pCPEncrypt(prov->hPrivate, key->hPrivate, hash ? hash->hPrivate : 0,
+			Final, dwFlags, pbData, pdwDataLen, dwBufLen);
+}
+
+/******************************************************************************
+ * CryptEnumProvidersW (ADVAPI32.@)
+ *
+ * Returns the next available CSP.
+ *
+ * PARAMS
+ *  dwIndex     [I] Index of the next provider to be enumerated.
+ *  pdwReserved [I] Reserved for future use and must be NULL.
+ *  dwFlags     [I] Reserved for future use and must be zero.
+ *  pdwProvType [O] DWORD designating the type of the provider.
+ *  pszProvName [O] Buffer that receives data from the provider.
+ *  pcbProvName [I/O] Specifies the size of pszProvName. Contains the number
+ *                    of bytes stored in the buffer on return.
+ *
+ *  RETURNS
+ *   Success: TRUE
+ *   Failure: FALSE
+ *
+ *  NOTES
+ *   If pszProvName is NULL, CryptEnumProvidersW sets the size of the name
+ *   for memory allocation purposes.
+ */
+BOOL WINAPI CryptEnumProvidersW (DWORD dwIndex, DWORD *pdwReserved,
+		DWORD dwFlags, DWORD *pdwProvType, LPWSTR pszProvName, DWORD *pcbProvName)
+{
+	HKEY hKey;
+	static const WCHAR providerW[] = {
+                'S','o','f','t','w','a','r','e','\\',
+                'M','i','c','r','o','s','o','f','t','\\',
+                'C','r','y','p','t','o','g','r','a','p','h','y','\\',
+                'D','e','f','a','u','l','t','s','\\',
+                'P','r','o','v','i','d','e','r',0
+        };
+	static const WCHAR typeW[] = {'T','y','p','e',0};
+
+	TRACE("(%d, %p, %d, %p, %p, %p)\n", dwIndex, pdwReserved, dwFlags,
+			pdwProvType, pszProvName, pcbProvName);
+
+	if (pdwReserved || !pcbProvName)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if (dwFlags)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+
+	if (RegOpenKeyW(HKEY_LOCAL_MACHINE, providerW, &hKey))
+	{
+		SetLastError(NTE_FAIL);
+		return FALSE;
+	}
+
+	if (!pszProvName)
+	{
+		DWORD numkeys;
+		WCHAR *provNameW;
+		
+		RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &numkeys, pcbProvName,
+				 NULL, NULL, NULL, NULL, NULL, NULL);
+		
+		if (!(provNameW = CRYPT_Alloc(*pcbProvName * sizeof(WCHAR))))
+		{
+			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+			return FALSE;
+		}
+
+		RegEnumKeyExW(hKey, dwIndex, provNameW, pcbProvName, NULL, NULL, NULL, NULL);
+		CRYPT_Free(provNameW);
+		(*pcbProvName)++;
+		*pcbProvName *= sizeof(WCHAR);
+
+		if (dwIndex >= numkeys)
+		{
+			SetLastError(ERROR_NO_MORE_ITEMS);
+			return FALSE;
+		}
+	} else {
+		DWORD size = sizeof(DWORD);
+		DWORD result;
+		HKEY subkey;
+		
+		result = RegEnumKeyW(hKey, dwIndex, pszProvName, *pcbProvName / sizeof(WCHAR));
+		if (result)
+		{
+			SetLastError(result);
+			return FALSE;
+		}
+		if (RegOpenKeyW(hKey, pszProvName, &subkey))
+			return FALSE;
+		if (RegQueryValueExW(subkey, typeW, NULL, NULL, (BYTE*)pdwProvType, &size))
+			return FALSE;
+		RegCloseKey(subkey);
+	}
+	RegCloseKey(hKey);
+	return TRUE;
+}
+
+/******************************************************************************
+ * CryptEnumProvidersA (ADVAPI32.@)
+ *
+ * See CryptEnumProvidersW.
+ */
+BOOL WINAPI CryptEnumProvidersA (DWORD dwIndex, DWORD *pdwReserved,
+		DWORD dwFlags, DWORD *pdwProvType, LPSTR pszProvName, DWORD *pcbProvName)
+{
+	PWSTR str = NULL;
+	DWORD bufsize;
+	BOOL ret; /* = FALSE; */
+
+	TRACE("(%d, %p, %08x, %p, %p, %p)\n", dwIndex, pdwReserved, dwFlags,
+			pdwProvType, pszProvName, pcbProvName);
+
+	if(!CryptEnumProvidersW(dwIndex, pdwReserved, dwFlags, pdwProvType, NULL, &bufsize))
+		return FALSE;
+	if ( pszProvName && !(str = CRYPT_Alloc(bufsize)) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	ret = CryptEnumProvidersW(dwIndex, pdwReserved, dwFlags, pdwProvType, str, &bufsize);
+	if (str)
+		CRYPT_UnicodeToANSI(str, &pszProvName, *pcbProvName);
+	*pcbProvName = bufsize / sizeof(WCHAR);  /* FIXME: not correct */
+	if (str)
+	{
+		CRYPT_Free(str);
+		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+		{
+			SetLastError(ERROR_MORE_DATA);
+			return FALSE;
+		}
+	}
+	return ret;
+}
+
+/******************************************************************************
+ * CryptEnumProviderTypesW (ADVAPI32.@)
+ *
+ * Retrieves the next type of CSP supported.
+ *
+ * PARAMS
+ *  dwIndex     [I] Index of the next provider to be enumerated.
+ *  pdwReserved [I] Reserved for future use and must be NULL.
+ *  dwFlags     [I] Reserved for future use and must be zero.
+ *  pdwProvType [O] DWORD designating the type of the provider.
+ *  pszTypeName [O] Buffer that receives data from the provider type.
+ *  pcbTypeName [I/O] Specifies the size of pszTypeName. Contains the number
+ *                    of bytes stored in the buffer on return.
+ *
+ *  RETURNS
+ *   Success: TRUE
+ *   Failure: FALSE
+ *
+ *  NOTES
+ *   If pszTypeName is NULL, CryptEnumProviderTypesW sets the size of the name
+ *   for memory allocation purposes.
+ */
+BOOL WINAPI CryptEnumProviderTypesW (DWORD dwIndex, DWORD *pdwReserved,
+		DWORD dwFlags, DWORD *pdwProvType, LPWSTR pszTypeName, DWORD *pcbTypeName)
+{
+	HKEY hKey, hSubkey;
+	DWORD keylen, numkeys, dwType;
+	PWSTR keyname, ch;
+	DWORD result;
+	static const WCHAR KEYSTR[] = {
+                'S','o','f','t','w','a','r','e','\\',
+                'M','i','c','r','o','s','o','f','t','\\',
+                'C','r','y','p','t','o','g','r','a','p','h','y','\\',
+                'D','e','f','a','u','l','t','s','\\',
+                'P','r','o','v','i','d','e','r',' ','T','y','p','e','s',0
+	};
+	static const WCHAR typenameW[] = {'T','y','p','e','N','a','m','e',0};
+
+	TRACE("(%d, %p, %08x, %p, %p, %p)\n", dwIndex, pdwReserved,
+		dwFlags, pdwProvType, pszTypeName, pcbTypeName);
+
+	if (pdwReserved || !pdwProvType || !pcbTypeName)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if (dwFlags)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+
+	if (RegOpenKeyW(HKEY_LOCAL_MACHINE, KEYSTR, &hKey))
+		return FALSE;
+
+	RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &numkeys, &keylen, NULL, NULL, NULL, NULL, NULL, NULL);
+	if (dwIndex >= numkeys)
+	{
+		SetLastError(ERROR_NO_MORE_ITEMS);
+		return FALSE;
+	}
+	keylen++;
+	if ( !(keyname = CRYPT_Alloc(keylen*sizeof(WCHAR))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	if ( RegEnumKeyW(hKey, dwIndex, keyname, keylen) ) {
+                CRYPT_Free(keyname);
+		return FALSE;
+        }
+	RegOpenKeyW(hKey, keyname, &hSubkey);
+	ch = keyname + strlenW(keyname);
+	/* Convert "Type 000" to 0, etc/ */
+	*pdwProvType = *(--ch) - '0';
+	*pdwProvType += (*(--ch) - '0') * 10;
+	*pdwProvType += (*(--ch) - '0') * 100;
+	CRYPT_Free(keyname);
+	
+	result = RegQueryValueExW(hSubkey, typenameW, NULL, &dwType, (LPBYTE)pszTypeName, pcbTypeName);
+	if (result)
+	{
+		SetLastError(result);
+		return FALSE;
+	}
+
+	RegCloseKey(hSubkey);
+	RegCloseKey(hKey);
+	return TRUE;
+}
+
+/******************************************************************************
+ * CryptEnumProviderTypesA (ADVAPI32.@)
+ *
+ * See CryptEnumProviderTypesW.
+ */
+BOOL WINAPI CryptEnumProviderTypesA (DWORD dwIndex, DWORD *pdwReserved,
+		DWORD dwFlags, DWORD *pdwProvType, LPSTR pszTypeName, DWORD *pcbTypeName)
+{
+	PWSTR str = NULL;
+	DWORD bufsize;
+	BOOL ret;
+
+	TRACE("(%d, %p, %08x, %p, %p, %p)\n", dwIndex, pdwReserved, dwFlags,
+			pdwProvType, pszTypeName, pcbTypeName);
+
+	if(!CryptEnumProviderTypesW(dwIndex, pdwReserved, dwFlags, pdwProvType, NULL, &bufsize))
+		return FALSE;
+	if ( pszTypeName && !(str = CRYPT_Alloc(bufsize)) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	ret = CryptEnumProviderTypesW(dwIndex, pdwReserved, dwFlags, pdwProvType, str, &bufsize);
+	if (str)
+		CRYPT_UnicodeToANSI(str, &pszTypeName, *pcbTypeName);
+	*pcbTypeName = bufsize / sizeof(WCHAR);
+	if (str)
+	{
+		CRYPT_Free(str);
+		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+		{
+			SetLastError(ERROR_MORE_DATA);
+			return FALSE;
+		}
+	}
+	return ret;
+}
+
+/******************************************************************************
+ * CryptExportKey (ADVAPI32.@)
+ * 
+ * Exports a cryptographic key from a CSP.
+ *
+ * PARAMS
+ *  hKey       [I] Handle to the key to export.
+ *  hExpKey    [I] Handle to a cryptographic key of the end user.
+ *  dwBlobType [I] Type of BLOB to be exported.
+ *  dwFlags    [I] CRYPT_DESTROYKEY/SSL2_FALLBACK/OAEP.
+ *  pbData     [O] Buffer to receive BLOB data.
+ *  pdwDataLen [I/O] Specifies the size of pbData.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  if pbData is NULL, CryptExportKey sets pdwDataLen as the size of the
+ *  buffer needed to hold the BLOB.
+ */
+BOOL WINAPI CryptExportKey (HCRYPTKEY hKey, HCRYPTKEY hExpKey, DWORD dwBlobType,
+		DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
+{
+	PCRYPTPROV prov;
+	PCRYPTKEY key = (PCRYPTKEY)hKey, expkey = (PCRYPTKEY)hExpKey;
+
+	TRACE("(0x%lx, 0x%lx, %d, %08x, %p, %p)\n", hKey, hExpKey, dwBlobType, dwFlags, pbData, pdwDataLen);
+
+	if (!key || !pdwDataLen || !key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = key->pProvider;
+	return prov->pFuncs->pCPExportKey(prov->hPrivate, key->hPrivate, expkey ? expkey->hPrivate : 0,
+			dwBlobType, dwFlags, pbData, pdwDataLen);
+}
+
+/******************************************************************************
+ * CryptGenKey (ADVAPI32.@)
+ *
+ * Generates a random cryptographic session key or a pub/priv key pair.
+ *
+ * PARAMS
+ *  hProv   [I] Handle to a CSP.
+ *  Algid   [I] Algorithm to use to make key.
+ *  dwFlags [I] Specifies type of key to make.
+ *  phKey   [I] Address of the handle to which the new key is copied.
+ *
+ *  RETURNS
+ *   Success: TRUE
+ *   Failure: FALSE
+ */
+BOOL WINAPI CryptGenKey (HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+	PCRYPTKEY key;
+
+	TRACE("(0x%lx, %d, %08x, %p)\n", hProv, Algid, dwFlags, phKey);
+
+	if (!prov)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (!phKey || !prov || prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if ( !(key = CRYPT_Alloc(sizeof(CRYPTKEY))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	key->pProvider = prov;
+
+	if (prov->pFuncs->pCPGenKey(prov->hPrivate, Algid, dwFlags, &key->hPrivate))
+        {
+            *phKey = (HCRYPTKEY)key;
+            return TRUE;
+        }
+
+	/* CSP error! */
+	CRYPT_Free(key);
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptGetDefaultProviderW (ADVAPI32.@)
+ *
+ * Finds the default CSP of a certain provider type.
+ *
+ * PARAMS
+ *  dwProvType  [I] Provider type to look for.
+ *  pdwReserved [I] Reserved for future use and must be NULL.
+ *  dwFlags     [I] CRYPT_MACHINE_DEFAULT/USER_DEFAULT
+ *  pszProvName [O] Name of the default CSP.
+ *  pcbProvName [I/O] Size of pszProvName
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  If pszProvName is NULL, pcbProvName will hold the size of the buffer for
+ *  memory allocation purposes on return.
+ */
+BOOL WINAPI CryptGetDefaultProviderW (DWORD dwProvType, DWORD *pdwReserved,
+		DWORD dwFlags, LPWSTR pszProvName, DWORD *pcbProvName)
+{
+	HKEY hKey;
+	PWSTR keyname;
+	DWORD result;
+	static const WCHAR nameW[] = {'N','a','m','e',0};
+
+	if (pdwReserved || !pcbProvName)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if (dwFlags & ~(CRYPT_USER_DEFAULT | CRYPT_MACHINE_DEFAULT))
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+	if (dwProvType > 999)
+	{
+		SetLastError(NTE_BAD_PROV_TYPE);
+		return FALSE;
+	}
+	if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, dwFlags & CRYPT_USER_DEFAULT)) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	if (RegOpenKeyW((dwFlags & CRYPT_USER_DEFAULT) ?  HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE ,keyname, &hKey))
+	{
+		CRYPT_Free(keyname);
+		SetLastError(NTE_PROV_TYPE_NOT_DEF);
+		return FALSE;
+	}
+	CRYPT_Free(keyname);
+	
+	result = RegQueryValueExW(hKey, nameW, NULL, NULL, (LPBYTE)pszProvName, pcbProvName); 
+	if (result)
+	{
+		if (result != ERROR_MORE_DATA)
+			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+		else
+			SetLastError(result);
+		
+		return FALSE;
+	}
+	
+	RegCloseKey(hKey);
+	return TRUE;
+}
+
+/******************************************************************************
+ * CryptGetDefaultProviderA (ADVAPI32.@)
+ *
+ * See CryptGetDefaultProviderW.
+ */
+BOOL WINAPI CryptGetDefaultProviderA (DWORD dwProvType, DWORD *pdwReserved,
+		DWORD dwFlags, LPSTR pszProvName, DWORD *pcbProvName)
+{
+	PWSTR str = NULL;
+	DWORD bufsize;
+	BOOL ret = FALSE;
+
+	TRACE("(%d, %p, %08x, %p, %p)\n", dwProvType, pdwReserved, dwFlags, pszProvName, pcbProvName);
+
+	CryptGetDefaultProviderW(dwProvType, pdwReserved, dwFlags, NULL, &bufsize);
+	if ( pszProvName && !(str = CRYPT_Alloc(bufsize)) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	ret = CryptGetDefaultProviderW(dwProvType, pdwReserved, dwFlags, str, &bufsize);
+	if (str)
+		CRYPT_UnicodeToANSI(str, &pszProvName, *pcbProvName);
+	*pcbProvName = bufsize / sizeof(WCHAR);
+	if (str)
+	{
+		CRYPT_Free(str);
+		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+		{
+			SetLastError(ERROR_MORE_DATA);
+			return FALSE;
+		}
+	}
+	return ret;
+}
+
+/******************************************************************************
+ * CryptGetHashParam (ADVAPI32.@)
+ *
+ * Retrieves data that controls the operations of a hash object.
+ *
+ * PARAMS
+ *  hHash      [I] Handle of the hash object to question.
+ *  dwParam    [I] Query type.
+ *  pbData     [O] Buffer that receives the value data.
+ *  pdwDataLen [I/O] Size of the pbData buffer.
+ *  dwFlags    [I] Reserved for future use and must be zero.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  If pbData is NULL, pdwDataLen will contain the length required.
+ */
+BOOL WINAPI CryptGetHashParam (HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData,
+		DWORD *pdwDataLen, DWORD dwFlags)
+{
+	PCRYPTPROV prov;
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+
+	TRACE("(0x%lx, %d, %p, %p, %08x)\n", hHash, dwParam, pbData, pdwDataLen, dwFlags);
+
+	if (!hash || !pdwDataLen || !hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = hash->pProvider;
+	return prov->pFuncs->pCPGetHashParam(prov->hPrivate, hash->hPrivate, dwParam,
+			pbData, pdwDataLen, dwFlags);
+}
+
+/******************************************************************************
+ * CryptGetKeyParam (ADVAPI32.@)
+ *
+ * Retrieves data that controls the operations of a key.
+ *
+ * PARAMS
+ *  hKey       [I] Handle to they key in question.
+ *  dwParam    [I] Specifies query type.
+ *  pbData     [O] Sequence of bytes to receive data.
+ *  pdwDataLen [I/O] Size of pbData.
+ *  dwFlags    [I] Reserved for future use and must be zero.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  If pbData is NULL, pdwDataLen is set to the needed length of the buffer.
+ */
+BOOL WINAPI CryptGetKeyParam (HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData,
+		DWORD *pdwDataLen, DWORD dwFlags)
+{
+	PCRYPTPROV prov;
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+
+	TRACE("(0x%lx, %d, %p, %p, %08x)\n", hKey, dwParam, pbData, pdwDataLen, dwFlags);
+
+	if (!key || !pdwDataLen || !key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = key->pProvider;
+	return prov->pFuncs->pCPGetKeyParam(prov->hPrivate, key->hPrivate, dwParam,
+			pbData, pdwDataLen, dwFlags);
+}
+
+/******************************************************************************
+ * CryptGetProvParam (ADVAPI32.@)
+ *
+ * Retrieves parameters that control the operations of a CSP.
+ *
+ * PARAMS
+ *  hProv      [I] Handle of the CSP in question.
+ *  dwParam    [I] Specifies query type.
+ *  pbData     [O] Buffer to receive the data.
+ *  pdwDataLen [I/O] Size of pbData.
+ *  dwFlags    [I] see MSDN Docs.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  If pbData is NULL, pdwDataLen is set to the needed buffer length.
+ */
+BOOL WINAPI CryptGetProvParam (HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,
+		DWORD *pdwDataLen, DWORD dwFlags)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+
+	TRACE("(0x%lx, %d, %p, %p, %08x)\n", hProv, dwParam, pbData, pdwDataLen, dwFlags);
+
+	if (!prov || prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	return prov->pFuncs->pCPGetProvParam(prov->hPrivate, dwParam, pbData, pdwDataLen, dwFlags);
+}
+
+/******************************************************************************
+ * CryptGetUserKey (ADVAPI32.@)
+ *
+ * Gets a handle of one of a user's two public/private key pairs.
+ *
+ * PARAMS
+ *  hProv     [I] Handle of a CSP.
+ *  dwKeySpec [I] Private key to use.
+ *  phUserKey [O] Pointer to the handle of the retrieved keys.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptGetUserKey (HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+	PCRYPTKEY key;
+
+	TRACE("(0x%lx, %d, %p)\n", hProv, dwKeySpec, phUserKey);
+
+	if (!prov)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (!phUserKey || prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if ( !(key = CRYPT_Alloc(sizeof(CRYPTKEY))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	key->pProvider = prov;
+
+	if (prov->pFuncs->pCPGetUserKey(prov->hPrivate, dwKeySpec, &key->hPrivate))
+        {
+            *phUserKey = (HCRYPTKEY)key;
+            return TRUE;
+        }
+
+	/* CSP Error */
+	CRYPT_Free(key);
+	*phUserKey = 0;
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptHashData (ADVAPI32.@)
+ *
+ * Adds data to a hash object.
+ *
+ * PARAMS
+ *  hHash     [I] Handle of the hash object.
+ *  pbData    [I] Buffer of data to be hashed.
+ *  dwDataLen [I] Number of bytes to add.
+ *  dwFlags   [I] Can be CRYPT_USERDATA
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptHashData (HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
+{
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+	PCRYPTPROV prov;
+
+	TRACE("(0x%lx, %p, %d, %08x)\n", hHash, pbData, dwDataLen, dwFlags);
+
+	if (!hash)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (!hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = hash->pProvider;
+	return prov->pFuncs->pCPHashData(prov->hPrivate, hash->hPrivate, pbData, dwDataLen, dwFlags);
+}
+
+/******************************************************************************
+ * CryptHashSessionKey (ADVAPI32.@)
+ *
+ * Compute the cryptographic hash of a session key object.
+ *
+ * PARAMS 
+ *  hHash   [I] Handle to the hash object.
+ *  hKey    [I] Handle to the key to be hashed.
+ *  dwFlags [I] Can be CRYPT_LITTLE_ENDIAN.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptHashSessionKey (HCRYPTHASH hHash, HCRYPTKEY hKey, DWORD dwFlags)
+{
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+	PCRYPTPROV prov;
+
+	TRACE("(0x%lx, 0x%lx, %08x)\n", hHash, hKey, dwFlags);
+
+	if (!hash || !key)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+
+	if (!hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = hash->pProvider;
+	return prov->pFuncs->pCPHashSessionKey(prov->hPrivate, hash->hPrivate, key->hPrivate, dwFlags);
+}
+
+/******************************************************************************
+ * CryptImportKey (ADVAPI32.@)
+ *
+ * Transfer a cryptographic key from a key BLOB into a cryptographic service provider (CSP).
+ *
+ * PARAMS
+ *  hProv     [I] Handle of a CSP.
+ *  pbData    [I] Contains the key to be imported.
+ *  dwDataLen [I] Length of the key.
+ *  hPubKey   [I] Cryptographic key that decrypts pdData
+ *  dwFlags   [I] Used only with a public/private key pair.
+ *  phKey     [O] Imported key.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptImportKey (HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen,
+		HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+	PCRYPTKEY pubkey = (PCRYPTKEY)hPubKey, importkey;
+
+	TRACE("(0x%lx, %p, %d, 0x%lx, %08x, %p)\n", hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
+
+	if (!prov || !pbData || !dwDataLen || !phKey || prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	if ( !(importkey = CRYPT_Alloc(sizeof(CRYPTKEY))) )
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	importkey->pProvider = prov;
+	if (prov->pFuncs->pCPImportKey(prov->hPrivate, pbData, dwDataLen,
+			pubkey ? pubkey->hPrivate : 0, dwFlags, &importkey->hPrivate))
+	{
+		*phKey = (HCRYPTKEY)importkey;
+		return TRUE;
+	}
+
+	CRYPT_Free(importkey);
+	return FALSE;
+}
+
+/******************************************************************************
+ * CryptSignHashW (ADVAPI32.@)
+ *
+ * Signs data.
+ *
+ * PARAMS
+ *  hHash        [I] Handle of the hash object to be signed.
+ *  dwKeySpec    [I] Private key to use.
+ *  sDescription [I] Should be NULL.
+ *  dwFlags      [I] CRYPT_NOHASHOID/X931_FORMAT.
+ *  pbSignature  [O] Buffer of the signature data.
+ *  pdwSigLen    [I/O] Size of the pbSignature buffer.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ *
+ * NOTES
+ *  Because of security flaws sDescription should not be used and should thus be
+ *  NULL. It is supported only for compatibility with Microsoft's Cryptographic
+ *  Providers.
+ */
+BOOL WINAPI CryptSignHashW (HCRYPTHASH hHash, DWORD dwKeySpec, LPCWSTR sDescription,
+		DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen)
+{
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+	PCRYPTPROV prov;
+
+	TRACE("(0x%lx, %d, %s, %08x, %p, %p)\n", 
+		hHash, dwKeySpec, debugstr_w(sDescription), dwFlags, pbSignature, pdwSigLen);
+
+	if (!hash)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (!pdwSigLen || !hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = hash->pProvider;
+	return prov->pFuncs->pCPSignHash(prov->hPrivate, hash->hPrivate, dwKeySpec, sDescription,
+		dwFlags, pbSignature, pdwSigLen);
+}
+
+/******************************************************************************
+ * CryptSignHashA (ADVAPI32.@)
+ *
+ * See CryptSignHashW.
+ */
+BOOL WINAPI CryptSignHashA (HCRYPTHASH hHash, DWORD dwKeySpec, LPCSTR sDescription,
+		DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen)
+{
+	LPWSTR wsDescription;
+	BOOL result;
+
+	TRACE("(0x%lx, %d, %s, %08x, %p, %p)\n", 
+		hHash, dwKeySpec, debugstr_a(sDescription), dwFlags, pbSignature, pdwSigLen);
+
+	CRYPT_ANSIToUnicode(sDescription, &wsDescription, -1);
+	result = CryptSignHashW(hHash, dwKeySpec, wsDescription, dwFlags, pbSignature, pdwSigLen);
+	CRYPT_Free(wsDescription);
+
+	return result;
+}
+
+/******************************************************************************
+ * CryptSetHashParam (ADVAPI32.@)
+ *
+ * Customizes the operations of a hash object.
+ *
+ * PARAMS
+ *  hHash   [I] Handle of the hash object to set parameters.
+ *  dwParam [I] HP_HMAC_INFO/HASHVAL.
+ *  pbData  [I] Value data buffer.
+ *  dwFlags [I] Reserved for future use and must be zero.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptSetHashParam (HCRYPTHASH hHash, DWORD dwParam, CONST BYTE *pbData, DWORD dwFlags)
+{
+	PCRYPTPROV prov;
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+
+	TRACE("(0x%lx, %d, %p, %08x)\n", hHash, dwParam, pbData, dwFlags);
+
+	if (!hash || !pbData || !hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = hash->pProvider;
+	return prov->pFuncs->pCPSetHashParam(prov->hPrivate, hash->hPrivate,
+			dwParam, pbData, dwFlags);
+}
+
+/******************************************************************************
+ * CryptSetKeyParam (ADVAPI32.@)
+ *
+ * Customizes a session key's operations.
+ *
+ * PARAMS
+ *  hKey    [I] Handle to the key to set values.
+ *  dwParam [I] See MSDN Doc.
+ *  pbData  [I] Buffer of values to set.
+ *  dwFlags [I] Only used when dwParam == KP_ALGID.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptSetKeyParam (HCRYPTKEY hKey, DWORD dwParam, CONST BYTE *pbData, DWORD dwFlags)
+{
+	PCRYPTPROV prov;
+	PCRYPTKEY key = (PCRYPTKEY)hKey;
+
+	TRACE("(0x%lx, %d, %p, %08x)\n", hKey, dwParam, pbData, dwFlags);
+
+	if (!key || !pbData || !key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	prov = key->pProvider;
+	return prov->pFuncs->pCPSetKeyParam(prov->hPrivate, key->hPrivate,
+			dwParam, pbData, dwFlags);
+}
+
+/******************************************************************************
+ * CryptSetProviderA (ADVAPI32.@)
+ *
+ * Specifies the current user's default CSP.
+ *
+ * PARAMS
+ *  pszProvName [I] Name of the new default CSP.
+ *  dwProvType  [I] Provider type of the CSP.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptSetProviderA (LPCSTR pszProvName, DWORD dwProvType)
+{
+	TRACE("(%s, %d)\n", pszProvName, dwProvType);
+	return CryptSetProviderExA(pszProvName, dwProvType, NULL, CRYPT_USER_DEFAULT);
+}
+
+/******************************************************************************
+ * CryptSetProviderW (ADVAPI32.@)
+ *
+ * See CryptSetProviderA.
+ */
+BOOL WINAPI CryptSetProviderW (LPCWSTR pszProvName, DWORD dwProvType)
+{
+	TRACE("(%s, %d)\n", debugstr_w(pszProvName), dwProvType);
+	return CryptSetProviderExW(pszProvName, dwProvType, NULL, CRYPT_USER_DEFAULT);
+}
+
+/******************************************************************************
+ * CryptSetProviderExW (ADVAPI32.@)
+ *
+ * Specifies the default CSP.
+ *
+ * PARAMS
+ *  pszProvName [I] Name of the new default CSP.
+ *  dwProvType  [I] Provider type of the CSP.
+ *  pdwReserved [I] Reserved for future use and must be NULL.
+ *  dwFlags     [I] See MSDN Doc.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptSetProviderExW (LPCWSTR pszProvName, DWORD dwProvType, DWORD *pdwReserved, DWORD dwFlags)
+{
+	HKEY hProvKey, hTypeKey;
+	PWSTR keyname;
+	static const WCHAR nameW[] = {'N','a','m','e',0};
+
+	TRACE("(%s, %d, %p, %08x)\n", debugstr_w(pszProvName), dwProvType, pdwReserved, dwFlags);
+
+	if (!pszProvName || pdwReserved)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if (dwProvType > MAXPROVTYPES)
+	{
+		SetLastError(NTE_BAD_PROV_TYPE);
+		return FALSE;
+	}
+	if (dwFlags & ~(CRYPT_MACHINE_DEFAULT | CRYPT_USER_DEFAULT | CRYPT_DELETE_DEFAULT)
+			|| dwFlags == CRYPT_DELETE_DEFAULT)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+
+	if (!(keyname = CRYPT_GetTypeKeyName(dwProvType, dwFlags & CRYPT_USER_DEFAULT)))
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+	if (RegOpenKeyW((dwFlags & CRYPT_USER_DEFAULT) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
+		keyname, &hTypeKey))
+	{
+		CRYPT_Free(keyname);
+		SetLastError(NTE_BAD_PROVIDER);
+		return FALSE;
+	}
+	CRYPT_Free(keyname);
+	
+	if (dwFlags & CRYPT_DELETE_DEFAULT)
+	{
+		RegDeleteValueW(hTypeKey, nameW);
+	}
+	else
+	{
+		if (!(keyname = CRYPT_GetProvKeyName(pszProvName)))
+		{
+			RegCloseKey(hTypeKey);
+			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+			return FALSE;
+		}
+		if (RegOpenKeyW((dwFlags & CRYPT_USER_DEFAULT) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
+			keyname, &hProvKey))
+		{
+			CRYPT_Free(keyname);
+			RegCloseKey(hTypeKey);
+			SetLastError(NTE_BAD_PROVIDER);
+			return FALSE;
+		}
+		CRYPT_Free(keyname);
+		
+		if (RegSetValueExW(hTypeKey, nameW, 0, REG_SZ, (const BYTE *)pszProvName,
+			(strlenW(pszProvName) + 1)*sizeof(WCHAR)))
+		{
+			RegCloseKey(hTypeKey);
+			RegCloseKey(hProvKey);
+			return FALSE;
+		}
+		
+		RegCloseKey(hProvKey);
+	}
+	RegCloseKey(hTypeKey);
+
+	return TRUE;
+}
+
+/******************************************************************************
+ * CryptSetProviderExA (ADVAPI32.@)
+ *
+ * See CryptSetProviderExW.
+ */
+BOOL WINAPI CryptSetProviderExA (LPCSTR pszProvName, DWORD dwProvType, DWORD *pdwReserved, DWORD dwFlags)
+{
+	BOOL ret = FALSE;
+	PWSTR str = NULL;
+
+	TRACE("(%s, %d, %p, %08x)\n", pszProvName, dwProvType, pdwReserved, dwFlags);
+
+	if (CRYPT_ANSIToUnicode(pszProvName, &str, -1))
+	{
+		ret = CryptSetProviderExW(str, dwProvType, pdwReserved, dwFlags);
+		CRYPT_Free(str);
+	}
+	return ret;
+}
+
+/******************************************************************************
+ * CryptSetProvParam (ADVAPI32.@)
+ *
+ * Customizes the operations of a CSP.
+ *
+ * PARAMS
+ *  hProv   [I] Handle of a CSP.
+ *  dwParam [I] See MSDN Doc.
+ *  pbData  [I] Buffer that contains a value to set as a parameter.
+ *  dwFlags [I] if dwParam is PP_USE_HARDWARE_RNG, dwFlags must be zero.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+BOOL WINAPI CryptSetProvParam (HCRYPTPROV hProv, DWORD dwParam, CONST BYTE *pbData, DWORD dwFlags)
+{
+	PCRYPTPROV prov = (PCRYPTPROV)hProv;
+
+	TRACE("(0x%lx, %d, %p, %08x)\n", hProv, dwParam, pbData, dwFlags);
+
+	if (!prov)
+	{
+		SetLastError(ERROR_INVALID_HANDLE);
+		return FALSE;
+	}
+	if (prov->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	if (dwFlags & PP_USE_HARDWARE_RNG)
+	{
+		FIXME("PP_USE_HARDWARE_RNG: What do I do with this?\n");
+		FIXME("\tLetting the CSP decide.\n");
+	}
+	if (dwFlags & PP_CLIENT_HWND)
+	{
+		/* FIXME: Should verify the parameter */
+		if (pbData /* && IsWindow((HWND)pbData) */)
+		{
+			crypt_hWindow = (HWND)(pbData);
+			return TRUE;
+		} else {
+			SetLastError(ERROR_INVALID_PARAMETER);
+			return FALSE;
+		}
+	}
+	/* All other flags go to the CSP */
+	return prov->pFuncs->pCPSetProvParam(prov->hPrivate, dwParam, pbData, dwFlags);
+}
+
+/******************************************************************************
+ * CryptVerifySignatureW (ADVAPI32.@)
+ *
+ * Verifies the signature of a hash object.
+ *
+ * PARAMS
+ *  hHash        [I] Handle of the hash object to verify.
+ *  pbSignature  [I] Signature data to verify.
+ *  dwSigLen     [I] Size of pbSignature.
+ *  hPubKey      [I] Handle to the public key to authenticate signature.
+ *  sDescription [I] Should be NULL.
+ *  dwFlags      [I] See MSDN doc.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ * 
+ * NOTES
+ *  Because of security flaws sDescription should not be used and should thus be
+ *  NULL. It is supported only for compatibility with Microsoft's Cryptographic
+ *  Providers.
+ */
+BOOL WINAPI CryptVerifySignatureW (HCRYPTHASH hHash, CONST BYTE *pbSignature, DWORD dwSigLen,
+		HCRYPTKEY hPubKey, LPCWSTR sDescription, DWORD dwFlags)
+{
+	PCRYPTHASH hash = (PCRYPTHASH)hHash;
+	PCRYPTKEY key = (PCRYPTKEY)hPubKey;
+	PCRYPTPROV prov;
+
+	TRACE("(0x%lx, %p, %d, 0x%lx, %s, %08x)\n", hHash, pbSignature,
+			dwSigLen, hPubKey, debugstr_w(sDescription), dwFlags);
+
+	if (!hash || !key ||
+	    !hash->pProvider || hash->pProvider->dwMagic != MAGIC_CRYPTPROV ||
+	    !key->pProvider || key->pProvider->dwMagic != MAGIC_CRYPTPROV)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+		
+	prov = hash->pProvider;
+	return prov->pFuncs->pCPVerifySignature(prov->hPrivate, hash->hPrivate, pbSignature, dwSigLen,
+		key->hPrivate, sDescription, dwFlags);
+}
+
+/******************************************************************************
+ * CryptVerifySignatureA (ADVAPI32.@)
+ *
+ * See CryptVerifySignatureW.
+ */
+BOOL WINAPI CryptVerifySignatureA (HCRYPTHASH hHash, CONST BYTE *pbSignature, DWORD dwSigLen,
+		HCRYPTKEY hPubKey, LPCSTR sDescription, DWORD dwFlags)
+{
+	LPWSTR wsDescription;
+	BOOL result;
+
+	TRACE("(0x%lx, %p, %d, 0x%lx, %s, %08x)\n", hHash, pbSignature,
+			dwSigLen, hPubKey, debugstr_a(sDescription), dwFlags);
+
+	CRYPT_ANSIToUnicode(sDescription, &wsDescription, -1);
+	result = CryptVerifySignatureW(hHash, pbSignature, dwSigLen, hPubKey, wsDescription, dwFlags);
+	CRYPT_Free(wsDescription);
+
+	return result;
+}
+
+/******************************************************************************
+ * SystemFunction030   (ADVAPI32.@)
+ *
+ * Tests if two blocks of 16 bytes are equal
+ *
+ * PARAMS
+ *  b1,b2   [I] block of 16 bytes
+ *
+ * RETURNS
+ *  TRUE  if blocks are the same
+ *  FALSE if blocks are different
+ */
+BOOL WINAPI SystemFunction030(PVOID b1, PVOID b2)
+{
+    return !memcmp(b1, b2, 0x10);
+}
+
+/******************************************************************************
+ * SystemFunction035   (ADVAPI32.@)
+ *
+ * Described here:
+http://disc.server.com/discussion.cgi?disc=148775;article=942;title=Coding%2FASM%2FSystem
+ *
+ * NOTES
+ *  Stub, always return TRUE.
+ */
+BOOL WINAPI SystemFunction035(LPCSTR lpszDllFilePath)
+{
+    FIXME("%s: stub\n", debugstr_a(lpszDllFilePath));
+    return TRUE;
+}
+
+/******************************************************************************
+ * SystemFunction036   (ADVAPI32.@)
+ *
+ * MSDN documents this function as RtlGenRandom and declares it in ntsecapi.h
+ *
+ * PARAMS
+ *  pbBufer [O] Pointer to memory to receive random bytes.
+ *  dwLen   [I] Number of random bytes to fetch.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+
+BOOL WINAPI SystemFunction036(PVOID pbBuffer, ULONG dwLen)
+{
+    int dev_random;
+#if 0
+    dev_random = open("/dev/urandom", O_RDONLY);
+    if (dev_random != -1)
+    {
+        if (read(dev_random, pbBuffer, dwLen) == dwLen)
+        {
+            close(dev_random);
+            return TRUE;
+        }
+        close(dev_random);
+    }
+    else
+        FIXME("couldn't open /dev/urandom\n");
+#endif
+    SetLastError(NTE_FAIL);
+    return FALSE;
+}    
+    
+/*
+   These functions have nearly identical prototypes to CryptProtectMemory and CryptUnprotectMemory,
+   in crypt32.dll.
+ */
+
+/******************************************************************************
+ * SystemFunction040   (ADVAPI32.@)
+ *
+ * MSDN documents this function as RtlEncryptMemory.
+ *
+ * PARAMS
+ *  memory [I/O] Pointer to memory to encrypt.
+ *  length [I] Length of region to encrypt in bytes.
+ *  flags  [I] Control whether other processes are able to decrypt the memory.
+ *    RTL_ENCRYPT_OPTION_SAME_PROCESS 
+ *    RTL_ENCRYPT_OPTION_CROSS_PROCESS 
+ *    RTL_ENCRYPT_OPTION_SAME_LOGON
+ *    
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: NTSTATUS error code
+ *
+ * NOTES
+ *  length must be a multiple of RTL_ENCRYPT_MEMORY_SIZE.
+ *  If flags are specified when encrypting, the same flag value must be given
+ *  when decrypting the memory.
+ */
+NTSTATUS WINAPI SystemFunction040(PVOID memory, ULONG length, ULONG flags)
+{
+	FIXME("(%p, %x, %x): stub [RtlEncryptMemory]\n", memory, length, flags);
+	return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction041  (ADVAPI32.@)
+ *
+ * MSDN documents this function as RtlDecryptMemory.
+ *
+ * PARAMS
+ *  memory [I/O] Pointer to memory to decrypt.
+ *  length [I] Length of region to decrypt in bytes.
+ *  flags  [I] Control whether other processes are able to decrypt the memory.
+ *    RTL_ENCRYPT_OPTION_SAME_PROCESS
+ *    RTL_ENCRYPT_OPTION_CROSS_PROCESS
+ *    RTL_ENCRYPT_OPTION_SAME_LOGON
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: NTSTATUS error code
+ *
+ * NOTES
+ *  length must be a multiple of RTL_ENCRYPT_MEMORY_SIZE.
+ *  If flags are specified when encrypting, the same flag value must be given
+ *  when decrypting the memory.
+ */
+NTSTATUS WINAPI SystemFunction041(PVOID memory, ULONG length, ULONG flags)
+{
+	FIXME("(%p, %x, %x): stub [RtlDecryptMemory]\n", memory, length, flags);
+	return STATUS_SUCCESS;
+}
Index: trunk/src/advapi32/crypt.cpp
===================================================================
--- trunk/src/advapi32/crypt.cpp	(revision 21325)
+++ 	(revision )
@@ -1,276 +1,0 @@
-/* $Id: crypt.cpp,v 1.3 2000-03-02 23:08:23 sandervl Exp $ */
-/*
- * dlls/advapi32/crypt.c
- */
-
-#include <os2win.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <odinwrap.h>
-#include <misc.h>
-#include "wincrypt.h"
-
-ODINDEBUGCHANNEL(ADVAPI32-CRYPT)
-
-/******************************************************************************
- * CryptAcquireContextA
- * Acquire a crypto provider context handle.
- * 
- * PARAMS
- * phProv: Pointer to HCRYPTPROV for the output.
- * pszContainer: FIXME (unknown)
- * pszProvider: FIXME (unknown)
- * dwProvType: Crypto provider type to get a handle.
- * dwFlags: flags for the operation
- *
- * RETURNS TRUE on success, FALSE on failure.
- */
-
-BOOL WINAPI CryptAcquireContextA( HCRYPTPROV *phProv, LPCSTR pszContainer,
-   	 	                  LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
-{
-    dprintf(("CryptAcquireContextA(%p, %s, %s, %ld, %08lx): FAKED.\n", phProv, pszContainer,
-	  pszProvider, dwProvType, dwFlags));
-    *phProv = 0x99000001;
-    return TRUE;
-//    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-//    return FALSE;
-}
-
-BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer,
-                                 LPCWSTR pszProvider, DWORD dwProvType,
-                                 DWORD dwFlags)
-{
-    dprintf(("CryptAcquireContextW(%p, %ls, %s, %ld, %08lx): FAKED.\n", phProv, pszContainer,
-	  pszProvider, dwProvType, dwFlags));
-    *phProv = 0x99000001;
-    return TRUE;
-//    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-//    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptReleaseContext %x %x", hProv, dwFlags));
-    return TRUE;
-//    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-//    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptGenKey(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags,
-                        HCRYPTKEY *phKey)
-{
-    dprintf(("NOT IMPLEMENTED: CryptGenKey %x %x %x %x", hProv, Algid, dwFlags, phKey));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData,
-                           DWORD dwFlags, HCRYPTKEY *phKey)
-{
-    dprintf(("NOT IMPLEMENTED: CryptDeriveKey"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptDestroyKey(HCRYPTKEY hKey)
-{
-    dprintf(("NOT IMPLEMENTED: CryptDestroyKey"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSetKeyParam(HCRYPTKEY hKey,DWORD dwParam,BYTE *pbData,DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSetKeyParam(%lx, %lx, %p, %lx): not implemented.\n", hKey, dwParam, pbData, dwFlags));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptGetKeyParam(HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptGetKeyParam"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSetHashParam"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen,DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptGetHashParam"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSetProvParam"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptGetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,DWORD *pdwDataLen,
-                              DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptGetProvParam"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer)
-{
-    dprintf(("NOT IMPLEMENTED: CryptGenRandom"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptGetUserKey(HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey)
-{
-    dprintf(("NOT IMPLEMENTED: CryptGetUserKey"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptExportKey(HCRYPTKEY hKey,HCRYPTKEY hExpKey, DWORD dwBlobType, DWORD dwFlags,
-                           BYTE *pbData, DWORD *pdwDataLen)
-{
-    dprintf(("NOT IMPLEMENTED: CryptExportKey"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptImportKey(HCRYPTPROV hProv,CONST BYTE *pbData, DWORD dwDataLen,
-                           HCRYPTKEY hPubKey, DWORD dwFlags,HCRYPTKEY *phKey)
-{
-    dprintf(("NOT IMPLEMENTED: CryptImportKey"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptEncrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final,
-                         DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen,
-                         DWORD dwBufLen)
-{
-    dprintf(("NOT IMPLEMENTED: CryptEncrypt"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags,
-                         BYTE *pbData, DWORD *pdwDataLen)
-{
-    dprintf(("NOT IMPLEMENTED: CryptDecrypt"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags,
-                            HCRYPTHASH *phHash)
-{
-    dprintf(("NOT IMPLEMENTED: CryptCreateHash"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen,
-                          DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptHashData"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptHashSessionKey(HCRYPTHASH hHash, HCRYPTKEY hKey, DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptHashSessionKey"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptDestroyHash(HCRYPTHASH hHash)
-{
-    dprintf(("NOT IMPLEMENTED: CryptDestroyHash"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSignHashA(HCRYPTHASH hHash, DWORD dwKeySpec, LPCSTR sDescription,
-                           DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSignHashA"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSignHashW(HCRYPTHASH hHash, DWORD dwKeySpec, LPCWSTR sDescription,
-                           DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSignHashW"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptVerifySignatureA(HCRYPTHASH hHash, CONST BYTE *pbSignature, DWORD dwSigLen,
-                                  HCRYPTKEY hPubKey, LPCSTR sDescription, DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptVerifySignatureA"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptVerifySignatureW(HCRYPTHASH hHash, CONST BYTE *pbSignature, DWORD dwSigLen,
-                                  HCRYPTKEY hPubKey, LPCWSTR sDescription, DWORD dwFlags)
-{
-    dprintf(("NOT IMPLEMENTED: CryptVerifySignatureW"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSetProviderA(LPCSTR pszProvName, DWORD dwProvType)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSetProviderA"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
-BOOL WINAPI CryptSetProviderW(LPCWSTR pszProvName, DWORD dwProvType)
-{
-    dprintf(("NOT IMPLEMENTED: CryptSetProviderW"));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-//******************************************************************************
-//******************************************************************************
Index: trunk/src/advapi32/crypt.h
===================================================================
--- trunk/src/advapi32/crypt.h	(revision 21326)
+++ trunk/src/advapi32/crypt.h	(revision 21326)
@@ -0,0 +1,99 @@
+/*
+ * Driver routines
+ *
+ * Copyright 2001 - Travis Michielsen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_CRYPT_H
+#define __WINE_CRYPT_H
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wincrypt.h"
+
+typedef struct tagPROVFUNCS
+{
+	BOOL (*WINAPI pCPAcquireContext)(HCRYPTPROV *phProv, LPSTR pszContainer, DWORD dwFlags, PVTableProvStruc pVTable);
+	BOOL (*WINAPI pCPCreateHash)(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash);
+	BOOL (*WINAPI pCPDecrypt)(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen);
+	BOOL (*WINAPI pCPDeriveKey)(HCRYPTPROV hProv, ALG_ID     Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL (*WINAPI pCPDestroyHash)(HCRYPTPROV hProv, HCRYPTHASH hHash);
+	BOOL (*WINAPI pCPDestroyKey)(HCRYPTPROV hProv, HCRYPTKEY hKey);
+	BOOL (*WINAPI pCPDuplicateHash)(HCRYPTPROV hUID, HCRYPTHASH hHash, DWORD *pdwReserved, DWORD dwFlags, HCRYPTHASH *phHash);
+	BOOL (*WINAPI pCPDuplicateKey)(HCRYPTPROV hUID, HCRYPTKEY hKey, DWORD *pdwReserved, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL (*WINAPI pCPEncrypt)(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen);
+	BOOL (*WINAPI pCPExportKey)(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubKey, DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen);
+	BOOL (*WINAPI pCPGenKey)(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL (*WINAPI pCPGenRandom)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
+	BOOL (*WINAPI pCPGetHashParam)(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
+	BOOL (*WINAPI pCPGetKeyParam)(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
+	BOOL (*WINAPI pCPGetProvParam)(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
+	BOOL (*WINAPI pCPGetUserKey)(HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey);
+	BOOL (*WINAPI pCPHashData)(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags);
+	BOOL (*WINAPI pCPHashSessionKey)(HCRYPTPROV hProv, HCRYPTHASH hHash, HCRYPTKEY hKey, DWORD dwFlags);
+	BOOL (*WINAPI pCPImportKey)(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL (*WINAPI pCPReleaseContext)(HCRYPTPROV hProv, DWORD dwFlags);
+	BOOL (*WINAPI pCPSetHashParam)(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, CONST BYTE *pbData, DWORD dwFlags);
+	BOOL (*WINAPI pCPSetKeyParam)(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, CONST BYTE *pbData, DWORD dwFlags);
+	BOOL (*WINAPI pCPSetProvParam)(HCRYPTPROV hProv, DWORD dwParam, CONST BYTE *pbData, DWORD dwFlags);
+	BOOL (*WINAPI pCPSignHash)(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwKeySpec, LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen);
+	BOOL (*WINAPI pCPVerifySignature)(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbSignature, DWORD dwSigLen, HCRYPTKEY hPubKey, LPCWSTR sDescription, DWORD dwFlags);
+} PROVFUNCS, *PPROVFUNCS;
+
+#define MAGIC_CRYPTPROV 0xA39E741F
+
+typedef struct tagCRYPTPROV
+{
+	DWORD dwMagic;
+	UINT refcount;
+	HMODULE hModule;
+	PPROVFUNCS pFuncs;
+        HCRYPTPROV hPrivate;  /*CSP's handle - Should not be given to application under any circumstances!*/
+	PVTableProvStruc pVTable;
+} CRYPTPROV, *PCRYPTPROV;
+
+typedef struct tagCRYPTKEY
+{
+	PCRYPTPROV pProvider;
+        HCRYPTKEY hPrivate;    /*CSP's handle - Should not be given to application under any circumstances!*/
+} CRYPTKEY, *PCRYPTKEY;
+
+typedef struct tagCRYPTHASH
+{
+	PCRYPTPROV pProvider;
+        HCRYPTHASH hPrivate;    /*CSP's handle - Should not be given to application under any circumstances!*/
+} CRYPTHASH, *PCRYPTHASH;
+
+#define MAXPROVTYPES 999
+
+extern unsigned char *CRYPT_DESkey8to7( unsigned char *dst, const unsigned char *key );
+extern unsigned char *CRYPT_DEShash( unsigned char *dst, const unsigned char *key,
+                                     const unsigned char *src );
+extern unsigned char *CRYPT_DESunhash( unsigned char *dst, const unsigned char *key,
+                                       const unsigned char *src );
+
+struct ustring {
+    DWORD Length;
+    DWORD MaximumLength;
+    unsigned char *Buffer;
+};
+
+NTSTATUS WINAPI SystemFunction032(struct ustring *data, struct ustring *key);
+
+#endif /* __WINE_CRYPT_H_ */
Index: trunk/src/advapi32/crypt_arc4.cpp
===================================================================
--- trunk/src/advapi32/crypt_arc4.cpp	(revision 21326)
+++ trunk/src/advapi32/crypt_arc4.cpp	(revision 21326)
@@ -0,0 +1,105 @@
+/*
+ *  Copyright 2006 Mike McCormack
+ *
+ *  based on arc4.cpp - written and placed in the public domain by Wei Dai
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* http://cryptopp.sourceforge.net/docs/ref521/arc4_8cpp-source.html */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+
+#include "crypt.h"
+
+typedef struct tag_arc4_info {
+    unsigned char state[256];
+    unsigned char x, y;
+} arc4_info;
+
+static void arc4_init(arc4_info *a4i, const BYTE *key, unsigned int keyLen)
+{
+    unsigned int keyIndex = 0, stateIndex = 0;
+    unsigned int i, a;
+
+    a4i->x = a4i->y = 0;
+
+    for (i=0; i<256; i++)
+        a4i->state[i] = i;
+
+    for (i=0; i<256; i++)
+    {
+        a = a4i->state[i];
+        stateIndex += key[keyIndex] + a;
+        stateIndex &= 0xff;
+        a4i->state[i] = a4i->state[stateIndex];
+        a4i->state[stateIndex] = a;
+        if (++keyIndex >= keyLen)
+            keyIndex = 0;
+    }
+}
+
+static void arc4_ProcessString(arc4_info *a4i, BYTE *inoutString, unsigned int length)
+{
+    BYTE *const s=a4i->state;
+    unsigned int x = a4i->x;
+    unsigned int y = a4i->y;
+    unsigned int a, b;
+
+    while(length--)
+    {
+        x = (x+1) & 0xff;
+        a = s[x];
+        y = (y+a) & 0xff;
+        b = s[y];
+        s[x] = b;
+        s[y] = a;
+        *inoutString++ ^= s[(a+b) & 0xff];
+    }
+
+    a4i->x = x;
+    a4i->y = y;
+}
+
+/******************************************************************************
+ * SystemFunction032  [ADVAPI32.@]
+ *
+ * Encrypts a string data using ARC4
+ *
+ * PARAMS
+ *   data    [I/O] data to encrypt
+ *   key     [I] key data
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ * NOTES
+ *  see http://web.it.kth.se/~rom/ntsec.html#crypto-strongavail
+ */
+NTSTATUS WINAPI SystemFunction032(struct ustring *data, struct ustring *key)
+{
+    arc4_info a4i;
+
+    arc4_init(&a4i, key->Buffer, key->Length);
+    arc4_ProcessString(&a4i, data->Buffer, data->Length);
+
+    return STATUS_SUCCESS;
+}
Index: trunk/src/advapi32/crypt_des.cpp
===================================================================
--- trunk/src/advapi32/crypt_des.cpp	(revision 21326)
+++ trunk/src/advapi32/crypt_des.cpp	(revision 21326)
@@ -0,0 +1,361 @@
+/*
+ *  Copyright 2004 Hans Leidekker
+ *  Copyright 2006 Mike McCormack
+ *
+ *  Based on DES.c from libcifs
+ *
+ *  Copyright (C) 2003, 2004 by Christopher R. Hertel
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+#include "crypt.h"
+
+static const unsigned char InitialPermuteMap[64] =
+{
+    57, 49, 41, 33, 25, 17,  9, 1,
+    59, 51, 43, 35, 27, 19, 11, 3,
+    61, 53, 45, 37, 29, 21, 13, 5,
+    63, 55, 47, 39, 31, 23, 15, 7,
+    56, 48, 40, 32, 24, 16,  8, 0,
+    58, 50, 42, 34, 26, 18, 10, 2,
+    60, 52, 44, 36, 28, 20, 12, 4,
+    62, 54, 46, 38, 30, 22, 14, 6
+ };
+
+static const unsigned char KeyPermuteMap[56] =
+{
+    49, 42, 35, 28, 21, 14,  7,  0,
+    50, 43, 36, 29, 22, 15,  8,  1,
+    51, 44, 37, 30, 23, 16,  9,  2,
+    52, 45, 38, 31, 55, 48, 41, 34,
+    27, 20, 13,  6, 54, 47, 40, 33,
+    26, 19, 12,  5, 53, 46, 39, 32,
+    25, 18, 11,  4, 24, 17, 10,  3,
+};
+
+static const unsigned char KeyRotation[16] =
+    { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
+
+static const unsigned char KeyCompression[48] =
+{
+    13, 16, 10, 23,  0,  4,  2, 27,
+    14,  5, 20,  9, 22, 18, 11,  3,
+    25,  7, 15,  6, 26, 19, 12,  1,
+    40, 51, 30, 36, 46, 54, 29, 39,
+    50, 44, 32, 47, 43, 48, 38, 55,
+    33, 52, 45, 41, 49, 35, 28, 31
+};
+
+static const unsigned char DataExpansion[48] =
+{
+    31,  0,  1,  2,  3,  4,  3,  4,
+     5,  6,  7,  8,  7,  8,  9, 10,
+    11, 12, 11, 12, 13, 14, 15, 16,
+    15, 16, 17, 18, 19, 20, 19, 20,
+    21, 22, 23, 24, 23, 24, 25, 26,
+    27, 28, 27, 28, 29, 30, 31,  0
+};
+
+static const unsigned char SBox[8][64] =
+{
+    {  /* S0 */
+        14,  0,  4, 15, 13,  7,  1,  4,  2, 14, 15,  2, 11, 13,  8,  1,
+         3, 10, 10,  6,  6, 12, 12, 11,  5,  9,  9,  5,  0,  3,  7,  8,
+         4, 15,  1, 12, 14,  8,  8,  2, 13,  4,  6,  9,  2,  1, 11,  7,
+        15,  5, 12, 11,  9,  3,  7, 14,  3, 10, 10,  0,  5,  6,  0, 13
+    },
+    {  /* S1 */
+        15,  3,  1, 13,  8,  4, 14,  7,  6, 15, 11,  2,  3,  8,  4, 14,
+         9, 12,  7,  0,  2,  1, 13, 10, 12,  6,  0,  9,  5, 11, 10,  5,
+         0, 13, 14,  8,  7, 10, 11,  1, 10,  3,  4, 15, 13,  4,  1,  2,
+         5, 11,  8,  6, 12,  7,  6, 12,  9,  0,  3,  5,  2, 14, 15,  9
+    },
+    {  /* S2 */
+        10, 13,  0,  7,  9,  0, 14,  9,  6,  3,  3,  4, 15,  6,  5, 10,
+         1,  2, 13,  8, 12,  5,  7, 14, 11, 12,  4, 11,  2, 15,  8,  1,
+        13,  1,  6, 10,  4, 13,  9,  0,  8,  6, 15,  9,  3,  8,  0,  7,
+        11,  4,  1, 15,  2, 14, 12,  3,  5, 11, 10,  5, 14,  2,  7, 12
+    },
+    {  /* S3 */
+         7, 13, 13,  8, 14, 11,  3,  5,  0,  6,  6, 15,  9,  0, 10,  3,
+         1,  4,  2,  7,  8,  2,  5, 12, 11,  1, 12, 10,  4, 14, 15,  9,
+        10,  3,  6, 15,  9,  0,  0,  6, 12, 10, 11,  1,  7, 13, 13,  8,
+        15,  9,  1,  4,  3,  5, 14, 11,  5, 12,  2,  7,  8,  2,  4, 14
+    },
+    {  /* S4 */
+         2, 14, 12, 11,  4,  2,  1, 12,  7,  4, 10,  7, 11, 13,  6,  1,
+         8,  5,  5,  0,  3, 15, 15, 10, 13,  3,  0,  9, 14,  8,  9,  6,
+         4, 11,  2,  8,  1, 12, 11,  7, 10,  1, 13, 14,  7,  2,  8, 13,
+        15,  6,  9, 15, 12,  0,  5,  9,  6, 10,  3,  4,  0,  5, 14,  3
+    },
+    {  /* S5 */
+        12, 10,  1, 15, 10,  4, 15,  2,  9,  7,  2, 12,  6,  9,  8,  5,
+         0,  6, 13,  1,  3, 13,  4, 14, 14,  0,  7, 11,  5,  3, 11,  8,
+         9,  4, 14,  3, 15,  2,  5, 12,  2,  9,  8,  5, 12, 15,  3, 10,
+         7, 11,  0, 14,  4,  1, 10,  7,  1,  6, 13,  0, 11,  8,  6, 13
+    },
+    {  /* S6 */
+         4, 13, 11,  0,  2, 11, 14,  7, 15,  4,  0,  9,  8,  1, 13, 10,
+         3, 14, 12,  3,  9,  5,  7, 12,  5,  2, 10, 15,  6,  8,  1,  6,
+         1,  6,  4, 11, 11, 13, 13,  8, 12,  1,  3,  4,  7, 10, 14,  7,
+        10,  9, 15,  5,  6,  0,  8, 15,  0, 14,  5,  2,  9,  3,  2, 12
+    },
+    {  /* S7 */
+        13,  1,  2, 15,  8, 13,  4,  8,  6, 10, 15,  3, 11,  7,  1,  4,
+        10, 12,  9,  5,  3,  6, 14, 11,  5,  0,  0, 14, 12,  9,  7,  2,
+         7,  2, 11,  1,  4, 14,  1,  7,  9,  4, 12, 10, 14,  8,  2, 13,
+         0, 15,  6, 12, 10,  9, 13,  0, 15,  3,  3,  5,  5,  6,  8, 11
+    }
+};
+
+static const unsigned char PBox[32] =
+{
+    15,  6, 19, 20, 28, 11, 27, 16,
+     0, 14, 22, 25,  4, 17, 30,  9,
+     1,  7, 23, 13, 31, 26,  2,  8,
+    18, 12, 29,  5, 21, 10,  3, 24
+};
+
+static const unsigned char FinalPermuteMap[64] =
+{
+     7, 39, 15, 47, 23, 55, 31, 63,
+     6, 38, 14, 46, 22, 54, 30, 62,
+     5, 37, 13, 45, 21, 53, 29, 61,
+     4, 36, 12, 44, 20, 52, 28, 60,
+     3, 35, 11, 43, 19, 51, 27, 59,
+     2, 34, 10, 42, 18, 50, 26, 58,
+     1, 33,  9, 41, 17, 49, 25, 57,
+     0, 32,  8, 40, 16, 48, 24, 56
+};
+
+#define CLRBIT( STR, IDX ) ( (STR)[(IDX)/8] &= ~(0x01 << (7 - ((IDX)%8))) )
+#define SETBIT( STR, IDX ) ( (STR)[(IDX)/8] |= (0x01 << (7 - ((IDX)%8))) )
+#define GETBIT( STR, IDX ) (( ((STR)[(IDX)/8]) >> (7 - ((IDX)%8)) ) & 0x01)
+
+static void Permute( unsigned char *dst, const unsigned char *src, const unsigned char *map, const int mapsize )
+{
+    int bitcount, i;
+
+    for (i = 0; i < mapsize; i++)
+        dst[i] = 0;
+
+    bitcount = mapsize * 8;
+
+    for (i = 0; i < bitcount; i++)
+    {
+        if (GETBIT( src, map[i] ))
+            SETBIT( dst, i );
+    }
+}
+
+static void KeyShiftLeft( unsigned char *key, const int numbits )
+{
+    int i;
+    unsigned char keep = key[0];
+
+    for (i = 0; i < numbits; i++)
+    {
+        int j;
+
+        for (j = 0; j < 7; j++)
+        {
+            if (j && (key[j] & 0x80))
+                key[j-1] |=  0x01;
+            key[j] <<= 1;
+        }
+
+        if (GETBIT( key, 27 ))
+        {
+            CLRBIT( key, 27 );
+            SETBIT( key, 55 );
+        }
+
+        if (keep & 0x80)
+            SETBIT( key, 27 );
+
+        keep <<= 1;
+    }
+}
+
+static void KeyShiftRight( unsigned char *key, const int numbits )
+{
+    int i;
+    unsigned char keep = key[6];
+
+    for (i = 0; i < numbits; i++)
+    {
+        int j;
+
+        for (j = 6; j >= 0; j--)
+        {
+            if (j!=6 && (key[j] & 0x01))
+                key[j+1] |=  0x80;
+            key[j] >>= 1;
+        }
+
+        if (GETBIT( key, 28 ))
+        {
+            CLRBIT( key, 28 );
+            SETBIT( key, 0 );
+        }
+
+        if (keep & 0x01)
+            SETBIT( key, 28 );
+
+        keep >>= 1;
+    }
+}
+
+static void sbox( unsigned char *dst, const unsigned char *src )
+{
+    int i;
+
+    for (i = 0; i < 4; i++)
+        dst[i] = 0;
+
+    for (i = 0; i < 8; i++)
+    {
+        int j, Snum, bitnum;
+
+        for (Snum = j = 0, bitnum = (i * 6); j < 6; j++, bitnum++)
+        {
+            Snum <<= 1;
+            Snum |= GETBIT( src, bitnum );
+        }
+
+        if (0 == (i%2))
+            dst[i/2] |= ((SBox[i][Snum]) << 4);
+        else
+            dst[i/2] |= SBox[i][Snum];
+    }
+}
+
+static void xor( unsigned char *dst, const unsigned char *a, const unsigned char *b, const int count )
+{
+    int i;
+
+    for (i = 0; i < count; i++)
+        dst[i] = a[i] ^ b[i];
+}
+
+unsigned char *CRYPT_DESkey8to7( unsigned char *dst, const unsigned char *key )
+{
+    int i;
+    unsigned char tmp[7];
+    static const unsigned char map8to7[56] =
+    {
+         0,  1,  2,  3,  4,  5,  6,
+         8,  9, 10, 11, 12, 13, 14,
+        16, 17, 18, 19, 20, 21, 22,
+        24, 25, 26, 27, 28, 29, 30,
+        32, 33, 34, 35, 36, 37, 38,
+        40, 41, 42, 43, 44, 45, 46,
+        48, 49, 50, 51, 52, 53, 54,
+        56, 57, 58, 59, 60, 61, 62
+    };
+
+    if ((dst == NULL) || (key == NULL))
+        return NULL;
+
+    Permute( tmp, key, map8to7, 7 );
+
+    for (i = 0; i < 7; i++)
+        dst[i] = tmp[i];
+
+    return dst;
+}
+
+unsigned char *CRYPT_DEShash( unsigned char *dst, const unsigned char *key, const unsigned char *src )
+{
+    int i;
+    unsigned char K[7];
+    unsigned char D[8];
+
+    Permute( K, key, KeyPermuteMap, 7 );
+    Permute( D, src, InitialPermuteMap, 8 );
+
+    for (i = 0; i < 16; i++)
+    {
+        int j;
+        unsigned char *L = D;
+        unsigned char *R = &(D[4]);
+        unsigned char  Rexp[6];
+        unsigned char  Rn[4];
+        unsigned char  SubK[6];
+
+        KeyShiftLeft( K, KeyRotation[i] );
+        Permute( SubK, K, KeyCompression, 6 );
+
+        Permute( Rexp, R, DataExpansion, 6 );
+        xor( Rexp, Rexp, SubK, 6 );
+
+        sbox( Rn, Rexp );
+        Permute( Rexp, Rn, PBox, 4 );
+        xor( Rn, L, Rexp, 4 );
+
+        for (j = 0; j < 4; j++)
+        {
+            L[j] = R[j];
+            R[j] = Rn[j];
+        }
+    }
+
+    Permute( dst, D, FinalPermuteMap, 8 );
+
+    return dst;
+}
+
+unsigned char *CRYPT_DESunhash( unsigned char *dst, const unsigned char *key, const unsigned char *src )
+{
+    int i;
+    unsigned char K[7];
+    unsigned char D[8];
+
+    Permute( K, key, KeyPermuteMap, 7 );
+    Permute( D, src, InitialPermuteMap, 8 );
+
+    for (i = 0; i < 16; i++)
+    {
+        int j;
+        unsigned char *L = D;
+        unsigned char *R = &(D[4]);
+        unsigned char  Rexp[6];
+        unsigned char  Rn[4];
+        unsigned char  SubK[6];
+
+        Permute( SubK, K, KeyCompression, 6 );
+
+        Permute( Rexp, R, DataExpansion, 6 );
+        xor( Rexp, Rexp, SubK, 6 );
+
+        sbox( Rn, Rexp );
+        Permute( Rexp, Rn, PBox, 4 );
+        xor( Rn, L, Rexp, 4 );
+
+        for (j = 0; j < 4; j++)
+        {
+            L[j] = R[j];
+            R[j] = Rn[j];
+        }
+
+        KeyShiftRight( K, KeyRotation[15 - i] );
+    }
+
+    Permute( dst, D, FinalPermuteMap, 8 );
+
+    return dst;
+}
Index: trunk/src/advapi32/crypt_lmhash.cpp
===================================================================
--- trunk/src/advapi32/crypt_lmhash.cpp	(revision 21326)
+++ trunk/src/advapi32/crypt_lmhash.cpp	(revision 21326)
@@ -0,0 +1,406 @@
+/*
+ *  Copyright 2004 Hans Leidekker
+ *
+ *  Based on LMHash.c from libcifs
+ *
+ *  Copyright (C) 2004 by Christopher R. Hertel
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+
+#include <string.h>
+
+#include "crypt.h"
+
+static const unsigned char CRYPT_LMhash_Magic[8] =
+    { 'K', 'G', 'S', '!', '@', '#', '$', '%' };
+
+static void CRYPT_LMhash( unsigned char *dst, const unsigned char *pwd, const int len )
+{
+    int i, max = 14;
+    unsigned char tmp_pwd[14] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+    max = len > max ? max : len;
+
+    for (i = 0; i < max; i++)
+        tmp_pwd[i] = pwd[i];
+
+    CRYPT_DEShash( dst, tmp_pwd, CRYPT_LMhash_Magic );
+    CRYPT_DEShash( &dst[8], &tmp_pwd[7], CRYPT_LMhash_Magic );
+}
+
+NTSTATUS WINAPI SystemFunction006( LPCSTR password, LPSTR hash )
+{
+    CRYPT_LMhash( (unsigned char*)hash, (const unsigned char*)password, strlen(password) );
+
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction008  [ADVAPI32.@]
+ *
+ * Creates a LM response from a challenge and a password hash
+ *
+ * PARAMS
+ *   challenge  [I] Challenge from authentication server
+ *   hash       [I] NTLM hash (from SystemFunction006)
+ *   response   [O] response to send back to the server
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ * NOTES
+ *  see http://davenport.sourceforge.net/ntlm.html#theLmResponse
+ *
+ */
+NTSTATUS WINAPI SystemFunction008(const BYTE *challenge, const BYTE *hash, LPBYTE response)
+{
+    BYTE key[7*3];
+
+    if (!challenge || !response)
+        return STATUS_UNSUCCESSFUL;
+
+    memset(key, 0, sizeof key);
+    memcpy(key, hash, 0x10);
+
+    CRYPT_DEShash(response, key, challenge);
+    CRYPT_DEShash(response+8, key+7, challenge);
+    CRYPT_DEShash(response+16, key+14, challenge);
+
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction009  [ADVAPI32.@]
+ *
+ * Seems to do the same as SystemFunction008 ...
+ */
+NTSTATUS WINAPI SystemFunction009(const BYTE *challenge, const BYTE *hash, LPBYTE response)
+{
+    return SystemFunction008(challenge, hash, response);
+}
+
+/******************************************************************************
+ * SystemFunction001  [ADVAPI32.@]
+ *
+ * Encrypts a single block of data using DES
+ *
+ * PARAMS
+ *   data    [I] data to encrypt    (8 bytes)
+ *   key     [I] key data           (7 bytes)
+ *   output  [O] the encrypted data (8 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ */
+NTSTATUS WINAPI SystemFunction001(const BYTE *data, const BYTE *key, LPBYTE output)
+{
+    if (!data || !output)
+        return STATUS_UNSUCCESSFUL;
+    CRYPT_DEShash(output, key, data);
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction002  [ADVAPI32.@]
+ *
+ * Decrypts a single block of data using DES
+ *
+ * PARAMS
+ *   data    [I] data to decrypt    (8 bytes)
+ *   key     [I] key data           (7 bytes)
+ *   output  [O] the decrypted data (8 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ */
+NTSTATUS WINAPI SystemFunction002(const BYTE *data, const BYTE *key, LPBYTE output)
+{
+    if (!data || !output)
+        return STATUS_UNSUCCESSFUL;
+    CRYPT_DESunhash(output, key, data);
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction003  [ADVAPI32.@]
+ *
+ * Hashes a key using DES and a fixed datablock
+ *
+ * PARAMS
+ *   key     [I] key data    (7 bytes)
+ *   output  [O] hashed key  (8 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ */
+NTSTATUS WINAPI SystemFunction003(const BYTE *key, LPBYTE output)
+{
+    if (!output)
+        return STATUS_UNSUCCESSFUL;
+    CRYPT_DEShash(output, key, CRYPT_LMhash_Magic);
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction004  [ADVAPI32.@]
+ *
+ * Encrypts a block of data with DES in ECB mode, preserving the length
+ *
+ * PARAMS
+ *   data    [I] data to encrypt
+ *   key     [I] key data (up to 7 bytes)
+ *   output  [O] buffer to receive encrypted data
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_BUFFER_TOO_SMALL     if the output buffer is too small
+ *  Failure: STATUS_INVALID_PARAMETER_2  if the key is zero length
+ *
+ * NOTES
+ *  Encrypt buffer size should be input size rounded up to 8 bytes
+ *   plus an extra 8 bytes.
+ */
+NTSTATUS WINAPI SystemFunction004(const struct ustring *in,
+                                  const struct ustring *key,
+                                  struct ustring *out)
+{
+    union {
+         unsigned char uc[8];
+         unsigned int  ui[2];
+    } data;
+    unsigned char deskey[7];
+    unsigned int crypt_len, ofs;
+
+    if (key->Length<=0)
+        return STATUS_INVALID_PARAMETER_2;
+
+    crypt_len = ((in->Length+7)&~7);
+    if (out->MaximumLength < (crypt_len+8))
+        return STATUS_BUFFER_TOO_SMALL;
+
+    data.ui[0] = in->Length;
+    data.ui[1] = 1;
+
+    if (key->Length<sizeof deskey)
+    {
+        memset(deskey, 0, sizeof deskey);
+        memcpy(deskey, key->Buffer, key->Length);
+    }
+    else
+        memcpy(deskey, key->Buffer, sizeof deskey);
+
+    CRYPT_DEShash(out->Buffer, deskey, data.uc);
+
+    for(ofs=0; ofs<(crypt_len-8); ofs+=8)
+        CRYPT_DEShash(out->Buffer+8+ofs, deskey, in->Buffer+ofs);
+
+    memset(data.uc, 0, sizeof data.uc);
+    memcpy(data.uc, in->Buffer+ofs, in->Length +8-crypt_len);
+    CRYPT_DEShash(out->Buffer+8+ofs, deskey, data.uc);
+
+    out->Length = crypt_len+8;
+
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction005  [ADVAPI32.@]
+ *
+ * Decrypts a block of data with DES in ECB mode
+ *
+ * PARAMS
+ *   data    [I] data to decrypt
+ *   key     [I] key data (up to 7 bytes)
+ *   output  [O] buffer to receive decrypted data
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_BUFFER_TOO_SMALL     if the output buffer is too small
+ *  Failure: STATUS_INVALID_PARAMETER_2  if the key is zero length
+ *
+ */
+NTSTATUS WINAPI SystemFunction005(const struct ustring *in,
+                                  const struct ustring *key,
+                                  struct ustring *out)
+{
+    union {
+         unsigned char uc[8];
+         unsigned int  ui[2];
+    } data;
+    unsigned char deskey[7];
+    unsigned int ofs, crypt_len;
+
+    if (key->Length<=0)
+        return STATUS_INVALID_PARAMETER_2;
+
+    if (key->Length<sizeof deskey)
+    {
+        memset(deskey, 0, sizeof deskey);
+        memcpy(deskey, key->Buffer, key->Length);
+    }
+    else
+        memcpy(deskey, key->Buffer, sizeof deskey);
+
+    CRYPT_DESunhash(data.uc, deskey, in->Buffer);
+
+    if (data.ui[1] != 1)
+        return STATUS_UNKNOWN_REVISION;
+
+    crypt_len = data.ui[0];
+    if (crypt_len > out->MaximumLength)
+        return STATUS_BUFFER_TOO_SMALL;
+
+    for (ofs=0; (ofs+8)<crypt_len; ofs+=8)
+        CRYPT_DESunhash(out->Buffer+ofs, deskey, in->Buffer+ofs+8);
+
+    if (ofs<crypt_len)
+    {
+        CRYPT_DESunhash(data.uc, deskey, in->Buffer+ofs+8);
+        memcpy(out->Buffer+ofs, data.uc, crypt_len-ofs);
+    }
+
+    out->Length = crypt_len;
+
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction012  [ADVAPI32.@]
+ * SystemFunction014  [ADVAPI32.@]
+ * SystemFunction016  [ADVAPI32.@]
+ * SystemFunction018  [ADVAPI32.@]
+ * SystemFunction020  [ADVAPI32.@]
+ * SystemFunction022  [ADVAPI32.@]
+ *
+ * Encrypts two DES blocks with two keys
+ *
+ * PARAMS
+ *   data    [I] data to encrypt (16 bytes)
+ *   key     [I] key data (two lots of 7 bytes)
+ *   output  [O] buffer to receive encrypted data (16 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL  if the input or output buffer is NULL
+ */
+NTSTATUS WINAPI SystemFunction012(const BYTE *in, const BYTE *key, LPBYTE out)
+{
+    if (!in || !out)
+        return STATUS_UNSUCCESSFUL;
+
+    CRYPT_DEShash(out, key, in);
+    CRYPT_DEShash(out+8, key+7, in+8);
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction013  [ADVAPI32.@]
+ * SystemFunction015  [ADVAPI32.@]
+ * SystemFunction017  [ADVAPI32.@]
+ * SystemFunction019  [ADVAPI32.@]
+ * SystemFunction021  [ADVAPI32.@]
+ * SystemFunction023  [ADVAPI32.@]
+ *
+ * Decrypts two DES blocks with two keys
+ *
+ * PARAMS
+ *   data    [I] data to decrypt (16 bytes)
+ *   key     [I] key data (two lots of 7 bytes)
+ *   output  [O] buffer to receive decrypted data (16 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL  if the input or output buffer is NULL
+ */
+NTSTATUS WINAPI SystemFunction013(const BYTE *in, const BYTE *key, LPBYTE out)
+{
+    if (!in || !out)
+        return STATUS_UNSUCCESSFUL;
+
+    CRYPT_DESunhash(out, key, in);
+    CRYPT_DESunhash(out+8, key+7, in+8);
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction024  [ADVAPI32.@]
+ *
+ * Encrypts two DES blocks with a 32 bit key...
+ *
+ * PARAMS
+ *   data    [I] data to encrypt (16 bytes)
+ *   key     [I] key data (4 bytes)
+ *   output  [O] buffer to receive encrypted data (16 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ */
+NTSTATUS WINAPI SystemFunction024(const BYTE *in, const BYTE *key, LPBYTE out)
+{
+    BYTE deskey[0x10];
+
+    memcpy(deskey, key, 4);
+    memcpy(deskey+4, key, 4);
+    memcpy(deskey+8, key, 4);
+    memcpy(deskey+12, key, 4);
+
+    CRYPT_DEShash(out, deskey, in);
+    CRYPT_DEShash(out+8, deskey+7, in+8);
+
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction025  [ADVAPI32.@]
+ *
+ * Decrypts two DES blocks with a 32 bit key...
+ *
+ * PARAMS
+ *   data    [I] data to encrypt (16 bytes)
+ *   key     [I] key data (4 bytes)
+ *   output  [O] buffer to receive encrypted data (16 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ */
+NTSTATUS WINAPI SystemFunction025(const BYTE *in, const BYTE *key, LPBYTE out)
+{
+    BYTE deskey[0x10];
+
+    memcpy(deskey, key, 4);
+    memcpy(deskey+4, key, 4);
+    memcpy(deskey+8, key, 4);
+    memcpy(deskey+12, key, 4);
+
+    CRYPT_DESunhash(out, deskey, in);
+    CRYPT_DESunhash(out+8, deskey+7, in+8);
+
+    return STATUS_SUCCESS;
+}
Index: trunk/src/advapi32/crypt_md4.cpp
===================================================================
--- trunk/src/advapi32/crypt_md4.cpp	(revision 21326)
+++ trunk/src/advapi32/crypt_md4.cpp	(revision 21326)
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2001 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * It is based on code in the public domain written by Colin
+ * Plumb in 1993. The algorithm is due to Ron Rivest.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD4_CTX structure, pass it to MD4Init, call MD4Update as
+ * needed on buffers full of bytes, and then call MD4Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+
+#include <string.h>
+
+typedef struct
+{
+    unsigned int buf[4];
+    unsigned int i[2];
+    unsigned char in[64];
+    unsigned char digest[16];
+} MD4_CTX;
+
+static void MD4Transform( unsigned int buf[4], unsigned int const in[16] );
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse( unsigned char *buf, unsigned longs )
+{
+    unsigned int t;
+
+    do {
+        t = ((unsigned)buf[3] << 8 | buf[2]) << 16 |
+            ((unsigned)buf[1] << 8 | buf[0]);
+        *(unsigned int *)buf = t;
+        buf += 4;
+    } while (--longs);
+}
+
+/*
+ * Start MD4 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+VOID WINAPI MD4Init( MD4_CTX *ctx )
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->i[0] = ctx->i[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+VOID WINAPI MD4Update( MD4_CTX *ctx, const unsigned char *buf, unsigned int len )
+{
+    register unsigned int t;
+
+    /* Update bitcount */
+    t = ctx->i[0];
+
+    if ((ctx->i[0] = t + (len << 3)) < t)
+        ctx->i[1]++;        /* Carry from low to high */
+
+    ctx->i[1] += len >> 29;
+    t = (t >> 3) & 0x3f;
+
+    /* Handle any leading odd-sized chunks */
+    if (t)
+    {
+        unsigned char *p = (unsigned char *)ctx->in + t;
+        t = 64 - t;
+
+        if (len < t)
+        {
+            memcpy( p, buf, len );
+            return;
+        }
+
+        memcpy( p, buf, t );
+        byteReverse( ctx->in, 16 );
+
+        MD4Transform( ctx->buf, (unsigned int *)ctx->in );
+
+        buf += t;
+        len -= t;
+    }
+
+    /* Process data in 64-byte chunks */
+    while (len >= 64)
+    {
+        memcpy( ctx->in, buf, 64 );
+        byteReverse( ctx->in, 16 );
+
+        MD4Transform( ctx->buf, (unsigned int *)ctx->in );
+
+        buf += 64;
+        len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+    memcpy( ctx->in, buf, len );
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+VOID WINAPI MD4Final( MD4_CTX *ctx )
+{
+    unsigned int count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->i[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8)
+    {
+        /* Two lots of padding:  Pad the first block to 64 bytes */
+        memset( p, 0, count );
+        byteReverse( ctx->in, 16 );
+        MD4Transform( ctx->buf, (unsigned int *)ctx->in );
+
+        /* Now fill the next block with 56 bytes */
+        memset( ctx->in, 0, 56 );
+    }
+    else
+    {
+        /* Pad block to 56 bytes */
+        memset( p, 0, count - 8 );
+    }
+
+    byteReverse( ctx->in, 14 );
+
+    /* Append length in bits and transform */
+    ((unsigned int *)ctx->in)[14] = ctx->i[0];
+    ((unsigned int *)ctx->in)[15] = ctx->i[1];
+
+    MD4Transform( ctx->buf, (unsigned int *)ctx->in );
+    byteReverse( (unsigned char *)ctx->buf, 4 );
+    memcpy( ctx->digest, ctx->buf, 16 );
+}
+
+/* The three core functions */
+
+#define rotl32(x,n)  (((x) << ((unsigned int)(n))) | ((x) >> (32 - (unsigned int)(n))))
+
+#define F( x, y, z ) (((x) & (y)) | ((~x) & (z)))
+#define G( x, y, z ) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H( x, y, z ) ((x) ^ (y) ^ (z))
+
+#define FF( a, b, c, d, x, s ) { \
+    (a) += F( (b), (c), (d) ) + (x); \
+    (a) = rotl32( (a), (s) ); \
+  }
+#define GG( a, b, c, d, x, s ) { \
+    (a) += G( (b), (c), (d) ) + (x) + (unsigned int)0x5a827999; \
+    (a) = rotl32( (a), (s) ); \
+  }
+#define HH( a, b, c, d, x, s ) { \
+    (a) += H( (b), (c), (d) ) + (x) + (unsigned int)0x6ed9eba1; \
+    (a) = rotl32( (a), (s) ); \
+  }
+
+/*
+ * The core of the MD4 algorithm
+ */
+static void MD4Transform( unsigned int buf[4], const unsigned int in[16] )
+{
+    register unsigned int a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    FF( a, b, c, d, in[0], 3 );
+    FF( d, a, b, c, in[1], 7 );
+    FF( c, d, a, b, in[2], 11 );
+    FF( b, c, d, a, in[3], 19 );
+    FF( a, b, c, d, in[4], 3 );
+    FF( d, a, b, c, in[5], 7 );
+    FF( c, d, a, b, in[6], 11 );
+    FF( b, c, d, a, in[7], 19 );
+    FF( a, b, c, d, in[8], 3 );
+    FF( d, a, b, c, in[9], 7 );
+    FF( c, d, a, b, in[10], 11 );
+    FF( b, c, d, a, in[11], 19 );
+    FF( a, b, c, d, in[12], 3 );
+    FF( d, a, b, c, in[13], 7 );
+    FF( c, d, a, b, in[14], 11 );
+    FF( b, c, d, a, in[15], 19 );
+
+    GG( a, b, c, d, in[0], 3 );
+    GG( d, a, b, c, in[4], 5 );
+    GG( c, d, a, b, in[8], 9 );
+    GG( b, c, d, a, in[12], 13 );
+    GG( a, b, c, d, in[1], 3 );
+    GG( d, a, b, c, in[5], 5 );
+    GG( c, d, a, b, in[9], 9 );
+    GG( b, c, d, a, in[13], 13 );
+    GG( a, b, c, d, in[2], 3 );
+    GG( d, a, b, c, in[6], 5 );
+    GG( c, d, a, b, in[10], 9 );
+    GG( b, c, d, a, in[14], 13 );
+    GG( a, b, c, d, in[3], 3 );
+    GG( d, a, b, c, in[7], 5 );
+    GG( c, d, a, b, in[11], 9 );
+    GG( b, c, d, a, in[15], 13 );
+
+    HH( a, b, c, d, in[0], 3 );
+    HH( d, a, b, c, in[8], 9 );
+    HH( c, d, a, b, in[4], 11 );
+    HH( b, c, d, a, in[12], 15 );
+    HH( a, b, c, d, in[2], 3 );
+    HH( d, a, b, c, in[10], 9 );
+    HH( c, d, a, b, in[6], 11 );
+    HH( b, c, d, a, in[14], 15 );
+    HH( a, b, c, d, in[1], 3 );
+    HH( d, a, b, c, in[9], 9 );
+    HH( c, d, a, b, in[5], 11 );
+    HH( b, c, d, a, in[13], 15 );
+    HH( a, b, c, d, in[3], 3 );
+    HH( d, a, b, c, in[11], 9 );
+    HH( c, d, a, b, in[7], 11 );
+    HH( b, c, d, a, in[15], 15 );
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
+/******************************************************************************
+ * SystemFunction007  [ADVAPI32.@]
+ *
+ * MD4 hash a unicode string
+ *
+ * PARAMS
+ *   string  [I] the string to hash
+ *   output  [O] the md4 hash of the string (16 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ */
+NTSTATUS WINAPI SystemFunction007(const UNICODE_STRING *string, LPBYTE hash)
+{
+    MD4_CTX ctx;
+
+    MD4Init( &ctx );
+    MD4Update( &ctx, (const BYTE *)string->Buffer, string->Length );
+    MD4Final( &ctx );
+    memcpy( hash, ctx.digest, 0x10 );
+
+    return STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * SystemFunction010  [ADVAPI32.@]
+ * SystemFunction011  [ADVAPI32.@]
+ *
+ * MD4 hashes 16 bytes of data
+ *
+ * PARAMS
+ *   unknown []  seems to have no effect on the output
+ *   data    [I] pointer to data to hash (16 bytes)
+ *   output  [O] the md4 hash of the data (16 bytes)
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS
+ *  Failure: STATUS_UNSUCCESSFUL
+ *
+ */
+NTSTATUS WINAPI SystemFunction010(LPVOID unknown, const BYTE *data, LPBYTE hash)
+{
+    MD4_CTX ctx;
+
+    MD4Init( &ctx );
+    MD4Update( &ctx, data, 0x10 );
+    MD4Final( &ctx );
+    memcpy( hash, ctx.digest, 0x10 );
+
+    return STATUS_SUCCESS;
+}
Index: trunk/src/advapi32/crypt_md5.cpp
===================================================================
--- trunk/src/advapi32/crypt_md5.cpp	(revision 21326)
+++ trunk/src/advapi32/crypt_md5.cpp	(revision 21326)
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2001 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * It is based on code in the public domain written by Colin
+ * Plumb in 1993. The algorithm is due to Ron Rivest.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5_CTX structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+
+typedef struct
+{
+    unsigned int i[2];
+    unsigned int buf[4];
+    unsigned char in[64];
+    unsigned char digest[16];
+} MD5_CTX;
+
+static void MD5Transform( unsigned int buf[4], const unsigned int in[16] );
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse( unsigned char *buf, unsigned longs )
+{
+    unsigned int t;
+
+    do {
+        t = ((unsigned)buf[3] << 8 | buf[2]) << 16 |
+            ((unsigned)buf[1] << 8 | buf[0]);
+        *(unsigned int *)buf = t;
+        buf += 4;
+    } while (--longs);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+VOID WINAPI MD5Init( MD5_CTX *ctx )
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->i[0] = ctx->i[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+VOID WINAPI MD5Update( MD5_CTX *ctx, const unsigned char *buf, unsigned int len )
+{
+    register unsigned int t;
+
+    /* Update bitcount */
+    t = ctx->i[0];
+
+    if ((ctx->i[0] = t + (len << 3)) < t)
+        ctx->i[1]++;        /* Carry from low to high */
+
+    ctx->i[1] += len >> 29;
+    t = (t >> 3) & 0x3f;
+
+    /* Handle any leading odd-sized chunks */
+    if (t)
+    {
+        unsigned char *p = (unsigned char *)ctx->in + t;
+        t = 64 - t;
+
+        if (len < t)
+        {
+            memcpy( p, buf, len );
+            return;
+        }
+
+        memcpy( p, buf, t );
+        byteReverse( ctx->in, 16 );
+
+        MD5Transform( ctx->buf, (unsigned int *)ctx->in );
+
+        buf += t;
+        len -= t;
+    }
+
+    /* Process data in 64-byte chunks */
+    while (len >= 64)
+    {
+        memcpy( ctx->in, buf, 64 );
+        byteReverse( ctx->in, 16 );
+
+        MD5Transform( ctx->buf, (unsigned int *)ctx->in );
+
+        buf += 64;
+        len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+    memcpy( ctx->in, buf, len );
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+VOID WINAPI MD5Final( MD5_CTX *ctx )
+{
+    unsigned int count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->i[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8)
+    {
+        /* Two lots of padding:  Pad the first block to 64 bytes */
+        memset( p, 0, count );
+        byteReverse( ctx->in, 16 );
+        MD5Transform( ctx->buf, (unsigned int *)ctx->in );
+
+        /* Now fill the next block with 56 bytes */
+        memset( ctx->in, 0, 56 );
+    }
+    else
+    {
+        /* Pad block to 56 bytes */
+        memset( p, 0, count - 8 );
+    }
+
+    byteReverse( ctx->in, 14 );
+
+    /* Append length in bits and transform */
+    ((unsigned int *)ctx->in)[14] = ctx->i[0];
+    ((unsigned int *)ctx->in)[15] = ctx->i[1];
+
+    MD5Transform( ctx->buf, (unsigned int *)ctx->in );
+    byteReverse( (unsigned char *)ctx->buf, 4 );
+    memcpy( ctx->digest, ctx->buf, 16 );
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1( x, y, z ) (x & y | ~x & z) */
+#define F1( x, y, z ) (z ^ (x & (y ^ z)))
+#define F2( x, y, z ) F1( z, x, y )
+#define F3( x, y, z ) (x ^ y ^ z)
+#define F4( x, y, z ) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP( f, w, x, y, z, data, s ) \
+        ( w += f( x, y, z ) + data,  w = w << s | w >> (32 - s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform( unsigned int buf[4], const unsigned int in[16] )
+{
+    register unsigned int a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP( F1, a, b, c, d, in[0] + 0xd76aa478, 7 );
+    MD5STEP( F1, d, a, b, c, in[1] + 0xe8c7b756, 12 );
+    MD5STEP( F1, c, d, a, b, in[2] + 0x242070db, 17 );
+    MD5STEP( F1, b, c, d, a, in[3] + 0xc1bdceee, 22 );
+    MD5STEP( F1, a, b, c, d, in[4] + 0xf57c0faf, 7 );
+    MD5STEP( F1, d, a, b, c, in[5] + 0x4787c62a, 12 );
+    MD5STEP( F1, c, d, a, b, in[6] + 0xa8304613, 17 );
+    MD5STEP( F1, b, c, d, a, in[7] + 0xfd469501, 22 );
+    MD5STEP( F1, a, b, c, d, in[8] + 0x698098d8, 7 );
+    MD5STEP( F1, d, a, b, c, in[9] + 0x8b44f7af, 12 );
+    MD5STEP( F1, c, d, a, b, in[10] + 0xffff5bb1, 17 );
+    MD5STEP( F1, b, c, d, a, in[11] + 0x895cd7be, 22 );
+    MD5STEP( F1, a, b, c, d, in[12] + 0x6b901122, 7 );
+    MD5STEP( F1, d, a, b, c, in[13] + 0xfd987193, 12 );
+    MD5STEP( F1, c, d, a, b, in[14] + 0xa679438e, 17 );
+    MD5STEP( F1, b, c, d, a, in[15] + 0x49b40821, 22 );
+
+    MD5STEP( F2, a, b, c, d, in[1] + 0xf61e2562, 5 );
+    MD5STEP( F2, d, a, b, c, in[6] + 0xc040b340, 9 );
+    MD5STEP( F2, c, d, a, b, in[11] + 0x265e5a51, 14 );
+    MD5STEP( F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20 );
+    MD5STEP( F2, a, b, c, d, in[5] + 0xd62f105d, 5 );
+    MD5STEP( F2, d, a, b, c, in[10] + 0x02441453, 9 );
+    MD5STEP( F2, c, d, a, b, in[15] + 0xd8a1e681, 14 );
+    MD5STEP( F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20 );
+    MD5STEP( F2, a, b, c, d, in[9] + 0x21e1cde6, 5 );
+    MD5STEP( F2, d, a, b, c, in[14] + 0xc33707d6, 9 );
+    MD5STEP( F2, c, d, a, b, in[3] + 0xf4d50d87, 14 );
+    MD5STEP( F2, b, c, d, a, in[8] + 0x455a14ed, 20 );
+    MD5STEP( F2, a, b, c, d, in[13] + 0xa9e3e905, 5 );
+    MD5STEP( F2, d, a, b, c, in[2] + 0xfcefa3f8, 9 );
+    MD5STEP( F2, c, d, a, b, in[7] + 0x676f02d9, 14 );
+    MD5STEP( F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20 );
+
+    MD5STEP( F3, a, b, c, d, in[5] + 0xfffa3942, 4 );
+    MD5STEP( F3, d, a, b, c, in[8] + 0x8771f681, 11 );
+    MD5STEP( F3, c, d, a, b, in[11] + 0x6d9d6122, 16 );
+    MD5STEP( F3, b, c, d, a, in[14] + 0xfde5380c, 23 );
+    MD5STEP( F3, a, b, c, d, in[1] + 0xa4beea44, 4 );
+    MD5STEP( F3, d, a, b, c, in[4] + 0x4bdecfa9, 11 );
+    MD5STEP( F3, c, d, a, b, in[7] + 0xf6bb4b60, 16 );
+    MD5STEP( F3, b, c, d, a, in[10] + 0xbebfbc70, 23 );
+    MD5STEP( F3, a, b, c, d, in[13] + 0x289b7ec6, 4 );
+    MD5STEP( F3, d, a, b, c, in[0] + 0xeaa127fa, 11 );
+    MD5STEP( F3, c, d, a, b, in[3] + 0xd4ef3085, 16 );
+    MD5STEP( F3, b, c, d, a, in[6] + 0x04881d05, 23 );
+    MD5STEP( F3, a, b, c, d, in[9] + 0xd9d4d039, 4 );
+    MD5STEP( F3, d, a, b, c, in[12] + 0xe6db99e5, 11 );
+    MD5STEP( F3, c, d, a, b, in[15] + 0x1fa27cf8, 16 );
+    MD5STEP( F3, b, c, d, a, in[2] + 0xc4ac5665, 23 );
+
+    MD5STEP( F4, a, b, c, d, in[0] + 0xf4292244, 6 );
+    MD5STEP( F4, d, a, b, c, in[7] + 0x432aff97, 10 );
+    MD5STEP( F4, c, d, a, b, in[14] + 0xab9423a7, 15 );
+    MD5STEP( F4, b, c, d, a, in[5] + 0xfc93a039, 21 );
+    MD5STEP( F4, a, b, c, d, in[12] + 0x655b59c3, 6 );
+    MD5STEP( F4, d, a, b, c, in[3] + 0x8f0ccc92, 10 );
+    MD5STEP( F4, c, d, a, b, in[10] + 0xffeff47d, 15 );
+    MD5STEP( F4, b, c, d, a, in[1] + 0x85845dd1, 21 );
+    MD5STEP( F4, a, b, c, d, in[8] + 0x6fa87e4f, 6 );
+    MD5STEP( F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10 );
+    MD5STEP( F4, c, d, a, b, in[6] + 0xa3014314, 15 );
+    MD5STEP( F4, b, c, d, a, in[13] + 0x4e0811a1, 21 );
+    MD5STEP( F4, a, b, c, d, in[4] + 0xf7537e82, 6 );
+    MD5STEP( F4, d, a, b, c, in[11] + 0xbd3af235, 10 );
+    MD5STEP( F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15 );
+    MD5STEP( F4, b, c, d, a, in[9] + 0xeb86d391, 21 );
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
Index: trunk/src/advapi32/crypt_sha.cpp
===================================================================
--- trunk/src/advapi32/crypt_sha.cpp	(revision 21326)
+++ trunk/src/advapi32/crypt_sha.cpp	(revision 21326)
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2004 Filip Navara
+ * Based on public domain SHA code by Steve Reid <steve@edmweb.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include "windef.h"
+
+/* SHA Context Structure Declaration */
+
+typedef struct {
+   ULONG Unknown[6];
+   ULONG State[5];
+   ULONG Count[2];
+   UCHAR Buffer[64];
+} SHA_CTX, *PSHA_CTX;
+
+/* SHA1 Helper Macros */
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+/* FIXME: This definition of DWORD2BE is little endian specific! */
+#define DWORD2BE(x) (((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000);
+/* FIXME: This definition of blk0 is little endian specific! */
+#define blk0(i) (Block[i] = (rol(Block[i],24)&0xFF00FF00)|(rol(Block[i],8)&0x00FF00FF))
+#define blk1(i) (Block[i&15] = rol(Block[(i+13)&15]^Block[(i+8)&15]^Block[(i+2)&15]^Block[i&15],1))
+#define f1(x,y,z) (z^(x&(y^z)))
+#define f2(x,y,z) (x^y^z)
+#define f3(x,y,z) ((x&y)|(z&(x|y)))
+#define f4(x,y,z) (x^y^z)
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+static void SHA1Transform(ULONG State[5], UCHAR Buffer[64])
+{
+   ULONG a, b, c, d, e;
+   ULONG *Block;
+
+   Block = (ULONG*)Buffer;
+
+   /* Copy Context->State[] to working variables */
+   a = State[0];
+   b = State[1];
+   c = State[2];
+   d = State[3];
+   e = State[4];
+
+   /* 4 rounds of 20 operations each. Loop unrolled. */
+   R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+   R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+   R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+   R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+   R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+   R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+   R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+   R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+   R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+   R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+   R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+   R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+   R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+   R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+   R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+   R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+   R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+   R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+   R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+   R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+   /* Add the working variables back into Context->State[] */
+   State[0] += a;
+   State[1] += b;
+   State[2] += c;
+   State[3] += d;
+   State[4] += e;
+
+   /* Wipe variables */
+   a = b = c = d = e = 0;
+}
+
+
+/******************************************************************************
+ * A_SHAInit [ADVAPI32.@]
+ *
+ * Initialize a SHA context structure.
+ *
+ * PARAMS
+ *  Context [O] SHA context
+ *
+ * RETURNS
+ *  Nothing
+ */
+VOID WINAPI
+A_SHAInit(PSHA_CTX Context)
+{
+   /* SHA1 initialization constants */
+   Context->State[0] = 0x67452301;
+   Context->State[1] = 0xEFCDAB89;
+   Context->State[2] = 0x98BADCFE;
+   Context->State[3] = 0x10325476;
+   Context->State[4] = 0xC3D2E1F0;
+   Context->Count[0] =
+   Context->Count[1] = 0;
+}
+
+/******************************************************************************
+ * A_SHAUpdate [ADVAPI32.@]
+ *
+ * Update a SHA context with a hashed data from supplied buffer.
+ *
+ * PARAMS
+ *  Context    [O] SHA context
+ *  Buffer     [I] hashed data
+ *  BufferSize [I] hashed data size
+ *
+ * RETURNS
+ *  Nothing
+ */
+VOID WINAPI
+A_SHAUpdate(PSHA_CTX Context, const unsigned char *Buffer, UINT BufferSize)
+{
+   ULONG BufferContentSize;
+
+   BufferContentSize = Context->Count[1] & 63;
+   Context->Count[1] += BufferSize;
+   if (Context->Count[1] < BufferSize)
+      Context->Count[0]++;
+   Context->Count[0] += (BufferSize >> 29);
+
+   if (BufferContentSize + BufferSize < 64)
+   {
+      RtlCopyMemory(&Context->Buffer[BufferContentSize], Buffer,
+                    BufferSize);
+   }
+   else
+   {
+      while (BufferContentSize + BufferSize >= 64)
+      {
+         RtlCopyMemory(Context->Buffer + BufferContentSize, Buffer,
+                       64 - BufferContentSize);
+         Buffer += 64 - BufferContentSize;
+         BufferSize -= 64 - BufferContentSize;
+         SHA1Transform(Context->State, Context->Buffer);
+         BufferContentSize = 0;
+      }
+      RtlCopyMemory(Context->Buffer + BufferContentSize, Buffer, BufferSize);
+   }
+}
+
+/******************************************************************************
+ * A_SHAFinal [ADVAPI32.@]
+ *
+ * Finalize SHA context and return the resulting hash.
+ *
+ * PARAMS
+ *  Context [I/O] SHA context
+ *  Result  [O] resulting hash
+ *
+ * RETURNS
+ *  Nothing
+ */
+VOID WINAPI
+A_SHAFinal(PSHA_CTX Context, PULONG Result)
+{
+   INT Pad, Index;
+   UCHAR Buffer[72];
+   ULONG *Count;
+   ULONG BufferContentSize, LengthHi, LengthLo;
+
+   BufferContentSize = Context->Count[1] & 63;
+   if (BufferContentSize >= 56)
+      Pad = 56 + 64 - BufferContentSize;
+   else
+      Pad = 56 - BufferContentSize;
+
+   LengthHi = (Context->Count[0] << 3) | (Context->Count[1] >> (32 - 3));
+   LengthLo = (Context->Count[1] << 3);
+
+   RtlZeroMemory(Buffer + 1, Pad - 1);
+   Buffer[0] = 0x80;
+   Count = (ULONG*)(Buffer + Pad);
+   Count[0] = DWORD2BE(LengthHi);
+   Count[1] = DWORD2BE(LengthLo);
+   A_SHAUpdate(Context, Buffer, Pad + 8);
+
+   for (Index = 0; Index < 5; Index++)
+      Result[Index] = DWORD2BE(Context->State[Index]);
+
+   A_SHAInit(Context);
+}
Index: trunk/src/advapi32/registry.c
===================================================================
--- trunk/src/advapi32/registry.c	(revision 21326)
+++ trunk/src/advapi32/registry.c	(revision 21326)
@@ -0,0 +1,236 @@
+/*
+ * Registry management
+ *
+ * Copyright (C) 1999 Alexandre Julliard
+ *
+ * Based on misc/registry.c code
+ * Copyright (C) 1996 Marcus Meissner
+ * Copyright (C) 1998 Matthew Becker
+ * Copyright (C) 1999 Sylvain St-Germain
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winerror.h"
+#include "winternl.h"
+#include "winuser.h"
+#include "thread.h"
+
+#include "wine/unicode.h"
+#include "debugtools.h"
+
+//WINE_DEFAULT_DEBUG_CHANNEL(reg);
+
+#define NtCurrentTeb GetThreadTEB
+TEB  *WIN32API GetThreadTEB();
+
+#define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
+#define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
+#define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)
+
+static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
+static BOOL hkcu_cache_disabled;
+
+static const WCHAR name_CLASSES_ROOT[] =
+    {'M','a','c','h','i','n','e','\\',
+     'S','o','f','t','w','a','r','e','\\',
+     'C','l','a','s','s','e','s',0};
+static const WCHAR name_LOCAL_MACHINE[] =
+    {'M','a','c','h','i','n','e',0};
+static const WCHAR name_USERS[] =
+    {'U','s','e','r',0};
+static const WCHAR name_PERFORMANCE_DATA[] =
+    {'P','e','r','f','D','a','t','a',0};
+static const WCHAR name_CURRENT_CONFIG[] =
+    {'M','a','c','h','i','n','e','\\',
+     'S','y','s','t','e','m','\\',
+     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+     'H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\',
+     'C','u','r','r','e','n','t',0};
+static const WCHAR name_DYN_DATA[] =
+    {'D','y','n','D','a','t','a',0};
+
+static const WCHAR * const root_key_names[NB_SPECIAL_ROOT_KEYS] =
+{
+    name_CLASSES_ROOT,
+    NULL,         /* HKEY_CURRENT_USER is determined dynamically */
+    name_LOCAL_MACHINE,
+    name_USERS,
+    name_PERFORMANCE_DATA,
+    name_CURRENT_CONFIG,
+    name_DYN_DATA
+};
+
+
+/* check if value type needs string conversion (Ansi<->Unicode) */
+static inline int is_string( DWORD type )
+{
+    return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
+}
+
+/* check if current version is NT or Win95 */
+static inline int is_version_nt(void)
+{
+    return !(GetVersion() & 0x80000000);
+}
+
+/* create one of the HKEY_* special root keys */
+static HKEY create_special_root_hkey( HANDLE hkey, DWORD access )
+{
+    HKEY ret = 0;
+    int idx = (UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST;
+
+    if (hkey == HKEY_CURRENT_USER)
+    {
+        if (RtlOpenCurrentUser( access, &hkey )) return 0;
+        TRACE( "HKEY_CURRENT_USER -> %p\n", hkey );
+
+        /* don't cache the key in the table if caching is disabled */
+        if (hkcu_cache_disabled)
+            return hkey;
+    }
+    else
+    {
+        OBJECT_ATTRIBUTES attr;
+        UNICODE_STRING name;
+
+        attr.Length = sizeof(attr);
+        attr.RootDirectory = 0;
+        attr.ObjectName = &name;
+        attr.Attributes = 0;
+        attr.SecurityDescriptor = NULL;
+        attr.SecurityQualityOfService = NULL;
+        RtlInitUnicodeString( &name, root_key_names[idx] );
+        if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
+        TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
+    }
+
+    if (!(ret = InterlockedCompareExchangePointer( (void **)&special_root_keys[idx], hkey, 0 )))
+        ret = hkey;
+    else
+        NtClose( hkey );  /* somebody beat us to it */
+    return ret;
+}
+
+/* map the hkey from special root to normal key if necessary */
+static inline HKEY get_special_root_hkey( HKEY hkey )
+{
+    HKEY ret = hkey;
+
+    if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
+    {
+        if (!(ret = special_root_keys[(UINT_PTR)hkey - (UINT_PTR)HKEY_SPECIAL_ROOT_FIRST]))
+            ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
+    }
+    return ret;
+}
+
+
+/******************************************************************************
+ * RegDeleteTreeW [ADVAPI32.@]
+ *
+ */
+LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
+{
+    LONG ret;
+    DWORD dwMaxSubkeyLen, dwMaxValueLen;
+    DWORD dwMaxLen, dwSize;
+    WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
+    HKEY hSubKey = hKey;
+
+    TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
+
+    if(lpszSubKey)
+    {
+        ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
+        if (ret) return ret;
+    }
+
+    /* Get highest length for keys, values */
+    ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
+            &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
+    if (ret) goto cleanup;
+
+    dwMaxSubkeyLen++;
+    dwMaxValueLen++;
+    dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
+    if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
+    {
+        /* Name too big: alloc a buffer for it */
+        if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
+        {
+            ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto cleanup;
+        }
+    }
+
+
+    /* Recursively delete all the subkeys */
+    while (TRUE)
+    {
+        dwSize = dwMaxLen;
+        if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
+                          NULL, NULL, NULL)) break;
+
+        ret = RegDeleteTreeW(hSubKey, lpszName);
+        if (ret) goto cleanup;
+    }
+
+    if (lpszSubKey)
+        ret = RegDeleteKeyW(hKey, lpszSubKey);
+    else
+        while (TRUE)
+        {
+            dwSize = dwMaxLen;
+            if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
+                  NULL, NULL, NULL, NULL)) break;
+
+            ret = RegDeleteValueW(hKey, lpszName);
+            if (ret) goto cleanup;
+        }
+
+cleanup:
+    /* Free buffer if allocated */
+    if (lpszName != szNameBuf)
+        HeapFree( GetProcessHeap(), 0, lpszName);
+    if(lpszSubKey)
+        RegCloseKey(hSubKey);
+    return ret;
+}
+
+/******************************************************************************
+ * RegDeleteTreeA [ADVAPI32.@]
+ *
+ */
+LSTATUS WINAPI RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
+{
+    LONG ret;
+    UNICODE_STRING lpszSubKeyW;
+
+    if (lpszSubKey) RtlCreateUnicodeStringFromAsciiz( &lpszSubKeyW, lpszSubKey);
+    else lpszSubKeyW.Buffer = NULL;
+    ret = RegDeleteTreeW( hKey, lpszSubKeyW.Buffer);
+    RtlFreeUnicodeString( &lpszSubKeyW );
+    return ret;
+}
