mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
25f7f8c025
The declarations in header files now use ordinary 'extern'. That means I have to arrange to put definitions matching those declarations in the appropriate modules; so I've made a macro DEFINE_WINDOWS_FUNCTION which performs a definition matching a prior DECLARE_WINDOWS_FUNCTION (and reusing the typedef made by the latter). This applies not only to the batch of functions that were marked GLOBAL in winstuff.h, but also the auxiliary sets marked WINCAPI_GLOBAL and WINSECUR_GLOBAL in wincapi.h and winsecur.h respectively.
113 lines
3.2 KiB
C
113 lines
3.2 KiB
C
/*
|
|
* wincapi.c: implementation of wincapi.h.
|
|
*/
|
|
|
|
#include "putty.h"
|
|
|
|
#if !defined NO_SECURITY
|
|
|
|
#include "putty.h"
|
|
#include "ssh.h"
|
|
|
|
#include "wincapi.h"
|
|
|
|
DEF_WINDOWS_FUNCTION(CryptProtectMemory);
|
|
|
|
bool got_crypt(void)
|
|
{
|
|
static bool attempted = false;
|
|
static bool successful;
|
|
static HMODULE crypt;
|
|
|
|
if (!attempted) {
|
|
attempted = true;
|
|
crypt = load_system32_dll("crypt32.dll");
|
|
successful = crypt &&
|
|
#ifdef COVERITY
|
|
/* The build toolchain I use with Coverity doesn't know
|
|
* about this function, so can't type-check it */
|
|
GET_WINDOWS_FUNCTION_NO_TYPECHECK(crypt, CryptProtectMemory)
|
|
#else
|
|
GET_WINDOWS_FUNCTION(crypt, CryptProtectMemory)
|
|
#endif
|
|
;
|
|
}
|
|
return successful;
|
|
}
|
|
|
|
#ifdef COVERITY
|
|
/*
|
|
* The hack I use to build for Coverity scanning, using winegcc and
|
|
* Makefile.mgw, didn't provide some defines in wincrypt.h last time I
|
|
* looked. Therefore, define them myself here, but enclosed in #ifdef
|
|
* COVERITY to ensure I don't make up random nonsense values for any
|
|
* real build.
|
|
*/
|
|
#ifndef CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
#define CRYPTPROTECTMEMORY_BLOCK_SIZE 16
|
|
#endif
|
|
#ifndef CRYPTPROTECTMEMORY_CROSS_PROCESS
|
|
#define CRYPTPROTECTMEMORY_CROSS_PROCESS 1
|
|
#endif
|
|
#endif
|
|
|
|
char *capi_obfuscate_string(const char *realname)
|
|
{
|
|
char *cryptdata;
|
|
int cryptlen;
|
|
unsigned char digest[32];
|
|
char retbuf[65];
|
|
int i;
|
|
|
|
cryptlen = strlen(realname) + 1;
|
|
cryptlen += CRYPTPROTECTMEMORY_BLOCK_SIZE - 1;
|
|
cryptlen /= CRYPTPROTECTMEMORY_BLOCK_SIZE;
|
|
cryptlen *= CRYPTPROTECTMEMORY_BLOCK_SIZE;
|
|
|
|
cryptdata = snewn(cryptlen, char);
|
|
memset(cryptdata, 0, cryptlen);
|
|
strcpy(cryptdata, realname);
|
|
|
|
/*
|
|
* CRYPTPROTECTMEMORY_CROSS_PROCESS causes CryptProtectMemory to
|
|
* use the same key in all processes with this user id, meaning
|
|
* that the next PuTTY process calling this function with the same
|
|
* input will get the same data.
|
|
*
|
|
* (Contrast with CryptProtectData, which invents a new session
|
|
* key every time since its API permits returning more data than
|
|
* was input, so calling _that_ and hashing the output would not
|
|
* be stable.)
|
|
*
|
|
* We don't worry too much if this doesn't work for some reason.
|
|
* Omitting this step still has _some_ privacy value (in that
|
|
* another user can test-hash things to confirm guesses as to
|
|
* where you might be connecting to, but cannot invert SHA-256 in
|
|
* the absence of any plausible guess). So we don't abort if we
|
|
* can't call CryptProtectMemory at all, or if it fails.
|
|
*/
|
|
if (got_crypt())
|
|
p_CryptProtectMemory(cryptdata, cryptlen,
|
|
CRYPTPROTECTMEMORY_CROSS_PROCESS);
|
|
|
|
/*
|
|
* We don't want to give away the length of the hostname either,
|
|
* so having got it back out of CryptProtectMemory we now hash it.
|
|
*/
|
|
hash_simple(&ssh_sha256, make_ptrlen(cryptdata, cryptlen), digest);
|
|
|
|
sfree(cryptdata);
|
|
|
|
/*
|
|
* Finally, make printable.
|
|
*/
|
|
for (i = 0; i < 32; i++) {
|
|
sprintf(retbuf + 2*i, "%02x", digest[i]);
|
|
/* the last of those will also write the trailing NUL */
|
|
}
|
|
|
|
return dupstr(retbuf);
|
|
}
|
|
|
|
#endif /* !defined NO_SECURITY */
|