OpenSolaris_b135/common/crypto/fips/fips_sha1_util.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/kmem.h>
#include <sys/systm.h>
#include <sys/sha1.h>
#include <sys/crypto/common.h>
#include <sys/cmn_err.h>
#ifndef _KERNEL
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <security/cryptoki.h>
#include <cryptoutil.h>
#include "softMAC.h"
#endif
#include <sha1/sha1_impl.h>

/*
 * fips_sha1_build_context()
 *
 * Description:
 *	This function allocates and initializes SHA1 context
 *	context.
 */
SHA1_CTX *
fips_sha1_build_context(void)
{
	SHA1_CTX *sha1_context;


#ifndef _KERNEL
	if ((sha1_context = malloc(sizeof (SHA1_CTX))) == NULL)
#else
	if ((sha1_context = kmem_zalloc(sizeof (SHA1_CTX),
	    KM_SLEEP)) == NULL)
#endif
		return (NULL);

	SHA1Init(sha1_context);

	return (sha1_context);

}

/*
 * fips_sha1_hash()
 *
 * Arguments:
 *	sha1_context:	pointer to SHA1 context
 *	in:	pointer to the input data to be hashed
 *	inlen:	length of the input data
 *	out:	pointer to the output data after hashing
 *
 * Description:
 *	This function calls the low-level SHA1 routines for hashing.
 *
 */
int
fips_sha1_hash(SHA1_CTX *sha1_context, uchar_t *in, ulong_t inlen, uchar_t *out)
{

	int rv;

	if (in != NULL) {
#ifdef	__sparcv9
		SHA1Update((SHA1_CTX *)sha1_context, in, (uint_t)inlen);
#else	/* !__sparcv9 */
		SHA1Update((SHA1_CTX *)sha1_context, in, inlen);
#endif	/* __sparcv9 */
		SHA1Final(out, (SHA1_CTX *)sha1_context);
		rv = CKR_OK;
	} else
		rv = CKR_ARGUMENTS_BAD;

	if (sha1_context)
#ifdef _KERNEL
		kmem_free(sha1_context, sizeof (SHA1_CTX));
#else
		free(sha1_context);
#endif
	return (rv);
}


#ifndef _KERNEL
soft_hmac_ctx_t *
fips_sha1_hmac_build_context(uint8_t *secret_key,
	unsigned int secret_key_length)
{

	soft_hmac_ctx_t *hmac_ctx;
	uint32_t sha1_ipad[SHA1_HMAC_INTS_PER_BLOCK];
	uint32_t sha1_opad[SHA1_HMAC_INTS_PER_BLOCK];

	hmac_ctx = malloc(sizeof (soft_hmac_ctx_t));

	if (hmac_ctx == NULL) {
		return (NULL);
	}

	hmac_ctx->hmac_len = SHA1_HASH_SIZE;
	bzero(sha1_ipad, SHA1_HMAC_BLOCK_SIZE);
	bzero(sha1_opad, SHA1_HMAC_BLOCK_SIZE);

	(void) memcpy(sha1_ipad, secret_key, secret_key_length);
	(void) memcpy(sha1_opad, secret_key, secret_key_length);

	sha1_hmac_ctx_init(&hmac_ctx->hc_ctx_u.sha1_ctx, sha1_ipad,
	    sha1_opad);

	return (hmac_ctx);

}

CK_RV
fips_hmac_sha1_hash(unsigned char *hmac_computed,
	uint8_t *secret_key,
	unsigned int secret_key_length,
	uint8_t *message,
	unsigned int message_length)
{

	soft_hmac_ctx_t *hmac_ctx = NULL;

	hmac_ctx = fips_sha1_hmac_build_context(secret_key,
	    secret_key_length);

	if (hmac_ctx == NULL)
		return (CKR_HOST_MEMORY);

	if (message != NULL) {
		SOFT_MAC_UPDATE(SHA1, &(hmac_ctx->hc_ctx_u.sha1_ctx),
		    message, message_length);
	}

	SOFT_MAC_FINAL(SHA1, &(hmac_ctx->hc_ctx_u.sha1_ctx), hmac_computed);

	free(hmac_ctx);
	return (CKR_OK);
}

#else /* _KERNEL */

/*
 * Initialize a SHA1-HMAC context.
 */
void
sha1_mac_init_ctx(sha1_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
{
	uint32_t ipad[SHA1_HMAC_INTS_PER_BLOCK];
	uint32_t opad[SHA1_HMAC_INTS_PER_BLOCK];
	uint_t i;

	bzero(ipad, SHA1_HMAC_BLOCK_SIZE);
	bzero(opad, SHA1_HMAC_BLOCK_SIZE);

	bcopy(keyval, ipad, length_in_bytes);
	bcopy(keyval, opad, length_in_bytes);

	/* XOR key with ipad (0x36) and opad (0x5c) */
	for (i = 0; i < SHA1_HMAC_INTS_PER_BLOCK; i++) {
		ipad[i] ^= 0x36363636;
		opad[i] ^= 0x5c5c5c5c;
	}

	/* perform SHA1 on ipad */
	SHA1Init(&ctx->hc_icontext);
	SHA1Update(&ctx->hc_icontext, (uint8_t *)ipad, SHA1_HMAC_BLOCK_SIZE);

	/* perform SHA1 on opad */
	SHA1Init(&ctx->hc_ocontext);
	SHA1Update(&ctx->hc_ocontext, (uint8_t *)opad, SHA1_HMAC_BLOCK_SIZE);
}

sha1_hmac_ctx_t *
fips_sha1_hmac_build_context(uint8_t *secret_key,
	unsigned int secret_key_length)
{
	sha1_hmac_ctx_t *sha1_hmac_ctx_tmpl;


	/*
	 * Allocate and initialize SHA1 context.
	 */
	sha1_hmac_ctx_tmpl = kmem_alloc(sizeof (sha1_hmac_ctx_t),
	    KM_SLEEP);
	if (sha1_hmac_ctx_tmpl == NULL)
		return (NULL);

	/*
	 * initialize ctx->hc_icontext and ctx->hc_ocontext
	 */
	sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, secret_key,
	    secret_key_length);


	sha1_hmac_ctx_tmpl->hc_mech_type = SHA1_HMAC_MECH_INFO_TYPE;


	return (sha1_hmac_ctx_tmpl);
}

void
fips_hmac_sha1_hash(sha1_hmac_ctx_t *sha1_hmac_ctx,
	uint8_t *message, uint32_t message_len,
	uint8_t *hmac_computed)
{

	/* do a SHA1 update of the inner context using the specified data */
	SHA1Update(&((sha1_hmac_ctx)->hc_icontext), message,
	    message_len);

	/*
	 * Do a SHA1 final on the inner context.
	 */
	SHA1Final(hmac_computed, &((sha1_hmac_ctx)->hc_icontext));

	/*
	 * Do an SHA1 update on the outer context, feeding the inner
	 * digest as data.
	 */
	SHA1Update(&((sha1_hmac_ctx)->hc_ocontext), hmac_computed,
	    SHA1_HASH_SIZE);

	/*
	 * Do a SHA1 final on the outer context, storing the computed
	 * digest in the caller's buffer.
	 */
	SHA1Final(hmac_computed, &((sha1_hmac_ctx)->hc_ocontext));

	kmem_free(sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
}

#endif

/*
 * SHA1 Power-On SelfTest(s).
 */
int
fips_sha1_post(void)
{

	/*
	 * SHA-1 Known Hash Message
	 * Source from NIST SHA1ShortMsg (L = 512-bits).
	 */
	static uint8_t sha1_known_hash_message[] = {
		0x7e, 0x3a, 0x4c, 0x32, 0x5c, 0xb9, 0xc5, 0x2b,
		0x88, 0x38, 0x7f, 0x93, 0xd0, 0x1a, 0xe8, 0x6d,
		0x42, 0x09, 0x8f, 0x5e, 0xfa, 0x7f, 0x94, 0x57,
		0x38, 0x8b, 0x5e, 0x74, 0xb6, 0xd2, 0x8b, 0x24,
		0x38, 0xd4, 0x2d, 0x8b, 0x64, 0x70, 0x33, 0x24,
		0xd4, 0xaa, 0x25, 0xab, 0x6a, 0xad, 0x15, 0x3a,
		0xe3, 0x0c, 0xd2, 0xb2, 0xaf, 0x4d, 0x5e, 0x5c,
		0x00, 0xa8, 0xa2, 0xd0, 0x22, 0x0c, 0x61, 0x16
	};

	/* SHA-1 Known Digest Message (160-bits). */
	static  uint8_t sha1_known_digest[] = {
		0xa3, 0x05, 0x44, 0x27, 0xcd, 0xb1, 0x3f, 0x16,
		0x4a, 0x61, 0x0b, 0x34, 0x87, 0x02, 0x72, 0x4c,
		0x80, 0x8a, 0x0d, 0xcc
	};

	/* Source from NIST HMAC.txt Count = 0 */
	static uint8_t HMAC_known_secret_key[] = {
		0x7b, 0x10, 0xf4, 0x12, 0x4b, 0x15, 0xc8, 0x2e
	};

	static uint8_t HMAC_known_secret_key_length
	    = sizeof (HMAC_known_secret_key);

	/* known SHA1 hmac - truncated (10 bytes) */
	static uint8_t known_SHA1_hmac[] = {
		0x4e, 0xad, 0x12, 0xc2, 0xfe, 0x3d, 0x6e, 0xa4,
		0x3a, 0xcb
	};

	static uint8_t hmac_sha1_known_hash_message[] = {
		0x27, 0xdc, 0xb5, 0xb1, 0xda, 0xf6, 0x0c, 0xfd,
		0x3e, 0x2f, 0x73, 0xd4, 0xd6, 0x4c, 0xa9, 0xc6,
		0x84, 0xf8, 0xbf, 0x71, 0xfc, 0x68, 0x2a, 0x46,
		0x79, 0x3b, 0x17, 0x90, 0xaf, 0xa4, 0xfe, 0xb1,
		0x00, 0xca, 0x7a, 0xaf, 0xf2, 0x6f, 0x58, 0xf0,
		0xe1, 0xd0, 0xed, 0x42, 0xf1, 0xcd, 0xad, 0x1f,
		0x47, 0x4a, 0xfa, 0x2e, 0x79, 0xd5, 0x3a, 0x0c,
		0x42, 0x89, 0x2c, 0x4d, 0x7b, 0x32, 0x7c, 0xbe,
		0x46, 0xb2, 0x95, 0xed, 0x8d, 0xa3, 0xb6, 0xec,
		0xab, 0x3d, 0x48, 0x51, 0x68, 0x7a, 0x6f, 0x81,
		0x2b, 0x79, 0xdf, 0x2f, 0x6b, 0x20, 0xf1, 0x1f,
		0x67, 0x06, 0xf5, 0x30, 0x17, 0x90, 0xca, 0x99,
		0x62, 0x5a, 0xad, 0x73, 0x91, 0xd8, 0x4f, 0x78,
		0x04, 0x3d, 0x2a, 0x0a, 0x23, 0x9b, 0x14, 0x77,
		0x98, 0x4c, 0x15, 0x7b, 0xbc, 0x92, 0x76, 0x06,
		0x4e, 0x7a, 0x1a, 0x40, 0x6b, 0x06, 0x12, 0xca
	};

	/* SHA-1 variables. */
	uint8_t sha1_computed_digest[SHA1_DIGEST_LENGTH];
	uint8_t hmac_computed[SHA1_HMAC_BLOCK_SIZE];
	SHA1_CTX *sha1_context = NULL;

#ifdef _KERNEL
	sha1_hmac_ctx_t *sha1_hmac_ctx = NULL;
#endif

	int rv;

	/* SHA-1 Known Answer Hashing Test. */
	sha1_context = fips_sha1_build_context();
	if (sha1_context == NULL)
		return (CKR_HOST_MEMORY);

	rv = fips_sha1_hash(sha1_context, sha1_known_hash_message,
	    FIPS_KNOWN_HMAC_MESSAGE_LENGTH, sha1_computed_digest);

	if ((rv != CKR_OK) ||
	    (memcmp(sha1_computed_digest, sha1_known_digest,
	    SHA1_DIGEST_LENGTH) != 0))
		return (CKR_DEVICE_ERROR);

#ifdef _KERNEL
	/* SHA-1 HMAC Known Answer Hashing Test */
	sha1_hmac_ctx = fips_sha1_hmac_build_context(HMAC_known_secret_key,
	    HMAC_known_secret_key_length);

	if (sha1_hmac_ctx == NULL)
		return (CKR_HOST_MEMORY);

	fips_hmac_sha1_hash(sha1_hmac_ctx, hmac_sha1_known_hash_message,
	    sizeof (hmac_sha1_known_hash_message), hmac_computed);
#else
	rv = fips_hmac_sha1_hash(hmac_computed, HMAC_known_secret_key,
	    HMAC_known_secret_key_length, hmac_sha1_known_hash_message,
	    sizeof (hmac_sha1_known_hash_message));

#endif

#ifdef _KERNEL
	if (memcmp(hmac_computed, known_SHA1_hmac,
	    sizeof (known_SHA1_hmac)) != 0)
	return (CKR_DEVICE_ERROR);
#else
	if ((rv != CKR_OK) ||
	    (memcmp(hmac_computed, known_SHA1_hmac,
	    sizeof (known_SHA1_hmac)) != 0))
	return (CKR_DEVICE_ERROR);
#endif

	return (rv);

}