/* Copyright 2015-2016 Amebis Copyright 2016 GÉANT This file is part of GÉANTLink. GÉANTLink is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GÉANTLink is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GÉANTLink. If not, see . */ #include "StdAfx.h" using namespace std; using namespace winstd; ////////////////////////////////////////////////////////////////////// // eap::create_des_key ////////////////////////////////////////////////////////////////////// crypt_key eap::create_des_key(_In_ HCRYPTPROV cp, _In_count_(size) const unsigned char *key, _In_ size_t size) { // Prepare exported key BLOB. struct key_blob_prefix { PUBLICKEYSTRUC header; DWORD size; } static const s_prefix = { { PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_DES, }, 8, }; sanitizing_blob key_blob; key_blob.reserve(sizeof(key_blob_prefix) + 8); key_blob.assign(reinterpret_cast(&s_prefix), reinterpret_cast(&s_prefix + 1)); // Inject parity bits. unsigned char out = 0, parity = 1; size_t i = 0, j = 7, bits = std::min(size * 8, 56); for (; i < bits; i++) { unsigned char bit = (key[i/8] & (1 << (7 - i%8))) ? 1 : 0; parity ^= bit; out |= bit << j; if (--j == 0) { out |= parity; key_blob.push_back(out); out = 0; parity = 1; j = 7; } } for (; i < 56; i++) { if (--j == 0) { out |= parity; key_blob.push_back(out); out = 0; parity = 1; j = 7; } } // Import key. crypt_key k; if (!k.import(cp, key_blob.data(), (DWORD)key_blob.size(), NULL, 0)) throw winstd::win_runtime_error(__FUNCTION__ " Error importing key 1/3."); return k; } ////////////////////////////////////////////////////////////////////// // eap::challenge_mschapv2 ////////////////////////////////////////////////////////////////////// void eap::challenge_mschapv2::randomize(_In_ HCRYPTPROV cp) { if (!CryptGenRandom(cp, sizeof(data), data)) throw win_runtime_error(__FUNCTION__ " Error creating randomness."); } ////////////////////////////////////////////////////////////////////// // eap::challenge_hash ////////////////////////////////////////////////////////////////////// eap::challenge_hash::challenge_hash() { } eap::challenge_hash::challenge_hash( _In_ HCRYPTPROV cp, _In_ const sanitizing_blob &challenge_server, _In_ const challenge_mschapv2 &challenge_client, _In_z_ const char *username) { crypt_hash hash; if (!hash.create(cp, CALG_SHA)) throw win_runtime_error(__FUNCTION__ " Creating SHA hash failed."); if (!CryptHashData(hash, (const BYTE*)&challenge_client , (DWORD)sizeof(challenge_client), 0) || !CryptHashData(hash, challenge_server.data(), (DWORD)challenge_server.size() , 0) || !CryptHashData(hash, (const BYTE*)username , (DWORD)strlen(username) , 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); unsigned char hash_val[20]; DWORD size_hash_val = sizeof(hash_val); if (!CryptGetHashParam(hash, HP_HASHVAL, hash_val, &size_hash_val, 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); memcpy(data, hash_val, sizeof(data)); SecureZeroMemory(hash_val, size_hash_val); } eap::challenge_hash::challenge_hash(_In_ const sanitizing_blob_f<8> &other) : sanitizing_blob_xf<8>(other) { } #ifdef _DEBUG eap::challenge_hash::challenge_hash(_Inout_ sanitizing_blob_zf<8> &&other) : sanitizing_blob_xf<8>(std::move(other)) { } #endif ////////////////////////////////////////////////////////////////////// // eap::nt_password_hash ////////////////////////////////////////////////////////////////////// eap::nt_password_hash::nt_password_hash() { } eap::nt_password_hash::nt_password_hash( _In_ HCRYPTPROV cp, _In_z_ const wchar_t *password) { crypt_hash hash; if (!hash.create(cp, CALG_MD4)) throw win_runtime_error(__FUNCTION__ " Creating MD4 hash failed."); if (!CryptHashData(hash, (const BYTE*)password, (DWORD)(wcslen(password) * sizeof(wchar_t)), 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); DWORD size_data = sizeof(data); if (!CryptGetHashParam(hash, HP_HASHVAL, data, &size_data, 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); } eap::nt_password_hash::nt_password_hash( _In_ HCRYPTPROV cp, _In_ const nt_password_hash &pwd_hash) { crypt_hash hash; if (!hash.create(cp, CALG_MD4)) throw win_runtime_error(__FUNCTION__ " Creating MD4 hash failed."); if (!CryptHashData(hash, (const BYTE*)&pwd_hash, (DWORD)sizeof(pwd_hash), 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); DWORD size_data = sizeof(data); if (!CryptGetHashParam(hash, HP_HASHVAL, data, &size_data, 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); } eap::nt_password_hash::nt_password_hash(_In_ const sanitizing_blob_f<16> &other) : sanitizing_blob_xf<16>(other) { } #ifdef _DEBUG eap::nt_password_hash::nt_password_hash(_Inout_ sanitizing_blob_zf<16> &&other) : sanitizing_blob_xf<16>(std::move(other)) { } #endif ////////////////////////////////////////////////////////////////////// // eap::nt_response ////////////////////////////////////////////////////////////////////// eap::nt_response::nt_response() { } eap::nt_response::nt_response( _In_ HCRYPTPROV cp, _In_ const sanitizing_blob &challenge_server, _In_ const challenge_mschapv2 &challenge_client, _In_z_ const char *username, _In_z_ const wchar_t *password) { challenge_hash challenge(cp, challenge_server, challenge_client, username); nt_password_hash hash_pwd(cp, password); // Prepare exported key BLOB. crypt_key key; DWORD size_data_enc; static const DWORD mode_ecb = CRYPT_MODE_ECB; // DesEncrypt(Challenge, 1st 7-octets of ZPasswordHash, giving 1st 8-octets of Response) key = create_des_key(cp, reinterpret_cast(&hash_pwd), 7); if (!CryptSetKeyParam(key, KP_MODE, (const BYTE*)&mode_ecb, 0)) throw win_runtime_error(__FUNCTION__ " Error setting ECB mode."); memcpy(data, &challenge, 8); size_data_enc = 8; if (!CryptEncrypt(key, NULL, FALSE, 0, data, &size_data_enc, 8)) throw win_runtime_error(__FUNCTION__ " Error encrypting message 1/3."); // DesEncrypt(Challenge, 2nd 7-octets of ZPasswordHash, giving 2nd 8-octets of Response) key = create_des_key(cp, reinterpret_cast(&hash_pwd) + 7, 7); if (!CryptSetKeyParam(key, KP_MODE, (const BYTE*)&mode_ecb, 0)) throw win_runtime_error(__FUNCTION__ " Error setting ECB mode."); memcpy(data + 8, &challenge, 8); size_data_enc = 8; if (!CryptEncrypt(key, NULL, FALSE, 0, data + 8, &size_data_enc, 8)) throw win_runtime_error(__FUNCTION__ " Error encrypting message 2/3."); // DesEncrypt(Challenge, 2nd 7-octets of ZPasswordHash, giving 2nd 8-octets of Response) key = create_des_key(cp, reinterpret_cast(&hash_pwd) + 14, 2); if (!CryptSetKeyParam(key, KP_MODE, (const BYTE*)&mode_ecb, 0)) throw win_runtime_error(__FUNCTION__ " Error setting ECB mode."); memcpy(data + 16, &challenge, 8); size_data_enc = 8; if (!CryptEncrypt(key, NULL, FALSE, 0, data + 16, &size_data_enc, 8)) throw win_runtime_error(__FUNCTION__ " Error encrypting message 3/3."); } eap::nt_response::nt_response(_In_ const sanitizing_blob_f<24> &other) : sanitizing_blob_xf<24>(other) { } #ifdef _DEBUG eap::nt_response::nt_response(_Inout_ sanitizing_blob_zf<24> &&other) : sanitizing_blob_xf<24>(std::move(other)) { } #endif ////////////////////////////////////////////////////////////////////// // eap::authenticator_response ////////////////////////////////////////////////////////////////////// eap::authenticator_response::authenticator_response() { } eap::authenticator_response::authenticator_response( _In_ HCRYPTPROV cp, _In_ const sanitizing_blob &challenge_server, _In_ const challenge_mschapv2 &challenge_client, _In_z_ const char *username, _In_z_ const wchar_t *password, _In_ const nt_response &nt_resp) { static const unsigned char s_magic1[39] = { 0x4d, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74 }; nt_password_hash hash_hash_pwd(cp, nt_password_hash(cp, password)); crypt_hash hash; if (!hash.create(cp, CALG_SHA)) throw win_runtime_error(__FUNCTION__ " Creating SHA hash failed."); if (!CryptHashData(hash, (const BYTE*)&hash_hash_pwd, (DWORD)sizeof(hash_hash_pwd), 0) || !CryptHashData(hash, (const BYTE*)&nt_resp , (DWORD)sizeof(nt_resp ), 0) || !CryptHashData(hash, s_magic1 , (DWORD)sizeof(s_magic1 ), 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); unsigned char hash_val[20]; DWORD size_hash_val = sizeof(hash_val); if (!CryptGetHashParam(hash, HP_HASHVAL, hash_val, &size_hash_val, 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); static const unsigned char s_magic2[41] = { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e }; challenge_hash challenge(cp, challenge_server, challenge_client, username); if (!hash.create(cp, CALG_SHA)) throw win_runtime_error(__FUNCTION__ " Creating SHA hash failed."); if (!CryptHashData(hash, hash_val , size_hash_val , 0) || !CryptHashData(hash, (const BYTE*)&challenge, (DWORD)sizeof(challenge), 0) || !CryptHashData(hash, s_magic2 , (DWORD)sizeof(s_magic2 ), 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); size_hash_val = sizeof(data); if (!CryptGetHashParam(hash, HP_HASHVAL, data, &size_hash_val, 0)) throw win_runtime_error(__FUNCTION__ " Error hashing data."); } eap::authenticator_response::authenticator_response(_In_ const sanitizing_blob_f<20> &other) : sanitizing_blob_xf<20>(other) { } #ifdef _DEBUG eap::authenticator_response::authenticator_response(_Inout_ sanitizing_blob_zf<20> &&other) : sanitizing_blob_xf<20>(std::move(other)) { } #endif