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