--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/eapol/eapol_framework/eapol_common/common/eap_crypto_api.cpp Thu Dec 17 08:47:43 2009 +0200
@@ -0,0 +1,6097 @@
+/*
+* Copyright (c) 2001-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: EAP and WLAN authentication protocols.
+*
+*/
+
+
+// This is enumeration of EAPOL source code.
+#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+ #undef EAP_FILE_NUMBER_ENUM
+ #define EAP_FILE_NUMBER_ENUM 22
+ #undef EAP_FILE_NUMBER_DATE
+ #define EAP_FILE_NUMBER_DATE 1127594498
+#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+
+
+
+#include "eap_am_memory.h"
+#include "eap_crypto_api.h"
+
+//--------------------------------------------------
+
+// This is simple optimization.
+const u32_t EAP_CRYPTO_API_SHA1_DIGEST_BUFFER_BYTE_SIZE = 20ul;
+const u32_t EAP_CRYPTO_API_SHA1_BLOCK_BYTE_SIZE = 64ul;
+
+const u32_t EAP_CRYPTO_API_SHA_256_DIGEST_BUFFER_BYTE_SIZE = 32ul;
+const u32_t EAP_CRYPTO_API_SHA_256_BLOCK_BYTE_SIZE = 64ul;
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT abs_crypto_cbc_block_algorithm_c::~abs_crypto_cbc_block_algorithm_c()
+{
+}
+
+
+EAP_FUNC_EXPORT abs_crypto_block_algorithm_c::~abs_crypto_block_algorithm_c()
+{
+}
+
+EAP_FUNC_EXPORT abs_crypto_stream_algorithm_c::~abs_crypto_stream_algorithm_c()
+{
+}
+
+EAP_FUNC_EXPORT abs_crypto_hash_algorithm_c::~abs_crypto_hash_algorithm_c()
+{
+}
+
+EAP_FUNC_EXPORT abs_crypto_hmac_algorithm_c::~abs_crypto_hmac_algorithm_c()
+{
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+
+EAP_FUNC_EXPORT crypto_hmac_c::~crypto_hmac_c()
+{
+ hmac_cleanup();
+
+ delete m_key;
+ m_key = 0;
+
+ delete m_ipad;
+ m_ipad = 0;
+
+ delete m_opad;
+ m_opad = 0;
+}
+
+EAP_FUNC_EXPORT crypto_hmac_c::crypto_hmac_c(
+ abs_eap_am_tools_c * const tools,
+ abs_crypto_hash_algorithm_c * const crypto_hash_algorithm,
+ const bool free_crypto_hash_algorithm)
+ : m_am_tools(tools)
+ , m_crypto_hash_algorithm(crypto_hash_algorithm)
+ , m_key(0)
+ , m_ipad(0)
+ , m_opad(0)
+ , m_is_valid(false)
+ , m_free_crypto_hash_algorithm(free_crypto_hash_algorithm)
+{
+ m_key = new eap_variable_data_c(m_am_tools);
+ if (m_key == 0)
+ {
+ return;
+ }
+
+ m_ipad = new eap_variable_data_c(m_am_tools);
+ if (m_ipad == 0)
+ {
+ return;
+ }
+
+ m_opad = new eap_variable_data_c(m_am_tools);
+ if (m_opad == 0)
+ {
+ return;
+ }
+
+ set_is_valid();
+}
+
+EAP_FUNC_EXPORT void crypto_hmac_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+EAP_FUNC_EXPORT bool crypto_hmac_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+EAP_FUNC_EXPORT u32_t crypto_hmac_c::get_digest_length()
+{
+ return m_crypto_hash_algorithm->get_digest_length();
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_hmac_c::initialize_pad(
+ eap_variable_data_c * const p_pad,
+ const u8_t pad_value)
+{
+ if (get_is_valid() == false)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ eap_status_e status = p_pad->set_buffer_length(
+ m_crypto_hash_algorithm->get_block_size());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ p_pad->set_data_length(m_crypto_hash_algorithm->get_block_size());
+
+ u32_t ind = 0ul;
+ u8_t * key = m_key->get_data(m_key->get_data_length());
+ u8_t * ipad = p_pad->get_data(p_pad->get_data_length());
+
+ for (ind = 0ul; ind < m_key->get_data_length(); ind++)
+ {
+ ipad[ind] = static_cast<u8_t>(key[ind] ^ pad_value);
+ }
+
+ for (ind = m_key->get_data_length()
+ ; ind < m_crypto_hash_algorithm->get_block_size(); ind++)
+ {
+ ipad[ind] = pad_value;
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_hmac_c::hmac_set_key(
+ const eap_variable_data_c * const hmac_key)
+{
+ if (hmac_key == 0
+ || hmac_key->get_is_valid_data() == false
+ || get_is_valid() == false)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = eap_status_process_general_error;
+
+ status = m_crypto_hash_algorithm->hash_init();
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ if (hmac_key->get_data_length()
+ > m_crypto_hash_algorithm->get_block_size())
+ {
+ status = m_crypto_hash_algorithm->hash_update(
+ hmac_key->get_data(hmac_key->get_data_length()),
+ hmac_key->get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_key->set_buffer_length(
+ m_crypto_hash_algorithm->get_digest_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ m_key->set_data_length(m_crypto_hash_algorithm->get_digest_length());
+
+ u32_t md_length = m_key->get_data_length();
+
+ status = m_crypto_hash_algorithm->hash_final(
+ m_key->get_data(m_key->get_data_length()),
+ &md_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_ASSERT(md_length == m_key->get_data_length());
+ }
+ else
+ {
+ status = m_key->set_copy_of_buffer(hmac_key);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // - - - - - - - - - - - - - - - - - - - -
+ // Initialize inner pad.
+
+ {
+ static const u8_t EAP_HMAC_IPAD = 0x36;
+
+ status = initialize_pad(
+ m_ipad,
+ EAP_HMAC_IPAD);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // - - - - - - - - - - - - - - - - - - - -
+ // Initialize outer pad.
+
+ {
+ static const u8_t EAP_HMAC_OPAD = 0x5C;
+
+ status = initialize_pad(
+ m_opad,
+ EAP_HMAC_OPAD);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ // - - - - - - - - - - - - - - - - - - - -
+
+ status = m_crypto_hash_algorithm->hash_init();
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_crypto_hash_algorithm->hash_update(
+ m_ipad->get_data(m_ipad->get_data_length()),
+ m_ipad->get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_hmac_c::hmac_update(
+ const void * const data,
+ const u32_t data_length)
+{
+ if (get_is_valid() == false)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = m_crypto_hash_algorithm->hash_update(
+ data,
+ data_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_hmac_c::hmac_final(
+ void * const message_digest,
+ u32_t *md_length_or_null)
+{
+ if (get_is_valid() == false)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_variable_data_c idigest(m_am_tools);
+
+ eap_status_e status = idigest.set_buffer_length(
+ m_crypto_hash_algorithm->get_digest_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ idigest.set_data_length(m_crypto_hash_algorithm->get_digest_length());
+
+ u32_t md_length = idigest.get_data_length();
+
+ status = m_crypto_hash_algorithm->hash_final(
+ idigest.get_data(idigest.get_data_length()),
+ &md_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_ASSERT(md_length == m_crypto_hash_algorithm->get_digest_length());
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_crypto_hash_algorithm->hash_init();
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_crypto_hash_algorithm->hash_update(
+ m_opad->get_data(m_opad->get_data_length()),
+ m_opad->get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_crypto_hash_algorithm->hash_update(
+ idigest.get_data(idigest.get_data_length()),
+ idigest.get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_crypto_hash_algorithm->hash_final(
+ message_digest,
+ md_length_or_null);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ if (md_length_or_null != 0)
+ {
+ EAP_ASSERT(*md_length_or_null
+ == m_crypto_hash_algorithm->get_digest_length());
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+
+EAP_FUNC_EXPORT eap_status_e crypto_hmac_c::hmac_128_final(
+ void * const message_digest,
+ u32_t *md_length_or_null)
+{
+ if (message_digest == 0)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ u32_t tmp_length = get_digest_length();
+ eap_variable_data_c tmp_digest(m_am_tools);
+ if (tmp_digest.get_is_valid() == false)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+ eap_status_e status = tmp_digest.set_buffer_length(tmp_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac_final(
+ tmp_digest.get_buffer(tmp_digest.get_buffer_length()),
+ &tmp_length);
+ if (status != eap_status_ok
+ || tmp_length != tmp_digest.get_buffer_length())
+ {
+ if (md_length_or_null != 0)
+ {
+ *md_length_or_null = 0;
+ }
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ else
+ {
+ status = tmp_digest.set_data_length(tmp_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ if (md_length_or_null != 0)
+ {
+ *md_length_or_null = HMAC_SHA1_128_SIZE;
+ }
+
+ m_am_tools->memmove(
+ message_digest,
+ tmp_digest.get_data(HMAC_SHA1_128_SIZE),
+ HMAC_SHA1_128_SIZE);
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_hmac_c::hmac_cleanup()
+{
+ if (m_key != 0)
+ {
+ m_key->reset();
+ }
+
+ if (m_ipad != 0)
+ {
+ m_ipad->reset();
+ }
+
+ if (m_opad != 0)
+ {
+ m_opad->reset();
+ }
+
+ if (m_free_crypto_hash_algorithm == true)
+ {
+ delete m_crypto_hash_algorithm;
+ }
+ m_crypto_hash_algorithm = 0;
+
+ m_is_valid = false;
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_cbc_c::~crypto_cbc_c()
+{
+ reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_cbc_c::crypto_cbc_c(
+ abs_eap_am_tools_c * const tools,
+ abs_crypto_block_algorithm_c * const crypto_block_algorithm,
+ const bool free_crypto_block_algorithm)
+ : m_am_tools(tools)
+ , m_crypto_block_algorithm(crypto_block_algorithm)
+ , m_is_valid(false)
+ , m_tmp_IV(0)
+ , m_encr_offset(0ul)
+ , m_encr_dispatch(0)
+ , m_encr_hold(0)
+ , m_saved_in_buffer(0)
+ , m_saved_out_buffer(0)
+ , m_iv_buffer_1(0)
+ , m_iv_buffer_2(0)
+ , m_free_crypto_block_algorithm(free_crypto_block_algorithm)
+{
+ m_tmp_IV = new eap_variable_data_c(m_am_tools);
+ m_encr_dispatch = new u8_t *[m_crypto_block_algorithm->get_block_size()];
+ m_encr_hold = new u8_t [m_crypto_block_algorithm->get_block_size()];
+ m_saved_in_buffer = new u8_t [m_crypto_block_algorithm->get_block_size()];
+ m_saved_out_buffer = new u8_t [m_crypto_block_algorithm->get_block_size()];
+ m_iv_buffer_1 = new u8_t [m_crypto_block_algorithm->get_block_size()];
+ m_iv_buffer_2 = new u8_t [m_crypto_block_algorithm->get_block_size()];
+
+ if (m_tmp_IV == 0
+ || m_encr_dispatch == 0
+ || m_encr_hold == 0
+ || m_saved_in_buffer == 0
+ || m_saved_out_buffer == 0
+ || m_iv_buffer_1 == 0
+ || m_iv_buffer_2 == 0)
+ {
+ reset();
+ }
+ else
+ {
+ set_is_valid();
+ }
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_cbc_c::reset()
+{
+ m_is_valid = false;
+
+ if (m_tmp_IV != 0)
+ {
+ m_tmp_IV->reset();
+ delete m_tmp_IV;
+ m_tmp_IV = 0;
+ }
+
+ if (m_crypto_block_algorithm != 0)
+ {
+ if (m_encr_dispatch != 0)
+ {
+ m_am_tools->memset(
+ m_encr_dispatch,
+ 0,
+ m_crypto_block_algorithm->get_block_size());
+ }
+
+ if (m_encr_hold != 0)
+ {
+ m_am_tools->memset(
+ m_encr_hold,
+ 0,
+ m_crypto_block_algorithm->get_block_size());
+ }
+ }
+
+ delete [] m_encr_dispatch;
+ m_encr_dispatch = 0;
+
+ delete [] m_encr_hold;
+ m_encr_hold = 0;
+
+ delete [] m_saved_in_buffer;
+ m_saved_in_buffer = 0;
+
+ delete [] m_saved_out_buffer;
+ m_saved_out_buffer = 0;
+
+ delete [] m_iv_buffer_1;
+ m_iv_buffer_1 = 0;
+
+ delete [] m_iv_buffer_2;
+ m_iv_buffer_2 = 0;
+
+ if (m_free_crypto_block_algorithm == true)
+ {
+ delete m_crypto_block_algorithm;
+ }
+ m_crypto_block_algorithm = 0;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_cbc_c::cbc_xor_block(
+ const void * const cipher_IV,
+ void * const data_block,
+ const u32_t block_size,
+ const u32_t key_length)
+{
+ EAP_UNREFERENCED_PARAMETER(block_size);
+ EAP_UNREFERENCED_PARAMETER(key_length);
+ EAP_ASSERT((block_size % m_crypto_block_algorithm->get_block_size()) == 0);
+ EAP_ASSERT((key_length % m_crypto_block_algorithm->get_key_length()) == 0);
+
+#if defined(USE_EAP_64_BIT_MULTIPLICATION)
+ if ((reinterpret_cast<u32_t>(cipher_IV) % sizeof(u64_t)) == 0
+ && (reinterpret_cast<u32_t>(data_block) % sizeof(u64_t)) == 0)
+ {
+ const u64_t * const pIV = static_cast<const u64_t *>(cipher_IV);
+ u64_t * const pdata = static_cast<u64_t *>(data_block);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u64_t); ind++)
+ {
+ pdata[ind] ^= pIV[ind];
+ }
+ }
+ else
+#endif //#if defined(USE_EAP_64_BIT_MULTIPLICATION)
+ if ((reinterpret_cast<u32_t>(cipher_IV) % sizeof(u32_t)) == 0
+ && (reinterpret_cast<u32_t>(data_block) % sizeof(u32_t)) == 0)
+ {
+ const u32_t * const pIV = static_cast<const u32_t *>(cipher_IV);
+ u32_t * const pdata = static_cast<u32_t *>(data_block);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u32_t); ind++)
+ {
+ pdata[ind] ^= pIV[ind];
+ }
+ }
+ else if ((reinterpret_cast<u32_t>(cipher_IV) % sizeof(u16_t)) == 0
+ && (reinterpret_cast<u32_t>(data_block) % sizeof(u16_t)) == 0)
+ {
+ const u16_t * const pIV = static_cast<const u16_t *>(cipher_IV);
+ u16_t * const pdata = static_cast<u16_t *>(data_block);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u16_t); ind++)
+ {
+ pdata[ind] ^= pIV[ind];
+ }
+ }
+ else
+ {
+ const u8_t * const pIV = static_cast<const u8_t *>(cipher_IV);
+ u8_t * const pdata = static_cast<u8_t *>(data_block);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u8_t); ind++)
+ {
+ pdata[ind] ^= pIV[ind];
+ }
+ }
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_cbc_c::cbc_copy_block(
+ void * const target,
+ const void * const source,
+ const u32_t block_size,
+ const u32_t key_length)
+{
+ EAP_UNREFERENCED_PARAMETER(key_length);
+ EAP_ASSERT((block_size % m_crypto_block_algorithm->get_block_size()) == 0);
+ EAP_ASSERT((key_length % m_crypto_block_algorithm->get_key_length()) == 0);
+
+#if defined(USE_EAP_64_BIT_MULTIPLICATION)
+ if ((reinterpret_cast<u32_t>(source) % sizeof(u64_t)) == 0
+ && (reinterpret_cast<u32_t>(target) % sizeof(u64_t)) == 0)
+ {
+ const u64_t * const p_source
+ = static_cast<const u64_t *>(source);
+ u64_t * const p_target = static_cast<u64_t *>(target);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u64_t); ind++)
+ {
+ p_target[ind] = p_source[ind];
+ }
+ }
+ else
+#endif //#if defined(USE_EAP_64_BIT_MULTIPLICATION)
+ if ((reinterpret_cast<u32_t>(source) % sizeof(u32_t)) == 0
+ && (reinterpret_cast<u32_t>(target) % sizeof(u32_t)) == 0)
+ {
+ const u32_t * const p_source
+ = static_cast<const u32_t *>(source);
+ u32_t * const p_target = static_cast<u32_t *>(target);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u32_t); ind++)
+ {
+ p_target[ind] = p_source[ind];
+ }
+ }
+ else if ((reinterpret_cast<u32_t>(source) % sizeof(u16_t)) == 0
+ && (reinterpret_cast<u32_t>(target) % sizeof(u16_t)) == 0)
+ {
+ const u16_t * const p_source
+ = static_cast<const u16_t *>(source);
+ u16_t * const p_target = static_cast<u16_t *>(target);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u16_t); ind++)
+ {
+ p_target[ind] = p_source[ind];
+ }
+ }
+ else
+ {
+ const u8_t * const p_source = static_cast<const u8_t *>(source);
+ u8_t * const p_target = static_cast<u8_t *>(target);
+
+ for (u32_t ind = 0u; ind < block_size/sizeof(u8_t); ind++)
+ {
+ p_target[ind] = p_source[ind];
+ }
+ }
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_cbc_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_cbc_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT const eap_variable_data_c * crypto_cbc_c::get_tmp_IV()
+{
+ return m_tmp_IV;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_cbc_c::get_encrypts()
+{
+ return m_crypto_block_algorithm->get_encrypts();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_cbc_c::get_key_length()
+{
+ return m_crypto_block_algorithm->get_key_length();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_cbc_c::get_block_size()
+{
+ return m_crypto_block_algorithm->get_block_size();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_cbc_c::aligned_data_length(
+ u32_t data_length)
+{
+ const u32_t fill_bytes = data_length
+ % (m_crypto_block_algorithm->get_block_size());
+
+ // NOTE, this will always add padding bytes (1...BLOCK_SIZE).
+ data_length += ((m_crypto_block_algorithm->get_block_size())-fill_bytes);
+
+ return data_length;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::add_padding_bytes(
+ void * const buffer,
+ const u32_t buffer_length,
+ const u8_t padding_byte)
+{
+ u8_t * const p_buffer = static_cast<u8_t *>(buffer);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("CBC: encrypt_function: crypto_cbc_c::add_padding_bytes(): buffer=0x%08x, buffer_length=%d, padding_byte=0x%02x\n"),
+ buffer,
+ buffer_length,
+ padding_byte));
+
+ for(u32_t ind = 0; ind < buffer_length; ind++)
+ {
+ p_buffer[ind] = padding_byte;
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_cbc_c::add_padding_bytes()"),
+ p_buffer,
+ buffer_length));
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::check_padding_bytes(
+ const void * const buffer,
+ const u32_t buffer_length,
+ const u8_t padding_byte)
+{
+ const u8_t * const p_buffer = static_cast<const u8_t *>(buffer);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("CBC: encrypt_function: crypto_cbc_c::check_padding_bytes(): buffer=0x%08x, buffer_length=%d, padding_byte=0x%02x\n"),
+ buffer,
+ buffer_length,
+ padding_byte));
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_cbc_c::check_padding_bytes()"),
+ p_buffer,
+ buffer_length));
+
+ for(u32_t ind = 0; ind < buffer_length; ind++)
+ {
+ if (p_buffer[ind] != padding_byte)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_padding);
+ }
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::set_encryption_key(
+ const void * const encryption_IV,
+ const u32_t encryption_IV_length,
+ const void * const key,
+ const u32_t key_length)
+{
+ eap_status_e status = m_tmp_IV->set_copy_of_buffer(
+ encryption_IV, encryption_IV_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return m_crypto_block_algorithm->set_encryption_key(
+ key,
+ key_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::set_decryption_key(
+ const void * const encryption_IV,
+ const u32_t encryption_IV_length,
+ const void * const key,
+ const u32_t key_length)
+{
+ eap_status_e status = m_tmp_IV->set_copy_of_buffer(
+ encryption_IV, encryption_IV_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return m_crypto_block_algorithm->set_decryption_key(
+ key,
+ key_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::internal_encrypt_data(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ if ((data_length % m_crypto_block_algorithm->get_block_size()) != 0)
+ {
+ return EAP_STATUS_RETURN(
+ m_am_tools,
+ eap_status_data_length_not_aligned_to_block_size);
+ }
+
+ const u8_t * const p_data_in = static_cast<const u8_t *>(data_in);
+ u8_t * const p_data_out = static_cast<u8_t *>(data_out);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("encrypt data_in"),
+ data_in, data_length));
+
+ cbc_copy_block(
+ m_saved_in_buffer,
+ data_in,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ cbc_xor_block(
+ m_tmp_IV->get_data(m_tmp_IV->get_data_length()),
+ m_saved_in_buffer,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ u32_t ind;
+ eap_status_e status = eap_status_ok;
+
+ for (ind = 0u; ind < data_length
+ ; ind += m_crypto_block_algorithm->get_block_size())
+ {
+ if (ind > 0u)
+ {
+ cbc_copy_block(
+ m_saved_in_buffer,
+ p_data_in+ind,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ cbc_xor_block(
+ p_data_out+(ind-m_crypto_block_algorithm->get_block_size()),
+ m_saved_in_buffer,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+ }
+
+ status = m_crypto_block_algorithm->encrypt_block(
+ m_saved_in_buffer,
+ m_saved_out_buffer,
+ m_crypto_block_algorithm->get_block_size());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ cbc_copy_block(
+ p_data_out+ind,
+ m_saved_out_buffer,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ }
+
+ // Save the last block.
+ status = m_tmp_IV->set_copy_of_buffer(
+ p_data_out+(ind-m_crypto_block_algorithm->get_block_size()),
+ m_crypto_block_algorithm->get_block_size());
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("encrypt data_out"),
+ data_out,
+ data_length));
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::encrypt_data(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ EAP_ASSERT(data_in != data_out);
+
+ eap_status_e status = internal_encrypt_data(
+ data_in,
+ data_out,
+ data_length);
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::encrypt_data(
+ void * const data_in_out,
+ const u32_t data_length)
+{
+
+ eap_status_e status = internal_encrypt_data(
+ data_in_out,
+ data_in_out,
+ data_length);
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::internal_decrypt_data(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ u8_t *saved_iv_buffer = m_iv_buffer_1;
+ u8_t *encrypted_buffer = m_iv_buffer_2;
+
+ if ((data_length % m_crypto_block_algorithm->get_block_size()) != 0u)
+ {
+ return EAP_STATUS_RETURN(
+ m_am_tools,
+ eap_status_data_length_not_aligned_to_block_size);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("decrypt data_in"),
+ data_in,
+ data_length));
+
+ const u8_t * const p_data_in = static_cast<const u8_t *>(data_in);
+ u8_t * const p_data_out = static_cast<u8_t *>(data_out);
+
+ cbc_copy_block(
+ saved_iv_buffer,
+ m_tmp_IV->get_data(m_tmp_IV->get_data_length()),
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ u32_t ind;
+ eap_status_e status = eap_status_ok;
+
+ for (ind = 0u; ind < data_length
+ ; ind += m_crypto_block_algorithm->get_block_size())
+ {
+ cbc_copy_block(
+ encrypted_buffer,
+ p_data_in+ind,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ cbc_copy_block(
+ m_saved_in_buffer,
+ p_data_in+ind,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ status = m_crypto_block_algorithm->decrypt_block(
+ m_saved_in_buffer,
+ m_saved_out_buffer,
+ m_crypto_block_algorithm->get_block_size());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ cbc_xor_block(
+ saved_iv_buffer,
+ m_saved_out_buffer,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ cbc_copy_block(
+ p_data_out+ind,
+ m_saved_out_buffer,
+ m_crypto_block_algorithm->get_block_size(),
+ m_crypto_block_algorithm->get_key_length());
+
+ u8_t *tmp = encrypted_buffer;
+ encrypted_buffer = saved_iv_buffer;
+ saved_iv_buffer = tmp;
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("decrypt data_out"),
+ data_out,
+ data_length));
+
+ // Save the last block.
+ status = m_tmp_IV->set_copy_of_buffer(
+ saved_iv_buffer,
+ m_crypto_block_algorithm->get_block_size());
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::decrypt_data(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ EAP_ASSERT(data_in != data_out);
+
+ eap_status_e status = internal_decrypt_data(
+ data_in,
+ data_out,
+ data_length);
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::decrypt_data(
+ void * const data_in_out,
+ const u32_t data_length)
+{
+
+ eap_status_e status = internal_decrypt_data(
+ data_in_out,
+ data_in_out,
+ data_length);
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::update_non_aligned(
+ const void * const msg_in,
+ void * const msg_out,
+ const u32_t msg_size)
+{
+ EAP_ASSERT_ALWAYS(msg_in != msg_out);
+
+ const u8_t *inp = reinterpret_cast<const u8_t *>(msg_in);
+ u8_t *oup = static_cast<u8_t *>(msg_out);
+ i32_t len = static_cast<i32_t>(msg_size);
+ i32_t tail;
+ eap_status_e status = eap_status_process_general_error;
+
+ if (m_encr_offset)
+ {
+ //
+ // Non aligned handling
+ //
+ while (len > 0
+ && m_encr_offset
+ < static_cast<i32_t>(m_crypto_block_algorithm->get_block_size()))
+ {
+ m_encr_dispatch[m_encr_offset] = oup++;
+ m_encr_hold[m_encr_offset++] = *inp++;
+ len--;
+ }
+
+ if (m_encr_offset == static_cast<i32_t>(m_crypto_block_algorithm->get_block_size()))
+ {
+ // Got full block, flush out
+ if (m_crypto_block_algorithm->get_encrypts() == true)
+ {
+ status = encrypt_data(
+ m_encr_hold,
+ m_crypto_block_algorithm->get_block_size());
+ }
+ else
+ {
+ status = decrypt_data(
+ m_encr_hold,
+ m_crypto_block_algorithm->get_block_size());
+ }
+
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ for (m_encr_offset = 0
+ ; m_encr_offset
+ < static_cast<i32_t>(m_crypto_block_algorithm->get_block_size())
+ ; ++m_encr_offset)
+ {
+ *(m_encr_dispatch[m_encr_offset]) = m_encr_hold[m_encr_offset];
+ }
+ m_encr_offset = 0;
+ }
+ // Either len == 0 or (encrypt->encr_offset) == 0, or both!!!
+ }
+
+ tail = len % m_crypto_block_algorithm->get_block_size();
+ len -= tail;
+ if (len > 0)
+ {
+ if (m_crypto_block_algorithm->get_encrypts() == true)
+ {
+ status = encrypt_data(
+ inp,
+ oup,
+ len);
+ }
+ else
+ {
+ status = decrypt_data(
+ inp,
+ oup,
+ len);
+ }
+
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ if (tail > 0)
+ {
+ oup += len;
+ inp += len;
+ while (m_encr_offset < tail)
+ {
+ m_encr_dispatch[m_encr_offset] = oup++;
+ m_encr_hold[m_encr_offset++] = *inp++;
+ }
+ status = eap_status_ok;
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::update_non_aligned(
+ void * const msg_in_out,
+ const u32_t msg_size)
+{
+ u8_t *msg = static_cast<u8_t *>(msg_in_out);
+ i32_t len = static_cast<i32_t>(msg_size);
+ i32_t tail;
+ eap_status_e status = eap_status_process_general_error;
+
+ if (m_encr_offset)
+ {
+ //
+ // Non aligned handling
+ //
+ while (len > 0
+ && m_encr_offset
+ < static_cast<i32_t>(m_crypto_block_algorithm->get_block_size()))
+ {
+ m_encr_dispatch[m_encr_offset] = msg;
+ m_encr_hold[m_encr_offset++] = *msg++;
+ len--;
+ }
+
+ if (m_encr_offset == static_cast<i32_t>(m_crypto_block_algorithm->get_block_size()))
+ {
+ // Got full block, flush out
+ if (m_crypto_block_algorithm->get_encrypts() == true)
+ {
+ status = encrypt_data(
+ m_encr_hold,
+ m_crypto_block_algorithm->get_block_size());
+ }
+ else
+ {
+ status = decrypt_data(
+ m_encr_hold,
+ m_crypto_block_algorithm->get_block_size());
+ }
+
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ for (m_encr_offset = 0
+ ; m_encr_offset
+ < static_cast<i32_t>(m_crypto_block_algorithm->get_block_size())
+ ; ++m_encr_offset)
+ {
+ *(m_encr_dispatch[m_encr_offset]) = m_encr_hold[m_encr_offset];
+ }
+ m_encr_offset = 0;
+ }
+ // Either len == 0 or (encrypt->encr_offset) == 0, or both!!!
+ }
+
+ tail = len % m_crypto_block_algorithm->get_block_size();
+ len -= tail;
+ if (len > 0)
+ {
+ if (m_crypto_block_algorithm->get_encrypts() == true)
+ {
+ status = encrypt_data(
+ msg,
+ len);
+ }
+ else
+ {
+ status = decrypt_data(
+ msg,
+ len);
+ }
+
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ if (tail > 0)
+ {
+ msg += len;
+ while (m_encr_offset < tail)
+ {
+ m_encr_dispatch[m_encr_offset] = msg;
+ m_encr_hold[m_encr_offset++] = *msg++;
+ }
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_cbc_c::finalize_non_aligned()
+{
+ eap_status_e status = eap_status_ok;
+
+ if (m_encr_offset > 0)
+ {
+ if ((m_encr_offset
+ % m_crypto_block_algorithm->get_block_size()) != 0u)
+ {
+ EAP_ASSERT_ALWAYS(
+ (m_encr_offset
+ % m_crypto_block_algorithm->get_block_size()) == 0u);
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_data_length_not_aligned_to_block_size);
+ }
+
+ i32_t ind;
+
+ /* Unfinished business... flush it out! */
+ if (m_crypto_block_algorithm->get_encrypts() == true)
+ {
+ status = encrypt_data(
+ m_encr_hold,
+ m_crypto_block_algorithm->get_block_size());
+ }
+ else
+ {
+ status = decrypt_data(
+ m_encr_hold,
+ m_crypto_block_algorithm->get_block_size());
+ }
+
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ for (ind = 0u; ind < m_encr_offset; ++ind)
+ {
+ *(m_encr_dispatch[ind]) = m_encr_hold[ind];
+ }
+ m_encr_offset = 0; /* (should not be needed, but... ) */
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_aes_c::~crypto_aes_c()
+{
+ if (m_aes_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->aes_cleanup(&m_aes_context);
+ }
+ m_aes_context.reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_aes_c::crypto_aes_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+ , m_aes_context(tools)
+ , m_block_size(0u)
+ , m_encrypt(false)
+{
+ m_block_size = m_am_tools->get_crypto()->aes_block_size();
+
+ m_aes_context.reset();
+
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_aes_c::get_encrypts()
+{
+ return m_encrypt;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_aes_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_aes_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_aes_c::get_key_length()
+{
+ return m_am_tools->get_crypto()->aes_key_length();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_aes_c::get_block_size()
+{
+ return m_block_size;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_c::set_encryption_key(
+ const void * const key,
+ const u32_t key_length)
+{
+ m_encrypt = true;
+
+ return m_am_tools->get_crypto()->aes_set_encryption_key(
+ &m_aes_context, static_cast<const u8_t *>(key), key_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_c::set_decryption_key(
+ const void * const key,
+ const u32_t key_length)
+{
+ m_encrypt = false;
+
+ return m_am_tools->get_crypto()->aes_set_decryption_key(
+ &m_aes_context, static_cast<const u8_t *>(key), key_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_c::encrypt_block(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_in) % 4) == 0));
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_out) % 4) == 0));
+
+ return m_am_tools->get_crypto()->aes_encrypt_block(
+ &m_aes_context,
+ static_cast<const u8_t *>(data_in),
+ static_cast<u8_t *>(data_out),
+ data_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_c::decrypt_block(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_in) % 4) == 0));
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_out) % 4) == 0));
+
+ return m_am_tools->get_crypto()->aes_decrypt_block(
+ &m_aes_context,
+ static_cast<const u8_t *>(data_in),
+ static_cast<u8_t *>(data_out), data_length);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_3des_ede_c::~crypto_3des_ede_c()
+{
+ if (m_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->cleanup_3des_ede(&m_context);
+ }
+ m_context.reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_3des_ede_c::crypto_3des_ede_c(
+ abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+ , m_context(tools)
+ , m_block_size(0u)
+ , m_encrypt(false)
+{
+ m_block_size = m_am_tools->get_crypto()->block_size_3des_ede();
+
+ m_context.reset();
+
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_3des_ede_c::get_encrypts()
+{
+ return m_encrypt;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_3des_ede_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_3des_ede_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_3des_ede_c::get_key_length()
+{
+ return m_am_tools->get_crypto()->key_length_3des_ede();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_3des_ede_c::get_block_size()
+{
+ return m_block_size;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_3des_ede_c::set_encryption_key(
+ const void * const key,
+ const u32_t key_length)
+{
+ m_encrypt = true;
+
+ return m_am_tools->get_crypto()->set_encryption_key_3des_ede(
+ &m_context, static_cast<const u8_t *>(key), key_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_3des_ede_c::set_decryption_key(
+ const void * const key,
+ const u32_t key_length)
+{
+ m_encrypt = false;
+
+ return m_am_tools->get_crypto()->set_decryption_key_3des_ede(
+ &m_context, static_cast<const u8_t *>(key), key_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_3des_ede_c::encrypt_block(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_in) % 4) == 0));
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_out) % 4) == 0));
+
+ return m_am_tools->get_crypto()->encrypt_block_3des_ede(
+ &m_context,
+ static_cast<const u8_t *>(data_in),
+ static_cast<u8_t *>(data_out),
+ data_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_3des_ede_c::decrypt_block(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_in) % 4) == 0));
+ EAP_ASSERT_TOOLS(m_am_tools, ((reinterpret_cast<u32_t>(data_out) % 4) == 0));
+
+ return m_am_tools->get_crypto()->decrypt_block_3des_ede(
+ &m_context,
+ static_cast<const u8_t *>(data_in),
+ static_cast<u8_t *>(data_out),
+ data_length);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_aes_wrap_c::~crypto_aes_wrap_c()
+{
+}
+
+EAP_FUNC_EXPORT crypto_aes_wrap_c::crypto_aes_wrap_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_aes(tools)
+ , m_key(tools)
+ , m_encrypt(false)
+ , m_is_valid(false)
+{
+ if (m_aes.get_is_valid() == false)
+ {
+ return;
+ }
+
+ if (m_key.get_is_valid() == false)
+ {
+ return;
+ }
+
+ set_is_valid();
+}
+
+EAP_FUNC_EXPORT void crypto_aes_wrap_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+EAP_FUNC_EXPORT bool crypto_aes_wrap_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+EAP_FUNC_EXPORT bool crypto_aes_wrap_c::get_encrypts()
+{
+ return m_encrypt;
+}
+
+EAP_FUNC_EXPORT u32_t crypto_aes_wrap_c::get_key_length()
+{
+ return m_aes.get_key_length();
+}
+
+EAP_FUNC_EXPORT u32_t crypto_aes_wrap_c::get_block_size()
+{
+ return EAP_CRYPTO_AES_WRAP_BLOCK_SIZE;
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_wrap_c::set_encryption_key(
+ const void * const key,
+ const u32_t key_length)
+{
+ eap_status_e status = m_key.set_copy_of_buffer(key, key_length);
+
+ m_encrypt = true;
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("AES-Wrap enc key"),
+ m_key.get_data(),
+ m_key.get_data_length()));
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_wrap_c::set_decryption_key(
+ const void * const key,
+ const u32_t key_length)
+{
+ eap_status_e status = m_key.set_copy_of_buffer(key, key_length);
+
+ m_encrypt = false;
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("AES-Wrap dec key"),
+ m_key.get_data(),
+ m_key.get_data_length()));
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_wrap_c::add_padding_bytes(
+ void * const buffer,
+ const u32_t buffer_length)
+{
+ if (buffer == 0
+ || buffer_length == 0)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ u8_t * data = static_cast<u8_t *>(buffer);
+
+ data[0] = 0xdd;
+
+ for (u32_t ind = 1ul; ind < buffer_length; ind++)
+ {
+ data[ind] = 0x00;
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_wrap_c::encrypt_block(
+ const void * const data_in,
+ const u32_t data_in_length,
+ void * const data_out,
+ const u32_t data_out_length)
+{
+#if !defined(DISABLE_CRYPTO_AES_WRAP)
+ /*
+ Inputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}, and
+ Key, K (the KEK).
+ Outputs: Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}.
+ */
+ if (data_in == 0
+ || data_out == 0
+ || (data_in_length % get_block_size()) != 0
+ || data_out_length < data_in_length+get_block_size())
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("plain data"),
+ data_in,
+ data_in_length));
+
+ /*
+ 1) Initialize variables.
+
+ Set A = IV, an initial value (see 2.2.3)
+ For i = 1 to n
+ R[i] = P[i]
+ */
+
+ u64_t A_integrity_reg;
+ EAP_ASSERT_TOOLS(m_am_tools, sizeof(A_integrity_reg) == sizeof(EAP_CRYPTO_AES_WRAP_DEFAULT_INITIAL_IV));
+ m_am_tools->memmove(&A_integrity_reg, EAP_CRYPTO_AES_WRAP_DEFAULT_INITIAL_IV, sizeof(A_integrity_reg));
+
+ eap_variable_data_c Register(m_am_tools);
+
+ eap_status_e status = Register.set_copy_of_buffer(data_in, data_in_length);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ /*
+ 2) Calculate intermediate values.
+
+ For j = 0 to 5
+ For i=1 to n
+ B = AES(K, A | R[i])
+ A = MSB(64, B) ^ t where t = (n*j)+i
+ R[i] = LSB(64, B)
+ */
+
+ u64_t n_block_count = Register.get_data_length() / 8ul;
+ u64_t B_tmp_buffer[2];
+ eap_variable_data_c data(m_am_tools);
+
+ status = data.set_buffer_length(sizeof(A_integrity_reg) + EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ for (u64_t j_ind = 0ul; j_ind <= 5ul; j_ind++)
+ {
+ for (u64_t i_ind = 1ul; i_ind <= n_block_count; i_ind++)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("\n")));
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_aes_wrap_c::encrypt_block(): j_ind %d, i_ind %d\n"),
+ j_ind,
+ i_ind));
+
+ eap_status_e status = m_aes.set_encryption_key(
+ m_key.get_data(),
+ m_key.get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("In A_integrity_reg"),
+ &A_integrity_reg,
+ sizeof(A_integrity_reg)));
+
+ status = data.set_copy_of_buffer(&A_integrity_reg, sizeof(A_integrity_reg));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u8_t * const Ri_reg = Register.get_data_offset(
+ static_cast<u32_t>((i_ind-1ul))*static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE),
+ static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE));
+ if (Ri_reg == 0)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL(" In Ri_reg"),
+ Ri_reg,
+ static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE)));
+
+ status = data.add_data(Ri_reg, EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_ASSERT_TOOLS(m_am_tools, sizeof(B_tmp_buffer) == data.get_data_length());
+
+ status = m_aes.encrypt_block(
+ data.get_data(),
+ B_tmp_buffer,
+ data.get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL(" Enc B_tmp_buffer"),
+ B_tmp_buffer,
+ sizeof(B_tmp_buffer)));
+
+ u64_t counter = m_am_tools->multiply_u64(n_block_count, j_ind) + i_ind;
+
+ A_integrity_reg = eap_htonll(
+ m_am_tools->xor_u64(
+ eap_ntohll(*B_tmp_buffer),
+ counter));
+
+ m_am_tools->memmove(Ri_reg, B_tmp_buffer+1, sizeof(u64_t));
+ }
+ }
+
+ /*
+ 3) Output the results.
+
+ Set C[0] = A
+ For i = 1 to n
+ C[i] = R[i]
+ */
+
+ u8_t * const C = static_cast<u8_t *>(data_out);
+
+ m_am_tools->memmove(C, &A_integrity_reg, EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+
+ for (u32_t i_ind = 1ul; i_ind <= n_block_count; i_ind++)
+ {
+ u32_t offset = static_cast<u32_t>(i_ind)*static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+
+ u8_t * const Ri_reg = Register.get_data_offset(
+ static_cast<u32_t>((i_ind-1ul))*static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE),
+ static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE));
+ if (Ri_reg == 0)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ m_am_tools->memmove((C + offset), Ri_reg, EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("encrypted data"),
+ data_out,
+ data_out_length));
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+
+#else // !defined(DISABLE_CRYPTO_AES_WRAP)
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
+#endif
+
+}
+
+EAP_FUNC_EXPORT eap_status_e crypto_aes_wrap_c::decrypt_block(
+ const void * const data_in,
+ const u32_t data_in_length,
+ void * const data_out,
+ const u32_t data_out_length)
+{
+#if !defined(DISABLE_CRYPTO_AES_WRAP)
+ /*
+ Inputs: Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}, and
+ Key, K (the KEK).
+ Outputs: Plaintext, n 64-bit values {P0, P1, K, Pn}.
+ */
+ if (data_in == 0
+ || data_out == 0
+ || (data_in_length % get_block_size()) != 0
+ || data_out_length < data_in_length-get_block_size())
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("encrypted data"),
+ data_in,
+ data_in_length));
+
+ /*
+ 1) Initialize variables.
+
+ Set A = C[0]
+ For i = 1 to n
+ R[i] = C[i]
+ */
+ u64_t A_integrity_reg(0ul);
+ const u8_t * const cipher_text = static_cast<const u8_t *>(data_in);
+
+ m_am_tools->memmove(&A_integrity_reg, cipher_text, EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+
+ eap_variable_data_c Register(m_am_tools);
+
+ eap_status_e status = Register.set_copy_of_buffer(
+ (cipher_text + static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE)),
+ data_in_length - static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ /*
+ 2) Compute intermediate values.
+
+ For j = 5 to 0
+ For i = n to 1
+ B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
+ A = MSB(64, B)
+ R[i] = LSB(64, B)
+ */
+
+ u64_t n_block_count = Register.get_data_length() / 8ul;
+ u64_t B_tmp_buffer[2];
+ eap_variable_data_c data(m_am_tools);
+
+ status = data.set_buffer_length(sizeof(A_integrity_reg) + EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u64_t j_ind(5ul);
+
+ for(;;)
+ {
+ for (u64_t i_ind = n_block_count; i_ind >= 1; i_ind--)
+ {
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("\n")));
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_aes_wrap_c::decrypt_block(): j_ind %d, i_ind %d\n"),
+ j_ind,
+ i_ind));
+
+ eap_status_e status = m_aes.set_decryption_key(
+ m_key.get_data(),
+ m_key.get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u64_t counter = m_am_tools->multiply_u64(n_block_count, j_ind) + i_ind;
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("In A_integrity_reg"),
+ &A_integrity_reg,
+ sizeof(A_integrity_reg)));
+
+ A_integrity_reg = eap_htonll(
+ m_am_tools->xor_u64(
+ eap_ntohll(A_integrity_reg),
+ counter));
+
+ status = data.set_copy_of_buffer(&A_integrity_reg, sizeof(A_integrity_reg));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u8_t * const Ri_reg = Register.get_data_offset(
+ static_cast<u32_t>((i_ind-1ul))*static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE),
+ static_cast<u32_t>(EAP_CRYPTO_AES_WRAP_BLOCK_SIZE));
+ if (Ri_reg == 0)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL(" In Ri_reg"),
+ Ri_reg,
+ EAP_CRYPTO_AES_WRAP_BLOCK_SIZE));
+
+ status = data.add_data(Ri_reg, EAP_CRYPTO_AES_WRAP_BLOCK_SIZE);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_ASSERT_TOOLS(m_am_tools, sizeof(B_tmp_buffer) == data.get_data_length());
+
+ status = m_aes.decrypt_block(
+ data.get_data(),
+ B_tmp_buffer,
+ data.get_data_length());
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL(" Dec B_tmp_buffer"),
+ B_tmp_buffer,
+ sizeof(B_tmp_buffer)));
+
+ A_integrity_reg = *B_tmp_buffer;
+
+ m_am_tools->memmove(Ri_reg, B_tmp_buffer+1, sizeof(u64_t));
+ }
+
+ if (j_ind == 0)
+ {
+ // Terminates the loop.
+ break;
+ }
+
+ // Decrementation must be after the termination test,
+ // because we need to run the loop also with j_ind value 0.
+ --j_ind;
+ }
+
+ /*
+ 3) Output results.
+
+ If A is an appropriate initial value (see 2.2.3),
+ Then
+ For i = 1 to n
+ P[i] = R[i]
+ Else
+ Return an error
+ */
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("plain data"),
+ Register.get_data(),
+ Register.get_data_length()));
+
+ if (m_am_tools->memcmp(&A_integrity_reg, EAP_CRYPTO_AES_WRAP_DEFAULT_INITIAL_IV, sizeof(A_integrity_reg)) == 0)
+ {
+ // OK
+ m_am_tools->memmove(data_out, Register.get_data(), Register.get_data_length());
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+ }
+ else
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure);
+ }
+
+#else // !defined(DISABLE_CRYPTO_AES_WRAP)
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
+
+#endif
+
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_random_c::~crypto_random_c()
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_random_c::crypto_random_c(
+ abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_random_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_random_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_random_c::get_rand_bytes(
+ void * const buffer,
+ const u32_t count)
+{
+ return m_am_tools->get_crypto()->get_rand_bytes(
+ static_cast<u8_t *>(buffer), count);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_random_c::get_rand_bytes(
+ eap_variable_data_c * const buffer,
+ const u32_t count)
+{
+ if (buffer == 0
+ || buffer->get_is_valid() == false)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = buffer->init(count);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = buffer->set_data_length(count);
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = get_rand_bytes(
+ buffer->get_data(),
+ buffer->get_data_length());
+ if (status != eap_status_ok)
+ {
+ buffer->reset();
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_random_c::get_rand_integer(
+ const u32_t minimum,
+ const u32_t maximum)
+{
+ const u32_t MAX_U32 = ~(static_cast<u32_t>(0ul));
+
+ u32_t random = 0ul;
+
+ if ((maximum - minimum) == MAX_U32 )
+ {
+ eap_status_e status = get_rand_bytes(&random, sizeof(random));
+ if (status != eap_status_ok)
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ u32_t frame = ((maximum+1)-minimum);
+ u32_t randomized = 0;
+ u32_t max_value = MAX_U32 - (MAX_U32 % frame);
+
+ do
+ {
+ eap_status_e status = get_rand_bytes(&randomized, sizeof(randomized));
+ if (status != eap_status_ok)
+ {
+ return 0;
+ }
+ }
+ while(randomized >= max_value);
+
+ random = ((randomized % frame) + minimum);
+ }
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("RANDOM u32_t %lu\n"),
+ random));
+
+ return random;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_random_c::add_rand_seed(
+ const void * const buffer,
+ const u32_t count)
+{
+ return m_am_tools->get_crypto()->add_rand_seed(
+ static_cast<const u8_t *>(buffer), count);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_random_c::add_rand_seed_hw_ticks()
+{
+ return m_am_tools->get_crypto()->add_rand_seed_hw_ticks();
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_sha_256_c::~crypto_sha_256_c()
+{
+ hash_cleanup();
+ m_sha_256_context.reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_sha_256_c::crypto_sha_256_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_sha_256_context(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha_256_c::copy_context(
+ const eap_variable_data_c * const sha_256_context)
+{
+ if (sha_256_context == 0
+ || sha_256_context->get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = m_am_tools->get_crypto()->sha_256_copy_context(
+ &m_sha_256_context,
+ sha_256_context);
+ if (status != eap_status_ok)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_sha_256_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_sha_256_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_sha_256_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_sha_256_c::get_digest_length()
+{
+ // This is simple optimization.
+ return EAP_CRYPTO_API_SHA_256_DIGEST_BUFFER_BYTE_SIZE;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_sha_256_c::get_block_size()
+{
+ // This is simple optimization.
+ return EAP_CRYPTO_API_SHA_256_BLOCK_BYTE_SIZE;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha_256_c::hash_init()
+{
+ eap_status_e status = m_am_tools->get_crypto()->sha_256_init(&m_sha_256_context);
+ if (m_sha_256_context.get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ if (status == eap_status_ok)
+ {
+ status = eap_status_allocation_error;
+ }
+ }
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha_256_c::hash_update(
+ const void * const data,
+ const u32_t data_length)
+{
+ eap_status_e status = m_am_tools->get_crypto()->sha_256_update(
+ &m_sha_256_context,
+ static_cast<const u8_t *>(data),
+ data_length);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha_256_c::hash_final(
+ void * const message_digest,
+ u32_t *md_length_or_null)
+{
+ eap_status_e status = m_am_tools->get_crypto()->sha_256_final(
+ &m_sha_256_context,
+ static_cast<u8_t *>(message_digest),
+ md_length_or_null);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha_256_c::hash_cleanup()
+{
+ if (m_sha_256_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->sha_256_cleanup(&m_sha_256_context);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT abs_crypto_hash_algorithm_c * crypto_sha_256_c::copy()
+{
+ crypto_sha_256_c * const new_context = new crypto_sha_256_c(m_am_tools);
+ if (new_context == 0)
+ {
+ return 0;
+ }
+
+ eap_status_e status = new_context->copy_context(&m_sha_256_context);
+ if (status != eap_status_ok)
+ {
+ delete new_context;
+ return 0;
+ }
+
+ return new_context;
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_sha1_c::~crypto_sha1_c()
+{
+ hash_cleanup();
+ m_sha1_context.reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_sha1_c::crypto_sha1_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_sha1_context(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha1_c::copy_context(
+ const eap_variable_data_c * const sha1_context)
+{
+ if (sha1_context == 0
+ || sha1_context->get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = m_am_tools->get_crypto()->sha1_copy_context(
+ &m_sha1_context,
+ sha1_context);
+ if (status != eap_status_ok)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_sha1_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_sha1_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_sha1_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_sha1_c::get_digest_length()
+{
+ // This is simple optimization.
+ return EAP_CRYPTO_API_SHA1_DIGEST_BUFFER_BYTE_SIZE;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_sha1_c::get_block_size()
+{
+ // This is simple optimization.
+ return EAP_CRYPTO_API_SHA1_BLOCK_BYTE_SIZE;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha1_c::hash_init()
+{
+ eap_status_e status = m_am_tools->get_crypto()->sha1_init(&m_sha1_context);
+ if (m_sha1_context.get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ if (status == eap_status_ok)
+ {
+ status = eap_status_allocation_error;
+ }
+ }
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha1_c::hash_update(
+ const void * const data,
+ const u32_t data_length)
+{
+ eap_status_e status = m_am_tools->get_crypto()->sha1_update(
+ &m_sha1_context,
+ static_cast<const u8_t *>(data),
+ data_length);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha1_c::hash_final(
+ void * const message_digest,
+ u32_t *md_length_or_null)
+{
+ eap_status_e status = m_am_tools->get_crypto()->sha1_final(
+ &m_sha1_context,
+ static_cast<u8_t *>(message_digest),
+ md_length_or_null);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_sha1_c::hash_cleanup()
+{
+ if (m_sha1_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->sha1_cleanup(&m_sha1_context);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT abs_crypto_hash_algorithm_c * crypto_sha1_c::copy()
+{
+ crypto_sha1_c * const new_context = new crypto_sha1_c(m_am_tools);
+ if (new_context == 0)
+ {
+ return 0;
+ }
+
+ eap_status_e status = new_context->copy_context(&m_sha1_context);
+ if (status != eap_status_ok)
+ {
+ delete new_context;
+ return 0;
+ }
+
+ return new_context;
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT
+crypto_ephemeral_diffie_hellman_c::~crypto_ephemeral_diffie_hellman_c()
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT
+crypto_ephemeral_diffie_hellman_c::crypto_ephemeral_diffie_hellman_c(
+ abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_ephemeral_diffie_hellman_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_ephemeral_diffie_hellman_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e
+crypto_ephemeral_diffie_hellman_c::generate_diffie_hellman_keys(
+ eap_variable_data_c * const own_private_dh_key,
+ eap_variable_data_c * const own_public_dh_key,
+ const void * const prime,
+ const u32_t prime_length,
+ const void * const group_generator,
+ const u32_t group_generator_length)
+{
+ return m_am_tools->get_crypto()->generate_diffie_hellman_keys(
+ own_private_dh_key,
+ own_public_dh_key,
+ static_cast<const u8_t *>(prime),
+ prime_length,
+ static_cast<const u8_t *>(group_generator),
+ group_generator_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e
+crypto_ephemeral_diffie_hellman_c::generate_g_power_to_xy(
+ const eap_variable_data_c * const own_private_dh_key,
+ const eap_variable_data_c * const peer_public_dh_key,
+ eap_variable_data_c * const shared_dh_key,
+ const void * const prime,
+ const u32_t prime_length,
+ const void * const group_generator,
+ const u32_t group_generator_length)
+{
+ return m_am_tools->get_crypto()->generate_g_power_to_xy(
+ own_private_dh_key,
+ peer_public_dh_key,
+ shared_dh_key,
+ static_cast<const u8_t *>(prime),
+ prime_length,
+ static_cast<const u8_t *>(group_generator),
+ group_generator_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e
+crypto_ephemeral_diffie_hellman_c::dh_cleanup(
+ const eap_variable_data_c * const dh_context)
+{
+ return m_am_tools->get_crypto()->dh_cleanup(
+ dh_context);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_md5_c::~crypto_md5_c()
+{
+ hash_cleanup();
+ m_md5_context.reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_md5_c::crypto_md5_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_md5_context(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md5_c::copy_context(
+ const eap_variable_data_c * const md5_context)
+{
+ if (md5_context == 0
+ || md5_context->get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = m_am_tools->get_crypto()->md5_copy_context(
+ &m_md5_context,
+ md5_context);
+ if (status != eap_status_ok)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_md5_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_md5_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_md5_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_md5_c::get_digest_length()
+{
+ return m_am_tools->get_crypto()->get_md5_digest_length(&m_md5_context);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_md5_c::get_block_size()
+{
+ return m_am_tools->get_crypto()->get_md5_block_size(&m_md5_context);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md5_c::hash_init()
+{
+ eap_status_e status = m_am_tools->get_crypto()->md5_init(&m_md5_context);
+
+ if (m_md5_context.get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ if (status == eap_status_ok)
+ {
+ status = eap_status_allocation_error;
+ }
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md5_c::hash_update(
+ const void * const data,
+ const u32_t data_length)
+{
+ eap_status_e status = m_am_tools->get_crypto()->md5_update(
+ &m_md5_context,
+ static_cast<const u8_t *>(data),
+ data_length);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md5_c::hash_final(
+ void * const message_digest,
+ u32_t *md_length_or_null)
+{
+ eap_status_e status = m_am_tools->get_crypto()->md5_final(
+ &m_md5_context,
+ static_cast<u8_t *>(message_digest),
+ md_length_or_null);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md5_c::hash_cleanup()
+{
+ if (m_md5_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->md5_cleanup(&m_md5_context);
+ }
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT abs_crypto_hash_algorithm_c * crypto_md5_c::copy()
+{
+ crypto_md5_c * const new_context = new crypto_md5_c(m_am_tools);
+ if (new_context == 0)
+ {
+ return 0;
+ }
+
+ eap_status_e status = new_context->copy_context(&m_md5_context);
+ if (status != eap_status_ok)
+ {
+ delete new_context;
+ return 0;
+ }
+
+ return new_context;
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_md4_c::~crypto_md4_c()
+{
+ hash_cleanup();
+ m_md4_context.reset();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_md4_c::crypto_md4_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_md4_context(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md4_c::copy_context(
+ const eap_variable_data_c * const md4_context)
+{
+ if (md4_context == 0
+ || md4_context->get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = m_am_tools->get_crypto()->md4_copy_context(
+ &m_md4_context,
+ md4_context);
+ if (status != eap_status_ok)
+ {
+ set_is_invalid();
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_md4_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_md4_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_md4_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_md4_c::get_digest_length()
+{
+ return m_am_tools->get_crypto()->get_md4_digest_length(&m_md4_context);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT u32_t crypto_md4_c::get_block_size()
+{
+ return m_am_tools->get_crypto()->get_md4_block_size(&m_md4_context);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md4_c::hash_init()
+{
+ // Cleanup the previous context.
+ hash_cleanup();
+
+ eap_status_e status = m_am_tools->get_crypto()->md4_init(&m_md4_context);
+
+ if (m_md4_context.get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ if (status == eap_status_ok)
+ {
+ status = eap_status_allocation_error;
+ }
+ }
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md4_c::hash_update(
+ const void * const data,
+ const u32_t data_length)
+{
+ eap_status_e status = m_am_tools->get_crypto()->md4_update(
+ &m_md4_context,
+ static_cast<const u8_t *>(data),
+ data_length);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md4_c::hash_final(
+ void * const message_digest,
+ u32_t *md_length_or_null)
+{
+ eap_status_e status = m_am_tools->get_crypto()->md4_final(
+ &m_md4_context,
+ static_cast<u8_t *>(message_digest),
+ md_length_or_null);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_md4_c::hash_cleanup()
+{
+ if (m_md4_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->md4_cleanup(&m_md4_context);
+ }
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT abs_crypto_hash_algorithm_c * crypto_md4_c::copy()
+{
+ crypto_md4_c * const new_context = new crypto_md4_c(m_am_tools);
+ if (new_context == 0)
+ {
+ return 0;
+ }
+
+ eap_status_e status = new_context->copy_context(&m_md4_context);
+ if (status != eap_status_ok)
+ {
+ delete new_context;
+ return 0;
+ }
+
+ return new_context;
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_rc4_c::~crypto_rc4_c()
+{
+ if (m_rc4_context.get_is_valid_data() == true)
+ {
+ m_am_tools->get_crypto()->rc4_cleanup(&m_rc4_context);
+ }
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_rc4_c::crypto_rc4_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_rc4_context(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_rc4_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_rc4_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_rc4_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rc4_c::set_key(
+ const eap_variable_data_c * const key)
+{
+ return m_am_tools->get_crypto()->rc4_set_key(&m_rc4_context, key);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rc4_c::discard_stream(
+ const u32_t count_of_discarded_octets)
+{
+ eap_status_e status = eap_status_ok;
+
+ for (u32_t ind = 0ul; ind < count_of_discarded_octets; ind++)
+ {
+ u8_t octet = 0;
+ status = encrypt_data(
+ &octet,
+ sizeof(octet));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ } // for()
+
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rc4_c::encrypt_data(
+ void * const data_in_out,
+ const u32_t data_length)
+{
+ return m_am_tools->get_crypto()->rc4_encrypt(
+ &m_rc4_context,
+ data_in_out,
+ data_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rc4_c::encrypt_data(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ return m_am_tools->get_crypto()->rc4_encrypt(
+ &m_rc4_context,
+ data_in,
+ data_out,
+ data_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rc4_c::decrypt_data(
+ void * const data_in_out,
+ const u32_t data_length)
+{
+ return m_am_tools->get_crypto()->rc4_decrypt(
+ &m_rc4_context,
+ data_in_out,
+ data_length);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rc4_c::decrypt_data(
+ const void * const data_in,
+ void * const data_out,
+ const u32_t data_length)
+{
+ return m_am_tools->get_crypto()->rc4_decrypt(
+ &m_rc4_context,
+ data_in,
+ data_out,
+ data_length);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_base_prf_c::~crypto_tls_base_prf_c()
+{
+ tls_prf_cleanup();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_base_prf_c::crypto_tls_base_prf_c(
+ abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_base_prf_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_base_prf_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_tls_base_prf_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_base_prf_c::tls_prf_A_value(
+ abs_crypto_hmac_algorithm_c * const hash,
+ eap_variable_data_c * const key,
+ eap_variable_data_c * const seed,
+ eap_variable_data_c * const A_output)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (hash == 0
+ || key == 0
+ || seed == 0
+ || A_output == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // First we initialize A value.
+
+ eap_status_e status = hash->hmac_set_key(key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hash->hmac_update(
+ seed->get_data(seed->get_data_length()),
+ seed->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u32_t hmac_md_length = hash->get_digest_length();
+
+ status = hash->hmac_final(
+ A_output->get_data(hmac_md_length),
+ &hmac_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_base_prf_c::tls_prf_one_round(
+ abs_crypto_hmac_algorithm_c * const hash,
+ const eap_variable_data_c * const key,
+ eap_variable_data_c * const A_input,
+ eap_variable_data_c * const seed,
+ void * const out_buffer,
+ const u32_t out_buffer_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (hash == 0
+ || key == 0
+ || A_input == 0
+ || seed == 0
+ || out_buffer == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = hash->hmac_set_key(key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hash->hmac_update(
+ A_input->get_data(A_input->get_data_length()),
+ A_input->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hash->hmac_update(
+ seed->get_data(seed->get_data_length()),
+ seed->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u32_t hmac_md_length = hash->get_digest_length();
+
+ if (hmac_md_length > out_buffer_length)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_buffer_too_short);
+ }
+
+ status = hash->hmac_final(
+ out_buffer,
+ &hmac_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_base_prf_c::tls_prf_cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_sha1_prf_c::~crypto_tls_sha1_prf_c()
+{
+ tls_prf_cleanup();
+
+ delete m_sha1_context;
+ m_sha1_context = 0;
+
+ delete m_A_sha1_context;
+ m_A_sha1_context = 0;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_sha1_prf_c::crypto_tls_sha1_prf_c(
+ abs_eap_am_tools_c * const tools)
+ : crypto_tls_base_prf_c(tools)
+ , m_am_tools(tools)
+ , m_sha1_context(0)
+ , m_A_sha1_context(0)
+ , m_sha1_key(tools)
+ , m_seed(tools)
+ , m_is_valid(false)
+{
+ {
+ crypto_sha1_c * sha1 = new crypto_sha1_c(m_am_tools);
+ if (sha1 == 0
+ || sha1->get_is_valid() == false)
+ {
+ delete sha1;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+
+ m_sha1_context = new crypto_hmac_c(m_am_tools, sha1, true);
+ if (m_sha1_context == 0
+ || m_sha1_context->get_is_valid() == false)
+ {
+ delete m_sha1_context;
+ m_sha1_context = 0;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+ }
+
+ {
+ crypto_sha1_c * sha1 = new crypto_sha1_c(m_am_tools);
+ if (sha1 == 0
+ || sha1->get_is_valid() == false)
+ {
+ delete sha1;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+
+ m_A_sha1_context = new crypto_hmac_c(m_am_tools, sha1, true);
+ if (m_A_sha1_context == 0
+ || m_A_sha1_context->get_is_valid() == false)
+ {
+ delete m_A_sha1_context;
+ m_A_sha1_context = 0;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+ }
+
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_sha1_prf_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_sha1_prf_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_tls_sha1_prf_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_sha1_prf_c::tls_prf_init(
+ const eap_variable_data_c * const secret,
+ const eap_variable_data_c * const label,
+ const eap_variable_data_c * const seed)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (secret->get_is_valid_data() == false
+ || secret->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if (label->get_is_valid_data() == false
+ || label->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // NOTE seed could be empty buffer.
+ if (seed->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c input(m_am_tools);
+
+ eap_status_e status = input.add_data(label);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = input.add_data(seed);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_seed.set_copy_of_buffer(&input);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): m_seed"),
+ m_seed.get_data(m_seed.get_data_length()),
+ m_seed.get_data_length()));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_sha1_key.set_copy_of_buffer(
+ secret);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): m_sha1_key"),
+ m_sha1_key.get_data(m_sha1_key.get_data_length()),
+ m_sha1_key.get_data_length()));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_sha1_prf_c::tls_prf_output(
+ void * const pseudo_random_data,
+ const u32_t pseudo_random_data_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (pseudo_random_data == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = eap_status_not_supported;
+
+ EAP_ASSERT_ALWAYS(get_is_valid() == true);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_A_sha1_context->hmac_set_key(&m_sha1_key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_sha1_context->hmac_set_key(&m_sha1_key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c A_sha1_output(m_am_tools);
+
+ status = A_sha1_output.init(m_A_sha1_context->get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ A_sha1_output.set_is_valid();
+ A_sha1_output.set_data_length(A_sha1_output.get_buffer_length());
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c sha1_output(m_am_tools);
+
+ status = sha1_output.init(
+ pseudo_random_data_length+m_sha1_context->get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ sha1_output.set_is_valid();
+ sha1_output.set_data_length(sha1_output.get_buffer_length());
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ {
+ u32_t hmac_sha1_md_length = m_sha1_context->get_digest_length();
+ u32_t sha1_count = sha1_output.get_data_length()
+ / m_sha1_context->get_digest_length();
+
+ // First we initialize A value:
+ // A(0) = seed
+ status = tls_prf_A_value(
+ m_A_sha1_context,
+ &m_sha1_key,
+ &m_seed,
+ &A_sha1_output);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // out(1) = HMAC_hash(secret, A(1) + seed)
+ status = tls_prf_one_round(
+ m_sha1_context,
+ &m_sha1_key,
+ &A_sha1_output,
+ &m_seed,
+ sha1_output.get_data_offset(0ul, hmac_sha1_md_length),
+ hmac_sha1_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ for (u32_t ind = 1ul; ind < sha1_count; ind++)
+ {
+ // Next A value is:
+ // A(i) = HMAC_hash(secret, A(i-1)).
+ status = tls_prf_A_value(
+ m_A_sha1_context,
+ &m_sha1_key,
+ &A_sha1_output,
+ &A_sha1_output);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // out(i) = HMAC_hash(secret, A(i) + seed)
+ status = tls_prf_one_round(
+ m_sha1_context,
+ &m_sha1_key,
+ &A_sha1_output,
+ &m_seed,
+ sha1_output.get_data_offset(
+ ind*hmac_sha1_md_length,
+ hmac_sha1_md_length),
+ hmac_sha1_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ } // for()
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ // Final operation is copy sha1_output to output buffer.
+
+ {
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_tls_sha1_prf_c::tls_prf_output(): sha1_output"),
+ sha1_output.get_data(pseudo_random_data_length),
+ pseudo_random_data_length));
+
+ EAP_ASSERT(pseudo_random_data_length <= sha1_output.get_data_length());
+
+ const u8_t * const sha1_buffer = sha1_output.get_data(
+ pseudo_random_data_length);
+ if (sha1_buffer == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u8_t * const p_pseudo_random_data
+ = static_cast<u8_t *>(pseudo_random_data);
+
+ m_am_tools->memmove(
+ p_pseudo_random_data,
+ sha1_buffer,
+ pseudo_random_data_length);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_tls_sha1_prf_c::tls_prf_output(): ")
+ EAPL("p_pseudo_random_data"),
+ p_pseudo_random_data,
+ pseudo_random_data_length));
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_sha1_prf_c::tls_prf_cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (m_sha1_context != 0)
+ {
+ m_sha1_context->hmac_cleanup();
+ }
+
+ if (m_A_sha1_context != 0)
+ {
+ m_A_sha1_context->hmac_cleanup();
+ }
+
+ m_sha1_key.reset();
+ m_seed.reset();
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_md5_prf_c::~crypto_tls_md5_prf_c()
+{
+ tls_prf_cleanup();
+
+ delete m_md5_context;
+ m_md5_context = 0;
+
+ delete m_A_md5_context;
+ m_A_md5_context = 0;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_md5_prf_c::crypto_tls_md5_prf_c(
+ abs_eap_am_tools_c * const tools)
+ : crypto_tls_base_prf_c(tools)
+ , m_am_tools(tools)
+ , m_md5_context(0)
+ , m_A_md5_context(0)
+ , m_md5_key(tools)
+ , m_seed(tools)
+ , m_is_valid(false)
+{
+ {
+ crypto_md5_c * md5 = new crypto_md5_c(m_am_tools);
+ if (md5 == 0
+ || md5->get_is_valid() == false)
+ {
+ delete md5;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+
+ m_md5_context = new crypto_hmac_c(m_am_tools, md5, true);
+ if (m_md5_context == 0
+ || m_md5_context->get_is_valid() == false)
+ {
+ delete m_md5_context;
+ m_md5_context = 0;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+ }
+
+ {
+ crypto_md5_c * md5 = new crypto_md5_c(m_am_tools);
+ if (md5 == 0
+ || md5->get_is_valid() == false)
+ {
+ delete md5;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+
+ m_A_md5_context = new crypto_hmac_c(m_am_tools, md5, true);
+ if (m_A_md5_context == 0
+ || m_A_md5_context->get_is_valid() == false)
+ {
+ delete m_A_md5_context;
+ m_A_md5_context = 0;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+ }
+
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_md5_prf_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_md5_prf_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_tls_md5_prf_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_md5_prf_c::tls_prf_init(
+ const eap_variable_data_c * const secret,
+ const eap_variable_data_c * const label,
+ const eap_variable_data_c * const seed)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (secret->get_is_valid_data() == false
+ || secret->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if (label->get_is_valid_data() == false
+ || label->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if (seed->get_is_valid_data() == false
+ || seed->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c input(m_am_tools);
+
+ eap_status_e status = input.add_data(label);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = input.add_data(seed);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_seed.set_copy_of_buffer(&input);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): m_seed"),
+ m_seed.get_data(m_seed.get_data_length()),
+ m_seed.get_data_length()));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_md5_key.set_copy_of_buffer(
+ secret);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): m_md5_key"),
+ m_md5_key.get_data(m_md5_key.get_data_length()),
+ m_md5_key.get_data_length()));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_md5_prf_c::tls_prf_output(
+ void * const pseudo_random_data,
+ const u32_t pseudo_random_data_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (pseudo_random_data == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = eap_status_not_supported;
+
+ EAP_ASSERT_ALWAYS(get_is_valid() == true);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_A_md5_context->hmac_set_key(&m_md5_key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_md5_context->hmac_set_key(&m_md5_key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c A_md5_output(m_am_tools);
+
+ status = A_md5_output.init(m_A_md5_context->get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ A_md5_output.set_is_valid();
+ A_md5_output.set_data_length(A_md5_output.get_buffer_length());
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c md5_output(m_am_tools);
+
+ status = md5_output.init(
+ pseudo_random_data_length+m_md5_context->get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ md5_output.set_is_valid();
+ md5_output.set_data_length(md5_output.get_buffer_length());
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ {
+ u32_t hmac_md5_md_length = m_md5_context->get_digest_length();
+ u32_t md5_count = md5_output.get_data_length()
+ / m_md5_context->get_digest_length();
+
+ // First we initialize A value:
+ // A(0) = seed
+ status = tls_prf_A_value(
+ m_A_md5_context,
+ &m_md5_key,
+ &m_seed,
+ &A_md5_output);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // out(1) = HMAC_hash(secret, A(1) + seed)
+ status = tls_prf_one_round(
+ m_md5_context,
+ &m_md5_key,
+ &A_md5_output,
+ &m_seed,
+ md5_output.get_data_offset(0ul, hmac_md5_md_length),
+ hmac_md5_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ for (u32_t ind = 1ul; ind < md5_count; ind++)
+ {
+ // Next A value is:
+ // A(i) = HMAC_hash(secret, A(i-1)).
+ status = tls_prf_A_value(
+ m_A_md5_context,
+ &m_md5_key,
+ &A_md5_output,
+ &A_md5_output);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // out(i) = HMAC_hash(secret, A(i) + seed)
+ status = tls_prf_one_round(
+ m_md5_context,
+ &m_md5_key,
+ &A_md5_output,
+ &m_seed,
+ md5_output.get_data_offset(
+ ind*hmac_md5_md_length,
+ hmac_md5_md_length),
+ hmac_md5_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ } // for()
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ // Final operation is copy md5_output to output buffer.
+
+ {
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_tls_md5_prf_c::tls_prf_output(): md5_output"),
+ md5_output.get_data(pseudo_random_data_length),
+ pseudo_random_data_length));
+
+ EAP_ASSERT(pseudo_random_data_length <= md5_output.get_data_length());
+
+ const u8_t * const md5_buffer
+ = md5_output.get_data(pseudo_random_data_length);
+ if (md5_buffer == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u8_t * const p_pseudo_random_data
+ = static_cast<u8_t *>(pseudo_random_data);
+
+ m_am_tools->memmove(
+ p_pseudo_random_data,
+ md5_buffer,
+ pseudo_random_data_length);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_tls_md5_prf_c::tls_prf_output(): ")
+ EAPL("p_pseudo_random_data"),
+ p_pseudo_random_data,
+ pseudo_random_data_length));
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_md5_prf_c::tls_prf_cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (m_md5_context != 0)
+ {
+ m_md5_context->hmac_cleanup();
+ }
+
+ if (m_A_md5_context != 0)
+ {
+ m_A_md5_context->hmac_cleanup();
+ }
+
+ m_md5_key.reset();
+ m_seed.reset();
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_prf_c::~crypto_tls_prf_c()
+{
+ tls_prf_cleanup();
+
+ delete m_tls_md5_prf;
+ m_tls_md5_prf = 0;
+
+ delete m_tls_sha1_prf;
+ m_tls_sha1_prf = 0;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_tls_prf_c::crypto_tls_prf_c(
+ abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_tls_md5_prf(0)
+ , m_tls_sha1_prf(0)
+ , m_is_valid(false)
+{
+ m_tls_md5_prf = new crypto_tls_md5_prf_c(tools);
+ if (m_tls_md5_prf == 0)
+ {
+ return;
+ }
+
+ m_tls_sha1_prf = new crypto_tls_sha1_prf_c(tools);
+ if (m_tls_sha1_prf == 0)
+ {
+ return;
+ }
+
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_prf_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_tls_prf_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_tls_prf_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_prf_c::tls_prf_init(
+ const eap_variable_data_c * const secret,
+ const eap_variable_data_c * const label,
+ const eap_variable_data_c * const seed)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (m_tls_md5_prf == 0
+ || m_tls_sha1_prf == 0)
+ {
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ if (secret->get_is_valid_data() == false
+ || secret->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if (label->get_is_valid_data() == false
+ || label->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if (seed->get_is_valid_data() == false
+ || seed->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ bool is_odd_key = false;
+ if ((secret->get_data_length() % 2) != 0)
+ {
+ // Odd length, one byte will be shared with both keys.
+ is_odd_key = true;
+ }
+
+ u32_t key_length = secret->get_data_length() / 2ul;
+ u32_t sha1_key_offset = key_length;
+
+ if (is_odd_key == true)
+ {
+ ++key_length;
+ }
+
+ eap_variable_data_c md5_secret(m_am_tools);
+ eap_variable_data_c sha1_secret(m_am_tools);
+
+ eap_status_e status = md5_secret.set_buffer(
+ secret->get_data_offset(0ul, key_length),
+ key_length,
+ false,
+ false);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1_secret.set_buffer(
+ secret->get_data_offset(sha1_key_offset, key_length),
+ key_length,
+ false,
+ false);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ status = m_tls_md5_prf->tls_prf_init(&md5_secret, label, seed);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_tls_sha1_prf->tls_prf_init(&sha1_secret, label, seed);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_prf_c::tls_prf_output(
+ void * const pseudo_random_data,
+ const u32_t pseudo_random_data_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = eap_status_not_supported;
+
+ EAP_ASSERT_ALWAYS(get_is_valid() == true);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c tls_md5_prf_output(m_am_tools);
+ eap_variable_data_c tls_sha1_prf_output(m_am_tools);
+
+
+ status = tls_md5_prf_output.init(pseudo_random_data_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ tls_md5_prf_output.set_is_valid();
+ tls_md5_prf_output.set_data_length(tls_md5_prf_output.get_buffer_length());
+
+ status = tls_sha1_prf_output.init(pseudo_random_data_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ tls_sha1_prf_output.set_is_valid();
+ tls_sha1_prf_output.set_data_length(
+ tls_sha1_prf_output.get_buffer_length());
+
+
+ status = m_tls_md5_prf->tls_prf_output(
+ tls_md5_prf_output.get_data(tls_md5_prf_output.get_data_length()),
+ tls_md5_prf_output.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_tls_sha1_prf->tls_prf_output(
+ tls_sha1_prf_output.get_data(tls_sha1_prf_output.get_data_length()),
+ tls_sha1_prf_output.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ // Final operation is XOR the md5_output and sha1_output.
+
+ {
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): tls_md5_prf_output"),
+ tls_md5_prf_output.get_data(tls_md5_prf_output.get_data_length()),
+ tls_md5_prf_output.get_data_length()));
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): tls_sha1_prf_output"),
+ tls_sha1_prf_output.get_data(
+ tls_sha1_prf_output.get_data_length()),
+ tls_sha1_prf_output.get_data_length()));
+
+ EAP_ASSERT(
+ pseudo_random_data_length
+ <= tls_md5_prf_output.get_data_length());
+ EAP_ASSERT(
+ pseudo_random_data_length
+ <= tls_sha1_prf_output.get_data_length());
+
+ const u8_t * const md5_buffer
+ = tls_md5_prf_output.get_data(pseudo_random_data_length);
+ const u8_t * const sha1_buffer
+ = tls_sha1_prf_output.get_data(pseudo_random_data_length);
+ u8_t * const p_pseudo_random_data
+ = static_cast<u8_t *>(pseudo_random_data);
+
+ for (u32_t ind = 0u; ind < pseudo_random_data_length; ind++)
+ {
+ p_pseudo_random_data[ind]
+ = static_cast<u8_t>((md5_buffer[ind] ^ sha1_buffer[ind]));
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): p_pseudo_random_data"),
+ p_pseudo_random_data,
+ pseudo_random_data_length));
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_tls_prf_c::tls_prf_cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (m_tls_md5_prf != 0)
+ {
+ m_tls_md5_prf->tls_prf_cleanup();
+ }
+
+ if (m_tls_sha1_prf != 0)
+ {
+ m_tls_sha1_prf->tls_prf_cleanup();
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+
+EAP_FUNC_EXPORT crypto_eap_fast_hmac_sha1_prf_c::~crypto_eap_fast_hmac_sha1_prf_c()
+{
+ t_prf_cleanup();
+
+ delete m_context;
+ m_context = 0;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_eap_fast_hmac_sha1_prf_c::crypto_eap_fast_hmac_sha1_prf_c(
+ abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_context(0)
+ , m_key(tools)
+ , m_S_value(tools)
+ , m_is_valid(false)
+{
+ {
+ crypto_sha1_c * sha1 = new crypto_sha1_c(m_am_tools);
+ if (sha1 == 0
+ || sha1->get_is_valid() == false)
+ {
+ delete sha1;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+
+ m_context = new crypto_hmac_c(m_am_tools, sha1, true);
+ if (m_context == 0
+ || m_context->get_is_valid() == false)
+ {
+ delete m_context;
+ m_context = 0;
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return;
+ }
+ }
+
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_eap_fast_hmac_sha1_prf_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_eap_fast_hmac_sha1_prf_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_eap_fast_hmac_sha1_prf_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_eap_fast_hmac_sha1_prf_c::t_prf_init(
+ const eap_variable_data_c * const key,
+ const eap_variable_data_c * const label,
+ const eap_variable_data_c * const seed)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (key->get_is_valid_data() == false
+ || key->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if (label->get_is_valid_data() == false
+ || label->get_data_length() == 0ul)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // NOTE seed could be empty buffer.
+ if (seed != 0
+ && seed->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ m_S_value.reset();
+
+ eap_status_e status = m_S_value.set_copy_of_buffer(label);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u8_t byte_counter(0ul);
+
+ status = m_S_value.add_data(&byte_counter, sizeof(byte_counter));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ if (seed != 0)
+ {
+ status = m_S_value.add_data(seed);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): m_S_value"),
+ m_S_value.get_data(),
+ m_S_value.get_data_length()));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_key.set_copy_of_buffer(key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("tls_prf_init(): m_key"),
+ m_key.get_data(),
+ m_key.get_data_length()));
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_eap_fast_hmac_sha1_prf_c::t_prf_output(
+ void * const pseudo_random_data,
+ const u16_t pseudo_random_data_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (pseudo_random_data == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ eap_status_e status = eap_status_not_supported;
+
+ EAP_ASSERT_ALWAYS(get_is_valid() == true);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ status = m_context->hmac_set_key(&m_key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c sha1_output(m_am_tools);
+
+ u32_t required_data = pseudo_random_data_length+m_context->get_digest_length();
+
+ status = sha1_output.init(
+ required_data);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ sha1_output.set_is_valid();
+ sha1_output.set_data_length(0ul);
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ {
+ u32_t hmac_sha1_md_length = m_context->get_digest_length();
+ u32_t sha1_count = required_data
+ / m_context->get_digest_length();
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ eap_variable_data_c T_value(m_am_tools);
+ if (T_value.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = T_value.set_buffer_length(hmac_sha1_md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = T_value.set_data_length(0ul);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - -
+
+ u16_t network_order_pseudo_random_data_length(eap_htons(pseudo_random_data_length));
+ u8_t byte_counter(0ul);
+
+ for (u32_t ind = 0ul; ind < sha1_count; ind++)
+ {
+ ++byte_counter;
+
+ // Next A value is:
+ // T(i) = HMAC_hash(key, T(i-1) + S + outputlength + 0x(i)).
+
+ status = m_context->hmac_set_key(&m_key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_context->hmac_update(T_value.get_data(), T_value.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_context->hmac_update(m_S_value.get_data(), m_S_value.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_context->hmac_update(&network_order_pseudo_random_data_length, sizeof(network_order_pseudo_random_data_length));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_context->hmac_update(&byte_counter, sizeof(byte_counter));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u32_t digest_length(m_context->get_digest_length());
+
+ status = T_value.set_data_length(digest_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = m_context->hmac_final(
+ T_value.get_data(),
+ &digest_length);
+
+ if (m_context->get_digest_length() != digest_length)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1_output.add_data(&T_value);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ } // for()
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ // Final operation is copy sha1_output to output buffer.
+
+ {
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_eap_fast_hmac_sha1_prf_c::tls_prf_output(): sha1_output"),
+ sha1_output.get_data(pseudo_random_data_length),
+ pseudo_random_data_length));
+
+ EAP_ASSERT(pseudo_random_data_length <= sha1_output.get_data_length());
+
+ const u8_t * const sha1_buffer = sha1_output.get_data(
+ pseudo_random_data_length);
+ if (sha1_buffer == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ u8_t * const p_pseudo_random_data
+ = static_cast<u8_t *>(pseudo_random_data);
+
+ m_am_tools->memmove(
+ p_pseudo_random_data,
+ sha1_buffer,
+ pseudo_random_data_length);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_EAP_AM_CRYPTO,
+ (EAPL("crypto_eap_fast_hmac_sha1_prf_c::tls_prf_output(): ")
+ EAPL("p_pseudo_random_data"),
+ p_pseudo_random_data,
+ pseudo_random_data_length));
+ }
+
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_eap_fast_hmac_sha1_prf_c::t_prf_cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ if (m_context != 0)
+ {
+ m_context->hmac_cleanup();
+ }
+
+ m_key.reset();
+ m_S_value.reset();
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_rsa_c::~crypto_rsa_c()
+{
+ cleanup();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_rsa_c::crypto_rsa_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_context(tools)
+ , m_is_valid(false)
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_rsa_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_rsa_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_rsa_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::init()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->rsa_init(&m_context);
+
+ if (m_context.get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ if (status == eap_status_ok)
+ {
+ status = eap_status_allocation_error;
+ }
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::encrypt_with_public_key(
+ const eap_variable_data_c * const public_rsa_key,
+ const eap_variable_data_c * const input_data,
+ eap_variable_data_c * const output_data)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()
+ ->rsa_encrypt_with_public_key(
+ &m_context,
+ public_rsa_key,
+ input_data,
+ output_data);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::decrypt_with_public_key(
+ const eap_variable_data_c * const public_rsa_key,
+ const eap_variable_data_c * const input_data,
+ eap_variable_data_c * const output_data)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()
+ ->rsa_decrypt_with_public_key(
+ &m_context,
+ public_rsa_key,
+ input_data,
+ output_data);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::encrypt_with_private_key(
+ const eap_variable_data_c * const private_rsa_key,
+ const eap_variable_data_c * const input_data,
+ eap_variable_data_c * const output_data)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()
+ ->rsa_encrypt_with_private_key(
+ &m_context,
+ private_rsa_key,
+ input_data,
+ output_data);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::decrypt_with_private_key(
+ const eap_variable_data_c * const private_rsa_key,
+ const eap_variable_data_c * const input_data,
+ eap_variable_data_c * const output_data)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()
+ ->rsa_decrypt_with_private_key(
+ &m_context,
+ private_rsa_key,
+ input_data,
+ output_data);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::sign(
+ const eap_variable_data_c * const private_rsa_key,
+ const eap_variable_data_c * const hash,
+ eap_variable_data_c * const signed_hash)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->rsa_sign(
+ &m_context,
+ private_rsa_key,
+ hash,
+ signed_hash);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::verify(
+ const eap_variable_data_c * const public_rsa_key,
+ const eap_variable_data_c * const hash,
+ const eap_variable_data_c * const signed_hash)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->rsa_verify(
+ &m_context,
+ public_rsa_key,
+ hash,
+ signed_hash);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_rsa_c::cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->rsa_cleanup(&m_context);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_dsa_c::~crypto_dsa_c()
+{
+ cleanup();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_dsa_c::crypto_dsa_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_context(tools)
+ , m_is_valid(false)
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_dsa_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void crypto_dsa_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_dsa_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_dsa_c::init()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->dsa_init(&m_context);
+
+ if (m_context.get_is_valid_data() == false)
+ {
+ set_is_invalid();
+ if (status == eap_status_ok)
+ {
+ status = eap_status_allocation_error;
+ }
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_dsa_c::sign(
+ const eap_variable_data_c * const private_dsa_key,
+ const eap_variable_data_c * const hash,
+ eap_variable_data_c * const signed_hash)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->dsa_sign(
+ &m_context,
+ private_dsa_key,
+ hash,
+ signed_hash);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_dsa_c::verify(
+ const eap_variable_data_c * const public_dsa_key,
+ const eap_variable_data_c * const dsa_param_p,
+ const eap_variable_data_c * const dsa_param_q,
+ const eap_variable_data_c * const dsa_param_g,
+ const eap_variable_data_c * const hash,
+ const eap_variable_data_c * const signed_hash)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->dsa_verify(
+ &m_context,
+ public_dsa_key,
+ dsa_param_p,
+ dsa_param_q,
+ dsa_param_g,
+ hash,
+ signed_hash);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_dsa_c::cleanup()
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ eap_status_e status = m_am_tools->get_crypto()->dsa_cleanup(&m_context);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_wpa_psk_password_hash_c::~crypto_wpa_psk_password_hash_c()
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_wpa_psk_password_hash_c::crypto_wpa_psk_password_hash_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+void crypto_wpa_psk_password_hash_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+void crypto_wpa_psk_password_hash_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_wpa_psk_password_hash_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+// These are the functions for calculating PSK from ascii string
+// taken from 802.11i D3.0
+
+/*
+* password - ascii string up to 63 characters in length
+* ssid - octet string up to 32 octets
+* ssidlength - length of ssid in octets
+* output must be 40 octets in length and outputs 256 bits of key
+*/
+EAP_FUNC_EXPORT eap_status_e crypto_wpa_psk_password_hash_c::password_hash(
+ const eap_variable_data_c * const password,
+ const eap_variable_data_c * const ssid,
+ eap_variable_data_c * const output,
+ void * object,
+ eap_status_e (*progress_callback)(void*, u32_t))
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("Hashing WPA PSK ASCII password.\n")));
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("password"),
+ password->get_data(),
+ password->get_data_length()));
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("ssid"),
+ ssid->get_data(),
+ ssid->get_data_length()));
+
+ // Buffer must be reset before new HASH is added to it.
+ // This causes the new HASH addition to the begin of the buffer.
+ // This is small optimization that does not free the old buffer.
+ eap_status_e status = output->reset_start_offset_and_data_length();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ if ((password->get_data_length() > 63) || (ssid->get_data_length() > 32))
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ status = password_hash_F(password, ssid, 4096, 1, output, object, progress_callback);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = password_hash_F(password, ssid, 4096, 2, output, object, progress_callback);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // truncate the buffer to 32 bytes
+ output->set_data_length(WPA_PSK_LENGTH);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("WPA PSK"),
+ output->get_data(),
+ output->get_data_length()));
+
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+eap_status_e crypto_wpa_psk_password_hash_c::password_hash_F(
+ const eap_variable_data_c * const password,
+ const eap_variable_data_c * const ssid,
+ u32_t iterations,
+ u32_t count,
+ eap_variable_data_c * const output,
+ void * object,
+ eap_status_e (*progress_callback)(void*, u32_t))
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+ eap_status_e status(eap_status_process_general_error);
+
+ crypto_sha1_c sha1(m_am_tools);
+
+ status = sha1.hash_init();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u32_t digest_length = sha1.get_digest_length();
+
+ crypto_hmac_c hmac(m_am_tools, &sha1, false);
+
+ u32_t i_ind, j_ind;
+
+ // Check for illegal characters
+ for (i_ind = 0; i_ind < password->get_data_length(); i_ind++)
+ {
+ u8_t * const character = password->get_data_offset(i_ind, 1);
+ if (character == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ if(!((*character >= 32) && (*character <= 126)))
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+ }
+
+ eap_variable_data_c digest(m_am_tools);
+ eap_variable_data_c digest1(m_am_tools);
+
+ status = digest.set_copy_of_buffer(ssid);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u8_t tmp[] = {
+ static_cast<u8_t>((count>>24) & 0xff),
+ static_cast<u8_t>((count>>16) & 0xff),
+ static_cast<u8_t>((count>>8) & 0xff),
+ static_cast<u8_t>(count & 0xff)
+ };
+
+ status = digest.add_data(tmp, sizeof(tmp));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac.hmac_set_key(password);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac.hmac_update(
+ digest.get_data(),
+ digest.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = digest1.set_buffer_length(digest_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac.hmac_final(
+ digest1.get_buffer(digest_length),
+ 0);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ digest1.set_data_length(digest_length);
+
+ status = digest.set_buffer_length(digest_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ digest.set_data_length(digest_length);
+
+ /* output = U1 */
+ status = output->add_data(&digest1);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u8_t * p_output = output->get_data_offset((count - 1) * digest_length, digest_length);
+ if (p_output == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+ }
+
+ u32_t callback_trigger = 0ul;
+
+ for (i_ind = 1; i_ind < iterations; i_ind++)
+ {
+ callback_trigger++;
+
+ if (callback_trigger > 400
+ && progress_callback != 0
+ && object != 0)
+ {
+ callback_trigger = 0;
+ status = progress_callback(object, 400);
+ if (status != eap_status_ok)
+ {
+ // This means that the operation was cancelled.
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("WPA PSK password hashing cancelled.\n")));
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ status = hmac.hmac_set_key(password);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_DATA_ERROR(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("illegal password:"),
+ password->get_data(),
+ password->get_data_length()));
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac.hmac_update(
+ digest1.get_data(),
+ digest1.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac.hmac_final(
+ digest.get_data(sha1.get_digest_length()),
+ 0);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ digest.set_data_length(digest_length);
+
+ status = digest1.set_copy_of_buffer(&digest);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ /* output = output xor Un */
+ u8_t * p_digest = digest.get_data(digest_length);
+ if (p_digest == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ for (j_ind = 0; j_ind < digest_length; j_ind++)
+ {
+ p_output[j_ind] ^= p_digest[j_ind];
+ }
+ } // for()
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+
+EAP_FUNC_EXPORT crypto_nt_hash_c::~crypto_nt_hash_c()
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_nt_hash_c::crypto_nt_hash_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+void crypto_nt_hash_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+void crypto_nt_hash_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_nt_hash_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_nt_hash_c::nt_password_hash(
+ const eap_variable_data_c * const password_utf8,
+ eap_variable_data_c * const password_hash,
+ const u32_t /* digest_size */)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+ if (password_utf8 == 0
+ || password_hash == 0)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ eap_variable_data_c tmp_password_unicode(m_am_tools);
+ eap_status_e status = m_am_tools->convert_utf8_to_unicode(tmp_password_unicode, *password_utf8);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ // Ms-Chap-V2 wants the byte order of password is little endian
+#if defined(EAP_BIG_ENDIAN)
+ {
+ u32_t password_size = tmp_password_unicode.get_data_length();
+ u8_t * password = tmp_password_unicode.get_data(password_size);
+ u8_t tmp;
+
+ for (i = 0; i < password_size; i += 2)
+ {
+ // Swap bytes
+ tmp = password[i];
+ password[i] = password[i + 1];
+ password[i + 1] = tmp;
+ }
+ }
+#endif // EAP_BIG_ENDIAN
+
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("EAP_type_MSCHAPV2: nt_password_hash(), password_unicode"),
+ tmp_password_unicode.get_data(),
+ tmp_password_unicode.get_data_length()));
+
+ crypto_md4_c md4(m_am_tools);
+
+ status = md4.hash_init();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = md4.hash_update(
+ tmp_password_unicode.get_data(),
+ tmp_password_unicode.get_data_length()); // unicode-chars
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ password_hash->reset();
+
+ status = password_hash->set_buffer_length(md4.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = password_hash->set_data_length(md4.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = md4.hash_final(password_hash->get_data(md4.get_digest_length()), 0);
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_nt_hash_c::hash_nt_password_hash(
+ const eap_variable_data_c * const password_hash,
+ eap_variable_data_c * const password_hash_hash,
+ const u32_t digest_size)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+ if (!password_hash
+ || !password_hash_hash)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ crypto_md4_c md4(m_am_tools);
+
+ eap_status_e status = md4.hash_init();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = md4.hash_update(password_hash->get_data(digest_size), digest_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ password_hash_hash->reset();
+
+ status = password_hash_hash->set_buffer_length(md4.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = password_hash_hash->set_data_length(md4.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = md4.hash_final(password_hash_hash->get_data(md4.get_digest_length()), 0);
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("EAP_type_MSCHAPV2: hash_nt_password_hash(), password_hash_hash"),
+ password_hash_hash->get_data(),
+ password_hash_hash->get_data_length()));
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+/* RFC 3079 */
+
+static const u8_t eap_type_mschapv2_magic1[] = {
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+ 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
+
+EAP_FUNC_EXPORT eap_status_e crypto_nt_hash_c::get_master_key(
+ const eap_variable_data_c * const in_password_hash_hash,
+ const eap_variable_data_c * const in_nt_response,
+ eap_variable_data_c * const out_master_key,
+ const u32_t in_master_key_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_mschapv2_c::get_master_key(): this = 0x%08x\n"),
+ this));
+
+ if (in_password_hash_hash == 0
+ || in_password_hash_hash->get_is_valid_data() == false
+ || in_nt_response == 0
+ || in_nt_response->get_is_valid_data() == false
+ || out_master_key == 0
+ || out_master_key->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ crypto_sha1_c sha1(m_am_tools);
+
+ eap_status_e status = sha1.hash_init();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_update(
+ in_password_hash_hash->get_data(),
+ in_password_hash_hash->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_update(
+ in_nt_response->get_data(),
+ in_nt_response->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_update(eap_type_mschapv2_magic1, sizeof(eap_type_mschapv2_magic1));
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ eap_variable_data_c digest(m_am_tools);
+ if (digest.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = digest.set_buffer_length(sha1.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = digest.set_data_length(sha1.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_final(
+ digest.get_data(), 0);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = out_master_key->set_copy_of_buffer(
+ digest.get_data(in_master_key_length),
+ in_master_key_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+static const u8_t eap_type_mschapv2_magic2[] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+ 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e };
+
+static const u8_t eap_type_mschapv2_magic3[] = {
+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+ 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e };
+
+
+EAP_FUNC_EXPORT eap_status_e crypto_nt_hash_c::get_asymmetric_start_key(
+ const eap_variable_data_c * const in_master_key,
+ eap_variable_data_c * const out_session_key,
+ const u32_t in_session_key_length,
+ const bool in_is_send,
+ const bool in_is_server)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_mschapv2_c::get_asymmetric_start_key(): this = 0x%08x\n"),
+ this));
+
+ if (in_master_key == 0
+ || in_master_key->get_is_valid_data() == false
+ || out_session_key == 0
+ || out_session_key->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ crypto_sha1_c sha1(m_am_tools);
+
+ eap_status_e status = sha1.hash_init();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ status = sha1.hash_update(
+ in_master_key->get_data(),
+ in_master_key->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ const u32_t padding_size = 40;
+
+ eap_variable_data_c padding(m_am_tools);
+ if (padding.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = padding.set_buffer_length(padding_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = padding.set_data_length(padding_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ const u32_t padding1_value = 0x00;
+
+ m_am_tools->memset(padding.get_data(), padding1_value, padding.get_data_length()); // padding1
+
+ status = sha1.hash_update(
+ padding.get_data(),
+ padding.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ {
+ const u8_t * magic = eap_type_mschapv2_magic2;
+
+ if (in_is_send == in_is_server)
+ {
+ magic = eap_type_mschapv2_magic3;
+ }
+
+ status = sha1.hash_update(magic, sizeof(eap_type_mschapv2_magic2)); // magic2 and magic3 are both 84 bytes
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ }
+
+ const u32_t padding2_value = 0xf2;
+
+ m_am_tools->memset(padding.get_data(), padding2_value, padding.get_data_length()); // padding2
+
+ status = sha1.hash_update(
+ padding.get_data(),
+ padding.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ eap_variable_data_c digest(m_am_tools);
+ if (digest.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = digest.set_buffer_length(sha1.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = digest.set_data_length(sha1.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_final(digest.get_data(), 0);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = out_session_key->set_copy_of_buffer(digest.get_data(in_session_key_length), in_session_key_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_nt_hash_c::get_new_key_from_sha(
+ const eap_variable_data_c * const in_start_key,
+ const eap_variable_data_c * const in_session_key,
+ eap_variable_data_c * const out_interim_key,
+ const u32_t in_interim_key_length)
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("eap_type_mschapv2_c::get_new_key_from_sha(): this = 0x%08x\n"),
+ this));
+
+ if (in_start_key == 0
+ || in_start_key->get_is_valid_data() == false
+ || in_session_key == 0
+ || in_session_key->get_is_valid_data() == false
+ || out_interim_key == 0
+ || out_interim_key->get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+ }
+
+ crypto_sha1_c sha1(m_am_tools);
+
+ eap_status_e status = sha1.hash_init();
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ status = sha1.hash_update(
+ in_start_key->get_data(),
+ in_start_key->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ const u32_t padding_size = 40;
+
+ eap_variable_data_c padding(m_am_tools);
+ if (padding.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = padding.set_buffer_length(padding_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = padding.set_data_length(padding_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ const u32_t padding1_value = 0x00;
+
+ m_am_tools->memset(padding.get_data(), padding1_value, padding.get_data_length()); // padding1
+
+ status = sha1.hash_update(
+ padding.get_data(),
+ padding.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_update(
+ in_session_key->get_data(),
+ in_session_key->get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ const u32_t padding2_value = 0xf2;
+
+ m_am_tools->memset(padding.get_data(), padding2_value, padding.get_data_length()); // padding2
+
+ status = sha1.hash_update(
+ padding.get_data(),
+ padding.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ eap_variable_data_c digest(m_am_tools);
+ if (digest.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = digest.set_buffer_length(sha1.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = digest.set_data_length(sha1.get_digest_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = sha1.hash_final(digest.get_data(), 0);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = out_interim_key->set_copy_of_buffer(digest.get_data(in_interim_key_length), in_interim_key_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+//--------------------------------------------------
+//--------------------------------------------------
+
+void crypto_kd_hmac_sha256_c::set_is_invalid()
+{
+ m_is_valid = false;
+}
+
+//--------------------------------------------------
+
+void crypto_kd_hmac_sha256_c::set_is_valid()
+{
+ m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_kd_hmac_sha256_c::~crypto_kd_hmac_sha256_c()
+{
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT crypto_kd_hmac_sha256_c::crypto_kd_hmac_sha256_c(abs_eap_am_tools_c * const tools)
+ : m_am_tools(tools)
+ , m_is_valid(false)
+{
+ set_is_valid();
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool crypto_kd_hmac_sha256_c::get_is_valid()
+{
+ return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e crypto_kd_hmac_sha256_c::expand_key(
+ eap_variable_data_c * const output,
+ const u32_t required_output_size,
+ const eap_variable_data_c * const key,
+ const eap_variable_data_c * const label
+ )
+{
+ EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+ EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n")));
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_kd_hmac_sha256_c::expand_key()\n")));
+
+ output->reset();
+
+ crypto_sha_256_c sha_256(m_am_tools);
+ if (sha_256.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ crypto_hmac_c hmac_sha_256(
+ m_am_tools,
+ &sha_256,
+ false);
+ if (hmac_sha_256.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_kd_hmac_sha256_c::expand_key(): key"),
+ key->get_data(),
+ key->get_data_length()));
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_kd_hmac_sha256_c::expand_key(): label"),
+ label->get_data(),
+ label->get_data_length()));
+
+ EAP_TRACE_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_kd_hmac_sha256_c::expand_key(): required_output_size %d\n"),
+ required_output_size));
+
+ const u32_t prf_digest_size(hmac_sha_256.get_digest_length());
+ const u32_t iterations((required_output_size + prf_digest_size - 1) / prf_digest_size);
+
+ eap_status_e status = output->set_buffer_length(iterations * prf_digest_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = output->set_data_length(iterations * prf_digest_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ eap_variable_data_c input(m_am_tools);
+ if (input.get_is_valid() == false)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+ }
+
+ status = input.set_buffer(label);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+
+ for (u32_t ind = 0ul; ind != iterations; ++ind)
+ {
+ status = hmac_sha_256.hmac_set_key(key);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = hmac_sha_256.hmac_update(
+ input.get_data(),
+ input.get_data_length());
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ u32_t md_length(prf_digest_size);
+
+ status = hmac_sha_256.hmac_final(
+ output->get_data_offset(ind*prf_digest_size, prf_digest_size),
+ &md_length);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ status = input.set_buffer(
+ output->get_data_offset(ind*prf_digest_size, prf_digest_size),
+ md_length,
+ false,
+ false);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+ } // for()
+
+ status = output->set_data_length(required_output_size);
+ if (status != eap_status_ok)
+ {
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+ }
+
+ EAP_TRACE_DATA_DEBUG(
+ m_am_tools,
+ TRACE_FLAGS_DEFAULT,
+ (EAPL("crypto_kd_hmac_sha256_c::expand_key(): output"),
+ output->get_data(),
+ output->get_data_length()));
+
+ EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+ return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+// End.