Encryption/decryption revised

- Number of memory copying reduced
- HMAC verification of server packets added
- Handshake hashing simplified
This commit is contained in:
Simon Rozman 2016-08-14 18:51:18 +02:00
parent 735d669887
commit 95e2f7e01b
4 changed files with 168 additions and 122 deletions

View File

@ -127,7 +127,7 @@ namespace eap
///
/// TLS message
///
struct message
struct message_header
{
unsigned char type; ///< Message type (one of `message_type_t` constants)
struct {
@ -135,7 +135,6 @@ namespace eap
unsigned char minor; ///< Minor version
} version; ///< SSL/TLS version
unsigned char length[2]; ///< Message length (in network byte order)
unsigned char data[1]; ///< Message data
};
#pragma pack(pop)
@ -284,30 +283,39 @@ namespace eap
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter A.1. Record Layer)](https://tools.ietf.org/html/rfc5246#appendix-A.1)
///
/// \param[in] type Message type
/// \param[in] msg Message data contents
/// \param[in] data Message data contents
/// \param[in] encrypt Should \p data get encrypted?
///
/// \returns TLS message message
///
static eap::sanitizing_blob make_message(_In_ tls_message_type_t type, _In_ const sanitizing_blob &msg);
eap::sanitizing_blob make_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &data, _In_ bool encrypt);
///
/// Makes a TLS message
/// Hashes handshake message for "finished" message validation.
///
/// \param[in] type Message type
/// \param[in] msg Message data contents
/// \param[in] encrypt Should the message be encrypted?
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.9. Finished)](https://tools.ietf.org/html/rfc5246#section-7.4.9)
///
/// \returns TLS message message
/// \param[in] data Data to hash
/// \param[in] size \p data size in bytes
///
inline eap::sanitizing_blob make_message(_In_ tls_message_type_t type, _In_ const sanitizing_blob &msg, _In_ bool encrypted)
inline void hash_handshake(_In_count_(size) const void *data, _In_ size_t size)
{
if (encrypted) {
// Make unencrypted handshake, encrypt it, then make a new handshake message.
sanitizing_blob msg_enc(make_message(type, msg));
encrypt_message(msg_enc);
return make_message(type, msg_enc);
} else
return make_message(type, msg);
CryptHashData(m_hash_handshake_msgs_md5 , (const BYTE*)data, (DWORD)size, 0);
CryptHashData(m_hash_handshake_msgs_sha1, (const BYTE*)data, (DWORD)size, 0);
}
///
/// Hashes handshake message for "finished" message validation.
///
/// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 7.4.9. Finished)](https://tools.ietf.org/html/rfc5246#section-7.4.9)
///
/// \param[in] data Data to hash
/// \param[in] size \p data size in bytes
///
template<class _Ty, class _Ax>
inline void hash_handshake(_In_ const std::vector<_Ty, _Ax> &data)
{
hash_handshake(data.data(), data.size() * sizeof(_Ty));
}
///
@ -391,16 +399,18 @@ namespace eap
///
/// Encrypt TLS message
///
/// \param[inout] msg TLS message to encrypt
/// \param[in] hdr Original TLS header for HMAC verification
/// \param[inout] data TLS message to encrypt
///
void encrypt_message(_Inout_ sanitizing_blob &msg);
void encrypt_message(_In_ const message_header *hdr, _Inout_ sanitizing_blob &data);
///
/// Decrypt TLS message
///
/// \param[inout] msg TLS message to decrypt
/// \param[in] hdr Original TLS header for HMAC verification
/// \param[inout] data TLS message to decrypt
///
void decrypt_message(_Inout_ sanitizing_blob &msg) const;
void decrypt_message(_In_ const message_header *hdr, _Inout_ sanitizing_blob &data);
///
/// Calculates pseudo-random P_hash data defined in RFC 5246
@ -478,7 +488,7 @@ namespace eap
tls_conn_state m_state; ///< TLS connection state for fast reconnect
sanitizing_blob m_padding_hmac_client; ///< Padding (key) for client side HMAC calculation
//sanitizing_blob m_padding_hmac_server; ///< Padding (key) for server side HMAC calculation
sanitizing_blob m_padding_hmac_server; ///< Padding (key) for server side HMAC calculation
winstd::crypt_key m_key_client; ///< Key for encrypting messages
winstd::crypt_key m_key_server; ///< Key for decrypting messages
@ -497,7 +507,8 @@ namespace eap
bool m_server_finished; ///< Did server send a valid finish message?
bool m_cipher_spec; ///< Did server specify cipher?
unsigned __int64 m_seq_num; ///< Sequence number for encryption
unsigned __int64 m_seq_num_client; ///< Sequence number for encrypting
unsigned __int64 m_seq_num_server; ///< Sequence number for decrypting
// The following members are required to avoid memory leakage in get_result()
EAP_ATTRIBUTES m_eap_attr_desc; ///< EAP Radius attributes descriptor

View File

@ -356,8 +356,10 @@ namespace eap
ALG_ID m_alg_encrypt; ///> Bulk encryption algorithm
size_t m_size_enc_key; ///> Encryption key size in bytes (has to comply with `m_alg_encrypt`)
size_t m_size_enc_iv; ///> Encryption initialization vector size in bytes (has to comply with `m_alg_encrypt`)
size_t m_size_enc_block; ///> Encryption block size in bytes (has to comply with `m_alg_encrypt`)
ALG_ID m_alg_mac; ///> Message authenticy check algorithm
size_t m_size_mac_key; ///> Message authenticy check algorithm key size (has to comply with `m_alg_mac`)
size_t m_size_mac_hash; ///> Message authenticy check algorithm result size (has to comply with `m_alg_mac`)
tls_master_secret m_master_secret; ///< TLS master secret
tls_random m_random_client; ///< Client tls_random
tls_random m_random_server; ///< Server tls_random

View File

@ -101,7 +101,8 @@ eap::method_tls::method_tls(_In_ module &module, _In_ config_method_tls &cfg, _I
m_server_hello_done(false),
m_server_finished(false),
m_cipher_spec(false),
m_seq_num(0),
m_seq_num_client(0),
m_seq_num_server(0),
m_blob_cfg(NULL),
method(module, cfg, cred)
{
@ -116,7 +117,7 @@ eap::method_tls::method_tls(_In_ const method_tls &other) :
m_packet_res(other.m_packet_res),
m_state(other.m_state),
m_padding_hmac_client(other.m_padding_hmac_client),
//m_padding_hmac_server(other.m_padding_hmac_server),
m_padding_hmac_server(other.m_padding_hmac_server),
m_key_client(other.m_key_client),
m_key_server(other.m_key_server),
m_key_mppe_send(other.m_key_mppe_send),
@ -129,7 +130,8 @@ eap::method_tls::method_tls(_In_ const method_tls &other) :
m_server_hello_done(other.m_server_hello_done),
m_server_finished(other.m_server_finished),
m_cipher_spec(other.m_cipher_spec),
m_seq_num(other.m_seq_num),
m_seq_num_client(other.m_seq_num_client),
m_seq_num_server(other.m_seq_num_server),
method(other)
{
}
@ -143,7 +145,7 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) :
m_packet_res(std::move(other.m_packet_res)),
m_state(std::move(other.m_state)),
m_padding_hmac_client(std::move(other.m_padding_hmac_client)),
//m_padding_hmac_server(std::move(other.m_padding_hmac_server)),
m_padding_hmac_server(std::move(other.m_padding_hmac_server)),
m_key_client(std::move(other.m_key_client)),
m_key_server(std::move(other.m_key_server)),
m_key_mppe_send(std::move(other.m_key_mppe_send)),
@ -156,7 +158,8 @@ eap::method_tls::method_tls(_Inout_ method_tls &&other) :
m_server_hello_done(std::move(other.m_server_hello_done)),
m_server_finished(std::move(other.m_server_finished)),
m_cipher_spec(std::move(other.m_cipher_spec)),
m_seq_num(std::move(other.m_seq_num)),
m_seq_num_client(std::move(other.m_seq_num_client)),
m_seq_num_server(std::move(other.m_seq_num_server)),
method(std::move(other))
{
}
@ -180,7 +183,7 @@ eap::method_tls& eap::method_tls::operator=(_In_ const method_tls &other)
m_packet_res = other.m_packet_res;
m_state = other.m_state;
m_padding_hmac_client = other.m_padding_hmac_client;
//m_padding_hmac_server = other.m_padding_hmac_server;
m_padding_hmac_server = other.m_padding_hmac_server;
m_key_client = other.m_key_client;
m_key_server = other.m_key_server;
m_key_mppe_send = other.m_key_mppe_send;
@ -193,7 +196,8 @@ eap::method_tls& eap::method_tls::operator=(_In_ const method_tls &other)
m_server_hello_done = other.m_server_hello_done;
m_server_finished = other.m_server_finished;
m_cipher_spec = other.m_cipher_spec;
m_seq_num = other.m_seq_num;
m_seq_num_client = other.m_seq_num_client;
m_seq_num_server = other.m_seq_num_server;
}
return *this;
@ -211,7 +215,7 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other)
m_packet_res = std::move(other.m_packet_res);
m_state = std::move(other.m_state);
m_padding_hmac_client = std::move(other.m_padding_hmac_client);
//m_padding_hmac_server = std::move(other.m_padding_hmac_server);
m_padding_hmac_server = std::move(other.m_padding_hmac_server);
m_key_client = std::move(other.m_key_client);
m_key_server = std::move(other.m_key_server);
m_key_mppe_send = std::move(other.m_key_mppe_send);
@ -224,7 +228,8 @@ eap::method_tls& eap::method_tls::operator=(_Inout_ method_tls &&other)
m_server_hello_done = std::move(other.m_server_hello_done);
m_server_finished = std::move(other.m_server_finished);
m_cipher_spec = std::move(other.m_cipher_spec);
m_seq_num = std::move(other.m_seq_num);
m_seq_num_client = std::move(other.m_seq_num_client);
m_seq_num_server = std::move(other.m_seq_num_server);
}
return *this;
@ -237,7 +242,7 @@ void eap::method_tls::begin_session(
_In_ HANDLE hTokenImpersonateUser,
_In_ DWORD dwMaxSendPacketSize)
{
eap::method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
// Create cryptographics provider.
if (!m_cp.create(NULL, MS_ENHANCED_PROV, PROV_RSA_FULL))
@ -343,7 +348,7 @@ void eap::method_tls::process_request_packet(
// Generate client randomness.
m_padding_hmac_client.clear();
//m_padding_hmac_server.clear();
m_padding_hmac_server.clear();
m_key_client.free();
m_key_server.free();
m_key_mppe_send.clear();
@ -363,7 +368,9 @@ void eap::method_tls::process_request_packet(
m_server_hello_done = false;
m_server_finished = false;
m_cipher_spec = false;
m_seq_num = 0;
m_seq_num_client = 0;
m_seq_num_server = 0;
}
switch (m_phase) {
@ -373,10 +380,9 @@ void eap::method_tls::process_request_packet(
m_packet_res.m_id = m_packet_req.m_id;
m_packet_res.m_flags = 0;
sanitizing_blob hello(make_client_hello());
hash_handshake(hello);
sanitizing_blob handshake(make_message(tls_message_type_handshake, hello, m_cipher_spec));
m_packet_res.m_data.assign(handshake.begin(), handshake.end());
CryptHashData(m_hash_handshake_msgs_md5 , hello.data(), (DWORD)hello.size(), 0);
CryptHashData(m_hash_handshake_msgs_sha1, hello.data(), (DWORD)hello.size(), 0);
m_phase = phase_req_server_hello;
@ -416,10 +422,9 @@ void eap::method_tls::process_request_packet(
if (m_send_client_cert) {
// Client certificate requested.
sanitizing_blob client_cert(make_client_cert());
hash_handshake(client_cert);
sanitizing_blob handshake(make_message(tls_message_type_handshake, client_cert, m_cipher_spec));
m_packet_res.m_data.insert(m_packet_res.m_data.end(), handshake.begin(), handshake.end());
CryptHashData(m_hash_handshake_msgs_md5 , client_cert.data(), (DWORD)client_cert.size(), 0);
CryptHashData(m_hash_handshake_msgs_sha1, client_cert.data(), (DWORD)client_cert.size(), 0);
}
// Generate pre-master secret. PMS will get sanitized in its destructor when going out-of-scope.
@ -434,10 +439,9 @@ void eap::method_tls::process_request_packet(
// Create client key exchange message, and append to packet.
sanitizing_blob client_key_exchange(make_client_key_exchange(pms));
hash_handshake(client_key_exchange);
sanitizing_blob handshake(make_message(tls_message_type_handshake, client_key_exchange, m_cipher_spec));
m_packet_res.m_data.insert(m_packet_res.m_data.end(), handshake.begin(), handshake.end());
CryptHashData(m_hash_handshake_msgs_md5 , client_key_exchange.data(), (DWORD)client_key_exchange.size(), 0);
CryptHashData(m_hash_handshake_msgs_sha1, client_key_exchange.data(), (DWORD)client_key_exchange.size(), 0);
if (m_send_client_cert) {
// TODO: Create and append certificate_verify message!
@ -458,10 +462,9 @@ void eap::method_tls::process_request_packet(
// Create finished message, and append to packet.
sanitizing_blob finished(make_finished());
hash_handshake(finished);
sanitizing_blob handshake(make_message(tls_message_type_handshake, finished, m_cipher_spec));
m_packet_res.m_data.insert(m_packet_res.m_data.end(), handshake.begin(), handshake.end());
CryptHashData(m_hash_handshake_msgs_md5 , finished.data(), (DWORD)finished.size(), 0);
CryptHashData(m_hash_handshake_msgs_sha1, finished.data(), (DWORD)finished.size(), 0);
pEapOutput->fAllowNotifications = FALSE;
pEapOutput->action = EapPeerMethodResponseActionSend;
@ -748,7 +751,7 @@ eap::sanitizing_blob eap::method_tls::make_change_chiper_spec()
1, // Message size (low-order byte)
1, // Message: change_cipher_spec is always "1"
};
return eap::sanitizing_blob(s_msg_css, s_msg_css + _countof(s_msg_css));
return sanitizing_blob(s_msg_css, s_msg_css + _countof(s_msg_css));
}
@ -782,30 +785,41 @@ eap::sanitizing_blob eap::method_tls::make_finished() const
}
eap::sanitizing_blob eap::method_tls::make_message(_In_ tls_message_type_t type, _In_ const sanitizing_blob &msg)
eap::sanitizing_blob eap::method_tls::make_message(_In_ tls_message_type_t type, _Inout_ sanitizing_blob &data, _In_ bool encrypt)
{
size_t size_msg = msg.size();
eap::sanitizing_blob msg_h;
msg_h.reserve(
1 + // SSL record type
2 + // SSL version
2 + // Message size
size_msg); // Message
size_t size_data = data.size();
assert(size_data <= 0xffff);
message_header hdr = {
(unsigned char)type, // SSL record type
{
3, // SSL major version
1, // SSL minor version
},
{
// Data length (unencrypted, network byte order)
(unsigned char)((size_data >> 8) & 0xff),
(unsigned char)((size_data ) & 0xff),
}
};
// SSL record type
msg_h.push_back((unsigned char)type);
sanitizing_blob msg;
if (encrypt) {
encrypt_message(&hdr, data);
// SSL version: TLS 1.0
msg_h.push_back(3); // SSL major version
msg_h.push_back(1); // SSL minor version
// Update message size.
size_t size_data_enc = data.size();
*(unsigned short*)hdr.length = htons((unsigned short)size_data_enc);
msg.reserve(sizeof(message_header) + size_data_enc);
} else
msg.reserve(sizeof(message_header) + size_data);
// Message
assert(size_msg <= 0xffff);
unsigned short size_msg_n = htons((unsigned short)size_msg);
msg_h.insert(msg_h.end(), (unsigned char*)&size_msg_n, (unsigned char*)(&size_msg_n + 1));
msg_h.insert(msg_h.end(), msg.begin(), msg.end());
// TLS header
msg.assign((const unsigned char*)&hdr, (const unsigned char*)(&hdr + 1));
return msg_h;
// Data
msg.insert(msg.end(), data.begin(), data.end());
return msg;
}
@ -828,8 +842,8 @@ void eap::method_tls::derive_keys()
_key_block += m_state.m_size_mac_key;
// server_write_MAC_secret
//m_padding_hmac_server.resize(sizeof(hash_hmac::padding_t));
//hash_hmac::inner_padding(m_cp, m_state.m_alg_mac, _key_block, m_state.m_size_mac_key, m_padding_hmac_server.data());
m_padding_hmac_server.resize(sizeof(hash_hmac::padding_t));
hash_hmac::inner_padding(m_cp, m_state.m_alg_mac, _key_block, m_state.m_size_mac_key, m_padding_hmac_server.data());
_key_block += m_state.m_size_mac_key;
// Microsoft CryptoAPI does not support importing clear text session keys.
@ -879,12 +893,14 @@ void eap::method_tls::derive_msk()
void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck, _In_ size_t size_pck)
{
sanitizing_blob data;
for (const unsigned char *pck = (const unsigned char*)_pck, *pck_end = pck + size_pck; pck < pck_end; ) {
if (pck + 5 > pck_end)
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete message header.");
const message *hdr = (const message*)pck;
const message_header *hdr = (const message_header*)pck;
const unsigned char
*msg = hdr->data,
*msg = (const unsigned char*)(hdr + 1),
*msg_end = msg + ntohs(*(unsigned short*)hdr->length);
if (msg_end > pck_end)
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete message data.");
@ -899,7 +915,7 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck,
case tls_message_type_alert:
if (m_cipher_spec) {
sanitizing_blob msg_dec(msg, msg_end);
decrypt_message(msg_dec);
decrypt_message(hdr, msg_dec);
process_alert(msg_dec.data(), msg_dec.size());
} else
process_alert(msg, msg_end - msg);
@ -908,7 +924,7 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck,
case tls_message_type_handshake:
if (m_cipher_spec) {
sanitizing_blob msg_dec(msg, msg_end);
decrypt_message(msg_dec);
decrypt_message(hdr, msg_dec);
process_handshake(msg_dec.data(), msg_dec.size());
} else
process_handshake(msg, msg_end - msg);
@ -919,7 +935,7 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck,
throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Application data should be encrypted.");
sanitizing_blob msg_dec(msg, msg_end);
decrypt_message(msg_dec);
decrypt_message(hdr, msg_dec);
process_application_data(msg_dec.data(), msg_dec.size());
break;
}
@ -927,7 +943,7 @@ void eap::method_tls::process_packet(_In_bytecount_(size_pck) const void *_pck,
default:
if (m_cipher_spec) {
sanitizing_blob msg_dec(msg, msg_end);
decrypt_message(msg_dec);
decrypt_message(hdr, msg_dec);
process_vendor_data(hdr->type, msg_dec.data(), msg_dec.size());
} else
process_vendor_data(hdr->type, msg, msg_end - msg);
@ -1020,8 +1036,10 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms
m_state.m_alg_encrypt = CALG_3DES;
m_state.m_size_enc_key = 192/8; // 3DES 192bits
m_state.m_size_enc_iv = 64/8; // 3DES 64bits
m_state.m_size_enc_block = 64/8; // 3DES 64bits
m_state.m_alg_mac = CALG_SHA1;
m_state.m_size_mac_key = 160/8; // SHA-1
m_state.m_size_mac_hash = 160/8; // SHA-1
} else
throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Other than requested cipher selected (received 0x%02x%02x).", rec[0], rec[1]));
@ -1109,8 +1127,7 @@ void eap::method_tls::process_handshake(_In_bytecount_(msg_size) const void *_ms
msg = rec_end;
}
CryptHashData(m_hash_handshake_msgs_md5 , (const BYTE*)_msg, (DWORD)msg_size, 0);
CryptHashData(m_hash_handshake_msgs_sha1, (const BYTE*)_msg, (DWORD)msg_size, 0);
hash_handshake(_msg, msg_size);
}
@ -1226,69 +1243,83 @@ void eap::method_tls::verify_server_trust() const
}
void eap::method_tls::encrypt_message(_Inout_ sanitizing_blob &msg)
void eap::method_tls::encrypt_message(_In_ const message_header *hdr, _Inout_ sanitizing_blob &data)
{
// Create a HMAC hash.
// Hash sequence number, TLS header, and message.
size_t size_data = data.size();
assert(size_data == ntohs(*(unsigned short*)hdr->length));
hash_hmac hash(m_cp, m_state.m_alg_mac, m_padding_hmac_client.data());
// Hash sequence number and message.
unsigned __int64 seq_num = htonll(m_seq_num);
if (!CryptHashData(hash, (const BYTE*)&seq_num, sizeof(seq_num), 0) ||
!CryptHashData(hash, msg.data(), (DWORD)msg.size(), 0))
unsigned __int64 seq_num = htonll(m_seq_num_client);
if (!CryptHashData(hash, (const BYTE*)&seq_num , sizeof(seq_num ), 0) ||
!CryptHashData(hash, (const BYTE*)hdr , sizeof(message_header), 0) ||
!CryptHashData(hash, data.data(), (DWORD)size_data , 0))
throw win_runtime_error(__FUNCTION__ " Error hashing data.");
// Calculate hash.
sanitizing_blob hmac;
hash.calculate(hmac);
// Remove SSL/TLS header (record type, version, message size).
msg.erase(msg.begin(), msg.begin() + 5);
size_t size =
msg.size() + // TLS message
size_t size_data_enc =
size_data + // TLS message
hmac.size() + // HMAC hash
1; // Padding length
// Calculate padding.
DWORD size_block = CryptGetKeyParam(m_key_client, KP_BLOCKLEN, size_block, 0) ? size_block / 8 : 0;
unsigned char size_padding = (unsigned char)((size_block - size) % size_block);
size += size_padding;
msg.reserve(size);
unsigned char size_padding = (unsigned char)((m_state.m_size_enc_block - size_data_enc) % m_state.m_size_enc_block);
size_data_enc += size_padding;
data.reserve(size_data_enc);
// Append HMAC hash.
msg.insert(msg.end(), hmac.begin(), hmac.end());
// Append padding.
msg.insert(msg.end(), size_padding + 1, size_padding);
// Append HMAC hash and padding.
data.insert(data.end(), hmac.begin(), hmac.end());
data.insert(data.end(), size_padding + 1, size_padding);
// Encrypt.
assert(size < 0xffffffff);
DWORD size2 = (DWORD)size;
if (!CryptEncrypt(m_key_client, NULL, FALSE, 0, msg.data(), &size2, (DWORD)size))
assert(size_data_enc < 0xffffffff);
DWORD size_data_enc2 = (DWORD)size_data_enc;
if (!CryptEncrypt(m_key_client, NULL, FALSE, 0, data.data(), &size_data_enc2, (DWORD)size_data_enc))
throw win_runtime_error(__FUNCTION__ " Error encrypting message.");
// Increment sequence number.
m_seq_num++;
m_seq_num_client++;
}
void eap::method_tls::decrypt_message(_Inout_ sanitizing_blob &msg) const
void eap::method_tls::decrypt_message(_In_ const message_header *hdr, _Inout_ sanitizing_blob &data)
{
// Decrypt.
if (!CryptDecrypt(m_key_server, NULL, FALSE, 0, msg))
if (!CryptDecrypt(m_key_server, NULL, FALSE, 0, data))
throw win_runtime_error(__FUNCTION__ " Error decrypting message.");
size_t size = msg.size();
size_t size = data.size();
if (size) {
// Check padding.
unsigned char padding = msg.back();
unsigned char padding = data.back();
size_t size_data = size - 1 - padding;
for (size_t i = size_data, i_end = size - 1; i < i_end; i++)
if (msg[i] != padding)
if (data[i] != padding)
throw invalid_argument(__FUNCTION__ " Incorrect message padding.");
// Remove padding.
msg.resize(size_data);
size_data -= m_state.m_size_mac_hash;
// Hash sequence number, TLS header (without length), original message length, and message.
hash_hmac hash(m_cp, m_state.m_alg_mac, m_padding_hmac_server.data());
unsigned __int64 seq_num = htonll(m_seq_num_server);
unsigned short size_data2 = htons((unsigned short)size_data);
if (!CryptHashData(hash, (const BYTE*)&seq_num , sizeof(seq_num), 0) ||
!CryptHashData(hash, (const BYTE*)hdr , 3, 0) ||
!CryptHashData(hash, (const BYTE*)&size_data2, 2, 0) ||
!CryptHashData(hash, data.data(), (DWORD)size_data, 0))
throw win_runtime_error(__FUNCTION__ " Error hashing data.");
sanitizing_blob hmac;
hash.calculate(hmac);
// Verify hash.
if (memcmp(&*(data.begin() + size_data), hmac.data(), m_state.m_size_mac_hash) != 0)
throw win_runtime_error(ERROR_DECRYPTION_FAILED, __FUNCTION__ " Integrity check failed.");
// Strip hash and padding.
data.resize(size_data);
// Increment sequence number.
m_seq_num_server++;
}
}

View File

@ -123,10 +123,12 @@ void eap::tls_master_secret::clear()
eap::tls_conn_state::tls_conn_state() :
m_alg_prf (0),
m_alg_encrypt (0),
m_size_enc_key(0),
m_size_enc_key (0),
m_size_enc_iv (0),
m_size_enc_block(0),
m_alg_mac (0),
m_size_mac_key(0)
m_size_mac_key (0),
m_size_mac_hash (0)
{
}