Files
m241Neelima/components/ip_net2-6.9/ipwps/src/ipwps_protocol_crypto.c
T
2026-07-30 11:19:44 +05:30

2622 lines
90 KiB
C

/* 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 <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_clib.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
/* Openssl header files */
#include <openssl/rand.h>
#include <openssl/dh.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#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