mirror of https://github.com/OpenVPN/openvpn-gui
Browse Source
- Username and, optionally, password as well as the private key passphrase are saved in config-specific registry keys - All saved data are kept encrypted using DPAPI - The passphrase dialog is skipped if a valid saved private key password is available. However, the user-auth dialog is always presented, prefilled with the saved username and password. Note: A text string "Save password" is added to three dialogs in all language resource files. Additional text with ids IDS_MENU_CLEARPASS and IDS_NFO_DELETE_PASS are added to the STRINGTABLE only in the English language resource file. All these need translations. Signed-off-by: Selva Nair <selva.nair@gmail.com>pull/52/head
Selva Nair
9 years ago
32 changed files with 691 additions and 157 deletions
@ -0,0 +1,263 @@
|
||||
#ifdef HAVE_CONFIG_H |
||||
#include "config.h" |
||||
#endif |
||||
|
||||
#include <windows.h> |
||||
#include <wincrypt.h> |
||||
|
||||
#include "main.h" |
||||
#include "registry.h" |
||||
#include "save_pass.h" |
||||
#include "passphrase.h" |
||||
|
||||
#define KEY_PASS_DATA L"key-data" |
||||
#define AUTH_PASS_DATA L"auth-data" |
||||
#define ENTROPY_DATA L"entropy" |
||||
#define AUTH_USER_DATA L"username" |
||||
#define ENTROPY_LEN 16 |
||||
|
||||
static DWORD |
||||
crypt_protect(BYTE *data, int szdata, char *entropy, BYTE **out) |
||||
{ |
||||
DATA_BLOB data_out; |
||||
DATA_BLOB data_in; |
||||
DATA_BLOB e; |
||||
|
||||
data_in.pbData = data; |
||||
data_in.cbData = szdata; |
||||
e.pbData = (BYTE*) entropy; |
||||
e.cbData = entropy? strlen(entropy) : 0; |
||||
|
||||
if(CryptProtectData(&data_in, NULL, &e, NULL, NULL, 0, &data_out)) |
||||
{ |
||||
*out = data_out.pbData; |
||||
return data_out.cbData; |
||||
} |
||||
PrintDebug(L"CryptProtectData failed (error = %lu)", GetLastError()); |
||||
return 0; |
||||
} |
||||
|
||||
static DWORD |
||||
crypt_unprotect(BYTE *data, int szdata, char *entropy, BYTE **out) |
||||
{ |
||||
DATA_BLOB data_in; |
||||
DATA_BLOB data_out = {0,0}; |
||||
DATA_BLOB e; |
||||
|
||||
data_in.pbData = data; |
||||
data_in.cbData = szdata; |
||||
e.pbData = (BYTE *) entropy; |
||||
e.cbData = entropy? strlen(entropy) : 0; |
||||
|
||||
if(CryptUnprotectData(&data_in, NULL, &e, NULL, NULL, 0, &data_out)) |
||||
{ |
||||
*out = data_out.pbData; |
||||
return data_out.cbData; |
||||
} |
||||
else |
||||
{ |
||||
PrintDebug(L"CryptUnprotectData: decryption failed"); |
||||
LocalFree (data_out.pbData); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* If not found in registry and generate is true, a new nul terminated |
||||
* random string is generated and saved in registry. |
||||
* Else a zero-length string is returned and registry is not updated. |
||||
*/ |
||||
static void |
||||
get_entropy(const WCHAR *config_name, char *e, int sz, BOOL generate) |
||||
{ |
||||
int len; |
||||
|
||||
len = GetConfigRegistryValue(config_name, ENTROPY_DATA, (BYTE *) e, sz); |
||||
if (len > 0) |
||||
{ |
||||
e[len-1] = '\0'; |
||||
PrintDebug(L"Got entropy from registry: %S (len = %d)", e, len); |
||||
return; |
||||
} |
||||
else if (generate && GetRandomPassword(e, sz)) |
||||
{ |
||||
e[sz-1] = '\0'; |
||||
PrintDebug(L"Created new entropy string : %S", e); |
||||
if (SetConfigRegistryValueBinary(config_name, ENTROPY_DATA, (BYTE *)e, sz)) |
||||
return; |
||||
} |
||||
if (generate) |
||||
PrintDebug(L"Failed to generate or save new entropy string -- using null string"); |
||||
*e = '\0'; |
||||
return; |
||||
} |
||||
/*
|
||||
* Given a nul terminated string password, encrypt it and save in |
||||
* a config specific registry key with specified name. |
||||
* Returns 1 on success. |
||||
*/ |
||||
static int |
||||
save_encrypted(const WCHAR *config_name, const WCHAR *password, const WCHAR *name) |
||||
{ |
||||
BYTE *out; |
||||
DWORD len = (wcslen(password) + 1) * sizeof(WCHAR); |
||||
char entropy[ENTROPY_LEN+1]; |
||||
|
||||
get_entropy(config_name, entropy, sizeof(entropy), true); |
||||
len = crypt_protect((BYTE*) password, len, entropy, &out); |
||||
if(len > 0) |
||||
{ |
||||
SetConfigRegistryValueBinary(config_name, name, out, len); |
||||
LocalFree(out); |
||||
return 1; |
||||
} |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Encrypt the nul terminated string password and store it in the |
||||
* registry with key name KEY_PASS_DATA. Returns 1 on success. |
||||
*/ |
||||
int |
||||
SaveKeyPass(const WCHAR *config_name, const WCHAR *password) |
||||
{ |
||||
return save_encrypted(config_name, password, KEY_PASS_DATA); |
||||
} |
||||
|
||||
/*
|
||||
* Encrypt the nul terminated string password and store it in the |
||||
* registry with key name AUTH_PASS_DATA. Returns 1 on success. |
||||
*/ |
||||
int |
||||
SaveAuthPass(const WCHAR *config_name, const WCHAR *password) |
||||
{ |
||||
return save_encrypted(config_name, password, AUTH_PASS_DATA); |
||||
} |
||||
|
||||
/*
|
||||
* Returns 1 on success, 0 on failure. password should have space |
||||
* for up to capacity wide chars incluing nul termination |
||||
*/ |
||||
static int |
||||
recall_encrypted(const WCHAR *config_name, WCHAR *password, DWORD capacity, const WCHAR *name) |
||||
{ |
||||
BYTE in[2048]; |
||||
BYTE *out; |
||||
DWORD len; |
||||
int retval = 0; |
||||
char entropy[ENTROPY_LEN+1]; |
||||
|
||||
get_entropy(config_name, entropy, sizeof(entropy), false); |
||||
|
||||
memset (password, 0, capacity); |
||||
|
||||
len = GetConfigRegistryValue(config_name, name, in, sizeof(in)); |
||||
if(len == 0) |
||||
return 0; |
||||
|
||||
len = crypt_unprotect(in, len, entropy, &out); |
||||
if(len == 0) |
||||
return 0; |
||||
|
||||
if (len <= capacity * sizeof(*password)) |
||||
{ |
||||
memcpy(password, out, len); |
||||
password[capacity-1] = L'\0'; /* in case the data was corrupted */ |
||||
retval = 1; |
||||
} |
||||
else |
||||
PrintDebug(L"recall_encrypted: saved '%s' too long (len = %d bytes)", name, len); |
||||
|
||||
SecureZeroMemory(out, len); |
||||
LocalFree(out); |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
/*
|
||||
* Reccall saved private key password. The buffer password should be |
||||
* have space for up to KEY_PASS_LEN WCHARs including nul. |
||||
* Returns 1 on success, 0 on failure. |
||||
*/ |
||||
int |
||||
RecallKeyPass(const WCHAR *config_name, WCHAR *password) |
||||
{ |
||||
return recall_encrypted(config_name, password, KEY_PASS_LEN, KEY_PASS_DATA); |
||||
} |
||||
|
||||
/*
|
||||
* Reccall saved auth password. The buffer password should be |
||||
* have space for up to USER_PASS_LEN WCHARs including nul. |
||||
* Returns 1 on success, 0 on failure. |
||||
*/ |
||||
int |
||||
RecallAuthPass(const WCHAR *config_name, WCHAR *password) |
||||
{ |
||||
return recall_encrypted(config_name, password, USER_PASS_LEN, AUTH_PASS_DATA); |
||||
} |
||||
|
||||
int |
||||
SaveUsername(const WCHAR *config_name, const WCHAR *username) |
||||
{ |
||||
DWORD len = (wcslen(username) + 1) * sizeof(*username); |
||||
SetConfigRegistryValueBinary(config_name, AUTH_USER_DATA,(BYTE *) username, len); |
||||
return 1; |
||||
} |
||||
/*
|
||||
* The buffer username should be have space for up to USER_PASS_LEN |
||||
* WCHARs including nul. |
||||
*/ |
||||
int |
||||
RecallUsername(const WCHAR *config_name, WCHAR *username) |
||||
{ |
||||
DWORD capacity = USER_PASS_LEN * sizeof(WCHAR); |
||||
DWORD len; |
||||
|
||||
len = GetConfigRegistryValue(config_name, AUTH_USER_DATA, (BYTE *) username, capacity); |
||||
if (len == 0) |
||||
return 0; |
||||
username[USER_PASS_LEN-1] = L'\0'; |
||||
return 1; |
||||
} |
||||
|
||||
void |
||||
DeleteSavedKeyPass(const WCHAR *config_name) |
||||
{ |
||||
DeleteConfigRegistryValue(config_name, KEY_PASS_DATA); |
||||
} |
||||
|
||||
void |
||||
DeleteSavedAuthPass(const WCHAR *config_name) |
||||
{ |
||||
DeleteConfigRegistryValue(config_name, AUTH_PASS_DATA); |
||||
} |
||||
|
||||
/* delete saved config-specific auth password and private key passphrase */ |
||||
void |
||||
DeleteSavedPasswords(const WCHAR *config_name) |
||||
{ |
||||
DeleteConfigRegistryValue(config_name, KEY_PASS_DATA); |
||||
DeleteConfigRegistryValue(config_name, AUTH_PASS_DATA); |
||||
DeleteConfigRegistryValue(config_name, ENTROPY_DATA); |
||||
} |
||||
|
||||
/* check if auth password is saved */ |
||||
BOOL |
||||
IsAuthPassSaved(const WCHAR *config_name) |
||||
{ |
||||
DWORD len = 0; |
||||
len = GetConfigRegistryValue(config_name, AUTH_PASS_DATA, NULL, 0); |
||||
PrintDebug(L"checking auth-pass-data in registry returned len = %d", len); |
||||
return (len > 0); |
||||
} |
||||
|
||||
/* check if key password is saved */ |
||||
BOOL |
||||
IsKeyPassSaved(const WCHAR *config_name) |
||||
{ |
||||
DWORD len = 0; |
||||
len = GetConfigRegistryValue(config_name, KEY_PASS_DATA, NULL, 0); |
||||
PrintDebug(L"checking key-pass-data in registry returned len = %d", len); |
||||
return (len > 0); |
||||
} |
@ -0,0 +1,23 @@
|
||||
#ifndef SAVEPASS_H |
||||
#define SAVEPASS_H |
||||
|
||||
#include <wchar.h> |
||||
|
||||
#define USER_PASS_LEN 128 |
||||
#define KEY_PASS_LEN 128 |
||||
|
||||
int SaveKeyPass(const WCHAR *config_name, const WCHAR *password); |
||||
int SaveAuthPass(const WCHAR *config_name, const WCHAR *password); |
||||
int SaveUsername(const WCHAR *config_name, const WCHAR *username); |
||||
|
||||
int RecallKeyPass(const WCHAR *config_name, WCHAR *password); |
||||
int RecallAuthPass(const WCHAR *config_name, WCHAR *password); |
||||
int RecallUsername(const WCHAR *config_name, WCHAR *username); |
||||
|
||||
void DeleteSavedAuthPass(const WCHAR *config_name); |
||||
void DeleteSavedKeyPass(const WCHAR *config_name); |
||||
void DeleteSavedPasswords(const WCHAR *config_name); |
||||
|
||||
BOOL IsAuthPassSaved(const WCHAR *config_name); |
||||
BOOL IsKeyPassSaved(const WCHAR *config_name); |
||||
#endif |
Loading…
Reference in new issue