Removed W->A from DEFWND_ImmIsUIMessageW.
[wine] / dlls / rsaenh / rsaenh.c
1 /*
2  * dlls/rsaenh/rsaenh.c
3  * RSAENH - RSA encryption for Wine
4  *
5  * Copyright 2002 TransGaming Technologies (David Hammerton)
6  * Copyright 2004 Mike McCormack for CodeWeavers
7  * Copyright 2004 Michael Jung
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public 
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26 #include "wine/library.h"
27 #include "wine/debug.h"
28
29 #include <stdarg.h>
30 #include <stdio.h>
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "wincrypt.h"
36 #include "lmcons.h"
37 #include "handle.h"
38 #include "implossl.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
41
42 /******************************************************************************
43  * CRYPTHASH - hash objects
44  */
45 #define RSAENH_MAGIC_HASH           0x85938417u
46 #define RSAENH_MAX_HASH_SIZE        36
47 #define RSAENH_HASHSTATE_IDLE       0
48 #define RSAENH_HASHSTATE_HASHING    1
49 #define RSAENH_HASHSTATE_FINISHED   2
50 typedef struct tagCRYPTHASH
51 {
52     OBJECTHDR    header;
53     ALG_ID       aiAlgid;
54     HCRYPTKEY    hKey;
55     HCRYPTPROV   hProv;
56     DWORD        dwHashSize;
57     DWORD        dwState;
58     HASH_CONTEXT context;
59     BYTE         abHashValue[RSAENH_MAX_HASH_SIZE];
60     PHMAC_INFO   pHMACInfo;
61 } CRYPTHASH;
62
63 /******************************************************************************
64  * CRYPTKEY - key objects
65  */
66 #define RSAENH_MAGIC_KEY           0x73620457u
67 #define RSAENH_MAX_KEY_SIZE        24
68 #define RSAENH_MAX_BLOCK_SIZE      24
69 #define RSAENH_KEYSTATE_IDLE       0
70 #define RSAENH_KEYSTATE_ENCRYPTING 1
71 #define RSAENH_KEYSTATE_DECRYPTING 2
72 typedef struct tagCRYPTKEY
73 {
74     OBJECTHDR   header;
75     ALG_ID      aiAlgid;
76     HCRYPTPROV  hProv;
77     DWORD       dwMode;
78     DWORD       dwModeBits;
79     DWORD       dwPermissions;
80     DWORD       dwKeyLen;
81     DWORD       dwSaltLen;
82     DWORD       dwBlockLen;
83     DWORD       dwState;
84     KEY_CONTEXT context;    
85     BYTE        abKeyValue[RSAENH_MAX_KEY_SIZE];
86     BYTE        abInitVector[RSAENH_MAX_BLOCK_SIZE];
87     BYTE        abChainVector[RSAENH_MAX_BLOCK_SIZE];
88 } CRYPTKEY;
89
90 /******************************************************************************
91  * KEYCONTAINER - key containers
92  */
93 #define RSAENH_PERSONALITY_BASE        0u
94 #define RSAENH_PERSONALITY_STRONG      1u
95 #define RSAENH_PERSONALITY_ENHANCED    2u
96
97 #define RSAENH_MAGIC_CONTAINER         0x26384993u
98 typedef struct tagKEYCONTAINER
99 {
100     OBJECTHDR    header;
101     DWORD        dwMode;
102     DWORD        dwPersonality;
103     DWORD        dwEnumAlgsCtr;
104     CHAR         szName[MAX_PATH];
105     CHAR         szProvName[MAX_PATH];
106     HCRYPTKEY    hKeyExchangeKeyPair;
107     HCRYPTKEY    hSignatureKeyPair;
108 } KEYCONTAINER;
109
110 /******************************************************************************
111  * Some magic constants
112  */
113 #define RSAENH_ENCRYPT                    1
114 #define RSAENH_DECRYPT                    0    
115 #define RSAENH_HMAC_DEF_IPAD_CHAR      0x36
116 #define RSAENH_HMAC_DEF_OPAD_CHAR      0x5c
117 #define RSAENH_HMAC_DEF_PAD_LEN          64
118 #define RSAENH_DES_EFFECTIVE_KEYLEN      56
119 #define RSAENH_DES_STORAGE_KEYLEN        64
120 #define RSAENH_3DES112_EFFECTIVE_KEYLEN 112
121 #define RSAENH_3DES112_STORAGE_KEYLEN   128
122 #define RSAENH_3DES_EFFECTIVE_KEYLEN    168
123 #define RSAENH_3DES_STORAGE_KEYLEN      192
124 #define RSAENH_MAGIC_RSA2        0x32415352
125 #define RSAENH_MAGIC_RSA1        0x31415352
126 #define RSAENH_PKC_BLOCKTYPE           0x02
127
128 #define RSAENH_MIN(a,b) ((a)<(b)?(a):(b))
129 /******************************************************************************
130  * aProvEnumAlgsEx - Defines the capabilities of the CSP personalities.
131  */
132 #define RSAENH_MAX_ENUMALGS 14
133 PROV_ENUMALGS_EX aProvEnumAlgsEx[3][RSAENH_MAX_ENUMALGS+1] =
134 {
135  {
136   {CALG_RC2,       40, 40,   56,0,                    4,"RC2",     24,"RSA Data Security's RC2"},
137   {CALG_RC4,       40, 40,   56,0,                    4,"RC4",     24,"RSA Data Security's RC4"},
138   {CALG_DES,       56, 56,   56,0,                    4,"DES",     31,"Data Encryption Standard (DES)"},
139   {CALG_SHA,      160,160,  160,CRYPT_FLAG_SIGNING,   6,"SHA-1",   30,"Secure Hash Algorithm (SHA-1)"},
140   {CALG_MD2,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD2",     27,"MD2 Message Digest 2 (MD2)"},
141   {CALG_MD4,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD4",     27,"MD4 Message Digest 4 (MD4)"},
142   {CALG_MD5,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD5",     27,"MD5 Message Digest 5 (MD5)"},
143   {CALG_SSL3_SHAMD5,288,288,288,0,                   12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"},
144   {CALG_MAC,        0,  0,    0,0,                    4,"MAC",     27,"Message Authentication Code"},
145   {CALG_RSA_SIGN, 512,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",14,"RSA Signature"},
146   {CALG_RSA_KEYX, 512,384, 1024,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",18,"RSA Key Exchange"},
147   {CALG_HMAC,       0,  0,    0,0,                    5,"HMAC",    23,"HMAC Hugo's MAC (HMAC)"},
148   {0,               0,  0,    0,0,                    1,"",         1,""}
149  },
150  {
151   {CALG_RC2,      128, 40,  128,0,                    4,"RC2",     24,"RSA Data Security's RC2"},
152   {CALG_RC4,      128, 40,  128,0,                    4,"RC4",     24,"RSA Data Security's RC4"},
153   {CALG_DES,       56, 56,   56,0,                    4,"DES",     31,"Data Encryption Standard (DES)"},
154   {CALG_3DES_112, 112,112,  112,0,                   13,"3DES TWO KEY",19,"Two Key Triple DES"},
155   {CALG_3DES,     168,168,  168,0,                    5,"3DES",    21,"Three Key Triple DES"},
156   {CALG_SHA,      160,160,  160,CRYPT_FLAG_SIGNING,   6,"SHA-1",   30,"Secure Hash Algorithm (SHA-1)"},
157   {CALG_MD2,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD2",     27,"MD2 Message Digest 2 (MD2)"},
158   {CALG_MD4,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD4",     27,"MD4 Message Digest 4 (MD4)"},
159   {CALG_MD5,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD5",     27,"MD5 Message Digest 5 (MD5)"},
160   {CALG_SSL3_SHAMD5,288,288,288,0,                   12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"},
161   {CALG_MAC,        0,  0,    0,0,                    4,"MAC",     27,"Message Authentication Code"},
162   {CALG_RSA_SIGN,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",14,"RSA Signature"},
163   {CALG_RSA_KEYX,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",18,"RSA Key Exchange"},
164   {CALG_HMAC,       0,  0,    0,0,                    5,"HMAC",    23,"HMAC Hugo's MAC (HMAC)"},
165   {0,               0,  0,    0,0,                    1,"",         1,""}
166  },
167  {
168   {CALG_RC2,      128, 40,  128,0,                    4,"RC2",     24,"RSA Data Security's RC2"},
169   {CALG_RC4,      128, 40,  128,0,                    4,"RC4",     24,"RSA Data Security's RC4"},
170   {CALG_DES,       56, 56,   56,0,                    4,"DES",     31,"Data Encryption Standard (DES)"},
171   {CALG_3DES_112, 112,112,  112,0,                   13,"3DES TWO KEY",19,"Two Key Triple DES"},
172   {CALG_3DES,     168,168,  168,0,                    5,"3DES",    21,"Three Key Triple DES"},
173   {CALG_SHA,      160,160,  160,CRYPT_FLAG_SIGNING,   6,"SHA-1",   30,"Secure Hash Algorithm (SHA-1)"},
174   {CALG_MD2,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD2",     27,"MD2 Message Digest 2 (MD2)"},
175   {CALG_MD4,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD4",     27,"MD4 Message Digest 4 (MD4)"},
176   {CALG_MD5,      128,128,  128,CRYPT_FLAG_SIGNING,   4,"MD5",     27,"MD5 Message Digest 5 (MD5)"},
177   {CALG_SSL3_SHAMD5,288,288,288,0,                   12,"SSL3 SHAMD5",12,"SSL3 SHAMD5"},
178   {CALG_MAC,        0,  0,    0,0,                    4,"MAC",     27,"Message Authentication Code"},
179   {CALG_RSA_SIGN,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_SIGN",14,"RSA Signature"},
180   {CALG_RSA_KEYX,1024,384,16384,CRYPT_FLAG_SIGNING|CRYPT_FLAG_IPSEC,9,"RSA_KEYX",18,"RSA Key Exchange"},
181   {CALG_HMAC,       0,  0,    0,0,                    5,"HMAC",    23,"HMAC Hugo's MAC (HMAC)"},
182   {0,               0,  0,    0,0,                    1,"",         1,""}
183  }
184 };
185
186 /******************************************************************************
187  * API forward declarations
188  */
189 BOOL WINAPI 
190 RSAENH_CPGetKeyParam(
191     HCRYPTPROV hProv, 
192     HCRYPTKEY hKey, 
193     DWORD dwParam, 
194     BYTE *pbData, 
195     DWORD *pdwDataLen, 
196     DWORD dwFlags
197 );
198
199 BOOL WINAPI 
200 RSAENH_CPEncrypt(
201     HCRYPTPROV hProv, 
202     HCRYPTKEY hKey, 
203     HCRYPTHASH hHash, 
204     BOOL Final, 
205     DWORD dwFlags, 
206     BYTE *pbData,
207     DWORD *pdwDataLen, 
208     DWORD dwBufLen
209 );
210
211 BOOL WINAPI 
212 RSAENH_CPGetHashParam(
213     HCRYPTPROV hProv, 
214     HCRYPTHASH hHash, 
215     DWORD dwParam, 
216     BYTE *pbData, 
217     DWORD *pdwDataLen, 
218     DWORD dwFlags
219 );
220
221 BOOL WINAPI 
222 RSAENH_CPExportKey(
223     HCRYPTPROV hProv, 
224     HCRYPTKEY hKey, 
225     HCRYPTKEY hPubKey, 
226     DWORD dwBlobType, 
227     DWORD dwFlags, 
228     BYTE *pbData, 
229     DWORD *pdwDataLen
230 );
231
232 BOOL WINAPI 
233 RSAENH_CPImportKey(
234     HCRYPTPROV hProv, 
235     CONST BYTE *pbData, 
236     DWORD dwDataLen, 
237     HCRYPTKEY hPubKey, 
238     DWORD dwFlags, 
239     HCRYPTKEY *phKey
240 );
241
242 /******************************************************************************
243  * CSP's handle table (used by all acquired key containers)
244  */
245 static HANDLETABLE handle_table;
246
247 /******************************************************************************
248  * DllMain (RSAENH.@)
249  *
250  * Initializes and destroys the handle table for the CSP's handles.
251  */
252 int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
253 {
254     switch (fdwReason)
255     {
256         case DLL_PROCESS_ATTACH:
257             init_handle_table(&handle_table);
258             break;
259
260         case DLL_PROCESS_DETACH:
261             destroy_handle_table(&handle_table);
262             break;
263     }
264     return 1;
265 }
266
267 /******************************************************************************
268  * copy_param [Internal]
269  *
270  * Helper function that supports the standard WINAPI protocol for querying data
271  * of dynamic size.
272  *
273  * PARAMS
274  *  pbBuffer      [O]   Buffer where the queried parameter is copied to, if it is large enough.
275  *                      May be NUL if the required buffer size is to be queried only.
276  *  pdwBufferSize [I/O] In: Size of the buffer at pbBuffer
277  *                      Out: Size of parameter pbParam
278  *  pbParam       [I]   Parameter value.
279  *  dwParamSize   [I]   Size of pbParam
280  *
281  * RETURN
282  *  Success: TRUE (pbParam was copied into pbBuffer or pbBuffer is NULL)
283  *  Failure: FALSE (pbBuffer is not large enough to hold pbParam). Last error: ERROR_MORE_DATA
284  */
285 static inline BOOL copy_param(
286     BYTE *pbBuffer, DWORD *pdwBufferSize, CONST BYTE *pbParam, DWORD dwParamSize) 
287 {
288     if (pbBuffer) 
289     {
290         if (dwParamSize > *pdwBufferSize) 
291         {
292             SetLastError(ERROR_MORE_DATA);
293             *pdwBufferSize = dwParamSize;
294             return FALSE;
295         }
296         memcpy(pbBuffer, pbParam, dwParamSize);
297     }
298     *pdwBufferSize = dwParamSize;
299     return TRUE;
300 }
301
302 /******************************************************************************
303  * get_algid_info [Internal]
304  *
305  * Query CSP capabilities for a given crypto algorithm.
306  * 
307  * PARAMS
308  *  pKeyContainer [I] Pointer to a key container of the CSP whose capabilities are to be queried.
309  *  algid         [I] Identifier of the crypto algorithm about which information is requested.
310  *
311  * RETURNS
312  *  Success: Pointer to a PROV_ENUMALGS_EX struct containing information about the crypto algorithm.
313  *  Failure: NULL (algid not supported)
314  */
315 static inline const PROV_ENUMALGS_EX* get_algid_info(KEYCONTAINER *pKeyContainer, ALG_ID algid) {
316     PROV_ENUMALGS_EX *iterator;
317
318     for (iterator = aProvEnumAlgsEx[pKeyContainer->dwPersonality]; iterator->aiAlgid; iterator++) {
319         if (iterator->aiAlgid == algid) return iterator;
320     }
321
322     return NULL;
323 }
324
325 /******************************************************************************
326  * free_hmac_info [Internal]
327  *
328  * Deeply free an HMAC_INFO struct.
329  *
330  * PARAMS
331  *  hmac_info [I] Pointer to the HMAC_INFO struct to be freed.
332  *
333  * NOTES
334  *  See Internet RFC 2104 for details on the HMAC algorithm.
335  */
336 static inline void free_hmac_info(PHMAC_INFO hmac_info) {
337     if (!hmac_info) return;
338     if (hmac_info->pbInnerString) HeapFree(GetProcessHeap(), 0, hmac_info->pbInnerString);
339     if (hmac_info->pbOuterString) HeapFree(GetProcessHeap(), 0, hmac_info->pbOuterString);
340     HeapFree(GetProcessHeap(), 0, hmac_info);
341 }
342
343 /******************************************************************************
344  * copy_hmac_info [Internal]
345  *
346  * Deeply copy an HMAC_INFO struct
347  *
348  * PARAMS
349  *  dst [O] Pointer to a location where the pointer to the HMAC_INFO copy will be stored.
350  *  src [I] Pointer to the HMAC_INFO struct to be copied.
351  *
352  * RETURNS
353  *  Success: TRUE
354  *  Failure: FALSE
355  *
356  * NOTES
357  *  See Internet RFC 2104 for details on the HMAC algorithm.
358  */
359 static BOOL copy_hmac_info(PHMAC_INFO *dst, PHMAC_INFO src) {
360     if (!src) return FALSE;
361     *dst = (PHMAC_INFO)HeapAlloc(GetProcessHeap(), 0, sizeof(HMAC_INFO));
362     if (!*dst) return FALSE;
363     memcpy(*dst, src, sizeof(HMAC_INFO));
364     (*dst)->pbInnerString = NULL;
365     (*dst)->pbOuterString = NULL;
366     if ((*dst)->cbInnerString == 0) (*dst)->cbInnerString = RSAENH_HMAC_DEF_PAD_LEN;
367     (*dst)->pbInnerString = (BYTE*)HeapAlloc(GetProcessHeap(), 0, (*dst)->cbInnerString);
368     if (!(*dst)->pbInnerString) {
369         free_hmac_info(*dst);
370         return FALSE;
371     }
372     if (src->cbInnerString) 
373         memcpy((*dst)->pbInnerString, src->pbInnerString, src->cbInnerString);
374     else 
375         memset((*dst)->pbInnerString, RSAENH_HMAC_DEF_IPAD_CHAR, RSAENH_HMAC_DEF_PAD_LEN);
376     if ((*dst)->cbOuterString == 0) (*dst)->cbOuterString = RSAENH_HMAC_DEF_PAD_LEN;
377     (*dst)->pbOuterString = (BYTE*)HeapAlloc(GetProcessHeap(), 0, (*dst)->cbOuterString);
378     if (!(*dst)->pbOuterString) {
379         free_hmac_info(*dst);
380         return FALSE;
381     }
382     if (src->cbOuterString) 
383         memcpy((*dst)->pbOuterString, src->pbOuterString, src->cbOuterString);
384     else 
385         memset((*dst)->pbOuterString, RSAENH_HMAC_DEF_OPAD_CHAR, RSAENH_HMAC_DEF_PAD_LEN);
386     return TRUE;
387 }
388
389 /******************************************************************************
390  * destroy_hash [Internal]
391  *
392  * Destructor for hash objects
393  *
394  * PARAMS
395  *  pCryptHash [I] Pointer to the hash object to be destroyed. 
396  *                 Will be invalid after function returns!
397  */
398 static void destroy_hash(OBJECTHDR *pCryptHash)
399 {
400     free_hmac_info(((CRYPTHASH*)pCryptHash)->pHMACInfo);
401     HeapFree(GetProcessHeap(), 0, pCryptHash);
402 }
403
404 /******************************************************************************
405  * init_hash [Internal]
406  *
407  * Initialize (or reset) a hash object
408  *
409  * PARAMS
410  *  pKeyContainer [I] Pointer to the key container the hash object belongs to.
411  *  pCryptHash    [I] The hash object to be initialized.
412  */
413 static inline BOOL init_hash(KEYCONTAINER *pKeyContainer, CRYPTHASH *pCryptHash) {
414     DWORD dwLen;
415     const PROV_ENUMALGS_EX *pAlgInfo;
416         
417     switch (pCryptHash->aiAlgid) 
418     {
419         case CALG_HMAC:
420             if (pCryptHash->pHMACInfo) { 
421                 pAlgInfo = get_algid_info(pKeyContainer, pCryptHash->pHMACInfo->HashAlgid);
422                 if (pAlgInfo) pCryptHash->dwHashSize = pAlgInfo->dwDefaultLen >> 3;
423                 return init_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context);
424             }
425             return TRUE;
426
427         case CALG_MAC:
428             dwLen = sizeof(DWORD);
429             RSAENH_CPGetKeyParam(pCryptHash->hProv, pCryptHash->hKey, KP_BLOCKLEN, 
430                                  (BYTE*)&pCryptHash->dwHashSize, &dwLen, 0);
431             pCryptHash->dwHashSize >>= 3;
432             return TRUE;
433
434         default:
435             return init_hash_impl(pCryptHash->aiAlgid, &pCryptHash->context);
436     }
437 }
438
439 /******************************************************************************
440  * update_hash [Internal]
441  *
442  * Hashes the given data and updates the hash object's state accordingly
443  *
444  * PARAMS
445  *  pCryptHash [I] Hash object to be updated.
446  *  pbData     [I] Pointer to data stream to be hashed.
447  *  dwDataLen  [I] Length of data stream.
448  */
449 static inline void update_hash(CRYPTHASH *pCryptHash, CONST BYTE *pbData, DWORD dwDataLen) {
450     BYTE *pbTemp;
451
452     switch (pCryptHash->aiAlgid)
453     {
454         case CALG_HMAC:
455             if (pCryptHash->pHMACInfo) 
456                 update_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, 
457                                  pbData, dwDataLen);
458             break;
459
460         case CALG_MAC:
461             pbTemp = (BYTE*)HeapAlloc(GetProcessHeap(), 0, dwDataLen);
462             if (!pbTemp) return;
463             memcpy(pbTemp, pbData, dwDataLen);
464             RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, (HCRYPTHASH)NULL, FALSE, 0, 
465                              pbTemp, &dwDataLen, dwDataLen);
466             HeapFree(GetProcessHeap(), 0, pbTemp);
467             break;
468
469         default:
470             update_hash_impl(pCryptHash->aiAlgid, &pCryptHash->context, pbData, dwDataLen);
471     }
472 }
473
474 /******************************************************************************
475  * finalize_hash [Internal]
476  *
477  * Finalizes the hash, after all data has been hashed with update_hash.
478  * No additional data can be hashed afterwards until the hash gets initialized again.
479  *
480  * PARAMS
481  *  pCryptHash [I] Hash object to be finalized.
482  */
483 static inline void finalize_hash(CRYPTHASH *pCryptHash) {
484     DWORD dwDataLen;
485         
486     switch (pCryptHash->aiAlgid)
487     {
488         case CALG_HMAC:
489             if (pCryptHash->pHMACInfo)
490                 finalize_hash_impl(pCryptHash->pHMACInfo->HashAlgid, &pCryptHash->context, 
491                                    pCryptHash->abHashValue);
492             break;
493
494         case CALG_MAC:
495             dwDataLen = 0;
496             RSAENH_CPEncrypt(pCryptHash->hProv, pCryptHash->hKey, (HCRYPTHASH)NULL, TRUE, 0, 
497                              pCryptHash->abHashValue, &dwDataLen, pCryptHash->dwHashSize);
498             break;
499
500         default:
501             finalize_hash_impl(pCryptHash->aiAlgid, &pCryptHash->context, pCryptHash->abHashValue);
502     }
503 }
504
505 /******************************************************************************
506  * destroy_key [Internal]
507  *
508  * Destructor for key objects
509  *
510  * PARAMS
511  *  pCryptKey [I] Pointer to the key object to be destroyed. 
512  *                Will be invalid after function returns!
513  */
514 static void destroy_key(OBJECTHDR *pCryptKey)
515 {
516     free_key_impl(((CRYPTKEY*)pCryptKey)->aiAlgid, &((CRYPTKEY*)pCryptKey)->context);
517     HeapFree(GetProcessHeap(), 0, pCryptKey);
518 }
519
520 /******************************************************************************
521  * setup_key [Internal]
522  *
523  * Initialize (or reset) a key object
524  *
525  * PARAMS
526  *  pCryptKey    [I] The key object to be initialized.
527  */
528 static inline void setup_key(CRYPTKEY *pCryptKey) {
529     pCryptKey->dwState = RSAENH_KEYSTATE_IDLE;
530     memcpy(pCryptKey->abChainVector, pCryptKey->abInitVector, sizeof(pCryptKey->abChainVector));
531     setup_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen, 
532                    pCryptKey->dwSaltLen, pCryptKey->abKeyValue);
533 }
534
535 /******************************************************************************
536  * new_key [Internal]
537  *
538  * Creates a new key object. If neither pbKey nor hHash is given a random key
539  * will be generated.
540  *
541  * PARAMS
542  *  hProv   [I] Handle to the provider to which the created key will belong.
543  *  aiAlgid [I] The new key shall use the crypto algorithm idenfied by aiAlgid.
544  *  dwFlags [I] Upper 16 bits give the key length.
545  *              Lower 16 bits: CRYPT_CREATE_SALT, CRYPT_NO_SALT
546  *  pbKey   [I] Byte stream to be used as key material. May be NULL.
547  *  hHash   [I] Handle to a hash object whose value will be used as key material. May be zero.
548  *
549  * RETURNS
550  *  Success: Handle to the created key.
551  *  Failure: INVALID_HANDLE_VALUE
552  */
553 static HCRYPTKEY new_key(HCRYPTPROV hProv, ALG_ID aiAlgid, DWORD dwFlags, BYTE *pbKey, 
554                          HCRYPTHASH hHash)
555 {
556     KEYCONTAINER *pKeyContainer;
557     HCRYPTKEY hCryptKey;
558     CRYPTKEY *pCryptKey;
559     CRYPTHASH *pCryptHash;
560     DWORD dwKeyLen = HIWORD(dwFlags), i;
561     const PROV_ENUMALGS_EX *peaAlgidInfo;
562     BYTE abHashValue[RSAENH_MAX_HASH_SIZE*2];
563
564     if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, (OBJECTHDR**)&pKeyContainer))
565     {
566         SetLastError(NTE_BAD_UID);
567         return (HCRYPTKEY)INVALID_HANDLE_VALUE;
568     }
569     
570     /* 
571      * Retrieve the CSP's capabilities for the given ALG_ID value
572      */
573     peaAlgidInfo = get_algid_info(pKeyContainer, aiAlgid);
574     if (!peaAlgidInfo) {
575         SetLastError(NTE_BAD_ALGID);
576         return (HCRYPTKEY)INVALID_HANDLE_VALUE;
577     }
578
579     /*
580      * Assume the default key length, if none is specified explicitly
581      */
582     if (dwKeyLen == 0) dwKeyLen = peaAlgidInfo->dwDefaultLen;
583     
584     /*
585      * Check if the requested key length is supported by the current CSP.
586      * Adjust key length's for DES algorithms.
587      */
588     switch (aiAlgid) {
589         case CALG_DES:
590             if (dwKeyLen == RSAENH_DES_EFFECTIVE_KEYLEN) {
591                 dwKeyLen = RSAENH_DES_STORAGE_KEYLEN;
592             }
593             if (dwKeyLen != RSAENH_DES_STORAGE_KEYLEN) {
594                 SetLastError(NTE_BAD_FLAGS);
595                 return (HCRYPTKEY)INVALID_HANDLE_VALUE;
596             }
597             break;
598
599         case CALG_3DES_112:
600             if (dwKeyLen == RSAENH_3DES112_EFFECTIVE_KEYLEN) {
601                 dwKeyLen = RSAENH_3DES112_STORAGE_KEYLEN;
602             }
603             if (dwKeyLen != RSAENH_3DES112_STORAGE_KEYLEN) {
604                 SetLastError(NTE_BAD_FLAGS);
605                 return (HCRYPTKEY)INVALID_HANDLE_VALUE;
606             }
607             break;
608
609         case CALG_3DES:
610             if (dwKeyLen == RSAENH_3DES_EFFECTIVE_KEYLEN) {
611                 dwKeyLen = RSAENH_3DES_STORAGE_KEYLEN;
612             }
613             if (dwKeyLen != RSAENH_3DES_STORAGE_KEYLEN) {
614                 SetLastError(NTE_BAD_FLAGS);
615                 return (HCRYPTKEY)INVALID_HANDLE_VALUE;
616             }
617             break;
618         
619         default:
620             if (dwKeyLen % 8 || 
621                 dwKeyLen > peaAlgidInfo->dwMaxLen || 
622                 dwKeyLen < peaAlgidInfo->dwMinLen) 
623             {
624                 SetLastError(NTE_BAD_FLAGS);
625                 return (HCRYPTKEY)INVALID_HANDLE_VALUE;
626             }
627     }
628
629     /* 
630      * If a valid hash handle is supplied, we derive the key material from the hash.
631      * If the hash value is not large enough for the claimed key, we have to construct
632      * a larger binary value based on the hash. This is documented in MSDN: CryptDeriveKey.
633      */
634     if (lookup_handle(&handle_table, hHash, RSAENH_MAGIC_HASH, (OBJECTHDR**)&pCryptHash)) {
635         DWORD dwLen = RSAENH_MAX_HASH_SIZE;
636
637         RSAENH_CPGetHashParam(pCryptHash->hProv, hHash, HP_HASHVAL, abHashValue, &dwLen, 0);
638     
639         if (dwLen < (dwKeyLen >> 3)) {
640             BYTE pad1[RSAENH_HMAC_DEF_PAD_LEN], pad2[RSAENH_HMAC_DEF_PAD_LEN], old_hashval[RSAENH_MAX_HASH_SIZE];
641
642             memcpy(old_hashval, pCryptHash->abHashValue, RSAENH_MAX_HASH_SIZE);
643             
644             for (i=0; i<RSAENH_HMAC_DEF_PAD_LEN; i++) {
645                 pad1[i] = RSAENH_HMAC_DEF_IPAD_CHAR ^ (i<dwLen ? abHashValue[i] : 0);
646                 pad2[i] = RSAENH_HMAC_DEF_OPAD_CHAR ^ (i<dwLen ? abHashValue[i] : 0);
647             }
648                 
649             init_hash(pKeyContainer, pCryptHash);
650             update_hash(pCryptHash, pad1, RSAENH_HMAC_DEF_PAD_LEN);
651             finalize_hash(pCryptHash);
652             memcpy(abHashValue, pCryptHash->abHashValue, pCryptHash->dwHashSize);
653
654             init_hash(pKeyContainer, pCryptHash);
655             update_hash(pCryptHash, pad2, RSAENH_HMAC_DEF_PAD_LEN);
656             finalize_hash(pCryptHash);
657             memcpy(abHashValue+pCryptHash->dwHashSize, pCryptHash->abHashValue, 
658                    pCryptHash->dwHashSize);
659
660             memcpy(pCryptHash->abHashValue, old_hashval, RSAENH_MAX_HASH_SIZE);
661         }
662
663         pbKey = abHashValue;
664     }
665     
666     hCryptKey = (HCRYPTKEY)new_object(&handle_table, sizeof(CRYPTKEY), RSAENH_MAGIC_KEY, 
667                                       destroy_key, (OBJECTHDR**)&pCryptKey);
668     if (hCryptKey != (HCRYPTKEY)INVALID_HANDLE_VALUE)
669     {
670         pCryptKey->aiAlgid = aiAlgid;
671         pCryptKey->hProv = hProv;
672         pCryptKey->dwModeBits = 0;
673         pCryptKey->dwPermissions = CRYPT_ENCRYPT | CRYPT_DECRYPT | CRYPT_READ | CRYPT_WRITE | 
674                                    CRYPT_MAC;
675         pCryptKey->dwKeyLen = dwKeyLen >> 3;
676         if ((dwFlags & CRYPT_CREATE_SALT) || (dwKeyLen == 40 && !(dwFlags & CRYPT_NO_SALT))) 
677             pCryptKey->dwSaltLen = 16 - pCryptKey->dwKeyLen;
678         else
679             pCryptKey->dwSaltLen = 0;
680         memset(pCryptKey->abKeyValue, 0, sizeof(pCryptKey->abKeyValue));
681         if (pbKey) memcpy(pCryptKey->abKeyValue, pbKey, RSAENH_MIN(pCryptKey->dwKeyLen, 
682                           sizeof(pCryptKey->abKeyValue)));
683         memset(pCryptKey->abInitVector, 0, sizeof(pCryptKey->abInitVector));
684             
685         switch(aiAlgid)
686         {
687             case CALG_RC4:
688                 pCryptKey->dwBlockLen = 0;
689                 pCryptKey->dwMode = 0;
690                 break;
691
692             case CALG_RC2:
693             case CALG_DES:
694             case CALG_3DES_112:
695             case CALG_3DES:
696                 pCryptKey->dwBlockLen = 8;
697                 pCryptKey->dwMode = CRYPT_MODE_CBC;
698                 break;
699
700             case CALG_RSA_KEYX:
701             case CALG_RSA_SIGN:
702                 pCryptKey->dwBlockLen = dwKeyLen >> 3;
703                 pCryptKey->dwMode = 0;
704                 break;
705         }
706
707         new_key_impl(pCryptKey->aiAlgid, &pCryptKey->context, pCryptKey->dwKeyLen);
708         setup_key(pCryptKey);
709     }
710
711     return hCryptKey;
712 }
713
714 /******************************************************************************
715  * destroy_key_container [Internal]
716  *
717  * Destructor for key containers. The user's signature and key exchange private
718  * keys are stored in the registry _IN_PLAINTEXT_.
719  * 
720  * PARAMS
721  *  pObjectHdr [I] Pointer to the key container to be destroyed.
722  */
723 static void destroy_key_container(OBJECTHDR *pObjectHdr)
724 {
725     KEYCONTAINER *pKeyContainer = (KEYCONTAINER*)pObjectHdr;
726     CRYPTKEY *pKey;
727     CHAR szRSABase[MAX_PATH];
728     HKEY hKey;
729     DWORD dwLen;
730     BYTE *pbKey;
731
732     /* On WinXP, persistent keys are stored in a file located at: 
733      * $AppData$\\Microsoft\\Crypto\\RSA\\$SID$\\some_hex_string 
734      */
735     sprintf(szRSABase, "Software\\Wine\\Crypto\\RSA\\%s", pKeyContainer->szName);
736
737     if (RegCreateKeyExA(HKEY_CURRENT_USER, szRSABase, 0, NULL, REG_OPTION_NON_VOLATILE, 
738                         KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
739     {
740         if (lookup_handle(&handle_table, pKeyContainer->hKeyExchangeKeyPair, RSAENH_MAGIC_KEY, 
741                           (OBJECTHDR**)&pKey))
742         {
743             if (RSAENH_CPExportKey(pKey->hProv, pKeyContainer->hKeyExchangeKeyPair, 0, 
744                                    PRIVATEKEYBLOB, 0, 0, &dwLen)) 
745             {
746                 pbKey = (BYTE*)HeapAlloc(GetProcessHeap(), 0, dwLen);
747                 if (pbKey) 
748                 {
749                     if (RSAENH_CPExportKey(pKey->hProv, pKeyContainer->hKeyExchangeKeyPair, 0,
750                                            PRIVATEKEYBLOB, 0, pbKey, &dwLen))
751                     {
752                         RegSetValueExA(hKey, "KeyExchangeKeyPair", 0, REG_BINARY, pbKey, dwLen);
753                     }
754                     HeapFree(GetProcessHeap(), 0, pbKey);
755                 }
756             }
757             release_handle(&handle_table, (unsigned int)pKeyContainer->hKeyExchangeKeyPair, 
758                            RSAENH_MAGIC_KEY);
759         }
760
761         if (lookup_handle(&handle_table, pKeyContainer->hSignatureKeyPair, RSAENH_MAGIC_KEY, 
762                           (OBJECTHDR**)&pKey))
763         {
764             if (RSAENH_CPExportKey(pKey->hProv, pKeyContainer->hSignatureKeyPair, 0, PRIVATEKEYBLOB,
765                                    0, 0, &dwLen)) 
766             {
767                 pbKey = (BYTE*)HeapAlloc(GetProcessHeap(), 0, dwLen);
768                 if (pbKey) 
769                 {
770                     if (RSAENH_CPExportKey(pKey->hProv, pKeyContainer->hSignatureKeyPair, 0, 
771                                            PRIVATEKEYBLOB, 0, pbKey, &dwLen))
772                     {
773                         RegSetValueExA(hKey, "SignatureKeyPair", 0, REG_BINARY, pbKey, dwLen);
774                     }
775                     HeapFree(GetProcessHeap(), 0, pbKey);
776                 }
777             }
778             release_handle(&handle_table, (unsigned int)pKeyContainer->hSignatureKeyPair, 
779                            RSAENH_MAGIC_KEY);
780         }
781         
782         RegCloseKey(hKey);
783     }
784     
785     HeapFree( GetProcessHeap(), 0, pKeyContainer );
786 }
787
788 /******************************************************************************
789  * new_key_container [Internal]
790  *
791  * Create a new key container. The personality (RSA Base, Strong or Enhanced CP) 
792  * of the CSP is determined via the pVTable->pszProvName string.
793  *
794  * PARAMS
795  *  pszContainerName [I] Name of the key container.
796  *  pVTable          [I] Callback functions and context info provided by the OS
797  *
798  * RETURNS
799  *  Success: Handle to the new key container.
800  *  Failure: INVALID_HANDLE_VALUE
801  */
802 static HCRYPTPROV new_key_container(PCHAR pszContainerName, PVTableProvStruc pVTable)
803 {
804     KEYCONTAINER *pKeyContainer;
805     HCRYPTPROV hKeyContainer;
806
807     hKeyContainer = (HCRYPTPROV)new_object(&handle_table, sizeof(KEYCONTAINER), RSAENH_MAGIC_CONTAINER,
808                                            destroy_key_container, (OBJECTHDR**)&pKeyContainer);
809     if (hKeyContainer != (HCRYPTPROV)INVALID_HANDLE_VALUE)
810     {
811         strncpy(pKeyContainer->szName, pszContainerName, MAX_PATH);
812         pKeyContainer->szName[MAX_PATH-1] = '\0';
813         pKeyContainer->dwMode = 0;
814         pKeyContainer->dwEnumAlgsCtr = 0;
815         pKeyContainer->hKeyExchangeKeyPair = (HCRYPTKEY)INVALID_HANDLE_VALUE;
816         pKeyContainer->hSignatureKeyPair = (HCRYPTKEY)INVALID_HANDLE_VALUE;
817         if (pVTable && pVTable->pszProvName) {
818             strncpy(pKeyContainer->szProvName, pVTable->pszProvName, MAX_PATH);
819             pKeyContainer->szProvName[MAX_PATH-1] = '\0';
820             if (!strcmp(pVTable->pszProvName, MS_DEF_PROV_A)) {
821                 pKeyContainer->dwPersonality = RSAENH_PERSONALITY_BASE;
822             } else if (!strcmp(pVTable->pszProvName, MS_ENHANCED_PROV_A)) {
823                 pKeyContainer->dwPersonality = RSAENH_PERSONALITY_ENHANCED;
824             } else {
825                 pKeyContainer->dwPersonality = RSAENH_PERSONALITY_STRONG;
826             }
827         }
828     }
829
830     return hKeyContainer;
831 }
832
833 /******************************************************************************
834  * read_key_container [Internal]
835  *
836  * Tries to read the persistent state of the key container (mainly the signature
837  * and key exchange private keys) given by pszContainerName.
838  *
839  * PARAMS
840  *  pszContainerName [I] Name of the key container to read from the registry
841  *  pVTable          [I] Pointer to context data provided by the operating system
842  *
843  * RETURNS
844  *  Success: Handle to the key container read from the registry
845  *  Failure: INVALID_HANDLE_VALUE
846  */
847 static HCRYPTPROV read_key_container(PCHAR pszContainerName, PVTableProvStruc pVTable)
848 {
849     CHAR szRSABase[MAX_PATH];
850     BYTE *pbKey;
851     HKEY hKey;
852     DWORD dwValueType, dwLen;
853     KEYCONTAINER *pKeyContainer;
854     HCRYPTPROV hKeyContainer;
855     
856     sprintf(szRSABase, "Software\\Wine\\Crypto\\RSA\\%s", pszContainerName);
857
858     if (RegOpenKeyExA(HKEY_CURRENT_USER, szRSABase, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
859     {
860         SetLastError(NTE_BAD_KEYSET);
861         return (HCRYPTPROV)INVALID_HANDLE_VALUE;
862     }
863
864     hKeyContainer = new_key_container(pszContainerName, pVTable);
865     if (hKeyContainer != (HCRYPTPROV)INVALID_HANDLE_VALUE)
866     {
867         if (!lookup_handle(&handle_table, hKeyContainer, RSAENH_MAGIC_CONTAINER, 
868                            (OBJECTHDR**)&pKeyContainer))
869             return (HCRYPTPROV)INVALID_HANDLE_VALUE;
870     
871         if (RegQueryValueExA(hKey, "KeyExchangeKeyPair", 0, &dwValueType, NULL, &dwLen) == 
872             ERROR_SUCCESS) 
873         {
874             pbKey = (BYTE*)HeapAlloc(GetProcessHeap(), 0, dwLen);
875             if (pbKey) 
876             {
877                 if (RegQueryValueExA(hKey, "KeyExchangeKeyPair", 0, &dwValueType, pbKey, &dwLen) ==
878                     ERROR_SUCCESS)
879                 {
880                     RSAENH_CPImportKey(hKeyContainer, pbKey, dwLen, 0, 0, 
881                                        &pKeyContainer->hKeyExchangeKeyPair);
882                 }
883                 HeapFree(GetProcessHeap(), 0, pbKey);
884             }
885         }
886
887         if (RegQueryValueExA(hKey, "SignatureKeyPair", 0, &dwValueType, NULL, &dwLen) == 
888             ERROR_SUCCESS) 
889         {
890             pbKey = (BYTE*)HeapAlloc(GetProcessHeap(), 0, dwLen);
891             if (pbKey) 
892             {
893                 if (RegQueryValueExA(hKey, "SignatureKeyPair", 0, &dwValueType, pbKey, &dwLen) == 
894                     ERROR_SUCCESS)
895                 {
896                     RSAENH_CPImportKey(hKeyContainer, pbKey, dwLen, 0, 0, 
897                                        &pKeyContainer->hSignatureKeyPair);
898                 }
899                 HeapFree(GetProcessHeap(), 0, pbKey);
900             }
901         }
902     }
903
904     return hKeyContainer;
905 }
906
907 /******************************************************************************
908  * CPAcquireContext (RSAENH.@)
909  *
910  * Acquire a handle to the key container specified by pszContainer
911  *
912  * PARAMS
913  *  phProv       [O] Pointer to the location the acquired handle will be written to.
914  *  pszContainer [I] Name of the desired key container. See Notes
915  *  dwFlags      [I] Flags. See Notes.
916  *  pVTable      [I] Pointer to a PVTableProvStruct containing callbacks.
917  * 
918  * RETURNS
919  *  Success: TRUE
920  *  Failure: FALSE
921  *
922  * NOTES
923  *  If pszContainer is NULL or points to a zero length string the user's login 
924  *  name will be used as the key container name.
925  *
926  *  If the CRYPT_NEW_KEYSET flag is set in dwFlags a new keyset will be created.
927  *  If a keyset with the given name already exists, the function fails and sets
928  *  last error to NTE_EXISTS. If CRYPT_NEW_KEYSET is not set and the specified
929  *  key container does not exist, function fails and sets last error to 
930  *  NTE_BAD_KEYSET.
931  */                         
932 BOOL WINAPI RSAENH_CPAcquireContext(HCRYPTPROV *phProv, LPSTR pszContainer,
933                    DWORD dwFlags, PVTableProvStruc pVTable)
934 {
935     DWORD dwLen;
936     CHAR szKeyContainerName[MAX_PATH] = "";
937
938     TRACE("(phProv=%p, pszContainer=%s, dwFlags=%08lx, pVTable=%p)\n", phProv, 
939           debugstr_a(pszContainer), dwFlags, pVTable);
940
941     SetLastError(ERROR_SUCCESS);
942         
943     if (!load_lib()) return FALSE;
944     
945     if (pszContainer ? strlen(pszContainer) : 0) 
946     {
947         strncpy(szKeyContainerName, pszContainer, MAX_PATH);
948         szKeyContainerName[MAX_PATH-1] = '\0';
949     } 
950     else
951     {
952         dwLen = MAX_PATH;
953         if (!GetUserNameA(szKeyContainerName, &dwLen)) return FALSE;
954     }
955         
956     switch (dwFlags) 
957     {
958         case 0:
959             *phProv = read_key_container(szKeyContainerName, pVTable);
960             break;
961
962         case CRYPT_NEWKEYSET:
963             *phProv = read_key_container(szKeyContainerName, pVTable);
964             if (*phProv != (HCRYPTPROV)INVALID_HANDLE_VALUE) 
965             {
966                 release_handle(&handle_table, (unsigned int)*phProv, RSAENH_MAGIC_CONTAINER);
967                 SetLastError(NTE_EXISTS);
968                 return FALSE;
969             }
970             *phProv = new_key_container(szKeyContainerName, pVTable);
971             break;
972                     
973         default:
974             *phProv = (unsigned int)INVALID_HANDLE_VALUE;
975             SetLastError(NTE_BAD_FLAGS);
976             return FALSE;
977     }
978                 
979     return *phProv != (unsigned int)INVALID_HANDLE_VALUE;
980 }
981
982 /******************************************************************************
983  * CPCreateHash (RSAENH.@)
984  *
985  * CPCreateHash creates and initalizes a new hash object.
986  *
987  * PARAMS
988  *  hProv   [I] Handle to the key container to which the new hash will belong.
989  *  Algid   [I] Identifies the hash algorithm, which will be used for the hash.
990  *  hKey    [I] Handle to a session key applied for keyed hashes.
991  *  dwFlags [I] Currently no flags defined. Must be zero.
992  *  phHash  [O] Points to the location where a handle to the new hash will be stored.
993  *
994  * RETURNS
995  *  Success: TRUE
996  *  Failure: FALSE
997  *
998  * NOTES
999  *  hKey is a handle to a session key applied in keyed hashes like MAC and HMAC.
1000  *  If a normal hash object is to be created (like e.g. MD2 or SHA1) hKey must be zero.
1001  */
1002 BOOL WINAPI RSAENH_CPCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, 
1003                                 HCRYPTHASH *phHash)
1004 {
1005     KEYCONTAINER *pKeyContainer;
1006     CRYPTHASH *pCryptHash;
1007     const PROV_ENUMALGS_EX *peaAlgidInfo;
1008         
1009     TRACE("(hProv=%08lx, Algid=%08x, hKey=%08lx, dwFlags=%08lx, phHash=%p)\n", hProv, Algid, hKey, 
1010           dwFlags, phHash);
1011
1012     if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, (OBJECTHDR**)&pKeyContainer)) 
1013     {
1014         SetLastError(NTE_BAD_UID);
1015         return FALSE;
1016     }
1017
1018     peaAlgidInfo = get_algid_info(pKeyContainer, Algid);
1019     if (!peaAlgidInfo)
1020     {
1021         SetLastError(NTE_BAD_ALGID);
1022         return FALSE;
1023     }
1024
1025     if (dwFlags)
1026     {
1027         SetLastError(NTE_BAD_FLAGS);
1028         return FALSE;
1029     }
1030
1031     if ((Algid == CALG_MAC || Algid == CALG_HMAC)) {
1032         CRYPTKEY *pCryptKey;
1033
1034         if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) {
1035             SetLastError(NTE_BAD_KEY);
1036             return FALSE;
1037         }
1038
1039         if ((Algid == CALG_MAC) && (GET_ALG_TYPE(pCryptKey->aiAlgid) != ALG_TYPE_BLOCK)) {
1040             SetLastError(NTE_BAD_KEY);
1041             return FALSE;
1042         }
1043     }
1044
1045     *phHash = (HCRYPTHASH)new_object(&handle_table, sizeof(CRYPTHASH), RSAENH_MAGIC_HASH,
1046                                      destroy_hash, (OBJECTHDR**)&pCryptHash);
1047     if (!pCryptHash) return FALSE;
1048     
1049     pCryptHash->aiAlgid = Algid;
1050     pCryptHash->hKey = hKey;
1051     pCryptHash->hProv = hProv;
1052     pCryptHash->dwState = RSAENH_HASHSTATE_IDLE;
1053     pCryptHash->pHMACInfo = (PHMAC_INFO)NULL;
1054     pCryptHash->dwHashSize = peaAlgidInfo->dwDefaultLen >> 3;
1055     
1056     return init_hash(pKeyContainer, pCryptHash);
1057 }
1058
1059 /******************************************************************************
1060  * CPDestroyHash (RSAENH.@)
1061  * 
1062  * Releases the handle to a hash object. The object is destroyed if it's reference
1063  * count reaches zero.
1064  *
1065  * PARAMS
1066  *  hProv [I] Handle to the key container to which the hash object belongs.
1067  *  hHash [I] Handle to the hash object to be released.
1068  *
1069  * RETURNS
1070  *  Success: TRUE
1071  *  Failure: FALSE 
1072  */
1073 BOOL WINAPI RSAENH_CPDestroyHash(HCRYPTPROV hProv, HCRYPTHASH hHash)
1074 {
1075     TRACE("(hProv=%08lx, hHash=%08lx)\n", hProv, hHash);
1076      
1077     if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
1078     {
1079         SetLastError(NTE_BAD_UID);
1080         return FALSE;
1081     }
1082         
1083     if (!release_handle(&handle_table, hHash, RSAENH_MAGIC_HASH)) 
1084     {
1085         SetLastError(NTE_BAD_HASH);
1086         return FALSE;
1087     }
1088     
1089     return TRUE;
1090 }
1091
1092 /******************************************************************************
1093  * CPDestroyKey (RSAENH.@)
1094  *
1095  * Releases the handle to a key object. The object is destroyed if it's reference
1096  * count reaches zero.
1097  *
1098  * PARAMS
1099  *  hProv [I] Handle to the key container to which the key object belongs.
1100  *  hKey  [I] Handle to the key object to be released.
1101  *
1102  * RETURNS
1103  *  Success: TRUE
1104  *  Failure: FALSE
1105  */
1106 BOOL WINAPI RSAENH_CPDestroyKey(HCRYPTPROV hProv, HCRYPTKEY hKey)
1107 {
1108     TRACE("(hProv=%08lx, hKey=%08lx)\n", hProv, hKey);
1109         
1110     if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
1111     {
1112         SetLastError(NTE_BAD_UID);
1113         return FALSE;
1114     }
1115         
1116     if (!release_handle(&handle_table, hKey, RSAENH_MAGIC_KEY)) 
1117     {
1118         SetLastError(NTE_BAD_KEY);
1119         return FALSE;
1120     }
1121     
1122     return TRUE;
1123 }
1124
1125 /******************************************************************************
1126  * CPDuplicateHash (RSAENH.@)
1127  *
1128  * Clones a hash object including it's current state.
1129  *
1130  * PARAMS
1131  *  hUID        [I] Handle to the key container the hash belongs to.
1132  *  hHash       [I] Handle to the hash object to be cloned.
1133  *  pdwReserved [I] Reserved. Must be NULL.
1134  *  dwFlags     [I] No flags are currently defined. Must be 0.
1135  *  phHash      [O] Handle to the cloned hash object.
1136  *
1137  * RETURNS
1138  *  Success: TRUE.
1139  *  Failure: FALSE.
1140  */
1141 BOOL WINAPI RSAENH_CPDuplicateHash(HCRYPTPROV hUID, HCRYPTHASH hHash, DWORD *pdwReserved, 
1142                                    DWORD dwFlags, HCRYPTHASH *phHash)
1143 {
1144     CRYPTHASH *pSrcHash, *pDestHash;
1145     
1146     TRACE("(hUID=%08lx, hHash=%08lx, pdwReserved=%p, dwFlags=%08lx, phHash=%p)\n", hUID, hHash, 
1147            pdwReserved, dwFlags, phHash);
1148
1149     if (!is_valid_handle(&handle_table, hUID, RSAENH_MAGIC_CONTAINER))
1150     {
1151         SetLastError(NTE_BAD_UID);
1152         return FALSE;
1153     }
1154
1155     if (!lookup_handle(&handle_table, hHash, RSAENH_MAGIC_HASH, (OBJECTHDR**)&pSrcHash))
1156     {
1157         SetLastError(NTE_BAD_HASH);
1158         return FALSE;
1159     }
1160
1161     if (!phHash || pdwReserved || dwFlags) 
1162     {
1163         SetLastError(ERROR_INVALID_PARAMETER);
1164         return FALSE;
1165     }
1166
1167     *phHash = (HCRYPTHASH)new_object(&handle_table, sizeof(CRYPTHASH), RSAENH_MAGIC_HASH, 
1168                                      destroy_hash, (OBJECTHDR**)&pDestHash);
1169     if (*phHash != (HCRYPTHASH)INVALID_HANDLE_VALUE)
1170     {
1171         memcpy(pDestHash, pSrcHash, sizeof(CRYPTHASH));
1172         duplicate_hash_impl(pSrcHash->aiAlgid, &pSrcHash->context, &pDestHash->context);
1173         copy_hmac_info(&pDestHash->pHMACInfo, pSrcHash->pHMACInfo);
1174     }
1175
1176     return *phHash != (HCRYPTHASH)INVALID_HANDLE_VALUE;
1177 }
1178
1179 /******************************************************************************
1180  * CPDuplicateKey (RSAENH.@)
1181  *
1182  * Clones a key object including it's current state.
1183  *
1184  * PARAMS
1185  *  hUID        [I] Handle to the key container the hash belongs to.
1186  *  hKey        [I] Handle to the key object to be cloned.
1187  *  pdwReserved [I] Reserved. Must be NULL.
1188  *  dwFlags     [I] No flags are currently defined. Must be 0.
1189  *  phHash      [O] Handle to the cloned key object.
1190  *
1191  * RETURNS
1192  *  Success: TRUE.
1193  *  Failure: FALSE.
1194  */
1195 BOOL WINAPI RSAENH_CPDuplicateKey(HCRYPTPROV hUID, HCRYPTKEY hKey, DWORD *pdwReserved, 
1196                                   DWORD dwFlags, HCRYPTKEY *phKey)
1197 {
1198     CRYPTKEY *pSrcKey, *pDestKey;
1199     
1200     TRACE("(hUID=%08lx, hKey=%08lx, pdwReserved=%p, dwFlags=%08lx, phKey=%p)\n", hUID, hKey, 
1201           pdwReserved, dwFlags, phKey);
1202
1203     if (!is_valid_handle(&handle_table, hUID, RSAENH_MAGIC_CONTAINER))
1204     {
1205         SetLastError(NTE_BAD_UID);
1206         return FALSE;
1207     }
1208
1209     if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pSrcKey))
1210     {
1211         SetLastError(NTE_BAD_KEY);
1212         return FALSE;
1213     }
1214
1215     if (!phKey || pdwReserved || dwFlags) 
1216     {
1217         SetLastError(ERROR_INVALID_PARAMETER);
1218         return FALSE;
1219     }
1220
1221     *phKey = (HCRYPTKEY)new_object(&handle_table, sizeof(CRYPTKEY), RSAENH_MAGIC_KEY, destroy_key, 
1222                                    (OBJECTHDR**)&pDestKey);
1223     if (*phKey != (HCRYPTKEY)INVALID_HANDLE_VALUE)
1224     {
1225         memcpy(pDestKey, pSrcKey, sizeof(CRYPTKEY));
1226         duplicate_key_impl(pSrcKey->aiAlgid, &pSrcKey->context, &pDestKey->context);
1227         return TRUE;
1228     }
1229     else
1230     {
1231         return FALSE;
1232     }
1233 }
1234
1235 /******************************************************************************
1236  * CPEncrypt (RSAENH.@)
1237  *
1238  * Encrypt data.
1239  *
1240  * PARAMS
1241  *  hProv      [I]   The key container hKey and hHash belong to.
1242  *  hKey       [I]   The key used to encrypt the data.
1243  *  hHash      [I]   An optional hash object for parallel hashing. See notes.
1244  *  Final      [I]   Indicates if this is the last block of data to encrypt.
1245  *  dwFlags    [I]   Currently no flags defined. Must be zero.
1246  *  pbData     [I/O] Pointer to the data to encrypt. Encrypted data will also be stored there. 
1247  *  pdwDataLen [I/O] I: Length of data to encrypt, O: Length of encrypted data.
1248  *  dwBufLen   [I]   Size of the buffer at pbData.
1249  *
1250  * RETURNS
1251  *  Success: TRUE.
1252  *  Failure: FALSE.
1253  *
1254  * NOTES
1255  *  If a hash object handle is provided in hHash, it will be updated with the plaintext. 
1256  *  This is useful for message signatures.
1257  *
1258  *  This function uses the standard WINAPI protocol for querying data of dynamic length. 
1259  * 
1260  * FIXME
1261  *  Parallel hashing not yet implemented.
1262  */
1263 BOOL WINAPI RSAENH_CPEncrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, 
1264                              DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen)
1265 {
1266     CRYPTKEY *pCryptKey;
1267     BYTE *in, out[RSAENH_MAX_BLOCK_SIZE], o[RSAENH_MAX_BLOCK_SIZE];
1268     DWORD dwEncryptedLen, i, j, k;
1269         
1270     TRACE("(hProv=%08lx, hKey=%08lx, hHash=%08lx, Final=%d, dwFlags=%08lx, pbData=%p, "
1271           "pdwDataLen=%p, dwBufLen=%ld)\n", hProv, hKey, hHash, Final, dwFlags, pbData, pdwDataLen,
1272           dwBufLen);
1273     
1274     if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
1275     {
1276         SetLastError(NTE_BAD_UID);
1277         return FALSE;
1278     }
1279
1280     if (dwFlags)
1281     {
1282         SetLastError(NTE_BAD_FLAGS);
1283         return FALSE;
1284     }
1285
1286     if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
1287     {
1288         SetLastError(NTE_BAD_KEY);
1289         return FALSE;
1290     }
1291
1292     if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) 
1293         pCryptKey->dwState = RSAENH_KEYSTATE_ENCRYPTING;
1294
1295     if (pCryptKey->dwState != RSAENH_KEYSTATE_ENCRYPTING) 
1296     {
1297         SetLastError(NTE_BAD_DATA);
1298         return FALSE;
1299     }
1300
1301     if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_BLOCK) {
1302         if (!Final && (*pdwDataLen % pCryptKey->dwBlockLen)) {
1303             SetLastError(NTE_BAD_DATA);
1304             return FALSE;
1305         }
1306
1307         dwEncryptedLen = (*pdwDataLen/pCryptKey->dwBlockLen+(Final?1:0))*pCryptKey->dwBlockLen;
1308         for (i=*pdwDataLen; i<dwEncryptedLen; i++) pbData[i] = dwEncryptedLen - *pdwDataLen;
1309         *pdwDataLen = dwEncryptedLen; 
1310
1311         if (*pdwDataLen > dwBufLen) 
1312         {
1313             SetLastError(ERROR_MORE_DATA);
1314             return FALSE;
1315         }
1316     
1317         for (i=0, in=pbData; i<*pdwDataLen; i+=pCryptKey->dwBlockLen, in+=pCryptKey->dwBlockLen) {
1318             switch (pCryptKey->dwMode) {
1319                 case CRYPT_MODE_ECB:
1320                     encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, in, out, 
1321                                        RSAENH_ENCRYPT);
1322                     break;
1323                 
1324                 case CRYPT_MODE_CBC:
1325                     for (j=0; j<pCryptKey->dwBlockLen; j++) in[j] ^= pCryptKey->abChainVector[j];
1326                     encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, in, out, 
1327                                        RSAENH_ENCRYPT);
1328                     memcpy(pCryptKey->abChainVector, out, pCryptKey->dwBlockLen);
1329                     break;
1330
1331                 case CRYPT_MODE_CFB:
1332                     for (j=0; j<pCryptKey->dwBlockLen; j++) {
1333                         encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, 
1334                                            pCryptKey->abChainVector, o, RSAENH_ENCRYPT);
1335                         out[j] = in[j] ^ o[0];
1336                         for (k=0; k<pCryptKey->dwBlockLen-1; k++) 
1337                             pCryptKey->abChainVector[k] = pCryptKey->abChainVector[k+1];
1338                         pCryptKey->abChainVector[k] = out[j];
1339                     }
1340                     break;
1341                     
1342                 default:
1343                     SetLastError(NTE_BAD_ALGID);
1344                     return FALSE;
1345             }
1346             memcpy(in, out, pCryptKey->dwBlockLen); 
1347         }
1348     } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) {
1349         encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen);
1350     }
1351
1352     if (Final) setup_key(pCryptKey);
1353
1354     return TRUE;
1355 }
1356
1357 /******************************************************************************
1358  * CPDecrypt (RSAENH.@)
1359  *
1360  * Decrypt data.
1361  *
1362  * PARAMS
1363  *  hProv      [I]   The key container hKey and hHash belong to.
1364  *  hKey       [I]   The key used to decrypt the data.
1365  *  hHash      [I]   An optional hash object for parallel hashing. See notes.
1366  *  Final      [I]   Indicates if this is the last block of data to decrypt.
1367  *  dwFlags    [I]   Currently no flags defined. Must be zero.
1368  *  pbData     [I/O] Pointer to the data to decrypt. Plaintext will also be stored there. 
1369  *  pdwDataLen [I/O] I: Length of ciphertext, O: Length of plaintext.
1370  *
1371  * RETURNS
1372  *  Success: TRUE.
1373  *  Failure: FALSE.
1374  *
1375  * NOTES
1376  *  If a hash object handle is provided in hHash, it will be updated with the plaintext. 
1377  *  This is useful for message signatures.
1378  *
1379  *  This function uses the standard WINAPI protocol for querying data of dynamic length. 
1380  * 
1381  * FIXME
1382  *  Parallel hashing not yet implemented.
1383  */
1384 BOOL WINAPI RSAENH_CPDecrypt(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, 
1385                              DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
1386 {
1387     CRYPTKEY *pCryptKey;
1388     BYTE *in, out[RSAENH_MAX_BLOCK_SIZE], o[RSAENH_MAX_BLOCK_SIZE];
1389     DWORD i, j, k;
1390
1391     TRACE("(hProv=%08lx, hKey=%08lx, hHash=%08lx, Final=%d, dwFlags=%08lx, pbData=%p, "
1392           "pdwDataLen=%p)\n", hProv, hKey, hHash, Final, dwFlags, pbData, pdwDataLen);
1393     
1394     if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
1395     {
1396         SetLastError(NTE_BAD_UID);
1397         return FALSE;
1398     }
1399
1400     if (dwFlags)
1401     {
1402         SetLastError(NTE_BAD_FLAGS);
1403         return FALSE;
1404     }
1405
1406     if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
1407     {
1408         SetLastError(NTE_BAD_KEY);
1409         return FALSE;
1410     }
1411
1412     if (pCryptKey->dwState == RSAENH_KEYSTATE_IDLE) 
1413         pCryptKey->dwState = RSAENH_KEYSTATE_DECRYPTING;
1414
1415     if (pCryptKey->dwState != RSAENH_KEYSTATE_DECRYPTING)
1416     {
1417         SetLastError(NTE_BAD_DATA);
1418         return FALSE;
1419     }
1420     
1421     if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_BLOCK) {
1422         for (i=0, in=pbData; i<*pdwDataLen; i+=pCryptKey->dwBlockLen, in+=pCryptKey->dwBlockLen) {
1423             switch (pCryptKey->dwMode) {
1424                 case CRYPT_MODE_ECB:
1425                     encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, in, out, 
1426                                        RSAENH_DECRYPT);
1427                     break;
1428                 
1429                 case CRYPT_MODE_CBC:
1430                     encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, in, out, 
1431                                        RSAENH_DECRYPT);
1432                     for (j=0; j<pCryptKey->dwBlockLen; j++) out[j] ^= pCryptKey->abChainVector[j];
1433                     memcpy(pCryptKey->abChainVector, in, pCryptKey->dwBlockLen);
1434                     break;
1435
1436                 case CRYPT_MODE_CFB:
1437                     for (j=0; j<pCryptKey->dwBlockLen; j++) {
1438                         encrypt_block_impl(pCryptKey->aiAlgid, &pCryptKey->context, 
1439                                            pCryptKey->abChainVector, o, RSAENH_ENCRYPT);
1440                         out[j] = in[j] ^ o[0];
1441                         for (k=0; k<pCryptKey->dwBlockLen-1; k++) 
1442                             pCryptKey->abChainVector[k] = pCryptKey->abChainVector[k+1];
1443                         pCryptKey->abChainVector[k] = in[j];
1444                     }
1445                     break;
1446                     
1447                 default:
1448                     SetLastError(NTE_BAD_ALGID);
1449                     return FALSE;
1450             }
1451             memcpy(in, out, pCryptKey->dwBlockLen);
1452         }
1453         if (Final) *pdwDataLen -= pbData[*pdwDataLen-1]; 
1454
1455     } else if (GET_ALG_TYPE(pCryptKey->aiAlgid) == ALG_TYPE_STREAM) {
1456         encrypt_stream_impl(pCryptKey->aiAlgid, &pCryptKey->context, pbData, *pdwDataLen);
1457     }
1458
1459     if (Final) setup_key(pCryptKey);
1460
1461     return TRUE;
1462 }
1463
1464 /******************************************************************************
1465  * CPExportKey (RSAENH.@)
1466  *
1467  * Export a key into a binary large object (BLOB).
1468  *
1469  * PARAMS
1470  *  hProv      [I]   Key container from which a key is to be exported.
1471  *  hKey       [I]   Key to be exported.
1472  *  hPubKey    [I]   Key used to encrypt sensitive BLOB data.
1473  *  dwBlobType [I]   SIMPLEBLOB, PUBLICKEYBLOB or PRIVATEKEYBLOB.
1474  *  dwFlags    [I]   Currently none defined.
1475  *  pbData     [O]   Pointer to a buffer where the BLOB will be written to.
1476  *  pdwDataLen [I/O] I: Size of buffer at pbData, O: Size of BLOB
1477  *
1478  * RETURNS
1479  *  Success: TRUE.
1480  *  Failure: FALSE.
1481  */
1482 BOOL WINAPI RSAENH_CPExportKey(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubKey, 
1483                                DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
1484 {
1485     CRYPTKEY *pCryptKey, *pPubKey;
1486     BLOBHEADER *pBlobHeader = (BLOBHEADER*)pbData;
1487     RSAPUBKEY *pRSAPubKey = (RSAPUBKEY*)(pBlobHeader+1);
1488     ALG_ID *pAlgid = (ALG_ID*)(pBlobHeader+1);
1489     DWORD dwDataLen, i;
1490     BYTE *pbRawData;
1491     
1492     TRACE("(hProv=%08lx, hKey=%08lx, hPubKey=%08lx, dwBlobType=%08lx, dwFlags=%08lx, pbData=%p,"
1493           "pdwDataLen=%p)\n", hProv, hKey, hPubKey, dwBlobType, dwFlags, pbData, pdwDataLen);
1494     
1495     if (!is_valid_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER))
1496     {
1497         SetLastError(NTE_BAD_UID);
1498         return FALSE;
1499     }
1500
1501     if (!lookup_handle(&handle_table, hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
1502     {
1503         SetLastError(NTE_BAD_KEY);
1504         return FALSE;
1505     }
1506
1507     switch ((BYTE)dwBlobType)
1508     {
1509         case SIMPLEBLOB:
1510             if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pPubKey)){
1511                 SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error_code? */
1512                 return FALSE;
1513             }
1514
1515             if (GET_ALG_CLASS(pCryptKey->aiAlgid) != ALG_CLASS_DATA_ENCRYPT) {
1516                 SetLastError(NTE_BAD_KEY); /* FIXME: error code? */
1517                 return FALSE;
1518             }
1519
1520             dwDataLen = sizeof(BLOBHEADER) + sizeof(ALG_ID) + pPubKey->dwBlockLen;
1521             if (pbData) {
1522                 if (*pdwDataLen < dwDataLen) {
1523                     SetLastError(ERROR_MORE_DATA);
1524                     *pdwDataLen = dwDataLen;
1525                     return FALSE;
1526                 }
1527
1528                 pBlobHeader->bType = SIMPLEBLOB;
1529                 pBlobHeader->bVersion = CUR_BLOB_VERSION;
1530                 pBlobHeader->reserved = 0;
1531                 pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
1532
1533                 *pAlgid = pPubKey->aiAlgid;
1534         
1535                 pbRawData = (BYTE*)(pAlgid+1);
1536                 pbRawData[0] = 0x00;
1537                 pbRawData[1] = RSAENH_PKC_BLOCKTYPE; 
1538                 for (i=2; i < pPubKey->dwBlockLen - pCryptKey->dwKeyLen - 1; i++) 
1539                     do gen_rand_impl(&pbRawData[i], 1); while (!pbRawData[i]);
1540                 pbRawData[i] = 0x00;
1541                 for (i=0; i<pCryptKey->dwKeyLen; i++) 
1542                     pbRawData[pPubKey->dwBlockLen - pCryptKey->dwKeyLen + i] = 
1543                         pCryptKey->abKeyValue[i];
1544     
1545                 encrypt_block_impl(pPubKey->aiAlgid, &pPubKey->context, pbRawData, pbRawData, 
1546                                    RSAENH_ENCRYPT); 
1547             }
1548             *pdwDataLen = dwDataLen;
1549             return TRUE;
1550             
1551         case PUBLICKEYBLOB:
1552             if (is_valid_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY)) {
1553                 SetLastError(NTE_BAD_KEY); /* FIXME: error code? */
1554                 return FALSE;
1555             }
1556
1557             if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) {
1558                 SetLastError(NTE_BAD_KEY);
1559                 return FALSE;
1560             }
1561
1562             dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + pCryptKey->dwKeyLen;
1563             if (pbData) {
1564                 if (*pdwDataLen < dwDataLen) {
1565                     SetLastError(ERROR_MORE_DATA);
1566                     *pdwDataLen = dwDataLen;
1567                     return FALSE;
1568                 }
1569
1570                 pBlobHeader->bType = PUBLICKEYBLOB;
1571                 pBlobHeader->bVersion = CUR_BLOB_VERSION;
1572                 pBlobHeader->reserved = 0;
1573                 pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
1574
1575                 pRSAPubKey->magic = RSAENH_MAGIC_RSA1; 
1576                 pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3;
1577         
1578                 export_public_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context, 
1579                                        pCryptKey->dwKeyLen, &pRSAPubKey->pubexp);
1580             }
1581             *pdwDataLen = dwDataLen;
1582             return TRUE;
1583
1584         case PRIVATEKEYBLOB:
1585             if ((pCryptKey->aiAlgid != CALG_RSA_KEYX) && (pCryptKey->aiAlgid != CALG_RSA_SIGN)) {
1586                 SetLastError(NTE_BAD_KEY);
1587                 return FALSE;
1588             }
1589     
1590             dwDataLen = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + 
1591                         2 * pCryptKey->dwKeyLen + 5 * ((pCryptKey->dwKeyLen + 1) >> 1);
1592             if (pbData) {
1593                 if (*pdwDataLen < dwDataLen) {
1594                     SetLastError(ERROR_MORE_DATA);
1595                     *pdwDataLen = dwDataLen;
1596                     return FALSE;
1597                 }
1598                 
1599                 pBlobHeader->bType = PRIVATEKEYBLOB;
1600                 pBlobHeader->bVersion = CUR_BLOB_VERSION;
1601                 pBlobHeader->reserved = 0;
1602                 pBlobHeader->aiKeyAlg = pCryptKey->aiAlgid;
1603
1604                 pRSAPubKey->magic = RSAENH_MAGIC_RSA2;
1605                 pRSAPubKey->bitlen = pCryptKey->dwKeyLen << 3;
1606                 
1607                 export_private_key_impl((BYTE*)(pRSAPubKey+1), &pCryptKey->context, 
1608                                         pCryptKey->dwKeyLen, &pRSAPubKey->pubexp);
1609             }
1610             *pdwDataLen = dwDataLen;
1611             return TRUE;
1612             
1613         default:
1614             SetLastError(NTE_BAD_TYPE); /* FIXME: error code? */
1615             return FALSE;
1616     }
1617 }
1618
1619 /******************************************************************************
1620  * CPImportKey (RSAENH.@)
1621  *
1622  * Import a BLOB'ed key into a key container.
1623  *
1624  * PARAMS
1625  *  hProv     [I] Key container into which the key is to be imported.
1626  *  pbData    [I] Pointer to a buffer which holds the BLOB.
1627  *  dwDataLen [I] Length of data in buffer at pbData.
1628  *  hPubKey   [I] Key used to decrypt sensitive BLOB data.
1629  *  dwFlags   [I] Currently none defined.
1630  *  phKey     [O] Handle to the imported key.
1631  *
1632  * RETURNS
1633  *  Success: TRUE.
1634  *  Failure: FALSE.
1635  */
1636 BOOL WINAPI RSAENH_CPImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen, 
1637                                HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey)
1638 {
1639     KEYCONTAINER *pKeyContainer;
1640     CRYPTKEY *pCryptKey, *pPubKey;
1641     CONST BLOBHEADER *pBlobHeader = (CONST BLOBHEADER*)pbData;
1642     CONST RSAPUBKEY *pRSAPubKey = (CONST RSAPUBKEY*)(pBlobHeader+1);
1643     CONST ALG_ID *pAlgid = (CONST ALG_ID*)(pBlobHeader+1);
1644     CONST BYTE *pbKeyStream = (CONST BYTE*)(pAlgid + 1);
1645     BYTE *pbDecrypted, abKeyValue[RSAENH_MAX_KEY_SIZE];
1646     DWORD dwKeyLen, i;
1647
1648     TRACE("(hProv=%08lx, pbData=%p, dwDataLen=%ld, hPubKey=%08lx, dwFlags=%08lx, phKey=%p)\n", 
1649         hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
1650     
1651     if (!lookup_handle(&handle_table, hProv, RSAENH_MAGIC_CONTAINER, (OBJECTHDR**)&pKeyContainer))
1652     {
1653         SetLastError(NTE_BAD_UID);
1654         return FALSE;
1655     }
1656
1657     if (dwDataLen < sizeof(BLOBHEADER) || 
1658         pBlobHeader->bVersion != CUR_BLOB_VERSION ||
1659         pBlobHeader->reserved != 0) 
1660     {
1661         SetLastError(NTE_BAD_DATA);
1662         return FALSE;
1663     }
1664
1665     switch (pBlobHeader->bType)
1666     {
1667         case PRIVATEKEYBLOB:    
1668             if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) || 
1669                 (pRSAPubKey->magic != RSAENH_MAGIC_RSA2) ||
1670                 (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + 
1671                     (2 * pRSAPubKey->bitlen >> 3) + (5 * ((pRSAPubKey->bitlen+8)>>4)))) 
1672             {
1673                 SetLastError(NTE_BAD_DATA);
1674                 return FALSE;
1675             }
1676     
1677             *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, MAKELONG(0,pRSAPubKey->bitlen), NULL, 
1678                              (HCRYPTHASH)0);
1679             if (!lookup_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) {
1680                 SetLastError(NTE_FAIL);
1681                 return FALSE;
1682             }
1683     
1684             return import_private_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context, 
1685                                            pRSAPubKey->bitlen/8, pRSAPubKey->pubexp);
1686                 
1687         case PUBLICKEYBLOB:
1688             if ((dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) || 
1689                 (pRSAPubKey->magic != RSAENH_MAGIC_RSA1) ||
1690                 (dwDataLen < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + (pRSAPubKey->bitlen >> 3))) 
1691             {
1692                 SetLastError(NTE_BAD_DATA);
1693                 return FALSE;
1694             }
1695     
1696             *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, MAKELONG(0,pRSAPubKey->bitlen), NULL, 
1697                              (HCRYPTHASH)0);
1698             if (!lookup_handle(&handle_table, *phKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey)) {
1699                 SetLastError(NTE_FAIL);
1700                 return FALSE;
1701             }
1702                 
1703             return import_public_key_impl((CONST BYTE*)(pRSAPubKey+1), &pCryptKey->context, 
1704                                           pRSAPubKey->bitlen >> 3, pRSAPubKey->pubexp);
1705                 
1706         case SIMPLEBLOB:
1707             if (!lookup_handle(&handle_table, hPubKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pPubKey) ||
1708                 pPubKey->aiAlgid != CALG_RSA_KEYX) 
1709             {
1710                 SetLastError(NTE_BAD_PUBLIC_KEY); /* FIXME: error code? */
1711                 return FALSE;
1712             }
1713
1714             if (dwDataLen < sizeof(BLOBHEADER)+sizeof(ALG_ID)+pPubKey->dwBlockLen) 
1715             {
1716                 SetLastError(NTE_BAD_DATA); /* FIXME: error code */
1717                 return FALSE;
1718             }
1719
1720             pbDecrypted = (BYTE*)HeapAlloc(GetProcessHeap(), 0, pPubKey->dwBlockLen);
1721             if (!pbDecrypted) return FALSE;
1722             encrypt_block_impl(pPubKey->aiAlgid, &pPubKey->context, pbKeyStream, pbDecrypted, 
1723                                RSAENH_DECRYPT);
1724
1725             for (i=2; i<pPubKey->dwBlockLen && pbDecrypted[i]; i++); 
1726             if ((i==pPubKey->dwBlockLen) ||
1727                 (pbDecrypted[0] != 0x00) ||
1728                 (pbDecrypted[1] != RSAENH_PKC_BLOCKTYPE))
1729             {
1730                 HeapFree(GetProcessHeap(), 0, pbDecrypted);
1731                 SetLastError(NTE_BAD_DATA); /* FIXME: error code */
1732                 return FALSE;
1733             }
1734
1735             dwKeyLen = pPubKey->dwBlockLen-i-1;
1736             memcpy(abKeyValue, pbDecrypted+i+1, dwKeyLen);
1737             HeapFree(GetProcessHeap(), 0, pbDecrypted);
1738     
1739             *phKey = new_key(hProv, pBlobHeader->aiKeyAlg, dwKeyLen<<19, abKeyValue, 0);
1740             return *phKey != (HCRYPTKEY)INVALID_HANDLE_VALUE;
1741
1742         default:
1743             SetLastError(NTE_BAD_TYPE); /* FIXME: error code? */
1744             return FALSE;
1745     }
1746 }
1747
1748 /******************************************************************************
1749  * CPGenKey (RSAENH.@)
1750  *
1751  * Generate a key in the key container
1752  *
1753  * PARAMS
1754  *  hProv   [I] Key container for which a key is to be generated.
1755  *  Algid   [I] Crypto algorithm identifier for the key to be generated.
1756  *  dwFlags [I] Upper 16 bits: Binary length of key. Lower 16 bits: Flags. See Notes
1757  *  phKey   [O] Handle to the generated key.
1758  *
1759  * RETURNS
1760  *  Success: TRUE.
1761  *  Failure: FALSE.
1762  *
1763  * FIXME
1764  *  Flags currently not considered.
1765  *
1766  * NOTES
1767  *  Private key-exchange- and signature-keys can be generated with Algid AT_KEYEXCHANGE
1768  *  and AT_SIGNATURE values.
1769  */
1770 BOOL WINAPI RSAENH_CPGenKey(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey)
1771 {
1772     KEYCONTAINER *pKeyContainer;
1773     BYTE abKeyValue[2048];
1774
1775     TRACE("(hProv=%08lx, aiAlgid=%d, dwFlags=%08lx, phKey=%p)\n", hProv, Algid, dwFlags, phKey);
1776
1777     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
1778                        (OBJECTHDR**)&pKeyContainer)) 
1779     {
1780         /* MSDN: hProv not containing valid context handle */
1781         SetLastError(NTE_BAD_UID);
1782         return FALSE;
1783     }
1784     
1785     switch (Algid)
1786     {
1787         case AT_SIGNATURE:
1788             RSAENH_CPDestroyKey(hProv, pKeyContainer->hSignatureKeyPair);
1789             pKeyContainer->hSignatureKeyPair = 
1790                 new_key(hProv, CALG_RSA_SIGN, dwFlags, abKeyValue, 0);
1791             copy_handle(&handle_table, pKeyContainer->hSignatureKeyPair, RSAENH_MAGIC_KEY, 
1792                         (unsigned int*)phKey);
1793             break;
1794
1795         case AT_KEYEXCHANGE:
1796             RSAENH_CPDestroyKey(hProv, pKeyContainer->hKeyExchangeKeyPair);
1797             pKeyContainer->hKeyExchangeKeyPair = new_key(hProv, CALG_RSA_KEYX, dwFlags, abKeyValue, 0);
1798             copy_handle(&handle_table, pKeyContainer->hKeyExchangeKeyPair, RSAENH_MAGIC_KEY, 
1799                         (unsigned int*)phKey);
1800             break;
1801         
1802         case CALG_RC2:
1803         case CALG_RC4:
1804         case CALG_DES:
1805             gen_rand_impl(abKeyValue, 2048);
1806             *phKey = new_key(hProv, Algid, dwFlags, abKeyValue, 0);
1807             break;
1808             
1809         default:
1810             /* MSDN: Algorithm not supported specified by Algid */
1811             SetLastError(NTE_BAD_ALGID);
1812             return FALSE;
1813     }
1814             
1815     return *phKey != (unsigned int)INVALID_HANDLE_VALUE;
1816 }
1817
1818 /******************************************************************************
1819  * CPGenRandom (RSAENH.@)
1820  *
1821  * Generate a random byte stream.
1822  *
1823  * PARAMS
1824  *  hProv    [I] Key container that is used to generate random bytes.
1825  *  dwLen    [I] Specifies the number of requested random data bytes.
1826  *  pbBuffer [O] Random bytes will be stored here.
1827  *
1828  * RETURNS
1829  *  Success: TRUE
1830  *  Failure: FALSE
1831  */
1832 BOOL WINAPI RSAENH_CPGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer)
1833 {
1834     KEYCONTAINER *pKeyContainer;
1835
1836     TRACE("(hProv=%08lx, dwLen=%ld, pbBuffer=%p)\n", hProv, dwLen, pbBuffer);
1837     
1838     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
1839                        (OBJECTHDR**)&pKeyContainer)) 
1840     {
1841         /* MSDN: hProv not containing valid context handle */
1842         SetLastError(NTE_BAD_UID);
1843         return FALSE;
1844     }
1845
1846     return gen_rand_impl(pbBuffer, dwLen);
1847 }
1848
1849 /******************************************************************************
1850  * CPGetHashParam (RSAENH.@)
1851  *
1852  * Query parameters of an hash object.
1853  *
1854  * PARAMS
1855  *  hProv      [I]   The kea container, which the hash belongs to.
1856  *  hHash      [I]   The hash object that is to be queried.
1857  *  dwParam    [I]   Specifies the parameter that is to be queried.
1858  *  pbData     [I]   Pointer to the buffer where the parameter value will be stored.
1859  *  pdwDataLen [I/O] I: Buffer length at pbData, O: Length of the parameter value.
1860  *  dwFlags    [I]   None currently defined.
1861  *
1862  * RETURNS
1863  *  Success: TRUE
1864  *  Failure: FALSE
1865  *
1866  * NOTES
1867  *  Valid dwParams are: HP_ALGID, HP_HASHSIZE, HP_HASHVALUE. The hash will be 
1868  *  finalized if HP_HASHVALUE is queried.
1869  */
1870 BOOL WINAPI RSAENH_CPGetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, 
1871                                   DWORD *pdwDataLen, DWORD dwFlags) 
1872 {
1873     CRYPTHASH *pCryptHash;
1874     KEYCONTAINER *pKeyContainer;
1875     BYTE abHashValue[RSAENH_MAX_HASH_SIZE];
1876         
1877     TRACE("(hProv=%08lx, hHash=%08lx, dwParam=%08lx, pbData=%p, pdwDataLen=%p, dwFlags=%08lx)\n", 
1878         hProv, hHash, dwParam, pbData, pdwDataLen, dwFlags);
1879     
1880     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
1881                        (OBJECTHDR**)&pKeyContainer)) 
1882     {
1883         SetLastError(NTE_BAD_UID);
1884         return FALSE;
1885     }
1886
1887     if (dwFlags)
1888     {
1889         SetLastError(NTE_BAD_FLAGS);
1890         return FALSE;
1891     }
1892     
1893     if (!lookup_handle(&handle_table, (unsigned int)hHash, RSAENH_MAGIC_HASH, 
1894                        (OBJECTHDR**)&pCryptHash))
1895     {
1896         SetLastError(NTE_BAD_HASH);
1897         return FALSE;
1898     }
1899
1900     if (!pdwDataLen)
1901     {
1902         SetLastError(ERROR_INVALID_PARAMETER);
1903         return FALSE;
1904     }
1905     
1906     switch (dwParam)
1907     {
1908         case HP_ALGID:
1909             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptHash->aiAlgid, 
1910                               sizeof(ALG_ID));
1911
1912         case HP_HASHSIZE:
1913             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptHash->dwHashSize, 
1914                               sizeof(DWORD));
1915
1916         case HP_HASHVAL:
1917             if (pCryptHash->dwState == RSAENH_HASHSTATE_IDLE) {
1918                 SetLastError(NTE_BAD_HASH_STATE);
1919                 return FALSE;
1920             }
1921             
1922             if (pbData && (pCryptHash->dwState != RSAENH_HASHSTATE_FINISHED))
1923             {
1924                 finalize_hash(pCryptHash);
1925                 if (pCryptHash->aiAlgid == CALG_HMAC) {
1926                     memcpy(abHashValue, pCryptHash->abHashValue, pCryptHash->dwHashSize);
1927                     init_hash(pKeyContainer, pCryptHash);
1928                     update_hash(pCryptHash, pCryptHash->pHMACInfo->pbOuterString, 
1929                                 pCryptHash->pHMACInfo->cbOuterString);
1930                     update_hash(pCryptHash, abHashValue, pCryptHash->dwHashSize);
1931                     finalize_hash(pCryptHash);
1932                 } 
1933                         
1934                 pCryptHash->dwState = RSAENH_HASHSTATE_FINISHED;
1935             }
1936             
1937             return copy_param(pbData, pdwDataLen, (CONST BYTE*)pCryptHash->abHashValue, 
1938                               pCryptHash->dwHashSize);
1939
1940         default:
1941             SetLastError(NTE_BAD_TYPE);
1942             return FALSE;
1943     }
1944 }
1945
1946 /******************************************************************************
1947  * CPSetKeyParam (RSAENH.@)
1948  *
1949  * Set a parameter of a key object
1950  *
1951  * PARAMS
1952  *  hProv   [I] The key container to which the key belongs.
1953  *  hKey    [I] The key for which a parameter is to be set.
1954  *  dwParam [I] Parameter type. See Notes.
1955  *  pbData  [I] Pointer to the parameter value.
1956  *  dwFlags [I] Currently none defined.
1957  *
1958  * RETURNS
1959  *  Success: TRUE.
1960  *  Failure: FALSE.
1961  *
1962  * NOTES:
1963  *  Defined dwParam types are:
1964  *   - KP_MODE: Values MODE_CBC, MODE_ECB, MODE_CFB.
1965  *   - KP_MODE_BITS: Shift width for cipher feedback mode. (Currently ignored by MS CSP's)
1966  *   - KP_PERMISSIONS: Or'ed combination of CRYPT_ENCRYPT, CRYPT_DECRYPT, 
1967  *                     CRYPT_EXPORT, CRYPT_READ, CRYPT_WRITE, CRYPT_MAC
1968  *   - KP_IV: Initialization vector
1969  */
1970 BOOL WINAPI RSAENH_CPSetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, 
1971                                  DWORD dwFlags)
1972 {
1973     CRYPTKEY *pCryptKey;
1974
1975     TRACE("(hProv=%08lx, hKey=%08lx, dwParam=%08lx, pbData=%p, dwFlags=%08lx)\n", hProv, hKey, 
1976           dwParam, pbData, dwFlags);
1977
1978     if (!is_valid_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER))
1979     {
1980         SetLastError(NTE_BAD_UID);
1981         return FALSE;
1982     }
1983
1984     if (dwFlags) {
1985         SetLastError(NTE_BAD_FLAGS);
1986         return FALSE;
1987     }
1988     
1989     if (!lookup_handle(&handle_table, (unsigned int)hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
1990     {
1991         SetLastError(NTE_BAD_KEY);
1992         return FALSE;
1993     }
1994     
1995     switch (dwParam) {
1996         case KP_MODE:
1997             pCryptKey->dwMode = *(DWORD*)pbData;
1998             return TRUE;
1999
2000         case KP_MODE_BITS:
2001             pCryptKey->dwModeBits = *(DWORD*)pbData;
2002             return TRUE;
2003
2004         case KP_PERMISSIONS:
2005             pCryptKey->dwPermissions = *(DWORD*)pbData;
2006             return TRUE;
2007
2008         case KP_IV:
2009             memcpy(pCryptKey->abInitVector, pbData, pCryptKey->dwBlockLen);
2010             return TRUE;
2011
2012         default:
2013             SetLastError(NTE_BAD_TYPE);
2014             return FALSE;
2015     }
2016 }
2017
2018 /******************************************************************************
2019  * CPGetKeyParam (RSAENH.@)
2020  *
2021  * Query a key parameter.
2022  *
2023  * PARAMS
2024  *  hProv      [I]   The key container, which the key belongs to.
2025  *  hHash      [I]   The key object that is to be queried.
2026  *  dwParam    [I]   Specifies the parameter that is to be queried.
2027  *  pbData     [I]   Pointer to the buffer where the parameter value will be stored.
2028  *  pdwDataLen [I/O] I: Buffer length at pbData, O: Length of the parameter value.
2029  *  dwFlags    [I]   None currently defined.
2030  *
2031  * RETURNS
2032  *  Success: TRUE
2033  *  Failure: FALSE
2034  *
2035  * NOTES
2036  *  Defined dwParam types are:
2037  *   - KP_MODE: Values MODE_CBC, MODE_ECB, MODE_CFB.
2038  *   - KP_MODE_BITS: Shift width for cipher feedback mode. 
2039  *                   (Currently ignored by MS CSP's - always eight)
2040  *   - KP_PERMISSIONS: Or'ed combination of CRYPT_ENCRYPT, CRYPT_DECRYPT, 
2041  *                     CRYPT_EXPORT, CRYPT_READ, CRYPT_WRITE, CRYPT_MAC
2042  *   - KP_IV: Initialization vector.
2043  *   - KP_KEYLEN: Bitwidth of the key.
2044  *   - KP_BLOCKLEN: Size of a block cipher block.
2045  *   - KP_SALT: Salt value.
2046  */
2047 BOOL WINAPI RSAENH_CPGetKeyParam(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, 
2048                                  DWORD *pdwDataLen, DWORD dwFlags)
2049 {
2050     CRYPTKEY *pCryptKey;
2051     DWORD dwBitLen;
2052         
2053     TRACE("(hProv=%08lx, hKey=%08lx, dwParam=%08lx, pbData=%p, pdwDataLen=%p dwFlags=%08lx)\n", 
2054           hProv, hKey, dwParam, pbData, pdwDataLen, dwFlags);
2055
2056     if (!is_valid_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER)) 
2057     {
2058         SetLastError(NTE_BAD_UID);
2059         return FALSE;
2060     }
2061
2062     if (dwFlags) {
2063         SetLastError(NTE_BAD_FLAGS);
2064         return FALSE;
2065     }
2066
2067     if (!lookup_handle(&handle_table, (unsigned int)hKey, RSAENH_MAGIC_KEY, (OBJECTHDR**)&pCryptKey))
2068     {
2069         SetLastError(NTE_BAD_KEY);
2070         return FALSE;
2071     }
2072
2073     switch (dwParam) 
2074     {
2075         case KP_IV:
2076             return copy_param(pbData, pdwDataLen, (CONST BYTE*)pCryptKey->abInitVector, 
2077                               pCryptKey->dwBlockLen);
2078         
2079         case KP_SALT:
2080             return copy_param(pbData, pdwDataLen, 
2081                     (CONST BYTE*)&pCryptKey->abKeyValue[pCryptKey->dwKeyLen], pCryptKey->dwSaltLen);
2082         
2083         case KP_KEYLEN:
2084             dwBitLen = pCryptKey->dwKeyLen << 3;
2085             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwBitLen, sizeof(DWORD));
2086         
2087         case KP_BLOCKLEN:
2088             dwBitLen = pCryptKey->dwBlockLen << 3;
2089             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwBitLen, sizeof(DWORD));
2090     
2091         case KP_MODE:
2092             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwMode, sizeof(DWORD));
2093
2094         case KP_MODE_BITS:
2095             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwModeBits, 
2096                               sizeof(DWORD));
2097     
2098         case KP_PERMISSIONS:
2099             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&pCryptKey->dwPermissions, 
2100                               sizeof(DWORD));
2101
2102         default:
2103             SetLastError(NTE_BAD_TYPE);
2104             return FALSE;
2105     }
2106 }
2107                         
2108 /******************************************************************************
2109  * CPGetProvParam (RSAENH.@)
2110  *
2111  * Query a CSP parameter.
2112  *
2113  * PARAMS
2114  *  hProv      [I]   The key container that is to be queried.
2115  *  dwParam    [I]   Specifies the parameter that is to be queried.
2116  *  pbData     [I]   Pointer to the buffer where the parameter value will be stored.
2117  *  pdwDataLen [I/O] I: Buffer length at pbData, O: Length of the parameter value.
2118  *  dwFlags    [I]   CRYPT_FIRST: Start enumeration (for PP_ENUMALGS{_EX}).
2119  *
2120  * RETURNS
2121  *  Success: TRUE
2122  *  Failure: FALSE
2123  * NOTES:
2124  *  Defined dwParam types:
2125  *   - PP_CONTAINER: Name of the key container.
2126  *   - PP_NAME: Name of the cryptographic service provider.
2127  *   - PP_SIG_KEYSIZE_INC: RSA signature keywidth granularity in bits.
2128  *   - PP_KEYX_KEYSIZE_INC: RSA key-exchange keywidth granularity in bits.
2129  *   - PP_ENUMALGS{_EX}: Query provider capabilities.
2130  */
2131 BOOL WINAPI RSAENH_CPGetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, 
2132                                   DWORD *pdwDataLen, DWORD dwFlags)
2133 {
2134     KEYCONTAINER *pKeyContainer;
2135     PROV_ENUMALGS provEnumalgs;
2136     DWORD dwTemp;
2137     
2138     TRACE("(hProv=%08lx, dwParam=%08lx, pbData=%p, pdwDataLen=%p, dwFlags=%08lx)\n", 
2139            hProv, dwParam, pbData, pdwDataLen, dwFlags);
2140
2141     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
2142                        (OBJECTHDR**)&pKeyContainer)) 
2143     {
2144         /* MSDN: hProv not containing valid context handle */
2145         SetLastError(NTE_BAD_UID);
2146         return FALSE;
2147     }
2148
2149     switch (dwParam) 
2150     {
2151         case PP_CONTAINER:
2152             return copy_param(pbData, pdwDataLen, (CONST BYTE*)pKeyContainer->szName, 
2153                               strlen(pKeyContainer->szName)+1);
2154
2155         case PP_NAME:
2156             return copy_param(pbData, pdwDataLen, (CONST BYTE*)pKeyContainer->szProvName, 
2157                               strlen(pKeyContainer->szProvName)+1);
2158
2159         case PP_SIG_KEYSIZE_INC:
2160         case PP_KEYX_KEYSIZE_INC:
2161             dwTemp = 8;
2162             return copy_param(pbData, pdwDataLen, (CONST BYTE*)&dwTemp, sizeof(dwTemp));
2163             
2164         case PP_ENUMALGS:
2165         case PP_ENUMALGS_EX:
2166             if (((pKeyContainer->dwEnumAlgsCtr >= RSAENH_MAX_ENUMALGS-1) ||
2167                  (!aProvEnumAlgsEx[pKeyContainer->dwPersonality]
2168                    [pKeyContainer->dwEnumAlgsCtr+1].aiAlgid)) && 
2169                 ((dwFlags & CRYPT_FIRST) != CRYPT_FIRST))
2170             {
2171                 SetLastError(ERROR_NO_MORE_ITEMS);
2172                 return FALSE;
2173             }
2174
2175             if (dwParam == PP_ENUMALGS) {    
2176                 if (pbData && (*pdwDataLen >= sizeof(PROV_ENUMALGS))) 
2177                     pKeyContainer->dwEnumAlgsCtr = ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) ? 
2178                         0 : pKeyContainer->dwEnumAlgsCtr+1;
2179             
2180                 provEnumalgs.aiAlgid = aProvEnumAlgsEx
2181                     [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].aiAlgid;
2182                 provEnumalgs.dwBitLen = aProvEnumAlgsEx
2183                     [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].dwDefaultLen;
2184                 provEnumalgs.dwNameLen = aProvEnumAlgsEx
2185                     [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].dwNameLen;
2186                 memcpy(provEnumalgs.szName, aProvEnumAlgsEx
2187                        [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr].szName, 
2188                        20*sizeof(CHAR));
2189             
2190                 return copy_param(pbData, pdwDataLen, (CONST BYTE*)&provEnumalgs, 
2191                                   sizeof(PROV_ENUMALGS));
2192             } else {
2193                 if (pbData && (*pdwDataLen >= sizeof(PROV_ENUMALGS_EX))) 
2194                     pKeyContainer->dwEnumAlgsCtr = ((dwFlags & CRYPT_FIRST) == CRYPT_FIRST) ? 
2195                         0 : pKeyContainer->dwEnumAlgsCtr+1;
2196             
2197                 return copy_param(pbData, pdwDataLen, 
2198                                   (CONST BYTE*)&aProvEnumAlgsEx
2199                                       [pKeyContainer->dwPersonality][pKeyContainer->dwEnumAlgsCtr], 
2200                                   sizeof(PROV_ENUMALGS_EX));
2201             }
2202
2203         default:
2204             /* MSDN: Unknown parameter number in dwParam */
2205             SetLastError(NTE_BAD_TYPE);
2206             return FALSE;
2207     }
2208     return FALSE;
2209 }
2210
2211 /******************************************************************************
2212  * CPDeriveKey (RSAENH.@)
2213  *
2214  * Derives a key from a hash value.
2215  *
2216  * PARAMS
2217  *  hProv     [I] Key container for which a key is to be generated.
2218  *  Algid     [I] Crypto algorithm identifier for the key to be generated.
2219  *  hBaseData [I] Hash from whose value the key will be derived.
2220  *  dwFlags   [I] See Notes.
2221  *  phKey     [O] The generated key.
2222  *
2223  * RETURNS
2224  *  Success: TRUE
2225  *  Failure: FALSE
2226  *
2227  * NOTES
2228  *  Defined flags:
2229  *   - CRYPT_EXPORTABLE: Key can be exported.
2230  *   - CRYPT_NO_SALT: No salt is used for 40 bit keys.
2231  *   - CRYPT_CREATE_SALT: Use remaining bits as salt value.
2232  */
2233 BOOL WINAPI RSAENH_CPDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, 
2234                                DWORD dwFlags, HCRYPTKEY *phKey)
2235 {
2236     KEYCONTAINER *pKeyContainer;
2237     
2238     TRACE("(hProv=%08lx, Algid=%d, hBaseData=%08lx, dwFlags=%08lx phKey=%p)\n", hProv, Algid, 
2239            hBaseData, dwFlags, phKey);
2240     
2241     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
2242                        (OBJECTHDR**)&pKeyContainer))
2243     {
2244         SetLastError(NTE_BAD_UID);
2245         return FALSE;
2246     }
2247
2248     if (!is_valid_handle(&handle_table, (unsigned int)hBaseData, RSAENH_MAGIC_HASH))
2249     {
2250         SetLastError(NTE_BAD_HASH);
2251         return FALSE;
2252     }
2253
2254     if (!phKey)
2255     {
2256         SetLastError(ERROR_INVALID_PARAMETER);
2257         return FALSE;
2258     }
2259
2260     *phKey = new_key(hProv, Algid, dwFlags, NULL, hBaseData);
2261     return *phKey == (HCRYPTKEY)INVALID_HANDLE_VALUE ? FALSE : TRUE;
2262 }
2263
2264 /******************************************************************************
2265  * CPGetUserKey (RSAENH.@)
2266  *
2267  * Returns a handle to the user's private key-exchange- or signature-key.
2268  *
2269  * PARAMS
2270  *  hProv     [I] The key container from which a user key is requested.
2271  *  dwKeySpec [I] AT_KEYEXCHANGE or AT_SIGNATURE
2272  *  phUserKey [O] Handle to the requested key or INVALID_HANDLE_VALUE in case of failure.
2273  *
2274  * RETURNS
2275  *  Success: TRUE.
2276  *  Failure: FALSE.
2277  *
2278  * NOTE
2279  *  A newly created key container does not contain private user key. Create them with CPGenKey.
2280  */
2281 BOOL WINAPI RSAENH_CPGetUserKey(HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey)
2282 {
2283     KEYCONTAINER *pKeyContainer;
2284
2285     TRACE("(hProv=%08lx, dwKeySpec=%08lx, phUserKey=%p)\n", hProv, dwKeySpec, phUserKey);
2286     
2287     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
2288                        (OBJECTHDR**)&pKeyContainer)) 
2289     {
2290         /* MSDN: hProv not containing valid context handle */
2291         SetLastError(NTE_BAD_UID);
2292         return FALSE;
2293     }
2294
2295     switch (dwKeySpec)
2296     {
2297         case AT_KEYEXCHANGE:
2298             copy_handle(&handle_table, pKeyContainer->hKeyExchangeKeyPair, RSAENH_MAGIC_KEY, 
2299                         (unsigned int*)phUserKey);
2300             break;
2301
2302         case AT_SIGNATURE:
2303             copy_handle(&handle_table, pKeyContainer->hSignatureKeyPair, RSAENH_MAGIC_KEY, 
2304                         (unsigned int*)phUserKey);
2305             break;
2306
2307         default:
2308             *phUserKey = (HCRYPTKEY)INVALID_HANDLE_VALUE;
2309     }
2310
2311     if (*phUserKey == (HCRYPTKEY)INVALID_HANDLE_VALUE)
2312     {
2313         /* MSDN: dwKeySpec parameter specifies non existent key */
2314         SetLastError(NTE_NO_KEY);
2315         return FALSE;
2316     }
2317
2318     return TRUE;
2319 }
2320
2321 /******************************************************************************
2322  * CPHashData (RSAENH.@)
2323  *
2324  * Updates a hash object with the given data.
2325  *
2326  * PARAMS
2327  *  hProv     [I] Key container to which the hash object belongs.
2328  *  hHash     [I] Hash object which is to be updated.
2329  *  pbData    [I] Pointer to data with which the hash object is to be updated.
2330  *  dwDataLen [I] Length of the data.
2331  *  dwFlags   [I] Currently none defined.
2332  *
2333  * RETURNS
2334  *  Success: TRUE.
2335  *  Failure: FALSE.
2336  *
2337  * NOTES
2338  *  The actual hash value is queried with CPGetHashParam, which will finalize 
2339  *  the hash. Updating a finalized hash will fail with a last error NTE_BAD_HASH_STATE.
2340  */
2341 BOOL WINAPI RSAENH_CPHashData(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbData, 
2342                               DWORD dwDataLen, DWORD dwFlags)
2343 {
2344     CRYPTHASH *pCryptHash;
2345     KEYCONTAINER *pKeyContainer;
2346         
2347     TRACE("(hProv=%08lx, hHash=%08lx, pbData=%p, dwDataLen=%ld, dwFlags=%08lx)\n", 
2348           hProv, hHash, pbData, dwDataLen, dwFlags);
2349
2350     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
2351                        (OBJECTHDR**)&pKeyContainer))
2352     {
2353         SetLastError(NTE_BAD_UID);
2354         return FALSE;
2355     }
2356
2357     if (dwFlags)
2358     {
2359         SetLastError(NTE_BAD_FLAGS);
2360         return FALSE;
2361     }
2362
2363     if (!lookup_handle(&handle_table, (unsigned int)hHash, RSAENH_MAGIC_HASH, 
2364                        (OBJECTHDR**)&pCryptHash))
2365     {
2366         SetLastError(NTE_BAD_HASH);
2367         return FALSE;
2368     }
2369
2370     if (!get_algid_info(pKeyContainer, pCryptHash->aiAlgid) || 
2371         pCryptHash->aiAlgid == CALG_SSL3_SHAMD5) 
2372     {
2373         SetLastError(NTE_BAD_ALGID);
2374         return FALSE;
2375     }
2376     
2377     if (pCryptHash->dwState == RSAENH_HASHSTATE_IDLE)
2378         pCryptHash->dwState = RSAENH_HASHSTATE_HASHING;
2379     
2380     if (pCryptHash->dwState != RSAENH_HASHSTATE_HASHING)
2381     {
2382         SetLastError(NTE_BAD_HASH_STATE);
2383         return FALSE;
2384     }
2385
2386     update_hash(pCryptHash, pbData, dwDataLen);
2387     return TRUE;
2388 }
2389
2390 /******************************************************************************
2391  * CPHashSessionKey (RSAENH.@)
2392  */
2393 BOOL WINAPI RSAENH_CPHashSessionKey(HCRYPTPROV hProv, HCRYPTHASH hHash, HCRYPTKEY hKey, 
2394                                     DWORD dwFlags)
2395 {
2396     FIXME("(stub)\n");
2397     return FALSE;
2398 }
2399
2400 /******************************************************************************
2401  * CPReleaseContext (RSAENH.@)
2402  *
2403  * Release a key container.
2404  *
2405  * PARAMS
2406  *  hProv   [I] Key container to be released.
2407  *  dwFlags [I] Currently none defined.
2408  *
2409  * RETURNS
2410  *  Success: TRUE
2411  *  Failure: FALSE
2412  */
2413 BOOL WINAPI RSAENH_CPReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
2414 {
2415     TRACE("(hProv=%08lx, dwFlags=%08lx)\n", hProv, dwFlags);
2416
2417     if (!release_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER)) 
2418     {
2419         /* MSDN: hProv not containing valid context handle */
2420         SetLastError(NTE_BAD_UID);
2421         return FALSE;
2422     }
2423
2424     return TRUE;
2425 }
2426
2427 /******************************************************************************
2428  * CPSetHashParam (RSAENH.@)
2429  * 
2430  * Set a parameter of a hash object
2431  *
2432  * PARAMS
2433  *  hProv   [I] The key container to which the key belongs.
2434  *  hHash   [I] The hash object for which a parameter is to be set.
2435  *  dwParam [I] Parameter type. See Notes.
2436  *  pbData  [I] Pointer to the parameter value.
2437  *  dwFlags [I] Currently none defined.
2438  *
2439  * RETURNS
2440  *  Success: TRUE.
2441  *  Failure: FALSE.
2442  *
2443  * NOTES:
2444  *  Currently only the HP_HMAC_INFO dwParam type is defined. 
2445  *  The HMAC_INFO struct will be deep copied into the hash object.
2446  *  See Internet RFC 2104 for details on the HMAC algorithm.
2447  */
2448 BOOL WINAPI RSAENH_CPSetHashParam(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, 
2449                                   BYTE *pbData, DWORD dwFlags)
2450 {
2451     CRYPTHASH *pCryptHash;
2452     CRYPTKEY *pCryptKey;
2453     KEYCONTAINER *pKeyContainer;
2454     int i;
2455
2456     TRACE("(hProv=%08lx, hHash=%08lx, dwParam=%08lx, pbData=%p, dwFlags=%08lx)\n", 
2457            hProv, hHash, dwParam, pbData, dwFlags);
2458
2459     if (!lookup_handle(&handle_table, (unsigned int)hProv, RSAENH_MAGIC_CONTAINER, 
2460                        (OBJECTHDR**)&pKeyContainer))
2461     {
2462         SetLastError(NTE_BAD_UID);
2463         return FALSE;
2464     }
2465
2466     if (dwFlags) {
2467         SetLastError(NTE_BAD_FLAGS);
2468         return FALSE;
2469     }
2470     
2471     if (!lookup_handle(&handle_table, (unsigned int)hHash, RSAENH_MAGIC_HASH, 
2472                        (OBJECTHDR**)&pCryptHash))
2473     {
2474         SetLastError(NTE_BAD_HASH);
2475         return FALSE;
2476     }
2477     
2478     switch (dwParam) {
2479         case HP_HMAC_INFO:
2480             free_hmac_info(pCryptHash->pHMACInfo);
2481             if (!copy_hmac_info(&pCryptHash->pHMACInfo, (PHMAC_INFO)pbData)) return FALSE;
2482             init_hash(pKeyContainer, pCryptHash);
2483
2484             if (!lookup_handle(&handle_table, pCryptHash->hKey, RSAENH_MAGIC_KEY, 
2485                                (OBJECTHDR**)&pCryptKey)) 
2486             {
2487                 SetLastError(NTE_FAIL); /* FIXME: correct error code? */
2488                 return FALSE;
2489             }
2490
2491             for (i=0; i<RSAENH_MIN(pCryptKey->dwKeyLen,pCryptHash->pHMACInfo->cbInnerString); i++) {
2492                 pCryptHash->pHMACInfo->pbInnerString[i] ^= pCryptKey->abKeyValue[i];
2493             }
2494             for (i=0; i<RSAENH_MIN(pCryptKey->dwKeyLen,pCryptHash->pHMACInfo->cbOuterString); i++) {
2495                 pCryptHash->pHMACInfo->pbOuterString[i] ^= pCryptKey->abKeyValue[i];
2496             }
2497             
2498             return RSAENH_CPHashData(hProv, hHash, pCryptHash->pHMACInfo->pbInnerString, 
2499                                      pCryptHash->pHMACInfo->cbInnerString, 0);
2500             
2501         default:
2502             SetLastError(NTE_BAD_TYPE);
2503             return FALSE;
2504     }
2505 }
2506
2507 /******************************************************************************
2508  * CPSetProvParam (RSAENH.@)
2509  */
2510 BOOL WINAPI RSAENH_CPSetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD dwFlags)
2511 {
2512     FIXME("(stub)\n");
2513     return FALSE;
2514 }
2515
2516 /******************************************************************************
2517  * CPSignHash (RSAENH.@)
2518  */
2519 BOOL WINAPI RSAENH_CPSignHash(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwKeySpec, 
2520                               LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature, 
2521                               DWORD *pdwSigLen)
2522 {
2523     FIXME("(stub)\n");
2524     return FALSE;
2525 }
2526
2527 /******************************************************************************
2528  * CPVerifySignature (RSAENH.@)
2529  */
2530 BOOL WINAPI RSAENH_CPVerifySignature(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *pbSignature, 
2531                                      DWORD dwSigLen, HCRYPTKEY hPubKey, LPCWSTR sDescription, 
2532                                      DWORD dwFlags)
2533 {
2534     FIXME("(stub)\n");
2535     return FALSE;
2536 }
2537
2538 static const WCHAR szProviderKeys[3][97] = {
2539     {   'S','o','f','t','w','a','r','e','\\',
2540         'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r',
2541         'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v',
2542         'i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ','B','a','s',
2543         'e',' ','C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r',
2544         'o','v','i','d','e','r',' ','v','1','.','0',0 },
2545     {   'S','o','f','t','w','a','r','e','\\',
2546         'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r',
2547         'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v',
2548         'i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ',
2549         'E','n','h','a','n','c','e','d',
2550         ' ','C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r',
2551         'o','v','i','d','e','r',' ','v','1','.','0',0 },
2552     {   'S','o','f','t','w','a','r','e','\\',
2553         'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r',
2554         'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v',
2555         'i','d','e','r','\\','M','i','c','r','o','s','o','f','t',' ','S','t','r','o','n','g',
2556         ' ','C','r','y','p','t','o','g','r','a','p','h','i','c',' ','P','r',
2557         'o','v','i','d','e','r',0 }
2558 };
2559 static const WCHAR szDefaultKey[] = { 'S','o','f','t','w','a','r','e','\\',
2560  'M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g','r',
2561  'a','p','h','y','\\','D','e','f','a','u','l','t','s','\\','P','r','o','v',
2562  'i','d','e','r',' ','T','y','p','e','s','\\','T','y','p','e',' ','0','0','1',0};
2563
2564 /******************************************************************************
2565  * DllRegisterServer (RSAENH.@)
2566  *
2567  * Dll self registration. 
2568  *
2569  * PARAMS
2570  *
2571  * RETURNS
2572  *  Success: S_OK.
2573  *    Failure: != S_OK
2574  * 
2575  * NOTES
2576  *  Registers the following keys:
2577  *   - HKLM\Software\Microsoft\Cryptography\Defaults\Provider\
2578  *       Microsoft Base Cryptographic Provider v1.0
2579  *   - HKLM\Software\Microsoft\Cryptography\Defaults\Provider\
2580  *       Microsoft Enhanced Cryptographic Provider
2581  *   - HKLM\Software\Microsoft\Cryptography\Defaults\Provider\
2582  *       Microsoft Strong Cryptographpic Provider
2583  *   - HKLM\Software\Microsoft\Cryptography\Defaults\Provider Types\Type 001
2584  */
2585 HRESULT WINAPI RSAENH_DllRegisterServer()
2586 {
2587     HKEY key;
2588     DWORD dp;
2589     long apiRet;
2590     int i;
2591
2592     for (i=0; i<3; i++) {
2593         apiRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szProviderKeys[i], 0, NULL,
2594             REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &dp);
2595
2596         if (apiRet == ERROR_SUCCESS)
2597         {
2598             if (dp == REG_CREATED_NEW_KEY)
2599             {
2600                 static const WCHAR szImagePath[] = { 'I','m','a','g','e',' ','P','a','t','h',0 };
2601                 static const WCHAR szRSABase[] = { 'r','s','a','e','n','h','.','d','l','l',0 };
2602                 static const WCHAR szType[] = { 'T','y','p','e',0 };
2603                 static const WCHAR szSignature[] = { 'S','i','g','n','a','t','u','r','e',0 };
2604                 DWORD type = 1;
2605                 DWORD sign = 0xdeadbeef;
2606                 RegSetValueExW(key, szImagePath, 0, REG_SZ, (LPBYTE)szRSABase, 
2607                                (lstrlenW(szRSABase) + 1) * sizeof(WCHAR));
2608                 RegSetValueExW(key, szType, 0, REG_DWORD, (LPBYTE)&type, sizeof(type));
2609                 RegSetValueExW(key, szSignature, 0, REG_BINARY, (LPBYTE)&sign, sizeof(sign));
2610             }
2611             RegCloseKey(key);
2612         }
2613     }
2614     if (apiRet == ERROR_SUCCESS)
2615         apiRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, szDefaultKey, 0, NULL, REG_OPTION_NON_VOLATILE,
2616                                  KEY_ALL_ACCESS, NULL, &key, &dp);
2617     if (apiRet == ERROR_SUCCESS)
2618     {
2619         if (dp == REG_CREATED_NEW_KEY)
2620         {
2621             static const WCHAR szName[] = { 'N','a','m','e',0 };
2622             static const WCHAR szRSAName[] = {
2623               'M','i','c','r','o','s','o','f','t',' ','S','t','r','o','n','g',' ',
2624               'C','r','y','p','t','o','g','r','a','p','h','i','c',' ',
2625               'P','r','o','v','i','d','e','r',0 };
2626             static const WCHAR szTypeName[] = { 'T','y','p','e','N','a','m','e',0 };
2627             static const WCHAR szRSATypeName[] = {
2628               'R','S','A',' ','F','u','l','l',' ',
2629               '(','S','i','g','n','a','t','u','r','e',' ','a','n','d',' ',
2630               'K','e','y',' ','E','x','c','h','a','n','g','e',')',0 };
2631
2632             RegSetValueExW(key, szName, 0, REG_SZ, (LPBYTE)szRSAName, sizeof(szRSAName));
2633             RegSetValueExW(key, szTypeName, 0, REG_SZ, (LPBYTE)szRSATypeName,sizeof(szRSATypeName));
2634         }
2635         RegCloseKey(key);
2636     }
2637     return HRESULT_FROM_WIN32(apiRet);
2638 }
2639
2640 /******************************************************************************
2641  * DllUnregisterServer (RSAENH.@)
2642  *
2643  * Dll self unregistration. 
2644  *
2645  * PARAMS
2646  *
2647  * RETURNS
2648  *  Success: S_OK
2649  *
2650  * NOTES
2651  *  For the relevant keys see DllRegisterServer.
2652  */
2653 HRESULT WINAPI RSAENH_DllUnregisterServer()
2654 {
2655     RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[0]);
2656     RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[1]);
2657     RegDeleteKeyW(HKEY_LOCAL_MACHINE, szProviderKeys[2]);
2658     RegDeleteKeyW(HKEY_LOCAL_MACHINE, szDefaultKey);
2659     return S_OK;
2660 }