wincapi.c 2.6 KB

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