cryptoapi.c 2.6 KB

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