Run entire source base through GNU indent to tidy up the varying
[u/mdw/putty] / mscrypto.c
CommitLineData
8f203108 1#define _WIN32_WINNT 0x0400
2#include <windows.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <wincrypt.h>
6#include "ssh.h"
7
8void fatalbox(char *fmt, ...);
9
10static HCRYPTKEY create_des_key(unsigned char *key);
11
12
13HCRYPTPROV hCryptProv;
32874aea 14HCRYPTKEY hDESKey[2][3] = { {0, 0, 0}, {0, 0, 0} }; /* global for now */
8f203108 15
16
17/* use Microsoft Enhanced Cryptographic Service Provider */
18#define CSP MS_ENHANCED_PROV
19
20
32874aea 21static BYTE PrivateKeyWithExponentOfOne[] = {
8f203108 22 0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00,
23 0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00,
24 0x01, 0x00, 0x00, 0x00, 0xAB, 0xEF, 0xFA, 0xC6,
25 0x7D, 0xE8, 0xDE, 0xFB, 0x68, 0x38, 0x09, 0x92,
26 0xD9, 0x42, 0x7E, 0x6B, 0x89, 0x9E, 0x21, 0xD7,
27 0x52, 0x1C, 0x99, 0x3C, 0x17, 0x48, 0x4E, 0x3A,
28 0x44, 0x02, 0xF2, 0xFA, 0x74, 0x57, 0xDA, 0xE4,
29 0xD3, 0xC0, 0x35, 0x67, 0xFA, 0x6E, 0xDF, 0x78,
30 0x4C, 0x75, 0x35, 0x1C, 0xA0, 0x74, 0x49, 0xE3,
31 0x20, 0x13, 0x71, 0x35, 0x65, 0xDF, 0x12, 0x20,
32 0xF5, 0xF5, 0xF5, 0xC1, 0xED, 0x5C, 0x91, 0x36,
33 0x75, 0xB0, 0xA9, 0x9C, 0x04, 0xDB, 0x0C, 0x8C,
34 0xBF, 0x99, 0x75, 0x13, 0x7E, 0x87, 0x80, 0x4B,
35 0x71, 0x94, 0xB8, 0x00, 0xA0, 0x7D, 0xB7, 0x53,
36 0xDD, 0x20, 0x63, 0xEE, 0xF7, 0x83, 0x41, 0xFE,
37 0x16, 0xA7, 0x6E, 0xDF, 0x21, 0x7D, 0x76, 0xC0,
38 0x85, 0xD5, 0x65, 0x7F, 0x00, 0x23, 0x57, 0x45,
39 0x52, 0x02, 0x9D, 0xEA, 0x69, 0xAC, 0x1F, 0xFD,
40 0x3F, 0x8C, 0x4A, 0xD0,
41
42 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46
47 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51
52 0x64, 0xD5, 0xAA, 0xB1,
53 0xA6, 0x03, 0x18, 0x92, 0x03, 0xAA, 0x31, 0x2E,
54 0x48, 0x4B, 0x65, 0x20, 0x99, 0xCD, 0xC6, 0x0C,
55 0x15, 0x0C, 0xBF, 0x3E, 0xFF, 0x78, 0x95, 0x67,
56 0xB1, 0x74, 0x5B, 0x60,
57
58 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66};
67
68
69
70/* ---------------------------------------------------------*
71 * Utility functions *
72 * ---------------------------------------------------------*/
73
74
32874aea 75int crypto_startup()
76{
77 if (CryptAcquireContext(&hCryptProv, "Putty", CSP, PROV_RSA_FULL,
78 CRYPT_NEWKEYSET) == 0) {
79 if (GetLastError() == NTE_EXISTS) {
80 if (CryptAcquireContext(&hCryptProv, "Putty", CSP,
81 PROV_RSA_FULL, 0) == 0) {
82 return FALSE; /* failed to acquire context - probably
83 * don't have high encryption installed! */
8f203108 84 }
85 } else
32874aea 86 return FALSE; /* failed to acquire context - probably
87 * don't have high encryption installed! */
8f203108 88 }
89 return TRUE;
90}
91
92
32874aea 93void crypto_wrapup()
94{
8f203108 95 int i, j;
32874aea 96 for (i = 0; i < 2; i++) {
97 for (j = 0; j < 3; j++) {
98 if (hDESKey[i][j])
8f203108 99 CryptDestroyKey(hDESKey[i][j]);
100 hDESKey[i][j] = 0;
101 }
102 }
32874aea 103 if (hCryptProv)
8f203108 104 CryptReleaseContext(hCryptProv, 0);
105 hCryptProv = 0;
106}
107
108
109/* ---------------------------------------------------------*
110 * Random number functions *
111 * ---------------------------------------------------------*/
112
32874aea 113int random_byte(void)
114{
8f203108 115 unsigned char b;
32874aea 116 if (!CryptGenRandom(hCryptProv, 1, &b))
8f203108 117 fatalbox("random number generator failure!");
118 return b;
119}
120
32874aea 121void random_add_noise(void *noise, int length)
122{
8f203108 123 /* do nothing */
124}
32874aea 125void random_init(void)
126{
8f203108 127 /* do nothing */
128}
32874aea 129void random_get_savedata(void **data, int *len)
130{
8f203108 131 /* do nothing */
132}
32874aea 133void noise_get_heavy(void (*func) (void *, int))
134{
8f203108 135 /* do nothing */
136}
32874aea 137void noise_get_light(void (*func) (void *, int))
138{
8f203108 139 /* do nothing */
140}
32874aea 141void noise_ultralight(DWORD data)
142{
8f203108 143 /* do nothing */
144}
32874aea 145void random_save_seed(void)
146{
8f203108 147 /* do nothing */
148}
149
150
151/* ---------------------------------------------------------*
152 * MD5 hash functions *
153 * ---------------------------------------------------------*/
154
155
32874aea 156void MD5Init(struct MD5Context *ctx)
157{
158 if (!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &ctx->hHash))
8f203108 159 fatalbox("Error during CryptBeginHash!\n");
160}
161
162
163void MD5Update(struct MD5Context *ctx,
32874aea 164 unsigned char const *buf, unsigned len)
165{
166 if (CryptHashData(ctx->hHash, buf, len, 0) == 0)
8f203108 167 fatalbox("Error during CryptHashSessionKey!\n");
168}
169
170
32874aea 171void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
172{
8f203108 173 DWORD cb = 16;
32874aea 174 if (CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &cb, 0) == 0)
8f203108 175 fatalbox("Error during CryptGetHashParam!\n");
32874aea 176 if (ctx->hHash)
8f203108 177 CryptDestroyHash(ctx->hHash);
178 ctx->hHash = 0;
179}
180
181
182/* ---------------------------------------------------------*
183 * RSA public key functions *
184 * ---------------------------------------------------------*/
185
186int makekey(unsigned char *data, struct RSAKey *result,
32874aea 187 unsigned char **keystr)
188{
8f203108 189
190 unsigned char *p = data;
191 int i;
192 int w, b;
193
194 /* get size (bits) of modulus */
195 result->bits = 0;
32874aea 196 for (i = 0; i < 4; i++)
8f203108 197 result->bits = (result->bits << 8) + *p++;
198
199 /* get size (bits) of public exponent */
200 w = 0;
32874aea 201 for (i = 0; i < 2; i++)
8f203108 202 w = (w << 8) + *p++;
32874aea 203 b = (w + 7) / 8; /* bits -> bytes */
8f203108 204
205 /* convert exponent to DWORD */
206 result->exponent = 0;
32874aea 207 for (i = 0; i < b; i++)
8f203108 208 result->exponent = (result->exponent << 8) + *p++;
209
210 /* get size (bits) of modulus */
211 w = 0;
32874aea 212 for (i = 0; i < 2; i++)
8f203108 213 w = (w << 8) + *p++;
32874aea 214 result->bytes = b = (w + 7) / 8; /* bits -> bytes */
8f203108 215
216 /* allocate buffer for modulus & copy it */
217 result->modulus = malloc(b);
218 memcpy(result->modulus, p, b);
219
220 /* update callers pointer */
32874aea 221 if (keystr)
222 *keystr = p; /* point at key string, second time */
8f203108 223
224 return (p - data) + b;
225}
226
227
32874aea 228void rsaencrypt(unsigned char *data, int length, struct RSAKey *rsakey)
229{
8f203108 230
231 int i;
232 unsigned char *pKeybuf, *pKeyin;
233 HCRYPTKEY hRsaKey;
234 PUBLICKEYSTRUC *pBlob;
235 RSAPUBKEY *pRPK;
236 unsigned char *buf;
237 DWORD dlen;
238 DWORD bufsize;
239
240 /* allocate buffer for public key blob */
32874aea 241 if ((pBlob = malloc(sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) +
242 rsakey->bytes)) == NULL)
8f203108 243 fatalbox("Out of memory");
244
245 /* allocate buffer for message encryption block */
246 bufsize = (length + rsakey->bytes) << 1;
32874aea 247 if ((buf = malloc(bufsize)) == NULL)
8f203108 248 fatalbox("Out of memory");
249
250 /* construct public key blob from host public key */
32874aea 251 pKeybuf = ((unsigned char *) pBlob) + sizeof(PUBLICKEYSTRUC) +
8f203108 252 sizeof(RSAPUBKEY);
32874aea 253 pKeyin = ((unsigned char *) rsakey->modulus);
8f203108 254 /* change big endian to little endian */
32874aea 255 for (i = 0; i < rsakey->bytes; i++)
256 pKeybuf[i] = pKeyin[rsakey->bytes - i - 1];
8f203108 257 pBlob->bType = PUBLICKEYBLOB;
258 pBlob->bVersion = 0x02;
259 pBlob->reserved = 0;
260 pBlob->aiKeyAlg = CALG_RSA_KEYX;
32874aea 261 pRPK =
262 (RSAPUBKEY *) (((unsigned char *) pBlob) + sizeof(PUBLICKEYSTRUC));
263 pRPK->magic = 0x31415352; /* "RSA1" */
8f203108 264 pRPK->bitlen = rsakey->bits;
265 pRPK->pubexp = rsakey->exponent;
266
267 /* import public key blob into key container */
32874aea 268 if (CryptImportKey(hCryptProv, (void *) pBlob,
269 sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) +
270 rsakey->bytes, 0, 0, &hRsaKey) == 0)
8f203108 271 fatalbox("Error importing RSA key!");
272
273 /* copy message into buffer */
274 memcpy(buf, data, length);
275 dlen = length;
276
277 /* using host public key, encrypt the message */
32874aea 278 if (CryptEncrypt(hRsaKey, 0, TRUE, 0, buf, &dlen, bufsize) == 0)
8f203108 279 fatalbox("Error encrypting using RSA key!");
280
281 /*
282 * For some strange reason, Microsoft CryptEncrypt using public
283 * key, returns the cyphertext in backwards (little endian)
284 * order, so reverse it!
285 */
32874aea 286 for (i = 0; i < (int) dlen; i++)
287 data[i] = buf[dlen - i - 1]; /* make it big endian */
8f203108 288
289 CryptDestroyKey(hRsaKey);
290 free(buf);
291 free(pBlob);
292
293}
294
295
32874aea 296int rsastr_len(struct RSAKey *key)
297{
8f203108 298 return 2 * (sizeof(DWORD) + key->bytes) + 10;
299}
300
301
32874aea 302void rsastr_fmt(char *str, struct RSAKey *key)
303{
8f203108 304
305 int len = 0, i;
306
32874aea 307 sprintf(str + len, "%04x", key->exponent);
308 len += strlen(str + len);
8f203108 309
310 str[len++] = '/';
32874aea 311 for (i = 1; i < key->bytes; i++) {
312 sprintf(str + len, "%02x", key->modulus[i]);
313 len += strlen(str + len);
8f203108 314 }
315 str[len] = '\0';
316}
317
318
319
320/* ---------------------------------------------------------*
321 * DES encryption / decryption functions *
322 * ---------------------------------------------------------*/
323
324
32874aea 325void des3_sesskey(unsigned char *key)
326{
8f203108 327 int i, j;
32874aea 328 for (i = 0; i < 2; i++) {
329 for (j = 0; j < 3; j++) {
8f203108 330 hDESKey[i][j] = create_des_key(key + (j * 8));
331 }
332 }
333}
334
335
32874aea 336void des3_encrypt_blk(unsigned char *blk, int len)
337{
8f203108 338
339 DWORD dlen;
340 dlen = len;
341
32874aea 342 if (CryptEncrypt(hDESKey[0][0], 0, FALSE, 0, blk, &dlen, len + 8) == 0)
8f203108 343 fatalbox("Error encrypting block!\n");
32874aea 344 if (CryptDecrypt(hDESKey[0][1], 0, FALSE, 0, blk, &dlen) == 0)
8f203108 345 fatalbox("Error encrypting block!\n");
32874aea 346 if (CryptEncrypt(hDESKey[0][2], 0, FALSE, 0, blk, &dlen, len + 8) == 0)
8f203108 347 fatalbox("Error encrypting block!\n");
348}
349
350
32874aea 351void des3_decrypt_blk(unsigned char *blk, int len)
352{
8f203108 353 DWORD dlen;
354 dlen = len;
355
32874aea 356 if (CryptDecrypt(hDESKey[1][2], 0, FALSE, 0, blk, &dlen) == 0)
8f203108 357 fatalbox("Error decrypting block!\n");
32874aea 358 if (CryptEncrypt(hDESKey[1][1], 0, FALSE, 0, blk, &dlen, len + 8) == 0)
8f203108 359 fatalbox("Error decrypting block!\n");
32874aea 360 if (CryptDecrypt(hDESKey[1][0], 0, FALSE, 0, blk, &dlen) == 0)
8f203108 361 fatalbox("Error decrypting block!\n");
362}
363
364
365struct ssh_cipher ssh_3des = {
366 des3_sesskey,
367 des3_encrypt_blk,
368 des3_decrypt_blk
369};
370
371
32874aea 372void des_sesskey(unsigned char *key)
373{
8f203108 374 int i;
32874aea 375 for (i = 0; i < 2; i++) {
8f203108 376 hDESKey[i][0] = create_des_key(key);
377 }
378}
379
380
32874aea 381void des_encrypt_blk(unsigned char *blk, int len)
382{
8f203108 383 DWORD dlen;
384 dlen = len;
32874aea 385 if (CryptEncrypt(hDESKey[0][0], 0, FALSE, 0, blk, &dlen, len + 8) == 0)
8f203108 386 fatalbox("Error encrypting block!\n");
387}
388
389
32874aea 390void des_decrypt_blk(unsigned char *blk, int len)
391{
8f203108 392 DWORD dlen;
393 dlen = len;
32874aea 394 if (CryptDecrypt(hDESKey[1][0], 0, FALSE, 0, blk, &dlen) == 0)
8f203108 395 fatalbox("Error decrypting block!\n");
396}
397
398struct ssh_cipher ssh_des = {
399 des_sesskey,
400 des_encrypt_blk,
401 des_decrypt_blk
402};
403
404
32874aea 405static HCRYPTKEY create_des_key(unsigned char *key)
406{
8f203108 407
408 HCRYPTKEY hSessionKey, hPrivateKey;
409 DWORD dlen = 8;
410 BLOBHEADER *pbh;
411 char buf[sizeof(BLOBHEADER) + sizeof(ALG_ID) + 256];
412
413 /*
414 * Need special private key to encrypt session key so we can
415 * import session key, since only encrypted session keys can be
416 * imported
417 */
32874aea 418 if (CryptImportKey(hCryptProv, PrivateKeyWithExponentOfOne,
419 sizeof(PrivateKeyWithExponentOfOne),
420 0, 0, &hPrivateKey) == 0)
8f203108 421 return 0;
422
423 /* now encrypt session key using special private key */
424 memcpy(buf + sizeof(BLOBHEADER) + sizeof(ALG_ID), key, 8);
32874aea 425 if (CryptEncrypt(hPrivateKey, 0, TRUE, 0,
426 buf + sizeof(BLOBHEADER) + sizeof(ALG_ID),
427 &dlen, 256) == 0)
8f203108 428 return 0;
429
430 /* build session key blob */
32874aea 431 pbh = (BLOBHEADER *) buf;
8f203108 432 pbh->bType = SIMPLEBLOB;
433 pbh->bVersion = 0x02;
434 pbh->reserved = 0;
435 pbh->aiKeyAlg = CALG_DES;
32874aea 436 *((ALG_ID *) (buf + sizeof(BLOBHEADER))) = CALG_RSA_KEYX;
8f203108 437
438 /* import session key into key container */
32874aea 439 if (CryptImportKey(hCryptProv, buf,
440 dlen + sizeof(BLOBHEADER) + sizeof(ALG_ID),
441 hPrivateKey, 0, &hSessionKey) == 0)
8f203108 442 return 0;
443
32874aea 444 if (hPrivateKey)
8f203108 445 CryptDestroyKey(hPrivateKey);
446
447 return hSessionKey;
448
449}