1 /*
2 * wincapi.c: implementation of wincapi.h.
3 */
4
5 #include "putty.h"
6
7 #if !defined NO_SECURITY
8
9 #include "putty.h"
10 #include "ssh.h"
11
12 #include "wincapi.h"
13
14 DEF_WINDOWS_FUNCTION(CryptProtectMemory);
15
got_crypt(void)16 bool got_crypt(void)
17 {
18 static bool attempted = false;
19 static bool successful;
20 static HMODULE crypt;
21
22 if (!attempted) {
23 attempted = true;
24 crypt = load_system32_dll("crypt32.dll");
25 successful = crypt &&
26 GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory);
27 }
28 return successful;
29 }
30
capi_obfuscate_string(const char * realname)31 char *capi_obfuscate_string(const char *realname)
32 {
33 char *cryptdata;
34 int cryptlen;
35 unsigned char digest[32];
36 char retbuf[65];
37 int i;
38
39 cryptlen = strlen(realname) + 1;
40 cryptlen += CRYPTPROTECTMEMORY_BLOCK_SIZE - 1;
41 cryptlen /= CRYPTPROTECTMEMORY_BLOCK_SIZE;
42 cryptlen *= CRYPTPROTECTMEMORY_BLOCK_SIZE;
43
44 cryptdata = snewn(cryptlen, char);
45 memset(cryptdata, 0, cryptlen);
46 strcpy(cryptdata, realname);
47
48 /*
49 * CRYPTPROTECTMEMORY_CROSS_PROCESS causes CryptProtectMemory to
50 * use the same key in all processes with this user id, meaning
51 * that the next PuTTY process calling this function with the same
52 * input will get the same data.
53 *
54 * (Contrast with CryptProtectData, which invents a new session
55 * key every time since its API permits returning more data than
56 * was input, so calling _that_ and hashing the output would not
57 * be stable.)
58 *
59 * We don't worry too much if this doesn't work for some reason.
60 * Omitting this step still has _some_ privacy value (in that
61 * another user can test-hash things to confirm guesses as to
62 * where you might be connecting to, but cannot invert SHA-256 in
63 * the absence of any plausible guess). So we don't abort if we
64 * can't call CryptProtectMemory at all, or if it fails.
65 */
66 if (got_crypt())
67 p_CryptProtectMemory(cryptdata, cryptlen,
68 CRYPTPROTECTMEMORY_CROSS_PROCESS);
69
70 /*
71 * We don't want to give away the length of the hostname either,
72 * so having got it back out of CryptProtectMemory we now hash it.
73 */
74 {
75 ssh_hash *h = ssh_hash_new(&ssh_sha256);
76 put_string(h, cryptdata, cryptlen);
77 ssh_hash_final(h, digest);
78 }
79
80 sfree(cryptdata);
81
82 /*
83 * Finally, make printable.
84 */
85 for (i = 0; i < 32; i++) {
86 sprintf(retbuf + 2*i, "%02x", digest[i]);
87 /* the last of those will also write the trailing NUL */
88 }
89
90 return dupstr(retbuf);
91 }
92
93 #endif /* !defined NO_SECURITY */
94