/* ipwps_protocol_crypto.c - IPWPS Protocol Cryptographic helper module implementation */ /* * Copyright (c) 2009 Wind River Systems, Inc. * * The right to copy, distribute, modify, or otherwise make use * of this software may be licensed only pursuant to the terms * of an applicable Wind River license agreement. * */ /* modification history -------------------- 01a,03Feb09,mry Created */ /* DESCRIPTION: * =========== * This library contains the IPWPS Protocol Cryptographic helper module * implementation. */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipwps_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include /* Openssl header files */ #include #include #include #include #include "ipwps_protocol.h" #include "ipwps_protocol_handler.h" #include "ipwps_private_api.h" #include "ipwps_common.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPWPS_PROTO_KEYLEN_DHKEY SHA256_DIGEST_LENGTH #define IPWPS_PROTO_KEYLEN_KDK SHA256_DIGEST_LENGTH #define IPWPS_PROTO_KEYLEN_PSK 16 /* i.e. 128 bits */ #define IPWPS_PROTO_CRYPTO_RANDSEED_LEN 256 #define IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR "Wi-Fi Easy and Secure Key Derivation" /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipwps_proto_dh_group_st { Ip_u8 *prime_value; Ip_u32 prime_len; Ip_u32 generator; } Ipwps_proto_dh_group; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* * **************************************************************************** * 8 DATA **************************************************************************** */ #ifdef IPWPS_DEBUG Ip_bool ipwps_proto_no_data_encryption = IP_FALSE; /* For Testing purposes */ #endif /* As specified by WPS spec, use the "1536-bit MODP Group" from RFC3526. * The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } * The generator of 2. */ IP_STATIC Ip_u8 IPWPS_PROTO_RFC3526_1536_MODP_GROUP_PRIME[]= { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, }; #define IPWPS_PROTO_RFC3526_1536_MODP_GROUP_GENERATOR 2 IP_STATIC Ipwps_proto_dh_group ipwps_proto_dh_group_rfc3526_1536_modp = { IPWPS_PROTO_RFC3526_1536_MODP_GROUP_PRIME, sizeof(IPWPS_PROTO_RFC3526_1536_MODP_GROUP_PRIME), IPWPS_PROTO_RFC3526_1536_MODP_GROUP_GENERATOR }; IP_STATIC Ipwps_proto_dh_group *ipwps_proto_default_dh_group = &ipwps_proto_dh_group_rfc3526_1536_modp; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC Ipwps_proto_dh_group * ipwps_proto_get_dh_group(Ipwps_proto_ctx *proto_ctx); IP_GLOBAL DH * ipwps_proto_generate_dh_keys(Ipwps_proto_dh_group *dh_grp, Ipwps_proto_key *pubkey); IP_STATIC Ip_err ipwps_proto_derive_dh_sharedsecret(DH *dh, Ipwps_proto_key *peer_pubkey, Ipwps_proto_key *secret); IP_STATIC Ip_err ipwps_proto_derive_dhkey(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *shared_secret, Ipwps_proto_key *dh_key); IP_STATIC Ip_err ipwps_proto_derive_kdk(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *dh_key, Ipwps_proto_key *kdk); IP_STATIC Ip_err ipwps_proto_perform_kdf(Ipwps_proto_key *key, Ipwps_proto_container **dataset, IP_CONST char *p_string, Ipwps_proto_key *result); IP_STATIC Ip_err ipwps_proto_perform_kdk_kdf(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *kdk, Ipwps_proto_key *session_keys); IP_STATIC void ipwps_proto_delete_dh(Ipwps_proto_ctx *proto_ctx); IP_STATIC Ip_err ipwps_proto_kwf_encrypt_data_with_iv(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_encrypt, Ipwps_proto_container *encrypted_data, Ipwps_proto_nonce *iv_to_use); /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipwps_proto_crypto_randgen(Ip_u8 *buf, Ip_u16 nbytes); /* *=========================================================================== * ipwps_proto_crypto_init *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_crypto_init(Ipwps_proto_ctx *proto_ctx) { #ifdef IPWPS_SEED_CRYPTO Ip_u32 rnd[IPWPS_PROTO_CRYPTO_RANDSEED_LEN]; #endif ip_assert(proto_ctx); if (proto_ctx->crypto_init) { return IPCOM_SUCCESS; } #if IPWPS_SEED_CRYPTO ipwps_proto_crypto_randgen((Ip_u8 *)rnd, sizeof(rnd)); RAND_seed((Ip_u8 *)rnd, sizeof(rnd)); #endif proto_ctx->crypto_init = IP_TRUE; return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_crypto_randgen *=========================================================================== * Description: Generate a Random byte stream of "nbytes" and store it in * provided buffer. * Parameters: * Returns: */ IP_GLOBAL void ipwps_proto_crypto_randgen(Ip_u8 *buf, Ip_u16 nbytes) { #if defined (IPWPS_USE_IPCOM_RAND) && defined(IPCOM_RAND) && IPCOM_RAND == 1 Ip_u16 remlen = nbytes; Ip_u32 *ptr = (Ip_u32 *)buf; Ip_u32 rand; ip_assert(buf); while (remlen > sizeof(Ip_u32)) { rand = ipcom_rand(); *ptr = rand; remlen -= sizeof(Ip_u32); ptr++; } if (remlen) { rand = ipcom_rand(); ipcom_memcpy((Ip_u8 *)ptr, &rand, remlen); } #else (void)RAND_bytes(buf, nbytes); #endif #ifdef IPWPS_DEBUG_PROTO_CRYPTO_RANDGEN ipwps_dump_data("ipwps_proto_crypto_randgen ::", buf, nbytes); #endif } /* *=========================================================================== * ipwps_proto_crypto_randdata *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_crypto_randdata(Ipwps_proto_container *container) { ip_assert(container); if (!IPWPS_PROTO_CONTAINER_ISVALID(*container)) { IPCOM_LOG0(ERR, "ipwps_proto_crypto_randdata :: Invalid container."); return IPCOM_ERR_FAILED; } ipwps_proto_crypto_randgen(container->data, container->len); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_set_device_password *=========================================================================== * Description: Set the device password associated with the protocol handler * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_proto_set_device_password(Ipwps_proto_ctx *proto_ctx, Ip_u8 *buf, Ip_u16 len) { ip_assert(proto_ctx); if (!buf || !len) { IPCOM_LOG0(ERR, "ipwps_proto_set_device_password :: null buf or zero len"); return IPCOM_ERR_INVALID_ARG; } if (ipwps_proto_alloc_and_copy_data(&proto_ctx->dev_pwd, buf, len) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_set_device_password :: failed to copy device password"); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_generate_local_keys *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_generate_local_keys(Ipwps_proto_ctx *proto_ctx) { Ipwps_proto_dh_group *dh_grp; ip_assert(proto_ctx); if (IPWPS_PROTO_KEY_ISVALID(proto_ctx->local_pub_key)) { IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: dh keys already generated"); return IPCOM_ERR_FAILED; } dh_grp = ipwps_proto_get_dh_group(proto_ctx); if (!dh_grp) { IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: failed to retrieve dh group"); return IPCOM_ERR_FAILED; } proto_ctx->dh = ipwps_proto_generate_dh_keys(dh_grp, &proto_ctx->local_pub_key); if (!proto_ctx->dh) { IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: failed to generate dh keys"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->local_pub_key)) { IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: Invalid dh key public key"); return IPCOM_ERR_FAILED; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_generate_local_keys :: local_pub_key:", proto_ctx->local_pub_key); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_derive_session_keys *=========================================================================== * Description: * DH structure is deleted when the shared secret is available. * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_derive_session_keys(Ipwps_proto_ctx *proto_ctx) { Ipwps_proto_key shared_secret, dh_key, kdk, session_keys; Ip_err rc; ip_assert(proto_ctx); IPWPS_PROTO_KEY_INIT(shared_secret); IPWPS_PROTO_KEY_INIT(dh_key); IPWPS_PROTO_KEY_INIT(kdk); IPWPS_PROTO_KEY_INIT(session_keys); if (!proto_ctx->dh) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: Invalid dh context"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->peer_pub_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: Invalid peer public key"); return IPCOM_ERR_FAILED; } rc = ipwps_proto_derive_dh_sharedsecret(proto_ctx->dh, &proto_ctx->peer_pub_key, &shared_secret); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(shared_secret)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to derive shared secret"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: shared_secret:", shared_secret); rc = ipwps_proto_derive_dhkey(proto_ctx, &shared_secret, &dh_key); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(dh_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to derive dhkey"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: dh_key:", dh_key); rc = ipwps_proto_derive_kdk(proto_ctx, &dh_key, &kdk); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(kdk)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to derive kdk"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: kdk:", kdk); rc = ipwps_proto_perform_kdk_kdf(proto_ctx, &kdk, &session_keys); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(session_keys)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to perform kdf"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: session_keys:", session_keys); rc = ipwps_proto_copy_data(&proto_ctx->auth_key, &session_keys, 0, IPWPS_PROTO_KEYLEN_AUTHKEY); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to copy auth_key"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: auth_key:", proto_ctx->auth_key); rc = ipwps_proto_copy_data(&proto_ctx->key_wrap_key, &session_keys, IPWPS_PROTO_KEYLEN_AUTHKEY, IPWPS_PROTO_KEYLEN_KEYWRAPKEY); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->key_wrap_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to copy key_wrap_key"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: key_wrap_key:", proto_ctx->key_wrap_key); rc = ipwps_proto_copy_data(&proto_ctx->emsk, &session_keys, IPWPS_PROTO_KEYLEN_AUTHKEY+IPWPS_PROTO_KEYLEN_KEYWRAPKEY, IPWPS_PROTO_KEYLEN_EMSK); if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->emsk)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to copy emsk"); rc = IPCOM_ERR_FAILED; goto done_sessionkeys; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: emsk:", proto_ctx->emsk); rc = IPCOM_SUCCESS; done_sessionkeys: ipwps_proto_delete_dh(proto_ctx); /* Done with it now */ ipwps_proto_container_delete(&shared_secret); ipwps_proto_container_delete(&dh_key); ipwps_proto_container_delete(&kdk); ipwps_proto_container_delete(&session_keys); if (rc != IPCOM_SUCCESS) { ipwps_proto_container_delete(&proto_ctx->auth_key); ipwps_proto_container_delete(&proto_ctx->key_wrap_key); ipwps_proto_container_delete(&proto_ctx->emsk); } return rc; } /* *=========================================================================== * ipwps_proto_derive_psks *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_derive_psks(Ipwps_proto_ctx *proto_ctx) { Ip_err rc = IPCOM_ERR_FAILED; HMAC_CTX hmac_ctx; Ip_u8 result[SHA256_DIGEST_LENGTH], *pwd_half; unsigned int len = SHA256_DIGEST_LENGTH, pwd_halflen; ip_assert(proto_ctx); if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_psks :: invalid auth_key"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_CONTAINER_ISVALID(proto_ctx->dev_pwd)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_psks :: invalid dev_pwd"); return IPCOM_ERR_FAILED; } /* For PSK1: Perform HMAC-SHA-256_AuthKey(1st half of device password) and use the 1st 128 bits of the result */ pwd_half = proto_ctx->dev_pwd.data; pwd_halflen = (proto_ctx->dev_pwd.len + 1) /2; HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, pwd_half, pwd_halflen); HMAC_Final(&hmac_ctx, result, &len); rc = ipwps_proto_alloc_and_copy_data(&proto_ctx->psk1, result, IPWPS_PROTO_KEYLEN_PSK); ipcom_memset(result, 0, sizeof(result)); if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->psk1) || (proto_ctx->psk1.len != IPWPS_PROTO_KEYLEN_PSK)) { IPCOM_LOG1(ERR,"ipwps_proto_derive_psks :: Invalid psk1 (%d)", proto_ctx->psk1.len); return IPCOM_ERR_FAILED; } /* For PSK2: Perform HMAC-SHA-256_AuthKey(2nd half of device password) and use the 1st 128 bits of the result */ pwd_half = proto_ctx->dev_pwd.data + pwd_halflen; pwd_halflen = proto_ctx->dev_pwd.len /2; HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, pwd_half, pwd_halflen); HMAC_Final(&hmac_ctx, result, &len); rc = ipwps_proto_alloc_and_copy_data(&proto_ctx->psk2, result, IPWPS_PROTO_KEYLEN_PSK); ipcom_memset(result, 0, sizeof(result)); if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->psk2) || (proto_ctx->psk2.len != IPWPS_PROTO_KEYLEN_PSK)) { IPCOM_LOG1(ERR,"ipwps_proto_derive_psks :: Invalid psk2 (%d)", proto_ctx->psk2.len); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_derive_devpwd_proof_hash *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_derive_devpwd_proof_hash ( Ipwps_proto_ctx *proto_ctx, Ipwps_proto_nonce *snonce, Ipwps_proto_key *psk, Ipwps_proto_key *pk_e, Ipwps_proto_key *pk_r, Ipwps_proto_hash *hash ) { Ip_err rc = IPCOM_ERR_FAILED; HMAC_CTX hmac_ctx; Ip_u8 result[SHA256_DIGEST_LENGTH]; unsigned int len = SHA256_DIGEST_LENGTH; ip_assert(proto_ctx); ip_assert(snonce); ip_assert(psk); ip_assert(pk_e); ip_assert(pk_r); ip_assert(hash); if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid auth_key"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_NONCE_ISVALID(*snonce)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid snonce"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(*psk)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid psk"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(*pk_e)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid pk_e"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(*pk_r)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid pk_r"); return IPCOM_ERR_FAILED; } /* Perform HMAC-SHA-256_AuthKey(snonce || psk || PKe || PKr) and use the 1st 128 bits of the result */ HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, snonce->data, snonce->len); HMAC_Update(&hmac_ctx, psk->data, psk->len); HMAC_Update(&hmac_ctx, pk_e->data, pk_e->len); HMAC_Update(&hmac_ctx, pk_r->data, pk_r->len); HMAC_Final(&hmac_ctx, result, &len); rc = ipwps_proto_alloc_and_copy_data(hash, result, IPWPS_PROTO_HASH_SIZE); ipcom_memset(result, 0, sizeof(result)); if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_HASH_ISVALID(*hash) || (hash->len != IPWPS_PROTO_HASH_SIZE)) { IPCOM_LOG1(ERR,"ipwps_proto_derive_devpwd_proof_hash :: Invalid hash (%d)", hash->len); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_calc_kwa *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_calc_kwa(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data) { HMAC_CTX hmac_ctx; Ip_u8 result[SHA256_DIGEST_LENGTH]; unsigned int offset, len = SHA256_DIGEST_LENGTH; ip_assert(proto_ctx); ip_assert(data); if (!IPWPS_PROTO_CONTAINER_ISVALID(*data)) { IPCOM_LOG0(ERR,"ipwps_proto_calc_kwa :: invalid data"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_calc_kwa :: invalid auth_key"); return IPCOM_ERR_FAILED; } /* Perform HMAC-SHA-256_AuthKey(data*) */ HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, data->data, data->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_LEN_KEYWRAPAUTH)); HMAC_Final(&hmac_ctx, result, &len); /* Copy authenticator bytes into end of msg2 and zero out result */ offset = data->len - IPWPS_PROTO_LEN_KEYWRAPAUTH; ipcom_memcpy(data->data+offset, result, IPWPS_PROTO_LEN_KEYWRAPAUTH); ipcom_memset(result, 0 , SHA256_DIGEST_LENGTH); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_verify_kwa *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_verify_kwa(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data) { Ip_err rc = IPCOM_SUCCESS; HMAC_CTX hmac_ctx; Ip_u8 result[SHA256_DIGEST_LENGTH]; unsigned int offset, len = SHA256_DIGEST_LENGTH; ip_assert(proto_ctx); ip_assert(data); if (!IPWPS_PROTO_CONTAINER_ISVALID(*data)) { IPCOM_LOG0(ERR,"ipwps_proto_verify_kwa :: invalid data"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_verify_kwa :: invalid auth_key"); return IPCOM_ERR_FAILED; } /* Perform HMAC-SHA-256_AuthKey(msg || msg2*) */ HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, data->data, data->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_LEN_KEYWRAPAUTH)); HMAC_Final(&hmac_ctx, result, &len); /* Copy authenticator bytes into end of msg2 and zero out result */ offset = data->len - IPWPS_PROTO_LEN_KEYWRAPAUTH; if (ipcom_memcmp(data->data+offset, result, IPWPS_PROTO_LEN_KEYWRAPAUTH) != 0) { IPCOM_LOG0(ERR,"ipwps_proto_verify_kwa :: key Wrap Authenticator mismatch"); rc = IPCOM_ERR_FAILED; } ipcom_memset(result, 0, sizeof(result)); return rc; } /* *=========================================================================== * ipwps_proto_calc_msgauth *=========================================================================== * Description: Calculate the Message authenticator: HMAC_AuthKey(msg1 ||msg2*) * excluding the last authenticator portion of msg2 and storing the result in * the excluded section of msg2. * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_calc_msgauth(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_data *msg1, Ipwps_proto_data *msg2) { HMAC_CTX hmac_ctx; Ip_u8 result[SHA256_DIGEST_LENGTH]; unsigned int offset, len = SHA256_DIGEST_LENGTH; ip_assert(proto_ctx); ip_assert(msg1); ip_assert(msg2); if (!msg1->len) { IPCOM_LOG1(ERR,"ipwps_proto_calc_msgauth :: invalid msg1 len", msg1->len); return IPCOM_ERR_FAILED; } if (msg2->len <= IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR) { IPCOM_LOG1(ERR,"ipwps_proto_calc_msgauth :: invalid msg2 len", msg2->len); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_calc_msgauth :: invalid auth_key"); return IPCOM_ERR_FAILED; } /* Perform HMAC-SHA-256_AuthKey(msg || msg2*) */ HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, msg1->data, msg1->len); HMAC_Update(&hmac_ctx, msg2->data, msg2->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR)); HMAC_Final(&hmac_ctx, result, &len); /* Copy authenticator bytes into end of msg2 and zero out result */ offset = msg2->len - IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR; ipcom_memcpy(msg2->data+offset, result, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR); ipcom_memset(result, 0 , sizeof(result)); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_verify_msgauth *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_verify_msgauth(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_data *msg1, Ipwps_proto_data *msg2) { Ip_err rc = IPCOM_SUCCESS; HMAC_CTX hmac_ctx; Ip_u8 result[SHA256_DIGEST_LENGTH]; unsigned int offset, len = SHA256_DIGEST_LENGTH; ip_assert(proto_ctx); ip_assert(msg1); ip_assert(msg2); if (!msg1->len) { IPCOM_LOG1(ERR,"ipwps_proto_verify_msgauth :: invalid msg1 len", msg1->len); return IPCOM_ERR_FAILED; } if (msg2->len <= IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR) { IPCOM_LOG1(ERR,"ipwps_proto_verify_msgauth :: invalid msg2 len", msg2->len); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) { IPCOM_LOG0(ERR,"ipwps_proto_verify_msgauth :: invalid auth_key"); return IPCOM_ERR_FAILED; } /* Perform HMAC-SHA-256_AuthKey(msg || msg2*) */ HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256()); HMAC_Update(&hmac_ctx, msg1->data, msg1->len); HMAC_Update(&hmac_ctx, msg2->data, msg2->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR)); HMAC_Final(&hmac_ctx, result, &len); /* Compary authenticator bytes to end of msg2 and zero out result */ offset = msg2->len - IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR; if (ipcom_memcmp(msg2->data+offset, result, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR) != 0) { IPCOM_LOG0(ERR,"ipwps_proto_verify_msgauth :: authenticator mismatch"); ipwps_dump_data("ipwps_proto_verify_msgauth :: msg2->data+offset:", msg2->data+offset, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR); ipwps_dump_data("ipwps_proto_verify_msgauth :: calculated auth:", result, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR); rc = IPCOM_ERR_FAILED; } ipcom_memset(result, 0, sizeof(result)); return rc; } /* *=========================================================================== * ipwps_proto_crypto_delete_all *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL void ipwps_proto_crypto_delete_all(Ipwps_proto_ctx *proto_ctx) { ip_assert(proto_ctx); ipwps_proto_delete_dh(proto_ctx); ipwps_proto_container_delete(&proto_ctx->local_pub_key); ipwps_proto_container_delete(&proto_ctx->peer_pub_key); ipwps_proto_container_delete(&proto_ctx->auth_key); ipwps_proto_container_delete(&proto_ctx->key_wrap_key); ipwps_proto_container_delete(&proto_ctx->emsk); ipwps_proto_container_delete(&proto_ctx->nonce1); ipwps_proto_container_delete(&proto_ctx->nonce2); ipwps_proto_container_delete(&proto_ctx->dev_pwd); ipwps_proto_container_delete(&proto_ctx->psk1); ipwps_proto_container_delete(&proto_ctx->psk2); ipwps_proto_container_delete(&proto_ctx->e_snonce1); ipwps_proto_container_delete(&proto_ctx->e_snonce2); ipwps_proto_container_delete(&proto_ctx->r_snonce1); ipwps_proto_container_delete(&proto_ctx->r_snonce2); ipwps_proto_container_delete(&proto_ctx->e_hash1); ipwps_proto_container_delete(&proto_ctx->e_hash2); ipwps_proto_container_delete(&proto_ctx->r_hash1); ipwps_proto_container_delete(&proto_ctx->r_hash2); } /* *=========================================================================== * ipwps_proto_kwf_encrypt_data *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_kwf_encrypt_data(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_encrypt, Ipwps_proto_container *encrypted_data) { return ipwps_proto_kwf_encrypt_data_with_iv(proto_ctx, data_to_encrypt, encrypted_data, IP_NULL); } /* *=========================================================================== * ipwps_proto_kwf_encrypt_data_with_iv *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC Ip_err ipwps_proto_kwf_encrypt_data_with_iv(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_encrypt, Ipwps_proto_container *encrypted_data, Ipwps_proto_nonce *iv_to_use) { Ip_err rc = IPCOM_SUCCESS; int remlen; Ip_u8 *ptr; Ipwps_proto_nonce iv; EVP_CIPHER_CTX cipher_ctx; int out_len=0; Ip_u8 block_size, padlen; Ipwps_proto_container pad; ip_assert(proto_ctx); ip_assert(data_to_encrypt); ip_assert(encrypted_data); IPWPS_PROTO_NONCE_INIT(iv); IPWPS_PROTO_CONTAINER_INIT(pad); if (!IPWPS_PROTO_CONTAINER_ISVALID(*data_to_encrypt)) { IPCOM_LOG0(ERR,"ipwps_proto_kwf_encrypt_data :: invalid data_to_encrypt"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_CONTAINER_ISVALID(*encrypted_data)) { IPCOM_LOG0(ERR,"ipwps_proto_kwf_encrypt_data :: invalid encrypted_data"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->key_wrap_key)) { IPCOM_LOG0(ERR,"ipwps_proto_kwf_encrypt_data :: invalid key_wrap_key"); return IPCOM_ERR_FAILED; } #ifdef IPWPS_DEBUG if (ipwps_proto_no_data_encryption) { /* pass in the clear without IV */ if (encrypted_data->len < data_to_encrypt->len) { IPCOM_LOG1(ERR,"ipwps_proto_kwf_encrypt_data :: invalid encrypted_data->len (%d)", encrypted_data->len); return IPCOM_ERR_FAILED; } IPCOM_LOG0(WARNING,"ipwps_proto_kwf_encrypt_data :: PASSING UNENCRYPTED DATA"); ipcom_memcpy(encrypted_data->data, data_to_encrypt->data, data_to_encrypt->len); encrypted_data->len = data_to_encrypt->len; return IPCOM_SUCCESS; } #endif /* Create a random IV and add it to start of encrypted data container*/ remlen = encrypted_data->len; ptr = encrypted_data->data; if (remlen < IPWPS_PROTO_IV_SIZE) { IPCOM_LOG2(ERR, "ipwps_proto_kwf_encrypt_data :: Not enough room to add IV (remlen = %d < %d)", remlen, IPWPS_PROTO_IV_SIZE); rc = IPCOM_ERR_FAILED; goto done_encrypt; } iv.len = IPWPS_PROTO_IV_SIZE; iv.data = ptr; if (iv_to_use && IPWPS_PROTO_NONCE_ISVALID(*iv_to_use) && (iv_to_use->len == IPWPS_PROTO_IV_SIZE)) { IPCOM_LOG0(DEBUG2,"ipwps_proto_kwf_encrypt_data :: using passed in IV"); ipcom_memcpy(iv.data, iv_to_use->data, IPWPS_PROTO_IV_SIZE); } else { if (ipwps_proto_crypto_randdata(&iv) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: ipwps_proto_crypto_randdata(&iv) failed"); rc = IPCOM_ERR_FAILED; goto done_encrypt; } } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_kwf_encrypt_data :: iv:", iv); ptr += IPWPS_PROTO_IV_SIZE; remlen -= IPWPS_PROTO_IV_SIZE; /* Initialize a Cipher context */ (void)EVP_CIPHER_CTX_init(&cipher_ctx); if (EVP_EncryptInit(&cipher_ctx, EVP_aes_128_cbc(), proto_ctx->key_wrap_key.data, iv.data) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptInit failed"); rc = IPCOM_ERR_FAILED; goto done_encrypt; } (void)EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); /* We will do the paddind ourselves */ /* Allocate and initialize pad data (PKCS#5) */ block_size = EVP_CIPHER_CTX_block_size(&cipher_ctx); padlen = block_size - (data_to_encrypt->len % block_size); if (ipwps_proto_alloc_data(&pad, padlen) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: failed to alloc pad data."); rc = IPCOM_ERR_FAILED; goto done_encrypt; } ipcom_memset(pad.data, padlen, padlen); /* Encrypt the data along with the pad */ if (EVP_EncryptUpdate(&cipher_ctx, ptr, &out_len, data_to_encrypt->data, data_to_encrypt->len) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptUpdate failed"); rc = IPCOM_ERR_FAILED; goto done_encrypt; } ptr += out_len; remlen -= out_len; if (remlen <= 0) { IPCOM_LOG1(ERR, "ipwps_proto_kwf_encrypt_data :: Not enough room to encrypt (remlen = %d)", remlen); rc = IPCOM_ERR_FAILED; goto done_encrypt; } if (EVP_EncryptUpdate(&cipher_ctx, ptr, &out_len, pad.data, pad.len) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptUpdate failed"); rc = IPCOM_ERR_FAILED; goto done_encrypt; } ptr += out_len; remlen -= out_len; if (remlen < 0) { IPCOM_LOG1(ERR, "ipwps_proto_kwf_encrypt_data :: Not enough room to encrypt pad (remlen = %d)", remlen); rc = IPCOM_ERR_FAILED; goto done_encrypt; } if (EVP_EncryptFinal(&cipher_ctx, ptr, &out_len) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptFinal failed"); rc = IPCOM_ERR_FAILED; goto done_encrypt; } ptr += out_len; remlen -= out_len; if (remlen < 0) { IPCOM_LOG1(CRIT, "ipwps_proto_kwf_encrypt_data :: remlen = %d at end of encryption", remlen); rc = IPCOM_ERR_FAILED; goto done_encrypt; } encrypted_data->len -= remlen; done_encrypt: ipwps_proto_container_delete(&pad); return rc; } /* *=========================================================================== * ipwps_proto_kwf_decrypt_data *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_kwf_decrypt_data(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_decrypt, Ipwps_proto_container *decrypted_data) { Ip_err rc = IPCOM_SUCCESS; int inlen, remlen; Ip_u8 *inptr, *outptr; Ipwps_proto_nonce iv; EVP_CIPHER_CTX cipher_ctx; int out_len=0; ip_assert(proto_ctx); ip_assert(data_to_decrypt); ip_assert(decrypted_data); IPWPS_PROTO_NONCE_INIT(iv); if (!IPWPS_PROTO_CONTAINER_ISVALID(*data_to_decrypt)) { IPCOM_LOG0(ERR,"ipwps_proto_kwf_decrypt_data :: invalid data_to_decrypt"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_CONTAINER_ISVALID(*decrypted_data)) { IPCOM_LOG0(ERR,"ipwps_proto_kwf_decrypt_data :: invalid decrypted_data"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->key_wrap_key)) { IPCOM_LOG0(ERR,"ipwps_proto_kwf_decrypt_data :: invalid key_wrap_key"); return IPCOM_ERR_FAILED; } #ifdef IPWPS_DEBUG if (ipwps_proto_no_data_encryption) { /* copy clear data without IV */ if (decrypted_data->len < data_to_decrypt->len) { IPCOM_LOG1(ERR,"ipwps_proto_kwf_decrypt_data :: invalid decrypted_data->len (%d)", decrypted_data->len); return IPCOM_ERR_FAILED; } IPCOM_LOG0(WARNING,"ipwps_proto_kwf_decrypt_data :: COPYING UNENCRYPTED DATA"); ipcom_memcpy(decrypted_data->data, data_to_decrypt->data, data_to_decrypt->len); decrypted_data->len = data_to_decrypt->len; return IPCOM_SUCCESS; } #endif /* Retrieve the IV prepended to the encrypted data container*/ inlen = data_to_decrypt->len; inptr = data_to_decrypt->data; if (inlen < IPWPS_PROTO_IV_SIZE) { IPCOM_LOG2(ERR, "ipwps_proto_kwf_decrypt_data :: Not enough room to retrieve IV (inlen = %d < %d)", inlen, IPWPS_PROTO_IV_SIZE); rc = IPCOM_ERR_FAILED; goto done_decrypt; } iv.len = IPWPS_PROTO_IV_SIZE; iv.data = inptr; IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_kwf_decrypt_data :: iv:", iv); inptr += IPWPS_PROTO_IV_SIZE; inlen -= IPWPS_PROTO_IV_SIZE; if (inlen == 0) { IPCOM_LOG2(ERR, "ipwps_proto_kwf_decrypt_data :: No data to decrypt", inlen, IPWPS_PROTO_IV_SIZE); rc = IPCOM_ERR_FAILED; goto done_decrypt; } if (decrypted_data->len < inlen) { IPCOM_LOG2(ERR, "ipwps_proto_kwf_decrypt_data :: Not enough room to decrypt data (%d < %d)", decrypted_data->len, inlen); rc = IPCOM_ERR_FAILED; goto done_decrypt; } outptr = decrypted_data->data; remlen = decrypted_data->len; /* Initialize a Cipher context and Decrypt the data */ (void)EVP_CIPHER_CTX_init(&cipher_ctx); if (EVP_DecryptInit(&cipher_ctx, EVP_aes_128_cbc(), proto_ctx->key_wrap_key.data, iv.data) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_decrypt_data :: EVP_DecryptInit failed"); rc = IPCOM_ERR_FAILED; goto done_decrypt; } (void)EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); /* We do the padding ourselves */ if (EVP_EncryptUpdate(&cipher_ctx, outptr, &out_len, inptr, inlen) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_decrypt_data :: EVP_EncryptUpdate failed"); rc = IPCOM_ERR_FAILED; goto done_decrypt; } outptr += out_len; decrypted_data->len = out_len; remlen -= out_len; if (EVP_EncryptFinal(&cipher_ctx, outptr, &out_len) <= 0) { IPCOM_LOG0(ERR, "ipwps_proto_kwf_decrypt_data :: EVP_EncryptFinal failed"); rc = IPCOM_ERR_FAILED; goto done_decrypt; } outptr += out_len; decrypted_data->len += out_len; remlen -= out_len; if (remlen < 0) { IPCOM_LOG1(CRIT, "ipwps_proto_kwf_decrypt_data :: remlen = %d at end of decryption", remlen); rc = IPCOM_ERR_FAILED; goto done_decrypt; } /* Now remove padding */ decrypted_data->len -= decrypted_data->data[decrypted_data->len-1]; done_decrypt: return rc; } /* *=========================================================================== * ipwps_proto_derive_dhkey *=========================================================================== * Description: Derive the WPS DHKey using the provided shared secret and * copy the result to the supplied dh_key. * Parameters: * Returns: */ IP_STATIC Ip_err ipwps_proto_derive_dhkey(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *shared_secret, Ipwps_proto_key *dh_key) { ip_assert(proto_ctx); ip_assert(shared_secret); ip_assert(dh_key); if (!IPWPS_PROTO_KEY_ISVALID(*shared_secret)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_dhkey :: invalid shared_secret"); return IPCOM_ERR_FAILED; } /* Perform SHA-256(shared_secret) and copy result to dh_key. * Note that shared_secret was calculated to be (g^AB mod p) */ dh_key->data = ipcom_malloc(IPWPS_PROTO_KEYLEN_DHKEY); if (!dh_key->data) { IPCOM_LOG0(CRIT, "ipwps_proto_derive_dhkey :: out of memory"); return IPCOM_ERR_NO_MEMORY; } SHA256(shared_secret->data, shared_secret->len, dh_key->data); dh_key->len = IPWPS_PROTO_KEYLEN_DHKEY; return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_derive_kdk *=========================================================================== * Description: Derive the WPS KDK using the provided DHKey and the nonce * values in the provided protocol context and then copy the * result to the supplied kdk. * Parameters: * Returns: */ IP_STATIC Ip_err ipwps_proto_derive_kdk(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *dh_key, Ipwps_proto_key *kdk) { Ip_err rc; unsigned int kdk_len = 0; HMAC_CTX hmac_ctx; #ifdef IPWPS_DEBUG_PROTO_CRYPTO_DATA Ipwps_proto_container mac_addr; #endif ip_assert(proto_ctx); ip_assert(dh_key); ip_assert(kdk); rc = ipwps_proto_alloc_data(kdk, IPWPS_PROTO_KEYLEN_KDK); if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_KEY_ISVALID(*kdk)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid kdk"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(*dh_key)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid dh_key"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_NONCE_ISVALID(proto_ctx->nonce1)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid nonce1"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_NONCE_ISVALID(proto_ctx->nonce2)) { IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid nonce2"); return IPCOM_ERR_FAILED; } if ((proto_ctx->enrollee_mac[0] | proto_ctx->enrollee_mac[1] | proto_ctx->enrollee_mac[2] | proto_ctx->enrollee_mac[3] | proto_ctx->enrollee_mac[4] | proto_ctx->enrollee_mac[5]) == 0) { IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid enrollee_mac"); return IPCOM_ERR_FAILED; } #ifdef IPWPS_DEBUG_PROTO_CRYPTO_DATA mac_addr.data = proto_ctx->enrollee_mac; mac_addr.len = 6; #endif IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_kdk :: enrollee_mac:", mac_addr); /* Perform HMAC-SHA-256_DHKey(NONCE1 || EnrolleeMAC || NONCE2) and copy result to kdk */ HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, dh_key->data, dh_key->len, EVP_sha256()); HMAC_Update(&hmac_ctx, proto_ctx->nonce1.data, proto_ctx->nonce1.len); HMAC_Update(&hmac_ctx, proto_ctx->enrollee_mac, 6); HMAC_Update(&hmac_ctx, proto_ctx->nonce2.data, proto_ctx->nonce2.len); HMAC_Final(&hmac_ctx, kdk->data, &kdk_len); kdk->len = (Ip_u16)kdk_len; if (kdk->len != IPWPS_PROTO_KEYLEN_KDK) { IPCOM_LOG2(ERR,"ipwps_proto_derive_kdk :: Invalid kdk len (%d, exp: %d)", kdk->len, IPWPS_PROTO_KEYLEN_KDK); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_perform_kdf *=========================================================================== * Description: Perform the WPS KDF function using the key and an optional set of data * using the personalization string provided and total key bits required. * Parameters: * Ipwps_proto_ctx *proto_ctx - A valid * Ipwps_proto_key *key - key to be used in the KDF function * Ipwps_proto_container **dataset - An array containing the data to be used in the kdf * by being prepended to the personalization string. * MUST be terminated with a NULL key element. * char *pstring - personalization string. * Ipwps_proto_key *result - The key to hold the result. * MUST have a valid allocated data and cotain as its length the total_key_bits required. * Returns: */ IP_STATIC Ip_err ipwps_proto_perform_kdf(Ipwps_proto_key *key, Ipwps_proto_container **dataset, IP_CONST char *pstring, Ipwps_proto_key *result) { Ip_u32 i, iterations, plen, temp_len, remlen, digestlen = SHA256_DIGEST_LENGTH; Ip_u8 total_key_bits[4]; Ip_u8 temp_result[SHA256_DIGEST_LENGTH]; Ipwps_proto_container *optdata; ip_assert(key); ip_assert(pstring); ip_assert(result); if (!IPWPS_PROTO_KEY_ISVALID(*key)) { IPCOM_LOG0(ERR,"ipwps_proto_perform_kdf :: Invalid key"); return IPCOM_ERR_FAILED; } plen = strlen(pstring); if (!plen) { IPCOM_LOG0(ERR,"ipwps_proto_perform_kdf :: Invalid plen"); return IPCOM_ERR_FAILED; } if (!IPWPS_PROTO_KEY_ISVALID(*result)) { IPCOM_LOG0(ERR,"ipwps_proto_perform_kdf :: Invalid result"); return IPCOM_ERR_FAILED; } IP_SET_HTONL(total_key_bits, (result->len * 8)); iterations = ((result->len*8) + (digestlen*8) -1)/(digestlen*8); temp_len = digestlen; remlen = result->len; /* Perform PRF (HMAC-SHA-256) */ for (i = 1; i <= iterations ; i++) { HMAC_CTX hmac_ctx; Ip_u8 i_be[4]; IP_SET_HTONL(i_be, i); HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, key->data, key->len, EVP_sha256()); HMAC_Update(&hmac_ctx, i_be, sizeof(i_be)); if (dataset) { int j=0; optdata = dataset[j]; while (optdata && IPWPS_PROTO_KEY_ISVALID(*optdata)) { HMAC_Update(&hmac_ctx, optdata->data, optdata->len); j++; } } HMAC_Update(&hmac_ctx, (Ip_u8 *)pstring, plen); HMAC_Update(&hmac_ctx, total_key_bits, sizeof(total_key_bits)); HMAC_Final(&hmac_ctx, temp_result, (unsigned int *)&temp_len); #if 0 IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: result (before):", *result); #endif if (i < iterations) { ipcom_memcpy(result->data+((i-1)*digestlen), temp_result, digestlen); remlen -= digestlen; } else { /* on last iter only copy enough */ ipcom_memcpy(result->data+((i-1)*digestlen), temp_result, remlen); remlen = 0; } ipcom_memset(temp_result, 0, sizeof(temp_result)); #if 0 IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: result (after):", *result); #endif } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_perform_kdk_kdf *=========================================================================== * Description: Perform the WPS KDF function to generate the session keys * using the provided KDK. * Parameters: * Returns: */ IP_STATIC Ip_err ipwps_proto_perform_kdk_kdf(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *kdk, Ipwps_proto_key *session_keys) { IP_CONST char *personalization_string = IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR; ip_assert(proto_ctx); ip_assert(kdk); ip_assert(session_keys); if (!IPWPS_PROTO_KEY_ISVALID(*kdk)) { IPCOM_LOG0(ERR,"ipwps_proto_perform_kdk_kdf :: Invalid kdk"); return IPCOM_ERR_FAILED; } if (ipwps_proto_alloc_data(session_keys, IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR,"ipwps_proto_perform_kdk_kdf :: failed to alloc session_keys"); return IPCOM_ERR_FAILED; } /* Perform kdf(KDK, "Wi-Fi Easy and Secure Key Derivation", IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL) */ if (ipwps_proto_perform_kdf(kdk, IP_NULL, personalization_string, session_keys) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR,"ipwps_proto_perform_kdk_kdf :: failed to perform kdf"); return IPCOM_ERR_FAILED; } if (session_keys->len != IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL) { IPCOM_LOG2(ERR,"ipwps_proto_perform_kdk_kdf :: Invalid kdk len (%d, exp: %d)", kdk->len, IPWPS_PROTO_KEYLEN_KDK); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_alloc_data *=========================================================================== * Description: * Allocate container data of length "len". * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_alloc_data(Ipwps_proto_container *container, Ip_u16 len) { ip_assert(container); /* Delete any lingering memory */ if (container->data) { ipcom_free(container->data); } container->len = 0; container->data = ipcom_calloc(1, len); if (!container->data) { IPCOM_LOG0(CRIT,"ipwps_proto_alloc_data :: out of memory"); return IPCOM_ERR_NO_MEMORY; } container->alloc_len = len; container->len = len; return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_alloc_and_copy_data *=========================================================================== * Description: * Allocate container data of length "len" and copy "data" into it. * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_alloc_and_copy_data(Ipwps_proto_container *container, Ip_u8 *data, Ip_u16 len) { Ip_err rc = IPCOM_SUCCESS; ip_assert(container); if (!len || !data) return IPCOM_ERR_FAILED; rc = ipwps_proto_alloc_data(container, len); if (rc == IPCOM_SUCCESS) { ipcom_memcpy(container->data, data, len); } return rc; } /* *=========================================================================== * ipwps_proto_duplicate_data *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_duplicate_data(Ipwps_proto_container *to, Ipwps_proto_container *from) { ip_assert(to); ip_assert(from); if (!from->data || !from->len) { return IPCOM_ERR_FAILED; } return ipwps_proto_alloc_and_copy_data(to, from->data, from->len); } /* *=========================================================================== * ipwps_proto_copy_data *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_copy_data(Ipwps_proto_container *dest, Ipwps_proto_container *src, Ip_u16 src_offset, Ip_u16 copy_len) { ip_assert(dest); ip_assert(src); if (!IPWPS_PROTO_CONTAINER_ISVALID(*src)) { IPCOM_LOG0(ERR,"ipwps_proto_copy_data :: Invalid src"); return IPCOM_ERR_FAILED; } if ((src_offset+copy_len) > src->len) { IPCOM_LOG3(ERR,"ipwps_proto_copy_data :: Invalid copy values (off: %d, copy: %d, len %d))", src_offset, copy_len, src->len); return IPCOM_ERR_FAILED; } if (ipwps_proto_alloc_data(dest, copy_len) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR,"ipwps_proto_copy_data :: ipwps_proto_alloc_data() failed"); return IPCOM_ERR_FAILED; } ipcom_memcpy(dest->data, src->data+src_offset, copy_len); dest->len = copy_len; return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_proto_compare_data *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_bool ipwps_proto_compare_data(Ipwps_proto_container *c1, Ipwps_proto_container *c2) { ip_assert(c1); ip_assert(c2); if (!IPWPS_PROTO_CONTAINER_ISVALID(*c1) || !IPWPS_PROTO_CONTAINER_ISVALID(*c2)) return IP_FALSE; if (c1->len != c2->len) return IP_FALSE; if (ipcom_memcmp(c1->data, c2->data, c1->len) != 0) return IP_FALSE; return IP_TRUE; } /* *=========================================================================== * ipwps_proto_container_delete *=========================================================================== * Description: Delete a data container after clearing its buffer * ONLY is the container has an allocated buffer. * Parameters: * Returns: */ IP_GLOBAL void ipwps_proto_container_delete(Ipwps_proto_container *container) { ip_assert(container); if (container->alloc_len && container->data) { ipcom_memset(container->data, 0, container->len); ipcom_free(container->data); } container->data = IP_NULL; container->len = 0; container->alloc_len = 0; } /* *=========================================================================== * ipwps_proto_generate_dh_keys *=========================================================================== * Description: * Generate Diffie-Hellman Private/Public key pair using the specified dh group * and copy the public key into the provided key structure. * DH structure is preserved since it contains the private key, but will be * destroyed once the dh shared secrets are computed by calling * ipwps_proto_derive_dh_sharedsecret(). * Parameters: * * Returns: * Pointer to a new DH structure if successful, IP_NULL otherwise. */ IP_GLOBAL DH * ipwps_proto_generate_dh_keys(Ipwps_proto_dh_group *dh_grp, Ipwps_proto_key *pubkey) { DH *dh; #if 0 int dh_codes; #endif ip_assert(pubkey); ip_assert(dh_grp); ip_assert(dh_grp->prime_value); dh = DH_new(); if (!dh) { IPCOM_LOG0(CRIT,"ipwps_proto_generate_dh_keys :: out of memory"); DH_free(dh); return IP_NULL; } dh->g = BN_new(); dh->p = BN_new(); if (!dh->g || !dh->p) { IPCOM_LOG0(CRIT,"ipwps_proto_generate_dh_keys :: out of memory (2)"); DH_free(dh); return IP_NULL; } (void)BN_set_word(dh->g, dh_grp->generator); (void)BN_bin2bn(dh_grp->prime_value, dh_grp->prime_len, dh->p); #if 0 if (!DH_check(dh, &dh_codes)) { IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: DH_check() failed"); return IP_NULL; } if (dh_codes) { if (dh_codes & DH_CHECK_P_NOT_PRIME) IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: p value is not prime"); if (dh_codes & DH_CHECK_P_NOT_SAFE_PRIME) IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: p value is not a safe prime"); if (dh_codes & DH_UNABLE_TO_CHECK_GENERATOR) IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: unable to check the generator value"); if (dh_codes & DH_NOT_SUITABLE_GENERATOR) IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: the g value is not a generator"); return IP_NULL; } #endif if (!DH_generate_key(dh)) { IPCOM_LOG2(ERR, "ipwps_proto_generate_dh_keys :: failed to generate DH key, (len %d, generator %d)", dh_grp->prime_len, dh_grp->generator); DH_free(dh); return IP_NULL; } pubkey->data = ipcom_malloc(BN_num_bytes(dh->pub_key)); if (!pubkey->data) { IPCOM_LOG0(CRIT, "ipwps_proto_generate_dh_keys: out of memory (2)"); DH_free(dh); return IP_NULL; } pubkey->len = BN_bn2bin(dh->pub_key, pubkey->data); return dh; } /* *=========================================================================== * ipwps_proto_derive_dh_sharedsecret *=========================================================================== * Description: * Generate Diffie-Hellman shared secret using the specified dh struct * and peer public key, then copy the result into the provided key structure. * Parameters: * * Returns: * IPCOM_SUCCESS if successful, error otherwise. */ IP_STATIC Ip_err ipwps_proto_derive_dh_sharedsecret(DH *dh, Ipwps_proto_key *peer_pubkey, Ipwps_proto_key *secret) { BIGNUM *bn_pub_key; int len; Ip_u32 n; Ip_err rc; ip_assert(dh); ip_assert(peer_pubkey); ip_assert(secret); bn_pub_key = BN_bin2bn(peer_pubkey->data, peer_pubkey->len, IP_NULL); if (!bn_pub_key) { IPCOM_LOG0(CRIT, "ipwps_proto_derive_dh_sharedsecret :: out of memory"); rc = IPCOM_ERR_NO_MEMORY; goto clean_up; } secret->data = ipcom_malloc(DH_size(dh)); if (!secret->data) { IPCOM_LOG0(CRIT, "ipwps_proto_derive_dh_sharedsecret :: out of memory (2)"); rc = IPCOM_ERR_NO_MEMORY; goto clean_up; } len = DH_compute_key(secret->data, bn_pub_key, dh); if (len == -1) { IPCOM_LOG0(ERR, "ipwps_proto_derive_dh_sharedsecret :: failed to create the DH derived shared secret"); rc = IPCOM_ERR_FAILED; goto clean_up; } secret->len = (Ip_u16)len; /* Pad key with zero to the left if key length less then dh key size */ n = DH_size(dh) - secret->len; if (n > 0) { ipcom_memmove(secret->data + n, secret->data, secret->len); ipcom_memset(secret->data, 0, (int)n); secret->len += n; } rc = IPCOM_SUCCESS; clean_up: BN_clear_free(bn_pub_key); return rc; } /* *=========================================================================== * ipwps_proto_delete_dh *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC void ipwps_proto_delete_dh(Ipwps_proto_ctx *proto_ctx) { ip_assert(proto_ctx); if (proto_ctx->dh) { DH_free(proto_ctx->dh); proto_ctx->dh = IP_NULL; } } /* *=========================================================================== * ipwps_proto_get_dh_group *=========================================================================== * Description: Retrieve the Diffie-Hellman group used by IPWPS * Parameters: * Returns: */ IP_STATIC Ipwps_proto_dh_group * ipwps_proto_get_dh_group(Ipwps_proto_ctx *proto_ctx) { ip_assert(proto_ctx); return ipwps_proto_default_dh_group; } #define IPWPS_PROTO_CRYPTO_TEST #ifdef IPWPS_PROTO_CRYPTO_TEST /* typedefs */ typedef struct Ipwps_proto_crypto_test_st { Ip_err (*testfn)(void); char *testname; } Ipwps_proto_crypto_test; typedef struct Ipwps_proto_dhkey_test_vector_st { char *input; Ip_u8 result[IPWPS_PROTO_KEYLEN_DHKEY]; } Ipwps_proto_dhkey_test_vector; typedef struct Ipwps_proto_kdf_test_vector_st { Ip_u8 key[256]; Ip_u16 keylen; char *personalization_string; Ip_u16 keybits; Ip_u8 result[256]; } Ipwps_proto_kdf_test_vector; typedef struct Ipwps_proto_hmacsha256_test_vector_st { Ip_u8 key[256]; Ip_u16 keylen; Ip_u16 numblocks; struct { Ip_u8 data[256]; Ip_u16 len; } block[16]; Ip_u8 result[SHA256_DIGEST_LENGTH]; Ip_u8 trancate_len; /* if not 0, indicates truncated result length */ } Ipwps_proto_hmacsha256_test_vector; typedef struct Ipwps_proto_kwf_test_vector_st { Ip_u8 keywrapkey[IPWPS_PROTO_KEYLEN_KEYWRAPKEY]; Ip_u8 iv[IPWPS_PROTO_NONCE_SIZE]; char *cleartext; Ip_u8 ciphertext[256]; Ip_u16 ciphertext_len; } Ipwps_proto_kwf_test_vector; /* Forward declerations */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_sessionkeys(void); IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhsharedsecrets(void); IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhkey(void); IP_GLOBAL Ip_err ipwps_proto_cryptotest_hmacsha256(void); IP_GLOBAL Ip_err ipwps_proto_cryptotest_kdf(void); IP_GLOBAL Ip_err ipwps_proto_cryptotest_kwf(void); /* Data */ IP_STATIC Ipwps_proto_crypto_test ipwps_proto_crypto_tests[] = { {ipwps_proto_cryptotest_dhkey, "DH KEY GENERATION"}, {ipwps_proto_cryptotest_hmacsha256, "HMAC-SHA-256"}, {ipwps_proto_cryptotest_kdf, "KDF FUNCTION"}, {ipwps_proto_cryptotest_dhsharedsecrets, "DH SHARED SECRETS"}, {ipwps_proto_cryptotest_sessionkeys, "SESSION KEYS"}, {ipwps_proto_cryptotest_kwf, "KWF ENCRYPTION/DECRYPTION"}, /* KEEP THIS LAST */ {IP_NULL, IP_NULL} }; IP_STATIC Ipwps_proto_dhkey_test_vector ipwps_proto_dhkey_test_vectors[] = { #if 0 /* Our code doesn't accept 0 length data currently */ {"", {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55} }, #endif {"abc", {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad} }, {"message digest", {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50} }, {"secure hash algorithm", {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d} }, {"SHA256 is considered to be safe", {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30} }, {"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1} }, {"For this sample, this 63-byte string will be used as input data", {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42} }, {"This is exactly 64 bytes long, not counting the terminating byte", {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} } }; IP_STATIC Ipwps_proto_hmacsha256_test_vector ipwps_proto_hmacsha256_test_vectors[] = { { /* RFC 4231 Test Case 1 */ {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, /*key */ 20, /* keylen */ 1, /* numblocks */ { {{0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65}/*{Hi There"},*/, 8} /* block #1 */ }, {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, /* result */ 0, /*trancate_len = none*/ }, /* RFC 4231 Test Case 2 */ { {0x4a, 0x65, 0x66, 0x65}, /*key = "Jefe"*/ 4, /* keylen */ 2, /* numblocks */ { {{0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20}, /*"what do ya want "*/ 16}, /* block #1 */ {{0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x3f}, /*"for nothing?"*/ 12} /* block #2 */ }, {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, /* result */ 0, /*trancate_len = none*/ }, /* RFC 4231 Test Case 3 */ { {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,}, /*key */ 20, /* keylen */ 1, /* numblocks */ { {{0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}, 50} /* block #1 */ }, {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, /* result */ 0, /*trancate_len = none*/ }, /* RFC 4231 Test Case 4 */ { {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}, /*key */ 25, /* keylen */ 1, /* numblocks */ { {{0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd}, 50}, /* block #1 */ }, {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, /* result */ 0, /*trancate_len = none*/ }, /* RFC 4231 Test Case 5 */ { {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}, /*key */ 20, /* keylen */ 2, /* numblocks */ { {{0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, 0x68, 0x20, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61}, /*"Test With Trunca"*/ 16}, /* block #1 */ {{0x74, 0x69, 0x6f, 0x6e}, /*"tion"*/ 4}, /* block #2 */ }, {0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b}, /* result */ 16, /*trancate_len = 16*/ }, /* RFC 4231 Test Case 6 */ { {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, /*key */ 131, /* keylen */ 4, /* numblocks */ { {{0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65}, /*"Test Using Large"*/ 16}, /* block #1 */ {{0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a}, /*"r Than Block-Siz"*/ 16}, /* block #2 */ {{0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79}, /*"e Key - Hash Key"*/ 16}, /* block #3 */ {{0x20, 0x46, 0x69, 0x72, 0x73, 0x74}, /*" First" */ 6}, /* block #4 */ }, {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, /* result */ 0, /*trancate_len = none*/ }, /* RFC 4231 Test Case 7 */ { {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, /*key */ 131, /* keylen */ 10, /* numblocks */ { {{0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75}, /*"This is a test u"*/ 16}, /* block #1 */ {{0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68}, /*"sing a larger th"*/ 16}, /* block #2 */ {{0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65}, /*"an block-size ke"*/ 16}, /* block #3 */ {{0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74}, /*"y and a larger t"*/ 16}, /* block #4 */ {{0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64}, /*"han block-size d"*/ 16}, /* block #5 */ {{0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65}, /*"ata. The key nee"*/ 16}, /* block #6 */ {{0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20}, /*"ds to be hashed "*/ 16}, /* block #7 */ {{0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65}, /*"before being use"*/ 16}, /* block #8 */ {{0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c}, /*"d by the HMAC al"*/ 16}, /* block #9 */ {{0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e}, /*"gorithm."*/ 8}, /* block #10 */ }, {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2}, /* result */ 0, /*trancate_len = none*/ }, }; IP_STATIC Ipwps_proto_kdf_test_vector ipwps_proto_kdf_test_vector[] = { { { 0x7c, 0x44, 0xd6, 0xca, 0x35, 0x55, 0x51, 0x5d, 0x38, 0xeb, 0xea, 0xe5, 0x92, 0x40, 0x4e, 0x4c, 0xf4, 0x13, 0x8e, 0x74, 0x5a, 0x90, 0x4b, 0xce, 0x77, 0x6f, 0x46, 0xb5, 0x0b, 0xb9, 0x40, 0x42 }, IPWPS_PROTO_KEYLEN_KDK, IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR, IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL*8, { 0xBB, 0xDB, 0x05, 0x4F, 0x92, 0x29, 0x66, 0x55, 0xC6, 0x31, 0xA3, 0xA9, 0x4A, 0x7C, 0xE1, 0xA0, 0xE5, 0x3B, 0xD0, 0xF6, 0xF7, 0x0C, 0x6E, 0x5F, 0x6E, 0xBD, 0xA3, 0xD9, 0x56, 0x2E, 0x48, 0x5F, 0xD0, 0x03, 0xFC, 0x98, 0xD8, 0x97, 0x23, 0x1C, 0x73, 0x89, 0x65, 0x0A, 0x81, 0x44, 0x8E, 0xCC, 0x1E, 0x6A, 0xD3, 0x2E, 0xC5, 0x67, 0x24, 0x6B, 0x5A, 0xE3, 0xF5, 0x6B, 0x90, 0x16, 0x4B, 0x52, 0x6F, 0x03, 0xBE, 0x17, 0x22, 0xCE, 0x81, 0xE7, 0xD3, 0x35, 0x9D, 0xD5, 0x8A, 0x89, 0x92, 0xEE } }, { { 0xdf, 0x28, 0xb5, 0x4a, 0x06, 0x87, 0x38, 0x13, 0x64, 0xfa, 0xbb, 0x2a, 0x4f, 0x80, 0x13, 0x0e, 0x71, 0xe6, 0xb5, 0xd2, 0xa9, 0x42, 0x30, 0x7b, 0xf8, 0x93, 0x52, 0x25, 0x77, 0x67, 0x0e, 0xfa }, IPWPS_PROTO_KEYLEN_KDK, IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR, IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL*8, { 0xC6, 0x2A, 0x04, 0xCA, 0xF2, 0xD4, 0x71, 0x0F, 0x9E, 0x31, 0x35, 0xB6, 0x82, 0x67, 0xC0, 0x15, 0xF7, 0x2D, 0x82, 0xBE, 0x1D, 0x76, 0x45, 0xEB, 0x15, 0x91, 0x03, 0xE5, 0x9A, 0xA0, 0x2B, 0xC2, 0x36, 0xA9, 0xF0, 0xE3, 0x4D, 0x2C, 0xEB, 0xC0, 0xCA, 0x5A, 0x98, 0x0A, 0x65, 0x3C, 0xB8, 0xAE, 0x50, 0x7D, 0x2E, 0x2C, 0xC1, 0x68, 0x91, 0x05, 0x21, 0x5B, 0xD4, 0x3B, 0xD8, 0xD3, 0xF6, 0xEE, 0x1E, 0x96, 0xA0, 0x67, 0xF9, 0x55, 0x36, 0x3F, 0xB7, 0x8B, 0x46, 0x4F, 0xEA, 0x77, 0x6D, 0x20 } }, { { 0x1f, 0x2b, 0xfd, 0x06, 0x3d, 0x6c, 0xd2, 0x47, 0xaf, 0xe5, 0x49, 0xfd, 0xc0, 0x4e, 0xc9, 0x53, 0x14, 0xa3, 0xff, 0x3c, 0xcb, 0x2e, 0x27, 0xfa, 0x93, 0x82, 0x96, 0xb4, 0x22, 0x70, 0xc0, 0x79 }, IPWPS_PROTO_KEYLEN_KDK, IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR, IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL*8, { 0xAA, 0x38, 0x4F, 0xC8, 0xDD, 0x9F, 0x8B, 0xD5, 0xD5, 0xC4, 0x7C, 0xA8, 0x5C, 0x43, 0x00, 0x2E, 0x7C, 0x1D, 0x91, 0xC5, 0x13, 0x74, 0x6A, 0xD3, 0xBC, 0x2E, 0xBF, 0xB9, 0xAF, 0x6B, 0x29, 0xC4, 0x8C, 0xE5, 0x10, 0x21, 0xBC, 0x88, 0x20, 0x14, 0xF1, 0x0A, 0x0A, 0xEB, 0xD6, 0x34, 0x80, 0x07, 0x7E, 0x02, 0x42, 0x4B, 0xD2, 0xEB, 0x54, 0x05, 0x40, 0x3C, 0xB1, 0x16, 0xA8, 0x4E, 0x2B, 0xFE, 0x1F, 0xD3, 0x13, 0x4C, 0x0C, 0x76, 0x13, 0x8C, 0x2E, 0xCF, 0x21, 0x92, 0x8C, 0xD4, 0x45, 0x61 } }, { { 0x34, 0x48, 0xfb, 0x02, 0xe6, 0x0d, 0xb0, 0x7c, 0x21, 0x80, 0xcc, 0x69, 0x1f, 0x6b, 0x42, 0x49, 0x72, 0x98, 0x79, 0x4f, 0x63, 0xc7, 0xbc, 0xd7, 0x1a, 0xe6, 0x70, 0x16, 0x86, 0x2e, 0x4e, 0xc9 }, 32, "This is a Personalization String", 384, { 0x64, 0xDC, 0x0A, 0xA7, 0x00, 0xBC, 0x59, 0x75, 0xC7, 0xF0, 0x0B, 0xC8, 0xCE, 0xC8, 0xC5, 0xB2, 0xCC, 0xB9, 0x07, 0x2B, 0xB9, 0x50, 0xCE, 0x8B, 0x7D, 0x46, 0xF5, 0x36, 0x0C, 0x84, 0xB8, 0x2D, 0x53, 0x3A, 0xCC, 0xE4, 0x20, 0x95, 0x18, 0x72, 0x1E, 0xDC, 0xDE, 0x90, 0x28, 0xD8, 0xED, 0xD3 } } }; IP_STATIC Ipwps_proto_kwf_test_vector ipwps_proto_kwf_test_vector[] = { { { 0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C, 0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49 }, { 0x8D, 0x6D, 0xC3, 0xAB, 0xF0, 0xA1, 0xD3, 0x47, 0x5B, 0x3E, 0xAB, 0x78, 0x65, 0xDB, 0x1C, 0xE3 }, "This is data that matches a 16 octet block size", /* 48 bytes */ { 0x27, 0xDF, 0x74, 0xC2, 0x13, 0x1A, 0xB2, 0x8E, 0x9A, 0x92, 0xB9, 0xFC, 0xDD, 0x12, 0x0F, 0xFB, 0xEE, 0x4B, 0x99, 0x0E, 0x9A, 0x35, 0xC3, 0xAE, 0xEF, 0xF2, 0xB8, 0xA3, 0xE7, 0xC2, 0x1B, 0x08, 0x87, 0x23, 0xB1, 0xA9, 0xE3, 0x10, 0x41, 0x71, 0xC6, 0x9F, 0x07, 0xCF, 0x62, 0x3A, 0xA0, 0x64, 0xF5, 0x86, 0x1E, 0xB6, 0x6C, 0x4A, 0xBC, 0xC0, 0x9F, 0xD0, 0xBD, 0x99, 0x32, 0x70, 0xAE, 0x71 }, 64 }, { { 0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C, 0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49 }, { 0x0A, 0x9F, 0xAB, 0x6F, 0xEE, 0xD2, 0x57, 0x6B, 0x54, 0xF8, 0xB7, 0x63, 0x67, 0x80, 0x72, 0x09 }, "This is data that is even less than a block", /* 44 bytes */ { 0xF9, 0xEC, 0xDA, 0x79, 0x9C, 0x37, 0xCF, 0x6A, 0xA0, 0x68, 0xF0, 0xBF, 0x46, 0x5B, 0x17, 0xB3, 0x2F, 0x9A, 0xA7, 0x9F, 0xD8, 0xDE, 0x39, 0x51, 0x4E, 0x4D, 0xCB, 0x81, 0xD2, 0xC5, 0x81, 0xA8, 0x24, 0x63, 0x7E, 0x3E, 0x37, 0xB7, 0x05, 0x96, 0x88, 0x25, 0xFE, 0x53, 0xFA, 0x5C, 0x04, 0x86 }, 48 }, { { 0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C, 0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49 }, { 0xAA, 0xFA, 0x5D, 0xFA, 0x66, 0x07, 0xD9, 0x9D, 0x88, 0x5B, 0xD3, 0x03, 0x03, 0xE8, 0x3D, 0x12 }, "This is data that is an odd size more than block", /* 49 bytes */ { 0x9B, 0x3C, 0x5A, 0x8A, 0xE5, 0x31, 0xCF, 0xA5, 0x3D, 0xD5, 0x51, 0x90, 0x71, 0x69, 0xC9, 0x3D, 0x47, 0x11, 0xB3, 0x81, 0xE2, 0xFC, 0xCD, 0x33, 0x50, 0x76, 0x2F, 0x24, 0x20, 0x15, 0x2F, 0xD8, 0xB1, 0xF0, 0x49, 0xED, 0xB2, 0xAA, 0xDD, 0x33, 0x50, 0x18, 0x20, 0xD0, 0xF9, 0x8F, 0x17, 0xEC, 0xBC, 0xC8, 0x6B, 0x60, 0x55, 0x03, 0xA8, 0x65, 0x29, 0xFC, 0x70, 0xBC, 0x63, 0x08, 0x23, 0x7D }, 64 }, { { 0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C, 0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49 }, { 0xF4, 0x51, 0x41, 0xE9, 0x6C, 0xB6, 0xA8, 0x96, 0x37, 0x9E, 0x12, 0x28, 0xD7, 0xF7, 0xEE, 0x7B }, "This is data that is odd size less than block", /* 47 bytes */ { 0x44, 0x47, 0x68, 0x73, 0xDA, 0x6C, 0x7E, 0xDE, 0x8A, 0xCB, 0x11, 0x9B, 0x4B, 0x68, 0x9F, 0xE1, 0x6F, 0xB8, 0x0B, 0xBB, 0xDC, 0x74, 0xAA, 0x74, 0x6F, 0x55, 0xAF, 0x45, 0x13, 0xFE, 0x00, 0xB2, 0x9F, 0xBD, 0x4C, 0x79, 0xB7, 0xE4, 0x8F, 0xAD, 0x76, 0xA7, 0x93, 0xD7, 0x8D, 0xB6, 0x55, 0x7B }, 48 } }; /* *=========================================================================== * ipwps_proto_cryptotest_runall *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_runall(void) { Ip_err rc = IPCOM_SUCCESS; Ipwps_proto_crypto_test *test = ipwps_proto_crypto_tests; while (test->testfn) { IPCOM_LOG1(INFO, "***** WPS CRYPTO TEST - %s (STARTED) *****", test->testname); if (test->testfn() != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "***** WPS CRYPTO TEST - %s (FAILED) *****", test->testname); rc = IPCOM_ERR_FAILED; } else { IPCOM_LOG1(INFO, "***** WPS CRYPTO TEST - %s (SUCCESSFUL) *****", test->testname); } test++; } return rc; } /* *=========================================================================== * ipwps_proto_cryptotest_sessionkeys *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_sessionkeys(void) { Ip_err rc = IPCOM_SUCCESS; Ip_u8 test_enrollee_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; Ipwps_proto_ctx *proto_ctx1, *proto_ctx2; Ipwps_proto_nonce nonce1, nonce2; IPWPS_PROTO_NONCE_INIT(nonce1); IPWPS_PROTO_NONCE_INIT(nonce2); proto_ctx1 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx)); proto_ctx2 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx)); if (!proto_ctx1 || !proto_ctx2) { IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_sessionkeys :: out of memory"); rc = IPCOM_ERR_NO_MEMORY; goto done_test1; } rc = ipwps_proto_generate_local_keys(proto_ctx1); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_generate_local_keys(proto_ctx1) failed"); rc = IPCOM_ERR_FAILED; goto done_test1; } rc = ipwps_proto_generate_local_keys(proto_ctx2); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_generate_local_keys(proto_ctx2) failed"); rc = IPCOM_ERR_FAILED; goto done_test1; } ipwps_proto_copy_data(&proto_ctx1->peer_pub_key, &proto_ctx2->local_pub_key, 0, proto_ctx2->local_pub_key.len); ipwps_proto_copy_data(&proto_ctx2->peer_pub_key, &proto_ctx1->local_pub_key, 0, proto_ctx1->local_pub_key.len); ipcom_memcpy(proto_ctx1->enrollee_mac, test_enrollee_mac, 6); ipcom_memcpy(proto_ctx2->enrollee_mac, test_enrollee_mac, 6); IPCOM_LOG6(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: enrollee_mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", test_enrollee_mac[0], test_enrollee_mac[1], test_enrollee_mac[2], test_enrollee_mac[3], test_enrollee_mac[4], test_enrollee_mac[5]); /* Alloc and Init nonces 1 and 2 */ if(ipwps_proto_alloc_data(&nonce1, IPWPS_PROTO_NONCE_SIZE) != IPCOM_SUCCESS) { rc = IPCOM_ERR_FAILED; goto done_test1; } if (ipwps_proto_crypto_randdata(&nonce1) != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_crypto_randdata(&nonce1) failed"); rc = IPCOM_ERR_FAILED; goto done_test1; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_sessionkeys :: nonce1:", nonce1); if(ipwps_proto_alloc_data(&nonce2, IPWPS_PROTO_NONCE_SIZE) != IPCOM_SUCCESS) { rc = IPCOM_ERR_FAILED; goto done_test1; } if (ipwps_proto_crypto_randdata(&nonce2) != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_crypto_randdata(&nonce2) failed"); rc = IPCOM_ERR_FAILED; goto done_test1; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_sessionkeys :: nonce2:", nonce2); ipwps_proto_copy_data(&proto_ctx1->nonce1, &nonce1, 0, nonce1.len); ipwps_proto_copy_data(&proto_ctx1->nonce2, &nonce2, 0, nonce2.len); ipwps_proto_copy_data(&proto_ctx2->nonce1, &nonce1, 0, nonce1.len); ipwps_proto_copy_data(&proto_ctx2->nonce2, &nonce2, 0, nonce2.len); rc = ipwps_proto_derive_session_keys(proto_ctx1); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_derive_session_keys(proto_ctx1) failed"); rc = IPCOM_ERR_FAILED; goto done_test1; } rc = ipwps_proto_derive_session_keys(proto_ctx2); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_derive_session_keys(proto_ctx2) failed"); rc = IPCOM_ERR_FAILED; goto done_test1; } if (!ipwps_proto_compare_data(&proto_ctx1->auth_key, &proto_ctx2->auth_key)) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: auth_key mismatch"); rc = IPCOM_ERR_FAILED; } if (!ipwps_proto_compare_data(&proto_ctx1->key_wrap_key, &proto_ctx2->key_wrap_key)) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: key_wrap_key mismatch"); rc = IPCOM_ERR_FAILED; } if (!ipwps_proto_compare_data(&proto_ctx1->emsk, &proto_ctx2->emsk)) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: emsk mismatch"); rc = IPCOM_ERR_FAILED; } if (rc == IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: session keys MATCH (OK)"); } done_test1: if (proto_ctx1) { ipwps_proto_crypto_delete_all(proto_ctx1); ipcom_free(proto_ctx1); } if (proto_ctx2) { ipwps_proto_crypto_delete_all(proto_ctx2); ipcom_free(proto_ctx2); } ipwps_proto_container_delete(&nonce1); ipwps_proto_container_delete(&nonce2); return rc; } /* *=========================================================================== * ipwps_proto_cryptotest_dhsharedsecrets *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhsharedsecrets(void) { Ip_err rc = IPCOM_SUCCESS; Ipwps_proto_ctx *proto_ctx1, *proto_ctx2; Ipwps_proto_key shared_secret1, shared_secret2; IPWPS_PROTO_KEY_INIT(shared_secret1); IPWPS_PROTO_KEY_INIT(shared_secret2); proto_ctx1 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx)); proto_ctx2 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx)); if (!proto_ctx1 || !proto_ctx2) { IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_dhsharedsecrets :: out of memory"); rc = IPCOM_ERR_NO_MEMORY; goto done_test2; } rc = ipwps_proto_generate_local_keys(proto_ctx1); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_generate_local_keys(proto_ctx1) failed"); rc = IPCOM_ERR_FAILED; goto done_test2; } rc = ipwps_proto_generate_local_keys(proto_ctx2); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_generate_local_keys(proto_ctx2) failed"); rc = IPCOM_ERR_FAILED; goto done_test2; } ipwps_proto_copy_data(&proto_ctx1->peer_pub_key, &proto_ctx2->local_pub_key, 0, proto_ctx2->local_pub_key.len); ipwps_proto_copy_data(&proto_ctx2->peer_pub_key, &proto_ctx1->local_pub_key, 0, proto_ctx1->local_pub_key.len); rc = ipwps_proto_derive_dh_sharedsecret(proto_ctx1->dh, &proto_ctx1->peer_pub_key, &shared_secret1); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_derive_dh_sharedsecret(proto_ctx1) failed"); rc = IPCOM_ERR_FAILED; goto done_test2; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhsharedsecrets :: shared_secret1:", shared_secret1); rc = ipwps_proto_derive_dh_sharedsecret(proto_ctx2->dh, &proto_ctx2->peer_pub_key, &shared_secret2); if (rc != IPCOM_SUCCESS) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_derive_dh_sharedsecret(proto_ctx2) failed"); rc = IPCOM_ERR_FAILED; goto done_test2; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhsharedsecrets :: shared_secret2:", shared_secret2); if (!ipwps_proto_compare_data(&shared_secret1, &shared_secret2)) { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: shared_secret2 mismatch (FAIL)"); rc = IPCOM_ERR_FAILED; } else { IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: shared secrets MATCH (OK)"); } done_test2: if (proto_ctx1) { ipwps_proto_crypto_delete_all(proto_ctx1); ipcom_free(proto_ctx1); } if (proto_ctx2) { ipwps_proto_crypto_delete_all(proto_ctx2); ipcom_free(proto_ctx2); } ipwps_proto_container_delete(&shared_secret1); ipwps_proto_container_delete(&shared_secret2); return rc; } /* *=========================================================================== * ipwps_proto_cryptotest_dhkey *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhkey(void) { Ip_err rc = IPCOM_SUCCESS; Ipwps_proto_dhkey_test_vector *vector; int i, numvectors = sizeof(ipwps_proto_dhkey_test_vectors)/sizeof(ipwps_proto_dhkey_test_vectors[0]); Ipwps_proto_ctx *proto_ctx; Ipwps_proto_key shared_secret, dh_key, result; IPWPS_PROTO_KEY_INIT(shared_secret); IPWPS_PROTO_KEY_INIT(dh_key); IPWPS_PROTO_KEY_INIT(result); proto_ctx = ipcom_calloc(1, sizeof(Ipwps_proto_ctx)); if (!proto_ctx) { IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_dhkeys :: out of memory"); rc = IPCOM_ERR_NO_MEMORY; goto done_test3; } for (i = 0; i < numvectors; i++) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: testing vector %i", i); vector = &ipwps_proto_dhkey_test_vectors[i]; shared_secret.data = (Ip_u8 *)vector->input; shared_secret.len = strlen(vector->input); result.data = vector->result; result.len = IPWPS_PROTO_KEYLEN_DHKEY; if (ipwps_proto_derive_dhkey(proto_ctx, &shared_secret, &dh_key) != IPCOM_SUCCESS) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: ipwps_proto_derive_dhkey() failed, vector %d test (FAILED)", i); rc = IPCOM_ERR_FAILED; } IPWPS_PROTO_CRYPTO_DUMPASCII("ipwps_proto_cryptotest_dhkey :: input:", shared_secret.data, shared_secret.len); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: dh_key:", dh_key); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: result:", result); if ((rc == IPCOM_SUCCESS) && !ipwps_proto_compare_data(&dh_key, &result)) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: dh_key mismatch, vector %d test (FAILED)", i); rc = IPCOM_ERR_FAILED; } else { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: vector %d test (PASSED)", i); } ipwps_proto_container_delete(&dh_key); } done_test3: if (proto_ctx) { ipwps_proto_crypto_delete_all(proto_ctx); ipcom_free(proto_ctx); } return rc; } /* *=========================================================================== * ipwps_proto_cryptotest_dhkey *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_hmacsha256(void) { Ipwps_proto_hmacsha256_test_vector *vector; int numvectors = sizeof(ipwps_proto_hmacsha256_test_vectors) / sizeof(ipwps_proto_hmacsha256_test_vectors[0]); Ip_err rc = IPCOM_SUCCESS, fullrc = IPCOM_SUCCESS; Ipwps_proto_key key; Ipwps_proto_hash digest, result; HMAC_CTX hmac_ctx; int i,j; IPWPS_PROTO_KEY_INIT(key); IPWPS_PROTO_HASH_INIT(digest); IPWPS_PROTO_HASH_INIT(result); for (i = 0; i < numvectors; i++) { rc = IPCOM_SUCCESS; IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: testing vector %i", i); vector = &ipwps_proto_hmacsha256_test_vectors[i]; key.data = vector->key; key.len = vector->keylen; result.data = vector->result; result.len = (vector->trancate_len ? vector->trancate_len : SHA256_DIGEST_LENGTH); if (ipwps_proto_alloc_data(&digest, SHA256_DIGEST_LENGTH) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_hmacsha256 :: out of memeory. TERMINATING test."); return IPCOM_ERR_FAILED; } HMAC_CTX_init(&hmac_ctx); HMAC_Init(&hmac_ctx, key.data, key.len, EVP_sha256()); for (j = 0; j < vector->numblocks; j++) { HMAC_Update(&hmac_ctx, vector->block[j].data, vector->block[j].len); } HMAC_Final(&hmac_ctx, digest.data, (unsigned int *)&digest.len); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_hmacsha256 :: digest:", digest); if (vector->trancate_len) { IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_hmacsha256 :: result (truncated):", result); if (vector->trancate_len > digest.len) { IPCOM_LOG3(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: digest len invalid for vector %d (%d > %d)", i, vector->trancate_len, digest.len); rc = IPCOM_ERR_FAILED; } else { digest.len = vector->trancate_len; } } else { IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_hmacsha256 :: result:", result); } if ((rc == IPCOM_SUCCESS) && !ipwps_proto_compare_data(&digest, &result)) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: digest mismatch for vector %d", i); rc = IPCOM_ERR_FAILED; } if (rc == IPCOM_SUCCESS) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: vector %d test (PASSED)", i); } else { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: vector %d test (FAILED)", i); fullrc = IPCOM_ERR_FAILED; } ipwps_proto_container_delete(&digest); } return fullrc; } /* *=========================================================================== * ipwps_proto_cryptotest_kdk_kdf *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_kdf(void) { Ip_err rc = IPCOM_SUCCESS; Ipwps_proto_kdf_test_vector *vector; int i, numvectors = sizeof(ipwps_proto_kdf_test_vector)/sizeof(ipwps_proto_kdf_test_vector[0]); Ipwps_proto_key key, derived_key, result; char *pstring; IPWPS_PROTO_KEY_INIT(key); IPWPS_PROTO_KEY_INIT(derived_key); IPWPS_PROTO_KEY_INIT(result); for (i = 0; i < numvectors; i++) { rc = IPCOM_SUCCESS; IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kdf :: testing vector %i", i); vector = &ipwps_proto_kdf_test_vector[i]; key.data = vector->key; key.len = vector->keylen; result.len = (vector->keybits)/8; result.data = vector->result; pstring = vector->personalization_string; if (ipwps_proto_alloc_data(&derived_key, result.len) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_kdf :: out of memeory. TERMINATING test."); return IPCOM_ERR_FAILED; } if (ipwps_proto_perform_kdf(&key, IP_NULL, pstring, &derived_key) != IPCOM_SUCCESS) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kdf :: ipwps_proto_perform_kdf() failed, vector %d test (FAILED)", i); rc = IPCOM_ERR_FAILED; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kdf :: key:", key); IPCOM_LOG2(DEBUG2, "ipwps_proto_cryptotest_kdf :: keybits=%d, Personalization String: \"%s\"", vector->keybits, pstring); IPWPS_PROTO_CRYPTO_DUMPHEX(" :: derived_key:", derived_key); IPWPS_PROTO_CRYPTO_DUMPHEX(" :: result:", result); if ((rc == IPCOM_SUCCESS) && !ipwps_proto_compare_data(&derived_key, &result)) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kdf :: derived_key mismatch, vector %d test (FAILED)", i); rc = IPCOM_ERR_FAILED; } else { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: vector %d test (PASSED)", i); } ipwps_proto_container_delete(&derived_key); } return rc; } /* *=========================================================================== * ipwps_proto_cryptotest_kwf *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_proto_cryptotest_kwf(void) { Ip_err rc = IPCOM_SUCCESS, fullrc = IPCOM_SUCCESS; Ipwps_proto_kwf_test_vector *vector; int i, numvectors = sizeof(ipwps_proto_kwf_test_vector)/sizeof(ipwps_proto_kwf_test_vector[0]); Ipwps_proto_nonce iv; Ipwps_proto_ctx *proto_ctx; Ipwps_proto_container dte, dtd, encr_result, expected_result, decr_result; IPWPS_PROTO_NONCE_INIT(iv); IPWPS_PROTO_CONTAINER_INIT(dte); IPWPS_PROTO_CONTAINER_INIT(dtd); IPWPS_PROTO_CONTAINER_INIT(encr_result); IPWPS_PROTO_CONTAINER_INIT(expected_result); IPWPS_PROTO_CONTAINER_INIT(decr_result); proto_ctx = ipcom_calloc(1, sizeof(Ipwps_proto_ctx)); if (!proto_ctx) { IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_kwf :: out of memory"); rc = fullrc = IPCOM_ERR_NO_MEMORY; goto done_test4; } for (i = 0; i < numvectors; i++) { rc = IPCOM_SUCCESS; IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kwf :: testing vector %i", i); vector = &ipwps_proto_kwf_test_vector[i]; proto_ctx->key_wrap_key.len = IPWPS_PROTO_KEYLEN_KEYWRAPKEY; proto_ctx->key_wrap_key.data = vector->keywrapkey; iv.len = IPWPS_PROTO_NONCE_SIZE; iv.data = vector->iv; dte.len = strlen(vector->cleartext)+1; dte.data = (Ip_u8 *)vector->cleartext; expected_result.len = vector->ciphertext_len; expected_result.data = vector->ciphertext; if (ipwps_proto_alloc_data(&dtd, 256) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_kwf :: out of memeory. TERMINATING test."); rc = fullrc = IPCOM_ERR_FAILED; goto done_test4; } rc = ipwps_proto_kwf_encrypt_data_with_iv(proto_ctx, &dte, &dtd, &iv); if ( rc != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf :: Failed to encrypt vector %i", i); fullrc = IPCOM_ERR_FAILED; continue; } encr_result.len = dtd.len - IPWPS_PROTO_NONCE_SIZE; encr_result.data = dtd.data + IPWPS_PROTO_NONCE_SIZE; IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: key_wrap_key:", proto_ctx->key_wrap_key); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: iv:", iv); IPWPS_PROTO_CRYPTO_DUMPASCII("ipwps_proto_cryptotest_kwf :: dte:", dte.data, dte.len); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: dte:", dte); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: dtd:", dtd); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: encr_result:", encr_result); IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: expected_result:", expected_result); /* Verify encryption result */ if (!ipwps_proto_compare_data(&expected_result, &encr_result)) { IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf ::encryption result mismatch, vector %d test (FAILED)", i); rc = fullrc = IPCOM_ERR_FAILED; } /* Decrypt and verify decryption result */ if (ipwps_proto_alloc_data(&decr_result, 256) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_kwf :: out of memeory. TERMINATING test."); rc = fullrc = IPCOM_ERR_FAILED; goto done_test4; } if (ipwps_proto_kwf_decrypt_data(proto_ctx, &dtd, &decr_result) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf :: Failed to decrypt vector %i", i); rc = fullrc = IPCOM_ERR_FAILED; continue; } IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: decr_result:", decr_result); if (!ipwps_proto_compare_data(&dte, &decr_result)) { IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf ::decryption result mismatch, vector %d test (FAILED)", i); rc = fullrc = IPCOM_ERR_FAILED; continue; } else { IPWPS_PROTO_CRYPTO_DUMPASCII("ipwps_proto_cryptotest_kwf :: decr_result:", decr_result.data, decr_result.len); } if (rc == IPCOM_SUCCESS) { IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: vector %d test (PASSED)", i); } } done_test4: if (proto_ctx) { ipwps_proto_container_delete(&dtd); ipwps_proto_container_delete(&decr_result); ipwps_proto_crypto_delete_all(proto_ctx); ipcom_free(proto_ctx); } return fullrc; } #endif