Index: dlls/rsabase/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/rsabase/Makefile.in,v
retrieving revision 1.2
diff -u -r1.2 Makefile.in
--- dlls/rsabase/Makefile.in	1 Mar 2004 21:20:33 -0000	1.2
+++ dlls/rsabase/Makefile.in	25 Jul 2004 08:25:50 -0000
@@ -7,7 +7,11 @@
 IMPORTS   = advapi32 kernel32
 
 C_SRCS = \
-	main.c
+	main.c \
+	handle.c \
+	implossl.c
+
+SUBDIRS = tests
 
 @MAKE_DLL_RULES@
 
Index: dlls/rsabase/main.c
===================================================================
RCS file: /home/wine/wine/dlls/rsabase/main.c,v
retrieving revision 1.7
diff -u -r1.7 main.c
--- dlls/rsabase/main.c	25 Jun 2004 01:17:37 -0000	1.7
+++ dlls/rsabase/main.c	25 Jul 2004 08:25:52 -0000
@@ -21,27 +21,24 @@
  * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
  */
 
-
 #include "config.h"
 #include "wine/port.h"
 
 #include <stdarg.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winbase.h"
 #include "winreg.h"
 #include "wincrypt.h"
+#include "lmcons.h"
+#include "handle.h"
+#include "rsabase.h"
 
 #ifdef HAVE_OPENSSL_SSL_H
-#define DSA __ssl_DSA  /* avoid conflict with commctrl.h */
-#undef FAR
-# include <openssl/rand.h>
-#undef FAR
-#define FAR do_not_use_this_in_wine
-#undef DSA
+#include "implossl.h"
 #endif
 
 #include "wine/library.h"
@@ -51,84 +48,316 @@
 
 #define RSABASE_MAGIC 0x52534100
 
-#ifdef HAVE_OPENSSL_SSL_H
-
-#ifndef SONAME_LIBCRYPTO
-#define SONAME_LIBCRYPTO "libcrypto.so"
-#endif
-
-static void *libcrypto;
-
-#define MAKE_FUNCPTR(f) static typeof(f) * p##f
-
-/* OpenSSL funtions that we use */
-MAKE_FUNCPTR(RAND_bytes);
-
-static BOOL load_libcrypto( void )
+#define RSASTRONG_NUM_ALGS 14
+PROV_ENUMALGS_EX aProvEnumAlgsEx[RSASTRONG_NUM_ALGS] = {
+ {CALG_RC2,        128, 40,  128,0,                                  4,"RC2",         24,"RSA Data Security's RC2"},
+ {CALG_RC4,        128, 40,  128,0,                                  4,"RC4",         24,"RSA Data Security's RC4"},
+ {CALG_DES,         56, 56,   56,0,                                  4,"DES",         31,"Data Encryption Standard (DES)"},
+ {CALG_3DES_112,   112,112,  112,0,                                 13,"3DES TWO KEY",19,"Two Key Triple DES"},
+ {CALG_3DES,       168,168,  168,0,                                  5,"3DES",        21,"Three Key Triple DES"},
+ {CALG_SHA,        160,160,  160,CRYPT_FLAG_SIGNING,                 6,"SHA-1",       30,"Secure Hash Algorithm (SHA-1)"},
+ {CALG_MD2,        128,128,  128,CRYPT_FLAG_SIGNING,                 4,"MD2",         27,"MD2 Message Digest 2 (MD2)"},
+ {CALG_MD4,        128,128,  128,CRYPT_FLAG_SIGNING,                 4,"MD4",         27,"MD4 Message Digest 4 (MD4)"},
+ {CALG_MD5,        128,128,  128,CRYPT_FLAG_SIGNING,                 4,"MD5",         27,"MD5 Message Digest 5 (MD5)"},
+ {CALG_SSL3_SHAMD5,288,288,  288,0,                                 12,"SSL3 SHAMD5", 12,"SSL3 SHAMD5"},
+ {CALG_MAC,          0,  0,    0,0,                                  4,"MAC",         27,"Message Authentication Code"},
+ {CALG_RSA_SIGN,  1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",    14,"RSA Signature"},
+ {CALG_RSA_KEYX,  1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",    18,"RSA Key Exchange"},
+ {CALG_HMAC,         0,  0,    0,0,                                  5,"HMAC",        23,"HMAC Hugo's MAC (HMAC)"}
+};
+
+unsigned int iEnumAlgs;
+HANDLETABLE handle_table;
+
+int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
+{
+	switch (fdwReason)
+	{
+		case DLL_PROCESS_ATTACH:
+			init_handle_table(&handle_table);
+			break;
+
+		case DLL_PROCESS_DETACH:
+			destruct_handle_table(&handle_table);
+			break;
+	}
+	return 1;
+}
+
+int is_algid_supported(ALG_ID algid)
+{
+	int i;
+	for (i=0; i<RSASTRONG_NUM_ALGS; i++)
+		if (aProvEnumAlgsEx[i].aiAlgid == algid)
+			return 1;
+	return 0;
+}
+
+unsigned int new_object(size_t cbSize, DESTRUCTOR destructor, OBJECTHDR **ppObject)
+{
+	OBJECTHDR *pObject;
+	unsigned int hObject;
+
+	if (ppObject)
+		*ppObject = NULL;
+	
+	pObject = (OBJECTHDR*)HeapAlloc(GetProcessHeap(), 0, cbSize);
+	if (!pObject) 
+		return (unsigned int)INVALID_HANDLE_VALUE;
+
+	pObject->refcount = 0;
+	pObject->destructor = destructor;
+
+	if (!alloc_handle(&handle_table, pObject, &hObject))
+		HeapFree(GetProcessHeap(), 0, pObject);
+	else 
+		if (ppObject)
+			*ppObject = pObject;
+
+	return hObject;
+}
+
+void crypt_hash_destructor(OBJECTHDR *pCryptHash)
+{
+	if (((CRYPTHASH*)pCryptHash)->pContext)
+		HeapFree(GetProcessHeap(), 0, ((CRYPTHASH*)pCryptHash)->pContext);
+	HeapFree(GetProcessHeap(), 0, pCryptHash);
+}
+
+HCRYPTHASH new_crypt_hash(ALG_ID aiAlgid, HCRYPTKEY hKey)
+{
+	HCRYPTHASH hCryptHash;
+	CRYPTHASH *pCryptHash;
+	
+	hCryptHash = (HCRYPTHASH)new_object(sizeof(CRYPTHASH), crypt_hash_destructor, (OBJECTHDR**)&pCryptHash);
+	if (hCryptHash != (HCRYPTHASH)INVALID_HANDLE_VALUE)
+	{
+		pCryptHash->aiAlgid = aiAlgid;
+		pCryptHash->hKey = hKey;
+		pCryptHash->fFinished = FALSE;
+		switch (aiAlgid)
+		{
+			case CALG_MD5:
+				pCryptHash->pContext = (PVOID)HeapAlloc(GetProcessHeap(), 0, sizeof(IMPL(md5_context)));
+				IMPL(md5_init)((IMPL(md5_context)*)pCryptHash->pContext);
+				break;
+			
+			default:
+				FIXME("ALG_ID %08x not implemented!\n", aiAlgid);
+				pCryptHash->pContext = NULL;
+		}
+	}
+
+	return hCryptHash;
+}
+
+void crypt_key_destructor(OBJECTHDR *pCryptKey)
+{
+	HeapFree(GetProcessHeap(), 0, pCryptKey);
+}
+
+HCRYPTKEY new_crypt_key(ALG_ID aiAlgid, DWORD dwKeyLen, BYTE *pbKey)
+{
+	HCRYPTKEY hCryptKey;
+	CRYPTKEY *pCryptKey;
+
+	hCryptKey = (HCRYPTKEY)new_object(sizeof(CRYPTKEY), crypt_key_destructor, (OBJECTHDR**)&pCryptKey);
+	if (hCryptKey != (HCRYPTKEY)INVALID_HANDLE_VALUE)
+	{
+		pCryptKey->aiAlgid = aiAlgid;
+		pCryptKey->dwKeyLen = dwKeyLen;
+		if (pbKey)
+			memcpy(pCryptKey->abKey, pbKey, dwKeyLen >> 3);
+	}
+
+	return hCryptKey;
+}
+
+HCRYPTKEY duplicate_key(HCRYPTKEY other)
+{
+	CRYPTKEY *pCryptKey;
+
+	if (!lookup_handle(&handle_table, other, (OBJECTHDR**)&pCryptKey)) 
+		return (HCRYPTKEY)INVALID_HANDLE_VALUE;
+
+	return new_crypt_key(pCryptKey->aiAlgid, pCryptKey->dwKeyLen, pCryptKey->abKey);
+}		
+
+void key_container_destructor(OBJECTHDR *pKeyContainer)
+{
+	CHAR szRSABase[MAX_PATH];
+	HKEY hKey;
+	DWORD dummy = 0xefbeadde;
+	
+	strcpy(szRSABase, "Software\\Wine\\rsabase\\");
+	strcat(szRSABase, ((KEYCONTAINER*)pKeyContainer)->szName);
+
+	if (RegCreateKeyExA(HKEY_CURRENT_USER, szRSABase, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
+	{
+		if (((KEYCONTAINER*)pKeyContainer)->hKeyExchangeKeyPair) 
+			RegSetValueExA(hKey, "KeyExchangeKeyPair", 0, REG_BINARY, (const BYTE *)&dummy, sizeof(dummy));
+	
+		if (((KEYCONTAINER*)pKeyContainer)->hSignatureKeyPair)
+			RegSetValueExA(hKey, "SignatureKeyPair", 0, REG_BINARY, (const BYTE *)&dummy, sizeof(dummy));
+	
+		RegCloseKey(hKey);
+	}
+		
+	release_handle(&handle_table, (unsigned int)((KEYCONTAINER*)pKeyContainer)->hSignatureKeyPair);
+	release_handle(&handle_table, (unsigned int)((KEYCONTAINER*)pKeyContainer)->hKeyExchangeKeyPair);
+	HeapFree( GetProcessHeap(), 0, pKeyContainer );
+}
+
+HCRYPTPROV new_key_container(PCHAR pszContainerName)
+{   
+	KEYCONTAINER *pKeyContainer;
+	HCRYPTPROV hKeyContainer;
+
+	hKeyContainer = (HCRYPTPROV)new_object(sizeof(KEYCONTAINER), key_container_destructor, (OBJECTHDR**)&pKeyContainer);
+	if (hKeyContainer != (HCRYPTPROV)INVALID_HANDLE_VALUE)
+	{
+		strncpy(pKeyContainer->szName, pszContainerName, MAX_PATH);
+		pKeyContainer->szName[MAX_PATH-1] = '\0';
+		pKeyContainer->dwMode = 0;
+		pKeyContainer->hKeyExchangeKeyPair = (HCRYPTKEY)INVALID_HANDLE_VALUE;
+    	pKeyContainer->hSignatureKeyPair = (HCRYPTKEY)INVALID_HANDLE_VALUE;
+	}
+
+   	return hKeyContainer;
+}					
+
+HCRYPTPROV read_key_container(PCHAR pszContainerName)
+{
+	CHAR szRSABase[MAX_PATH];
+	HKEY hKey;
+	DWORD dwValueType;
+	KEYCONTAINER *pKeyContainer;
+	HCRYPTPROV hKeyContainer;
+	
+	strcpy(szRSABase, "Software\\Wine\\rsabase\\");
+	strcat(szRSABase, pszContainerName);
+
+	if (RegOpenKeyExA(HKEY_CURRENT_USER, szRSABase, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+	{
+		SetLastError(NTE_BAD_KEYSET);
+		return (HCRYPTPROV)INVALID_HANDLE_VALUE;
+	}
+
+	hKeyContainer = new_key_container(pszContainerName);
+	if (hKeyContainer != (HCRYPTPROV)INVALID_HANDLE_VALUE)
+	{
+		if (!lookup_handle(&handle_table, hKeyContainer, (OBJECTHDR**)&pKeyContainer))
+			return (HCRYPTPROV)INVALID_HANDLE_VALUE;
+	
+		if (RegQueryValueExA(hKey, "KeyExchangeKeyPair", 0, &dwValueType, NULL, NULL) == ERROR_SUCCESS)
+			pKeyContainer->hKeyExchangeKeyPair = new_crypt_key(CALG_RSA_KEYX, 0, NULL);
+	
+		if (RegQueryValueExA(hKey, "SignatureKeyPair", 0, &dwValueType, NULL, NULL) == ERROR_SUCCESS)
+			pKeyContainer->hSignatureKeyPair = new_crypt_key(CALG_RSA_SIGN, 0, NULL);
+	}
+
+	return hKeyContainer;
+}
+
+/******************************************************************************
+ *  get_key_container_name [Internal]
+ *  
+ * Derives the name of the key container based on the string pszContainer.
+ * If pszContainer is NULL or points to an empty string, the name of the current
+ * user is returned via pszKeyContainerName. Otherwise pszContainer is copied to
+ * pszKeyContainerName. If the container name does not fit into cbMax bytes, 0 is
+ * returned.
+ */
+DWORD get_key_container_name(LPSTR pszKeyContainerName, LPSTR pszContainer, DWORD cbMax)
 {
-    libcrypto = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
-    if (!libcrypto)
-    {
-        MESSAGE("Couldn't load %s, RSA encryption not available.\n", SONAME_LIBCRYPTO);
-        MESSAGE("Install the openssl package if you're have problems.\n");
-        return FALSE;
-    }
-
-    #define GETFUNC(x) \
-    p##x = wine_dlsym(libcrypto, #x, NULL, 0); \
-    if (!p##x) \
-    { \
-        ERR("failed to load symbol %s\n", #x); \
-        return FALSE; \
-    }
-
-    GETFUNC(RAND_bytes);
-
-    return TRUE;
+	if (pszContainer ? strlen(pszContainer) : 0) 
+	{
+		if (strlen(pszContainer) < cbMax)
+		{
+			strcpy(pszKeyContainerName, pszContainer);
+			return 1;
+		}
+		else 
+		{
+			pszKeyContainerName[0] = '\0';
+			return 0;
+		}
+	}
+	else 
+	{
+		return GetUserNameA(pszKeyContainerName, &cbMax);
+	}
 }
 
-#endif
-
-typedef struct _RSA_CryptProv
-{
-    DWORD dwMagic;
-} RSA_CryptProv;
-
 BOOL WINAPI RSA_CPAcquireContext(HCRYPTPROV *phProv, LPSTR pszContainer,
                    DWORD dwFlags, PVTableProvStruc pVTable)
 {
-    BOOL ret = FALSE;
+	CHAR szKeyContainerName[MAX_PATH];
 
     TRACE("%p %s %08lx %p\n", phProv, debugstr_a(pszContainer),
            dwFlags, pVTable);
 
-#ifdef HAVE_OPENSSL_SSL_H
-
-    if( !load_libcrypto() )
-        return FALSE;
-    else
-    {
-        RSA_CryptProv *cp = HeapAlloc( GetProcessHeap(), 0, sizeof (RSA_CryptProv) );
-        if( !cp )
-        {
-            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            return FALSE;
-        }
-
-        cp->dwMagic = RSABASE_MAGIC;
-
-        *phProv = (HCRYPTPROV) cp;
-        ret = TRUE;
-    }
-#endif
-
-    return ret;
+	if (!IMPL(load_lib)())
+	{
+		/* MSDN: Failed to load or initalize provider DLL */
+		SetLastError(NTE_PROVIDER_DLL_FAIL);
+		return FALSE;
+	}
+		
+	if (!get_key_container_name(szKeyContainerName, pszContainer, MAX_PATH)) 
+	{
+		SetLastError(NTE_BAD_KEYSET_PARAM);
+		return FALSE;
+	}
+		
+	switch (dwFlags) 
+	{
+		case 0:
+			*phProv = read_key_container(szKeyContainerName);
+			break;
+
+		case CRYPT_NEWKEYSET:
+			*phProv = read_key_container(szKeyContainerName);
+			if (*phProv != (HCRYPTPROV)INVALID_HANDLE_VALUE) 
+			{
+				release_handle(&handle_table, (unsigned int)*phProv);
+				SetLastError(NTE_EXISTS);
+				return FALSE;
+			}
+			*phProv = new_key_container(szKeyContainerName);
+			break;
+					
+		default:
+			*phProv = (unsigned int)INVALID_HANDLE_VALUE;
+			SetLastError(NTE_BAD_FLAGS);
+			return FALSE;
+	}
+				
+	return *phProv != (unsigned int)INVALID_HANDLE_VALUE;
 }
 
 BOOL WINAPI RSA_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash)
 {
-    FIXME("%08lx %d %08lx %08lx %p\n", hProv, Algid, hKey, dwFlags, phHash);
-    return FALSE;
+	if (!is_valid_handle(&handle_table, hProv)) 
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	if (!is_algid_supported(Algid))
+	{
+		SetLastError(NTE_BAD_ALGID);
+		return FALSE;
+	}
+
+	if (dwFlags)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+
+	*phHash = new_crypt_hash(Algid, hKey);
+	return TRUE;
 }
 
 BOOL WINAPI RSA_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
@@ -137,22 +366,207 @@
     return FALSE;
 }
 
-BOOL WINAPI RSA_CPDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey)
+BOOL WINAPI RSA_CPGetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+	CRYPTHASH *pCryptHash;
+	DWORD dwDataLen;
+		
+	if (!is_valid_handle(&handle_table, (unsigned int)hProv)) 
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	if (dwFlags)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+	
+	if (!lookup_handle(&handle_table, (unsigned int)hHash, (OBJECTHDR**)&pCryptHash))
+	{
+		SetLastError(NTE_BAD_HASH);
+		return FALSE;
+	}
+
+	if (!pdwDataLen)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+
+	dwDataLen = *pdwDataLen;
+	*pdwDataLen = 0;
+	
+	switch (dwParam)
+	{
+		case HP_ALGID: 
+			*pdwDataLen = sizeof(ALG_ID);
+			if (pbData)
+			{
+				if (dwDataLen < *pdwDataLen)
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+				*(ALG_ID*)pbData = pCryptHash->aiAlgid;
+			}
+			return TRUE;
+
+		case HP_HASHSIZE:
+			*pdwDataLen = sizeof(DWORD);
+			if (pbData)
+			{
+				if (dwDataLen < *pdwDataLen)
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+
+				switch (pCryptHash->aiAlgid)
+				{
+					case CALG_MD5:
+						*(DWORD*)pbData = 16;
+						break;
+
+					default:
+						FIXME("Unsupported Algid: %08x\n", pCryptHash->aiAlgid);
+						SetLastError(NTE_FAIL);
+						return FALSE;
+				}
+			}
+			return TRUE;
+
+		case HP_HASHVALUE:
+			switch (pCryptHash->aiAlgid)
+			{
+				case CALG_MD5:
+					*pdwDataLen = 16;
+					break;
+
+				default:
+					FIXME("Unsupported Algid: %08x\n", pCryptHash->aiAlgid);
+					SetLastError(NTE_FAIL);
+					return FALSE;
+			}
+			
+			if (pbData)
+			{
+				if (dwDataLen < *pdwDataLen)
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+
+				switch (pCryptHash->aiAlgid)
+				{
+					case CALG_MD5:
+						IMPL(md5_get_digest)((IMPL(md5_context)*)pCryptHash->pContext, (unsigned char*)pbData);
+						break;
+
+					default:
+						FIXME("Unsupported Algid: %08x\n", pCryptHash->aiAlgid);
+						SetLastError(NTE_FAIL);
+						return FALSE;
+				}
+
+				pCryptHash->fFinished = TRUE;
+			}
+			return TRUE;
+
+		default:
+			SetLastError(NTE_BAD_TYPE);
+			return FALSE;
+	}
+}
+
+BOOL WINAPI RSA_CPDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey)
+{	
+	DWORD cLen = 0;
+	BYTE *pbHashValue;
+		
+	if (!is_valid_handle(&handle_table, (unsigned int)hProv))
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	if (!is_valid_handle(&handle_table, (unsigned int)hBaseData))
+	{
+		SetLastError(NTE_BAD_HASH);
+		return FALSE;
+	}
+
+	if (!phKey)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}
+	
+	if (!RSA_CPGetHashParam(hProv, hBaseData, HP_HASHVALUE, NULL, &cLen, 0))
+		return FALSE;
+			
+	pbHashValue = (BYTE*)HeapAlloc(GetProcessHeap(), 0, cLen);
+	if (!pbHashValue)
+	{
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return FALSE;
+	}
+
+	if (!RSA_CPGetHashParam(hProv, hBaseData, HP_HASHVALUE, pbHashValue, &cLen, 0))
+	{
+		HeapFree(GetProcessHeap(), 0, pbHashValue);
+		return FALSE;
+	}
+
+	switch (Algid)
+	{
+		case CALG_RC2:
+			*phKey = new_crypt_key(Algid, 128, pbHashValue);
+			break;
+
+		default:
+			HeapFree(GetProcessHeap(), 0, pbHashValue);
+			FIXME("Unimplemented Algid: %08x\n", Algid);
+			SetLastError(NTE_FAIL);
+			return FALSE;
+	}
+
+	return TRUE;
 }
 
 BOOL WINAPI RSA_CPDestroyHash(HCRYPTPROV hProv, HCRYPTHASH hHash)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+ 	if (!is_valid_handle(&handle_table, hProv))
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+		
+	if (!release_handle(&handle_table, hHash)) 
+	{
+		SetLastError(NTE_BAD_KEY);
+		return FALSE;
+	}
+	
+    return TRUE;
 }
 
 BOOL WINAPI RSA_CPDestroyKey(HCRYPTPROV hProv, HCRYPTKEY hKey)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+	if (!is_valid_handle(&handle_table, hProv))
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+		
+	if (!release_handle(&handle_table, hKey)) 
+	{
+		SetLastError(NTE_BAD_KEY);
+		return FALSE;
+	}
+	
+    return TRUE;
 }
 
 BOOL WINAPI RSA_CPDuplicateHash(HCRYPTPROV hUID, HCRYPTHASH hHash, DWORD *pdwReserved, DWORD dwFlags, HCRYPTHASH *phHash)
@@ -163,8 +577,20 @@
 
 BOOL WINAPI RSA_CPDuplicateKey(HCRYPTPROV hUID, HCRYPTKEY hKey, DWORD *pdwReserved, DWORD dwFlags, HCRYPTKEY *phKey)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+	if (!is_valid_handle(&handle_table, hUID))
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	*phKey = duplicate_key(hKey);
+	if (*phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
+	{
+		SetLastError(NTE_BAD_KEY);
+		return FALSE;
+	}
+		
+    return TRUE;
 }
 
 BOOL WINAPI RSA_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen)
@@ -181,35 +607,56 @@
 
 BOOL WINAPI RSA_CPGenKey(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+	KEYCONTAINER *pKeyContainer;
+
+	if (!lookup_handle(&handle_table, (unsigned int)hProv, (OBJECTHDR**)&pKeyContainer)) 
+	{
+		/* MSDN: hProv not containing valid context handle */
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+	
+	switch (Algid)
+	{
+		case AT_SIGNATURE:
+			RSA_CPDestroyKey(hProv, pKeyContainer->hSignatureKeyPair);
+			*phKey = pKeyContainer->hSignatureKeyPair = new_crypt_key(CALG_RSA_SIGN, 0, NULL);
+			break;
+
+		case AT_KEYEXCHANGE:
+			RSA_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair);
+			*phKey = pKeyContainer->hKeyExchangeKeyPair = new_crypt_key(CALG_RSA_KEYX, 0, NULL);
+			break;
+		
+		case CALG_RC2:
+		case CALG_RC4:
+		case CALG_DES:
+			*phKey = new_crypt_key(Algid, 0, NULL);
+			break;
+			
+		default:
+			/* MSDN: Algorithm not supported specified by Algid */
+			SetLastError(NTE_BAD_ALGID);
+			return FALSE;
+	}
+			
+	return *phKey != (unsigned int)INVALID_HANDLE_VALUE;
 }
 
 BOOL WINAPI RSA_CPGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer)
 {
-    BOOL ret = FALSE;
-    RSA_CryptProv *cp = (RSA_CryptProv*) hProv;
+	KEYCONTAINER *pKeyContainer;
 
     TRACE("%08lx %ld %p\n", hProv, dwLen, pbBuffer);
 
-    if( cp && ( cp->dwMagic != RSABASE_MAGIC ) )
-        return FALSE;
-
-#ifdef HAVE_OPENSSL_SSL_H
-
-    if( !pRAND_bytes)
-        return FALSE;
-    ret = pRAND_bytes( pbBuffer, dwLen );
-
-#endif
-
-    return ret;
-}
+	if (!lookup_handle(&handle_table, (unsigned int)hProv, (OBJECTHDR**)&pKeyContainer)) 
+	{
+		/* MSDN: hProv not containing valid context handle */
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
 
-BOOL WINAPI RSA_CPGetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
-{
-    FIXME("(stub)\n");
-    return FALSE;
+	return IMPL(random_bytes)(pbBuffer, dwLen);
 }
 
 BOOL WINAPI RSA_CPGetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
@@ -220,20 +667,165 @@
 
 BOOL WINAPI RSA_CPGetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
 {
-    FIXME("(stub)\n");
+	KEYCONTAINER *pKeyContainer;
+	DWORD dwDataLen = *pdwDataLen;
+	static const char szProviderName[] = "Microsoft Strong Cryptographic Provider";
+
+	if (!lookup_handle(&handle_table, (unsigned int)hProv, (OBJECTHDR**)&pKeyContainer)) 
+	{
+		/* MSDN: hProv not containing valid context handle */
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	switch (dwParam) 
+	{
+		case PP_CONTAINER:
+			*pdwDataLen = strlen(pKeyContainer->szName)+1;
+			if (pbData)
+			{
+				if (*pdwDataLen > dwDataLen)
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+				strcpy(pbData, pKeyContainer->szName);
+			}
+			return TRUE;
+
+		case PP_NAME:
+			*pdwDataLen = strlen(szProviderName)+1;
+			if (pbData)
+			{
+				if (*pdwDataLen > dwDataLen)
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+				strcpy(pbData, szProviderName);
+			}
+			return TRUE;
+
+		case PP_ENUMALGS:
+			if ((iEnumAlgs >= RSASTRONG_NUM_ALGS-1) && ((dwFlags & CRYPT_FIRST) != CRYPT_FIRST))
+			{
+				SetLastError(ERROR_NO_MORE_ITEMS);
+				return FALSE;
+			}
+			*pdwDataLen = sizeof(PROV_ENUMALGS);
+			if (pbData) 
+			{
+				if (*pdwDataLen > dwDataLen) 
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+				iEnumAlgs = ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) ? 0 : iEnumAlgs+1;
+				((PROV_ENUMALGS*)pbData)->aiAlgid = aProvEnumAlgsEx[iEnumAlgs].aiAlgid;
+				((PROV_ENUMALGS*)pbData)->dwBitLen = aProvEnumAlgsEx[iEnumAlgs].dwDefaultLen;
+				((PROV_ENUMALGS*)pbData)->dwNameLen = aProvEnumAlgsEx[iEnumAlgs].dwNameLen;
+				memcpy(((PROV_ENUMALGS*)pbData)->szName, aProvEnumAlgsEx[iEnumAlgs].szName, 20*sizeof(CHAR));
+			}
+			return TRUE;
+
+		case PP_ENUMALGS_EX:
+			if ((iEnumAlgs >= RSASTRONG_NUM_ALGS-1) && ((dwFlags & CRYPT_FIRST) != CRYPT_FIRST))
+			{
+				SetLastError(ERROR_NO_MORE_ITEMS);
+				return FALSE;
+			}
+			*pdwDataLen = sizeof(PROV_ENUMALGS_EX);
+			if (pbData) 
+			{
+				if (*pdwDataLen > dwDataLen) 
+				{
+					SetLastError(ERROR_MORE_DATA);
+					return FALSE;
+				}
+				iEnumAlgs = ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) ? 0 : iEnumAlgs+1;
+				memcpy(pbData, &aProvEnumAlgsEx[iEnumAlgs], sizeof(PROV_ENUMALGS_EX));
+			}
+			return TRUE;
+
+		default:
+			/* MSDN: Unknown parameter number in dwParam */
+			SetLastError(NTE_BAD_TYPE);
+			return FALSE;
+	}
     return FALSE;
 }
 
 BOOL WINAPI RSA_CPGetUserKey(HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+	KEYCONTAINER *pKeyContainer;
+
+	if (!lookup_handle(&handle_table, (unsigned int)hProv, (OBJECTHDR**)&pKeyContainer)) 
+	{
+		/* MSDN: hProv not containing valid context handle */
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	switch (dwKeySpec)
+	{
+		case AT_KEYEXCHANGE:
+			copy_handle(&handle_table, pKeyContainer->hKeyExchangeKeyPair, (unsigned int*)phUserKey);
+			break;
+
+		case AT_SIGNATURE:
+			copy_handle(&handle_table, pKeyContainer->hSignatureKeyPair, (unsigned int*)phUserKey);
+			break;
+
+		default:
+			*phUserKey = (HCRYPTKEY)INVALID_HANDLE_VALUE;
+	}
+
+	if (*phUserKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
+	{
+		/* MSDN: dwKeySpec parameter specifies non existent key */
+		SetLastError(NTE_NO_KEY);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 BOOL WINAPI RSA_CPHashData(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
 {
-    FIXME("(stub)\n");
-    return FALSE;
+	CRYPTHASH *pCryptHash;
+		
+	if (!is_valid_handle(&handle_table, (unsigned int)hProv))
+	{
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
+
+	if (dwFlags)
+	{
+		SetLastError(NTE_BAD_FLAGS);
+		return FALSE;
+	}
+
+	if (!lookup_handle(&handle_table, (unsigned int)hProv, (OBJECTHDR**)&pCryptHash))
+	{
+		SetLastError(NTE_BAD_HASH);
+		return FALSE;
+	}
+
+	if (pCryptHash->fFinished)
+	{
+		SetLastError(NTE_BAD_HASH_STATE);
+		return FALSE;
+	}
+	
+	switch (pCryptHash->aiAlgid)
+	{
+		case CALG_MD5:
+			IMPL(md5_update)((IMPL(md5_context)*)pCryptHash->pContext, (const void *)pbData, (unsigned int)dwDataLen);
+			break;
+	}
+    
+	return TRUE;
 }
 
 BOOL WINAPI RSA_CPHashSessionKey(HCRYPTPROV hProv, HCRYPTHASH hHash, HCRYPTKEY hKey, DWORD dwFlags)
@@ -250,14 +842,14 @@
 
 BOOL WINAPI RSA_CPReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
 {
-    RSA_CryptProv *cp = (RSA_CryptProv*) hProv;
-
     TRACE("%08lx %08lx\n", hProv, dwFlags);
 
-    if( cp && ( cp->dwMagic != RSABASE_MAGIC ) )
-        return FALSE;
-
-    HeapFree( GetProcessHeap(), 0, cp );
+	if (!release_handle(&handle_table, (unsigned int)hProv)) 
+	{
+		/* MSDN: hProv not containing valid context handle */
+		SetLastError(NTE_BAD_UID);
+		return FALSE;
+	}
 
     return TRUE;
 }
@@ -340,8 +932,14 @@
               'M','i','c','r','o','s','o','f','t',' ','B','a','s','e',' ','C',
               'r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r',
               'o','v','i','d','e','r',' ','v','1','.','0',0 };
+			static const WCHAR szTypeName[] = { 'T','y','p','e','N','a','m','e',0 };
+			static const WCHAR szRSATypeName[] = {
+			  'R','S','A',' ','F','u','l','l',' ',
+			  '(','S','i','g','n','a','t','u','r','e',' ','a','n','d',' ',
+			  'K','e','y',' ','E','x','c','h','a','n','g','e',')',0 };
 
             RegSetValueExW(key, szName, 0, REG_SZ, (LPBYTE)szRSAName, sizeof(szRSAName));
+			RegSetValueExW(key, szTypeName, 0, REG_SZ, (LPBYTE)szRSATypeName, sizeof(szRSATypeName));
         }
         RegCloseKey(key);
     }
--- /dev/null	2004-06-05 20:01:53.000000000 +0200
+++ dlls/rsabase/handle.c	2004-07-24 10:05:32.000000000 +0200
@@ -0,0 +1,445 @@
+/*
+ * dlls/rsabase/handle.c
+ * Support code to manage HANDLE tables.
+ *
+ * Copyright 2004 Michael Jung
+ *
+ * based on code by Mike McCormack (dlls/msi/handle.c)
+ * and Alexandre Julliard (server/handle.c)
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "handle.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(handle);
+
+/* NT handles are multiples of four and non zero */
+#define HANDLE2INDEX(h) (((h)>>2)-1)
+#define INDEX2HANDLE(i) (((i)+1)<<2)
+
+/******************************************************************************
+ *  init_handle_table
+ *
+ * Initializes the HANDLETABLE structure pointed to by lpTable
+ *
+ * PARAMS
+ *  lpTable [I] Pointer to the HANDLETABLE structure, which is to be initalized.
+ *
+ * NOTES
+ *  Note that alloc_handle_table calls init_handle_table on it's own, which 
+ *  means that you only have to call init_handle_table, if you use a global
+ *  variable of type HANDLETABLE for your handle table. However, in this
+ *  case you have to call destruct_handle_table when you don't need the table
+ *  any more.
+ */
+void init_handle_table(HANDLETABLE *lpTable)
+{
+	TRACE("(lpTable=%p)\n", lpTable);
+		
+	lpTable->paEntries = NULL;
+	lpTable->iEntries = 0;
+	lpTable->iFirstFree = 0;
+	InitializeCriticalSection(&lpTable->mutex);
+}
+
+/******************************************************************************
+ *  destruct_handle_table
+ *
+ * Destructs the handle table.
+ * 
+ * PARAMS
+ *  lpTable [I] Pointer to the handle table, which is to be destructed.
+ *
+ * NOTES
+ *  Note that release_handle_table takes care of this.
+ */
+void destruct_handle_table(HANDLETABLE *lpTable)
+{
+	TRACE("(lpTable=%p)\n", lpTable);
+		
+	if (lpTable->paEntries) 
+		HeapFree(GetProcessHeap(), 0, lpTable->paEntries);
+	DeleteCriticalSection(&lpTable->mutex);
+}
+
+/******************************************************************************
+ *  is_valid_handle_impl [Internal]
+ */
+int is_valid_handle_impl(HANDLETABLE *lpTable, unsigned int handle)
+{
+	unsigned int index = HANDLE2INDEX(handle);
+		
+	/* NT does not use zero handle values */
+	if (!handle)
+		return 0;
+	/* NT handles are multiples of four */
+	if (handle & 0x3) 
+		return 0;
+	/* Check for index out of table bounds */	
+	if (index >= lpTable->iEntries)
+		return 0;
+	/* Check if this handle is currently allocated */
+	if (!lpTable->paEntries[index].pObject)
+		return 0;
+	return 1;
+}
+
+/******************************************************************************
+ *  is_valid_handle
+ *
+ * Tests if handle is valid given the specified handle table
+ * 
+ * PARAMS
+ *  lpTable [I] Pointer to the handle table, with respect to which the handle's 
+ *              validness is tested.
+ *  handle  [I] The handle tested for validness.
+ *
+ * RETURNS
+ *  non zero,  if handle is valid.
+ *  zero,      if handle is not valid.
+ */
+int is_valid_handle(HANDLETABLE *lpTable, unsigned int handle)
+{
+	int ret;
+
+	TRACE("(lpTable=%p, handle=%d)\n", lpTable, handle);
+	
+	EnterCriticalSection(&lpTable->mutex);
+	ret = is_valid_handle_impl(lpTable, handle);
+	LeaveCriticalSection(&lpTable->mutex);
+
+	return ret;
+}
+
+/******************************************************************************
+ *  alloc_handle_table
+ *
+ * Allocates a new handle table
+ * 
+ * PARAMS
+ *  lplpTable [O] Pointer to the variable, to which the pointer to the newly
+ *                allocated handle table is written.
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull (out of process heap memory)
+ *
+ * NOTES
+ *  If all you need is a single handle table, you may as well declare a global 
+ *  variable of type HANDLETABLE and call init_handle_table on your own. 
+ */
+int alloc_handle_table(HANDLETABLE **lplpTable)
+{
+	TRACE("(lplpTable=%p)\n", lplpTable);
+		
+	*lplpTable = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLETABLE));
+	if (*lplpTable) 
+	{
+		init_handle_table(*lplpTable);
+		return 1;
+	}
+	else
+		return 0;
+}
+
+/******************************************************************************
+ *  release_handle_table
+ *
+ * Releases a handle table and frees the resources occupied by it.
+ *
+ * PARAMS
+ *  lpTable [I] Pointer to the handle table, which is to be released.
+ *
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull
+ *
+ * NOTES
+ *   All valid handles still in the table are released also.
+ */
+int release_handle_table(HANDLETABLE *lpTable) 
+{
+	TRACE("(lpTable=%p)\n", lpTable);
+		
+	release_all_handles(lpTable);
+	destruct_handle_table(lpTable);
+	return (int)HeapFree(GetProcessHeap(), 0, lpTable);
+}
+
+/******************************************************************************
+ *  grow_handle_table_impl [Internal]
+ *
+ * Grows the number of entries in the given table by TABLE_SIZE_INCREMENT
+ *
+ * PARAMS 
+ *  lpTable [I] Pointer to the table, which is to be grown
+ *
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull (out of memory on process heap)
+ *
+ * NOTES
+ *  This is a support function for alloc_handle. Do not call!
+ */
+int grow_handle_table_impl(HANDLETABLE *lpTable) 
+{
+	HANDLETABLEENTRY *newEntries;
+	unsigned int i, newIEntries;
+
+	newIEntries = lpTable->iEntries + TABLE_SIZE_INCREMENT;
+
+	newEntries = (HANDLETABLEENTRY*)HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLETABLEENTRY)*newIEntries);
+	if (!newEntries) 
+		return 0;
+
+	if (lpTable->paEntries)
+	{
+		memcpy(newEntries, lpTable->paEntries, sizeof(HANDLETABLEENTRY)*lpTable->iEntries);
+		HeapFree(GetProcessHeap(), 0, lpTable->paEntries);
+	}
+
+	for (i=lpTable->iEntries; i<newIEntries; i++)
+	{
+		newEntries[i].pObject = NULL;
+		newEntries[i].iNextFree = i+1;
+	}
+
+	lpTable->paEntries = newEntries;
+	lpTable->iEntries = newIEntries;
+
+	return 1;
+}
+
+/******************************************************************************
+ *  alloc_handle_impl [Internal]
+ */
+int alloc_handle_impl(HANDLETABLE *lpTable, OBJECTHDR *lpObject, unsigned int *lpHandle)
+{
+	if (lpTable->iFirstFree >= lpTable->iEntries) 
+		if (!grow_handle_table_impl(lpTable))
+		{
+			*lpHandle = (unsigned int)INVALID_HANDLE_VALUE;
+			return 0;
+		}
+
+	*lpHandle = INDEX2HANDLE(lpTable->iFirstFree);
+	
+	lpTable->paEntries[lpTable->iFirstFree].pObject = lpObject;
+	lpTable->iFirstFree = lpTable->paEntries[lpTable->iFirstFree].iNextFree;
+	lpObject->refcount++;
+
+	return 1;
+}
+
+/******************************************************************************
+ *  alloc_handle
+ *
+ * Allocates a new handle to the specified object in a given handle table.
+ *
+ * PARAMS
+ *  lpTable  [I] Pointer to the handle table, from which the new handle is 
+ *               allocated.
+ *  lpObject [I] Pointer to the object, for which a handle shall be allocated.
+ *  lpHandle [O] Pointer to a handle variable, into which the handle value will
+ *               be stored. If not successfull, this will be 
+ *               INVALID_HANDLE_VALUE
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull (no free handle)
+ */
+int alloc_handle(HANDLETABLE *lpTable, OBJECTHDR *lpObject, unsigned int *lpHandle)
+{
+	int ret;
+		
+	TRACE("(lpTable=%p, lpObject=%p, lpHandle=%p)\n", lpTable, lpObject, lpHandle);
+		
+	EnterCriticalSection(&lpTable->mutex);
+	ret = alloc_handle_impl(lpTable, lpObject, lpHandle);
+	LeaveCriticalSection(&lpTable->mutex);
+
+	return ret;
+}
+
+/******************************************************************************
+ *  release_handle_impl [Internal]
+ */
+int release_handle_impl(HANDLETABLE *lpTable, unsigned int handle)
+{
+	unsigned int index;
+	OBJECTHDR *pObject;
+	
+	if (!is_valid_handle_impl(lpTable, handle))
+		return 0;
+
+	index = HANDLE2INDEX(handle);
+
+	pObject = lpTable->paEntries[index].pObject;
+	pObject->refcount--;
+	if (pObject->refcount == 0)
+		if (pObject->destructor)
+			pObject->destructor(pObject);
+
+	lpTable->paEntries[index].pObject = NULL;
+	lpTable->paEntries[index].iNextFree = lpTable->iFirstFree;
+	lpTable->iFirstFree = index;
+	
+	return 1;
+}
+
+/******************************************************************************
+ *  release_handle
+ *
+ * Releases resources occupied by the specified handle in the given table.
+ * The reference count of the handled object is decremented. If it becomes
+ * zero and if the 'destructor' function pointer member is non NULL, the
+ * destructor function will be called. Note that release_handle does not 
+ * release resources other than the handle itself. If this is wanted, do it
+ * in the destructor function.
+ *
+ * PARAMS
+ *  lpTable [I] Pointer to the handle table, from which a handle is to be 
+ *              released.
+ *  handle  [I] The handle, which is to be released
+ *
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull (invalid handle)
+ */
+int release_handle(HANDLETABLE *lpTable, unsigned int handle)
+{
+	int ret;
+
+	TRACE("(lpTable=%p, hande=%d)\n", lpTable, handle);
+	
+	EnterCriticalSection(&lpTable->mutex);
+	ret = release_handle_impl(lpTable, handle);
+	LeaveCriticalSection(&lpTable->mutex);
+	
+	return ret;
+}
+
+/******************************************************************************
+ *  release_all_handles_impl [Internal]
+ */
+void release_all_handles_impl(HANDLETABLE *lpTable) 
+{
+	unsigned int i;
+
+	for (i=0; i<lpTable->iEntries; i++) 
+		if (lpTable->paEntries[i].pObject)
+			release_handle_impl(lpTable, INDEX2HANDLE(i));
+}
+
+/******************************************************************************
+ *  release_all_handles
+ *
+ * Releases all valid handles in the given handle table and shrinks the table 
+ * to zero size.
+ *
+ * PARAMS
+ *  lpTable [I] The table of which all valid handles shall be released.
+ */
+void release_all_handles(HANDLETABLE *lpTable) 
+{
+	TRACE("(lpTable=%p)\n", lpTable);
+		
+	EnterCriticalSection(&lpTable->mutex);
+	release_all_handles_impl(lpTable);
+	LeaveCriticalSection(&lpTable->mutex);
+}
+
+/******************************************************************************
+ *  lookup_handle_impl [Internal]
+ */
+int lookup_handle_impl(HANDLETABLE *lpTable, unsigned int handle, OBJECTHDR **lplpObject)
+{
+	if (!is_valid_handle_impl(lpTable, handle)) 
+	{
+		*lplpObject = NULL;
+		return 0;
+	}
+
+	*lplpObject = lpTable->paEntries[HANDLE2INDEX(handle)].pObject;
+	return 1;
+}
+
+/******************************************************************************
+ *  lookup_handle
+ *
+ * Returns the object identified by the handle in the given handle table
+ *
+ * PARAMS
+ *  lpTable    [I] Pointer to the handle table, in which the handle is looked up.
+ *  handle     [I] The handle, which is to be looked up
+ *	lplpObject [O] Pointer to the variable, into which the pointer to the 
+ *	               object looked up is copied.
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull (invalid handle)
+ */
+int lookup_handle(HANDLETABLE *lpTable, unsigned int handle, OBJECTHDR **lplpObject)
+{
+	int ret;
+	
+	TRACE("(lpTable=%p, handle=%d, lplpObject=%p)\n", lpTable, handle, lplpObject);
+	
+	EnterCriticalSection(&lpTable->mutex);
+	ret = lookup_handle_impl(lpTable, handle, lplpObject);
+	LeaveCriticalSection(&lpTable->mutex);
+	
+	return ret;
+}
+
+/******************************************************************************
+ *  copy_handle
+ *
+ * Copies a handle. Increments reference count in the object referenced by the
+ * handle
+ *
+ * PARAMS
+ *  lpTable [I] Pointer to the handle table, which holds the handle to be copied.
+ *  handle  [I] The handle to be copied.
+ *  copy    [O] Pointer to a handle variable, where the copied handle is put.
+ *
+ * RETURNS
+ *  non zero,  if successfull
+ *  zero,      if not successfull (invalid handle or out of memory)
+ */
+int copy_handle(HANDLETABLE *lpTable, unsigned int handle, unsigned int *copy)
+{
+	OBJECTHDR *pObject;
+	int ret;
+		
+	TRACE("(lpTable=%p, handle=%d, copy=%p)\n", lpTable, handle, copy);
+
+	EnterCriticalSection(&lpTable->mutex);
+	if (!lookup_handle_impl(lpTable, handle, &pObject)) 
+	{
+		*copy = (unsigned int)INVALID_HANDLE_VALUE;
+		LeaveCriticalSection(&lpTable->mutex);
+		return 0;
+	}
+
+	ret = alloc_handle_impl(lpTable, pObject, copy);
+	LeaveCriticalSection(&lpTable->mutex);
+	return ret;
+}							
--- /dev/null	2004-06-05 20:01:53.000000000 +0200
+++ dlls/rsabase/handle.h	2004-07-24 10:05:32.000000000 +0200
@@ -0,0 +1,72 @@
+/*
+ * dlls/rsabse/handle.h
+ * Support code to manage HANDLE tables.
+ *
+ * Copyright 2004 Michael Jung
+ *
+ * based on code by Mike McCormack (dlls/msi/handle.c)
+ * and Alexandre Julliard (server/handle.c)
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __WINE_HANDLE_H
+#define __WINE_HANDLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TABLE_SIZE_INCREMENT 32
+
+struct tagOBJECTHDR;
+typedef struct tagOBJECTHDR OBJECTHDR;
+typedef void (*DESTRUCTOR)(OBJECTHDR *object);
+struct tagOBJECTHDR
+{
+	UINT        refcount;
+	DESTRUCTOR	destructor;
+};
+
+typedef struct tagHANDLETABLEENTRY
+{
+	OBJECTHDR    *pObject;
+	unsigned int iNextFree;
+} HANDLETABLEENTRY;
+
+typedef struct tagHANDLETABLE
+{
+    unsigned int     iEntries;
+    unsigned int     iFirstFree;
+    HANDLETABLEENTRY *paEntries;
+	CRITICAL_SECTION mutex;
+} HANDLETABLE;
+
+int  alloc_handle_table   (HANDLETABLE **lplpTable);
+void init_handle_table    (HANDLETABLE *lpTable);
+void release_all_handles  (HANDLETABLE *lpTable);
+int  release_handle_table (HANDLETABLE *lpTable);
+void destruct_handle_table(HANDLETABLE *lpTable);
+int  alloc_handle         (HANDLETABLE *lpTable, OBJECTHDR *lpObject, unsigned int *lpHandle);
+int  release_handle       (HANDLETABLE *lpTable, unsigned int handle);
+int  copy_handle          (HANDLETABLE *lpTable, unsigned int handle, unsigned int *copy);
+int  lookup_handle        (HANDLETABLE *lpTable, unsigned int handle, OBJECTHDR **lplpObject);
+int  is_valid_handle      (HANDLETABLE *lpTable, unsigned int handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WINE_HANDLE_H */
--- /dev/null	2004-06-05 20:01:53.000000000 +0200
+++ dlls/rsabase/implossl.c	2004-07-24 10:09:08.000000000 +0200
@@ -0,0 +1,82 @@
+#include "config.h"
+#ifdef HAVE_OPENSSL_SSL_H
+
+#include "wine/port.h"
+#include "wine/library.h"
+#include "wine/debug.h"
+
+#include <openssl/rand.h>
+
+#include "implossl.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+
+#ifndef SONAME_LIBCRYPTO
+#define SONAME_LIBCRYPTO "libcrypto.so"
+#endif
+
+static void *libcrypto;
+
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
+
+/* OpenSSL funtions that we use */
+MAKE_FUNCPTR(RAND_bytes);
+MAKE_FUNCPTR(MD5_Init);
+MAKE_FUNCPTR(MD5_Update);
+MAKE_FUNCPTR(MD5_Final);
+
+int IMPLOSSL_load_lib( void )
+{
+    libcrypto = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
+    if (!libcrypto)
+    {
+        MESSAGE("Couldn't load %s, RSA encryption not available.\n", SONAME_LIBCRYPTO);
+        MESSAGE("Install the openssl package if you're have problems.\n");
+        return 0;
+    }
+
+    #define GETFUNC(x) \
+    p##x = wine_dlsym(libcrypto, #x, NULL, 0); \
+    if (!p##x) \
+    { \
+        ERR("failed to load symbol %s\n", #x); \
+        return FALSE; \
+    }
+
+    GETFUNC(RAND_bytes);
+	GETFUNC(MD5_Init);
+	GETFUNC(MD5_Update);
+	GETFUNC(MD5_Final);
+
+    return 1;
+}
+
+int IMPLOSSL_random_bytes(unsigned char *pbBuffer, unsigned int cbLen)
+{
+	if (!pRAND_bytes)
+		return 0;
+	return pRAND_bytes(pbBuffer, cbLen);
+}
+
+int IMPLOSSL_md5_init(IMPLOSSL_md5_context *ctx)
+{
+	if (!pMD5_Init)
+		return 0;
+	return pMD5_Init(ctx);
+}
+
+int IMPLOSSL_md5_update(IMPLOSSL_md5_context *ctx, const void *pbData, unsigned int cbLen)
+{
+	if (!pMD5_Update)
+		return 0;
+	return pMD5_Update(ctx, pbData, cbLen);
+}
+
+int IMPLOSSL_md5_get_digest(IMPLOSSL_md5_context *ctx, unsigned char *pbBuffer)
+{
+	if (!pMD5_Final)
+		return 0;
+	return pMD5_Final(pbBuffer, ctx);
+}
+
+#endif /* HAVE_OPENSSL_SSL_H */
--- /dev/null	2004-06-05 20:01:53.000000000 +0200
+++ dlls/rsabase/implossl.h	2004-07-24 22:16:06.000000000 +0200
@@ -0,0 +1,16 @@
+#ifndef __WINE_IMPLOSSL_H
+#define __WINE_IMPLOSSL_H
+
+#include <openssl/md5.h>
+
+#define IMPL(f) IMPLOSSL_##f
+
+typedef MD5_CTX IMPLOSSL_md5_context;
+
+int IMPLOSSL_load_lib(void);
+int IMPLOSSL_random_bytes(unsigned char *pbBuffer, unsigned int cbLen);
+int IMPLOSSL_md5_init(IMPLOSSL_md5_context *ctx);
+int IMPLOSSL_md5_update(IMPLOSSL_md5_context *ctx, const void *pbData, unsigned int cbLen);
+int IMPLOSSL_md5_get_digest(IMPLOSSL_md5_context *ctx, unsigned char *pbBuffer);
+
+#endif /* __WINE_IMPLOSSL_H */
--- /dev/null	2004-06-05 20:01:53.000000000 +0200
+++ dlls/rsabase/rsabase.h	2004-07-24 22:53:25.000000000 +0200
@@ -0,0 +1,48 @@
+#ifndef __WINE_RSABASE_H
+#define __WINE_RSABASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct tagCRYPTHASH
+{
+	OBJECTHDR header;
+	ALG_ID aiAlgid;
+	HCRYPTKEY hKey;
+	PVOID pContext;
+	BOOL fFinished;
+} CRYPTHASH;
+		
+typedef struct tagCRYPTKEY
+{
+	OBJECTHDR header;
+	ALG_ID aiAlgid;
+	DWORD dwKeyLen;
+	BYTE abKey[16];
+} CRYPTKEY;
+
+#define MODE_EPHEMERAL      0x00000001u
+#define MODE_SILENT         0x00000002u
+#define MODE_MACHINE_KEYSET 0x00000004u
+
+typedef struct tagKEYCONTAINER
+{
+	OBJECTHDR    header;
+	DWORD        dwMode;
+	CHAR         szName[MAX_PATH];
+	HCRYPTKEY    hKeyExchangeKeyPair;
+	HCRYPTKEY    hSignatureKeyPair;
+} KEYCONTAINER;
+
+HCRYPTHASH new_crypt_hash(ALG_ID aiAlgid, HCRYPTKEY hKey);
+HCRYPTKEY new_crypt_key(ALG_ID aiAlgid, DWORD dwKeyLen, BYTE *pbKey);
+HCRYPTKEY duplicate_key(HCRYPTKEY other);
+HCRYPTPROV new_key_container(PCHAR pszContainerName);
+HCRYPTPROV read_key_container(PCHAR pszContainerName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WINE_RSABASE_H */
