From: Florian Forster Date: Tue, 28 Jan 2014 20:49:40 +0000 (+0100) Subject: libcollectdclient: Add encryption support for Windows. X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=aa1bb336496e7ae6e4d3a672d0aa994ee0b07156;p=collectd.git libcollectdclient: Add encryption support for Windows. --- diff --git a/src/libcollectdclient/network_buffer.c b/src/libcollectdclient/network_buffer.c index 44a58c81..83a3ba8e 100644 --- a/src/libcollectdclient/network_buffer.c +++ b/src/libcollectdclient/network_buffer.c @@ -125,7 +125,11 @@ struct lcc_network_buffer_s char *username; char *password; -#if HAVE_LIBGCRYPT +#if WIN32 + HCRYPTPROV hProv; + size_t encr_header_len; + BYTE encr_iv[16]; +#elif HAVE_LIBGCRYPT gcry_cipher_hd_t encr_cypher; size_t encr_header_len; char encr_iv[16]; @@ -521,7 +525,6 @@ static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */ return (0); } /* }}} int nb_add_value_list */ -/* TODO: Add encryption for Windows */ #if WIN32 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ { @@ -531,7 +534,6 @@ static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ BYTE hash[32] = { 0 }; DWORD hash_size = sizeof (hash) / sizeof (hash[0]); - HCRYPTPROV hProv; HCRYPTHASH hHash; HCRYPTKEY hKey; BOOL status; @@ -543,15 +545,18 @@ static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE)); buffer_size = (DWORD) (nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE)); - status = CryptAcquireContext (&hProv, - /* szContainer = */ NULL, - /* CSP name = */ NULL, - /* provider type = */ PROV_RSA_AES, - /* flags = */ CRYPT_VERIFYCONTEXT); - if (!status) - return (-1); + if (!nb->hProv) + { + status = CryptAcquireContext (&nb->hProv, + /* szContainer = */ NULL, + /* CSP name = */ NULL, + /* provider type = */ PROV_RSA_AES, + /* flags = */ CRYPT_VERIFYCONTEXT); + if (!status) + return (-1); + } - status = CreateHMAC (hProv, + status = CreateHMAC (nb->hProv, /* algorithm = */ CALG_SHA_256, /* lpbKey = */ (LPBYTE) nb->password, /* dwKeySize = */ (DWORD) strlen (nb->password), @@ -559,10 +564,7 @@ static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ /* lphHash = */ &hHash, /* lphKey = */ &hKey); if (!status) - { - CryptReleaseContext (hProv, /* dwFlags = */ 0); return (-1); - } status = CryptHashData (hHash, /* pbData = */ buffer, @@ -572,7 +574,6 @@ static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ { CryptDestroyHash (hHash); CryptDestroyKey (hKey); - CryptReleaseContext (hProv, /* dwFlags = */ 0); return (-1); } @@ -585,7 +586,6 @@ static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ { CryptDestroyHash (hHash); CryptDestroyKey (hKey); - CryptReleaseContext (hProv, /* dwFlags = */ 0); return (-1); } @@ -594,9 +594,185 @@ static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ CryptDestroyHash (hHash); CryptDestroyKey (hKey); - CryptReleaseContext (hProv, /* dwFlags = */ 0); return (0); } /* }}} int nb_add_signature */ + +static int nb_key_from_password (HCRYPTPROV hProv, /* {{{ */ + LPCSTR pbPassword, LPBYTE pbIv, HCRYPTKEY *phKey) +{ + HCRYPTHASH hHash = 0; + HCRYPTKEY hKey = 0; + + struct + { + PUBLICKEYSTRUC pks; + DWORD dwKeySize; + BYTE pbKey[32]; + } keyData; + DWORD cypherMode = CRYPT_MODE_OFB; + + BOOL status; + + memset (&keyData, 0, sizeof (keyData)); + keyData.pks.bType = PLAINTEXTKEYBLOB; + keyData.pks.bVersion = CUR_BLOB_VERSION; + keyData.pks.reserved = 0; + keyData.dwKeySize = 32; + + status = CryptCreateHash (hProv, + /* algorithm = */ CALG_SHA_256, + /* hKey = */ 0, + /* dwFlags = */ 0, + /* out phHash = */ &hHash); + if (!status) + return (-1); + + status = CryptHashData (hHash, + /* pbData = */ (void *) pbPassword, + /* dwDataSize = */ strlen (pbPassword), + /* dwFlags = */ 0); + if (!status) + { + CryptDestroyHash (hHash); + return (-1); + } + + status = CryptGetHashParam (hHash, + /* dwParam = */ HP_HASHVAL, + /* pbData = */ keyData.pbKey, + /* pwdDataLen = */ &keyData.dwKeySize, + /* dwFlags = */ 0); + if (!status) + { + CryptDestroyHash (hHash); + return (-1); + } + CryptDestroyHash (hHash); + assert (keyData.dwKeySize == 32); + + status = CryptImportKey (hProv, + /* pbData = */ (void *) &keyData, + /* dwDataLen = */ sizeof (keyData), + /* hPubKey = */ 0, + /* dwFlags = */ 0, + /* phKey = */ &hKey); + if (!status) + return (-1); + + status = CryptSetKeyParam (hKey, + /* dwParam = */ KP_MODE, + /* pbData = */ (void *) &cypherMode, + /* dwFlags = */ 0); + if (!status) + { + CryptDestroyKey (hKey); + return (-1); + } + + status = CryptSetKeyParam (hKey, + /* dwParam = */ KP_IV, + /* pbData = */ (void *) pbIv, + /* dwFlags = */ 0); + if (!status) + { + CryptDestroyKey (hKey); + return (-1); + } + + *phKey = hKey; + return (0); +} /* }}} nb_key_from_password */ + +static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */ +{ + HCRYPTHASH hHash = 0; + HCRYPTKEY hKey = 0; + DWORD package_length; + BYTE *encr_ptr; /* pointer to data being encrypted */ + DWORD encr_size; + + BYTE *hash_data_ptr; /* pointer to data being hashed */ + DWORD hash_data_size; + DWORD hash_code_size = 20; + + WORD pkg_length; + BOOL status; + + /* Fill in the package length */ + package_length = nb->size - nb->free; + pkg_length = htons ((uint16_t) package_length); + memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length)); + + /* Calculate what to hash */ + hash_data_ptr = (BYTE *) (nb->buffer + PART_ENCRYPTION_AES256_SIZE); + hash_data_size = package_length - nb->encr_header_len; + + /* Calculate what to encrypt */ + encr_ptr = hash_data_ptr - hash_code_size; + encr_size = hash_data_size + hash_code_size; + + if (!nb->hProv) + { + status = CryptAcquireContext (&nb->hProv, + /* szContainer = */ NULL, + /* CSP name = */ NULL, + /* provider type = */ PROV_RSA_AES, + /* flags = */ CRYPT_VERIFYCONTEXT); + if (!status) + return (-1); + } + + status = CryptCreateHash (nb->hProv, + /* algorithm = */ CALG_SHA1, + /* hKey = */ 0, + /* dwFlags = */ 0, + /* out phHash = */ &hHash); + if (!status) + return (-1); + + status = CryptHashData (hHash, + /* pbData = */ hash_data_ptr, + /* dwDataSize = */ hash_data_size, + /* dwFlags = */ 0); + if (!status) + { + CryptDestroyHash (hHash); + return (-1); + } + + status = CryptGetHashParam (hHash, + /* dwParam = */ HP_HASHVAL, + /* pbData = */ (void *) encr_ptr, + /* pwdDataLen = */ &hash_code_size, + /* dwFlags = */ 0); + if (!status) + { + CryptDestroyHash (hHash); + return (-1); + } + CryptDestroyHash (hHash); + + status = nb_key_from_password (nb->hProv, + nb->password, nb->encr_iv, &hKey); + if (!status) + return (-1); + + status = CryptEncrypt (hKey, + /* hHash = */ 0, + /* Final = */ 1, /* last call to CryptEncrypt() */ + /* dwFlags = */ 0, + /* pbData = */ encr_ptr, + /* pdwDataLen = */ &encr_size, + /* dwBufLen = */ encr_size); + if (!status) + { + CryptDestroyKey (hKey); + return (-1); + } + + CryptDestroyKey (hKey); + return (0); +} /* }}} int nb_add_encryption */ #elif HAVE_LIBGCRYPT static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */ { @@ -881,10 +1057,7 @@ int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */ if (nb == NULL) return (EINVAL); -#if WIN32 - if (nb->seclevel == SIGN) - nb_add_signature (nb); -#elif HAVE_LIBGCRYPT +#if WIN32 || HAVE_LIBGCRYPT if (nb->seclevel == SIGN) nb_add_signature (nb); else if (nb->seclevel == ENCRYPT)