changeset 8029:d7695059e7a6

6703956 Solaris cryptographic framework needs a FIPS-186-2 certifiable RNG
author Hai-May Chao <Hai-May.Chao@Sun.COM>
date Thu, 06 Nov 2008 16:52:01 -0800
parents cd6790ddf574
children 2b963e8d757a
files usr/src/common/crypto/rng/fips_random.c usr/src/common/crypto/rng/fips_random.h usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/crypto/api/kcf_random.c usr/src/uts/common/crypto/io/swrand.c usr/src/uts/common/sys/random.h usr/src/uts/intel/swrand/Makefile usr/src/uts/sparc/swrand/Makefile usr/src/uts/sun4v/io/n2rng/n2rng_provider.c usr/src/uts/sun4v/n2rng/Makefile
diffstat 11 files changed, 370 insertions(+), 298 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/crypto/rng/fips_random.c	Thu Nov 06 16:52:01 2008 -0800
@@ -0,0 +1,137 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <rng/fips_random.h>
+#include <sys/sha1.h>
+
+/*
+ * Adds val1 and val2 and stores result into sum.  The various input
+ * pointers can be exactly aliased.  (They cannot be offset and
+ * overlapping, but no one would ever do that.)  Values are big endian
+ * by words and native byte order within words.  The return value's
+ * 2-bit is 0 if the result is zero, it's 1 bit is carry out.  (This
+ * is reused code.  The return code is not used by n2rng.)  Thus,
+ * calling with both carryin and complement_val2 ones does a
+ * subtraction.  A null sum pointer parameter is allowed.  The
+ * subtraction features were required when this code was orginally
+ * written so it could do a mod q operation.
+ */
+static int
+fips_add160(uint32_t *sum, uint32_t const *val1, uint32_t const *val2,
+    const unsigned carryin, const int complement_val2)
+{
+	int i;
+	uint32_t partialsum;
+	uint32_t carry = (carryin > 0);
+	uint32_t non_zero = 0;
+
+	for (i = 4; i >= 0; --i) {
+		partialsum = val1[i] + (complement_val2 ? ~val2[i] : val2[i]) +
+		    carry;
+		if (carry) {
+			carry = (partialsum <= val1[i]);
+		} else {
+			carry = (partialsum < val1[i]);
+		}
+		if (sum) {
+			sum[i] = partialsum;
+		}
+		non_zero |= partialsum;
+	}
+
+	return (((non_zero != 0) * 2) | carry);
+}
+
+/*
+ * Computes a new random value, which is stored in x_j; updates
+ * XKEY.  XSEED_j is additional input.  In principle, we should
+ * protect XKEY, perhaps by putting it on a non-pagable page, but we
+ * aways clobber XKEY with fresh entropy just before we use it.  And
+ * step 3d irreversibly updates it just after we use it.  The only
+ * risk is that if an attacker captured the state while the entropy
+ * generator was broken, the attacker could predict future values.
+ * There are two cases: 1.  The attack gets root access to a live
+ * system.  But there is no defense against that.  2.  The attacker
+ * gets access to a crash dump.  But by then no values are being
+ * generated.
+ *
+ * Note that XSEEDj is overwritten with sensitive stuff, and must be
+ * zeroed by the caller.  We use two separate symbols (XVAL and
+ * XSEEDj) to make each step match the notation in FIPS 186-2.
+ */
+void
+fips_random_inner(uint32_t *key, uint32_t *x_j,
+    uint32_t *XSEED_j)
+{
+	int		i;
+	SHA1_CTX	sha1_context;
+	/* Alias to preserve terminology from FIPS 186-2 */
+#define	XVAL XSEED_j
+	/*
+	 * K&R section A8.7: If the array has fixed size, the number
+	 * of initializers may not exceed the number of members in the
+	 * array; if there are fewer, the trailing members are
+	 * initialized with 0.
+	 */
+	static const char	zero[SHA1BLOCKBYTES - SHA1BYTES] = {0};
+
+	/*
+	 * Step 3b: XVAL = (XKEY + XSEED_sub_j) mod 2^b.  The mod is
+	 * implicit in the 160 bit representation.  Note that XVAL and
+	 * XSEED_j are actually the same location.
+	 */
+	(void) fips_add160(XVAL, key, XSEED_j, 0, 0);
+	/*
+	 * Step 3c: x_sub_j = G(t, XVAL).
+	 */
+	SHA1Init(&sha1_context);
+	SHA1Update(&sha1_context, (unsigned char *)XVAL, SHA1BYTES);
+	/*
+	 * Filling to 64 bytes is requried by FIPS 186-2 Appendix 3.3.
+	 * It also triggers SHA1Transform (the steps a-e of the spec).
+	 *
+	 * zero is a const char[], but SHA1update does not declare its
+	 * second parameter const, even though it does not modify it,
+	 * so we cast to suppress a compiler warning.
+	 */
+	SHA1Update(&sha1_context, (unsigned char *)zero,
+	    SHA1BLOCKBYTES - SHA1BYTES);
+	/*
+	 * The code below directly accesses the state field of
+	 * sha1_context, which is of type SHA1_CTX, defined in sha1.h.
+	 */
+	/* copy out to x_j */
+	for (i = 0; i < 5; i++) {
+		x_j[i] = sha1_context.state[i];
+	}
+	/*
+	 * Step 3d: XKEY = (1 + XKEY + x_sub_j) mod 2^b.  b=160.  The
+	 * mod 2^160 is implicit in the 160 bit representation.  The
+	 * one is added via the carry-in flag.
+	 */
+	(void) fips_add160(key, key, x_j, 1, 0);
+#undef XVAL
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/crypto/rng/fips_random.h	Thu Nov 06 16:52:01 2008 -0800
@@ -0,0 +1,47 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_COMMON_CRYPTO_FIPS_RANDOM_H
+#define	_COMMON_CRYPTO_FIPS_RANDOM_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define	SHA1BLOCKBITS		512
+#define	SHA1BLOCKBYTES		(SHA1BLOCKBITS >> 3)
+#define	SHA1WORDS		5
+#define	BYTES_IN_WORD		4
+#define	SHA1BYTES		(BYTES_IN_WORD * SHA1WORDS)
+
+extern void fips_random_inner(uint32_t *, uint32_t *, uint32_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _COMMON_CRYPTO_FIPS_RANDOM_H */
--- a/usr/src/uts/common/Makefile.files	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/common/Makefile.files	Thu Nov 06 16:52:01 2008 -0800
@@ -1370,7 +1370,7 @@
 		kcf_keys.o kcf_mac.o kcf_mech_tabs.o kcf_miscapi.o \
 		kcf_object.o kcf_policy.o kcf_prov_lib.o kcf_prov_tabs.o \
 		kcf_sched.o kcf_session.o kcf_sign.o kcf_spi.o kcf_verify.o \
-		kcf_random.o modes.o ecb.o cbc.o ctr.o ccm.o gcm.o
+		kcf_random.o modes.o ecb.o cbc.o ctr.o ccm.o gcm.o fips_random.o
 
 CRYPTOADM_OBJS += cryptoadm.o
 
--- a/usr/src/uts/common/Makefile.rules	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/common/Makefile.rules	Thu Nov 06 16:52:01 2008 -0800
@@ -60,6 +60,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(COMMONBASE)/crypto/rng/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(COMMONBASE)/crypto/rsa/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1258,6 +1262,9 @@
 $(LINTS_DIR)/%.ln:		$(COMMONBASE)/crypto/modes/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(COMMONBASE)/crypto/rng/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(COMMONBASE)/crypto/rsa/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/crypto/api/kcf_random.c	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/common/crypto/api/kcf_random.c	Thu Nov 06 16:52:01 2008 -0800
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file implements the interfaces that the /dev/random
  * driver uses for read(2), write(2) and poll(2) on /dev/random or
@@ -44,9 +42,9 @@
  * kmem-magazine-style, to avoid cache line contention.
  *
  * LOCKING HIERARCHY:
- *	1) rmp->rm_lock protects the per-cpu pseudo-random generators.
+ *	1) rmp->rm_mag.rm_lock protects the per-cpu pseudo-random generators.
  * 	2) rndpool_lock protects the high-quality randomness pool.
- *		It may be locked while a rmp->rm_lock is held.
+ *		It may be locked while a rmp->rm_mag.rm_lock is held.
  *
  * A history note: The kernel API and the software-based algorithms in this
  * file used to be part of the /dev/random driver.
@@ -68,6 +66,7 @@
 #include <sys/sysmacros.h>
 #include <sys/cpuvar.h>
 #include <sys/taskq.h>
+#include <rng/fips_random.h>
 
 #define	RNDPOOLSIZE		1024	/* Pool size in bytes */
 #define	MINEXTRACTBYTES		20
@@ -95,16 +94,6 @@
 
 /* HMAC-SHA1 */
 #define	HMAC_KEYSIZE			20
-#define	HMAC_BLOCK_SIZE			64
-#define	HMAC_KEYSCHED			sha1keysched_t
-#define	SET_ENCRYPT_KEY(k, s, ks)	hmac_key((k), (s), (ks))
-#define	HMAC_ENCRYPT(ks, p, s, d)	hmac_encr((ks), (uint8_t *)(p), s, d)
-
-/* HMAC-SHA1 "keyschedule" */
-typedef struct sha1keysched_s {
-	SHA1_CTX ictx;
-	SHA1_CTX octx;
-} sha1keysched_t;
 
 /*
  * Cache of random bytes implemented as a circular buffer. findex and rindex
@@ -130,9 +119,6 @@
 static void rndc_getbytes(uint8_t *ptr, size_t len);
 static void rnd_handler(void *);
 static void rnd_alloc_magazines();
-static void hmac_key(uint8_t *, size_t, void *);
-static void hmac_encr(void *, uint8_t *, size_t, uint8_t *);
-
 
 void
 kcf_rnd_init()
@@ -577,11 +563,9 @@
  * of cache-line-padding structures.
  */
 #define	RND_CPU_CACHE_SIZE	64
-#define	RND_CPU_PAD_SIZE	RND_CPU_CACHE_SIZE*5
+#define	RND_CPU_PAD_SIZE	RND_CPU_CACHE_SIZE*6
 #define	RND_CPU_PAD (RND_CPU_PAD_SIZE - \
-	(sizeof (kmutex_t) + 3*sizeof (uint8_t *) + sizeof (HMAC_KEYSCHED) + \
-	sizeof (uint64_t) + 3*sizeof (uint32_t) + sizeof (rnd_stats_t)))
-
+	sizeof (rndmag_t))
 /*
  * Per-CPU random state.  Somewhat like like kmem's magazines, this provides
  * a per-CPU instance of the pseudo-random generator.  We have it much easier
@@ -599,18 +583,24 @@
 	uint8_t 	*rm_buffer;	/* Start of buffer */
 	uint8_t		*rm_eptr;	/* End of buffer */
 	uint8_t		*rm_rptr;	/* Current read pointer */
-	HMAC_KEYSCHED 	rm_ks;		/* seed */
-	uint64_t 	rm_counter;	/* rotating counter for extracting */
 	uint32_t	rm_oblocks;	/* time to rekey? */
 	uint32_t	rm_ofuzz;	/* Rekey backoff state */
 	uint32_t	rm_olimit;	/* Hard rekey limit */
 	rnd_stats_t	rm_stats;	/* Per-CPU Statistics */
-	uint8_t		rm_pad[RND_CPU_PAD];
+	uint32_t	rm_key[SHA1WORDS];	/* FIPS XKEY */
+	uint32_t	rm_seed[SHA1WORDS];	/* seed for rekey */
+	uint32_t	rm_previous[SHA1WORDS]; /* previous random bytes */
 } rndmag_t;
 
+typedef struct rndmag_pad_s
+{
+	rndmag_t	rm_mag;
+	uint8_t		rm_pad[RND_CPU_PAD];
+} rndmag_pad_t;
+
 /*
- * Generate random bytes for /dev/urandom by encrypting a
- * rotating counter with a key created from bytes extracted
+ * Generate random bytes for /dev/urandom by applying the
+ * FIPS 186-2 algorithm with a key created from bytes extracted
  * from the pool.  A maximum of PRNG_MAXOBLOCKS output blocks
  * is generated before a new key is obtained.
  *
@@ -619,30 +609,32 @@
  * Called with rmp locked; releases lock.
  */
 static int
-rnd_generate_pseudo_bytes(rndmag_t *rmp, uint8_t *ptr, size_t len)
+rnd_generate_pseudo_bytes(rndmag_pad_t *rmp, uint8_t *ptr, size_t len)
 {
 	size_t bytes = len;
 	int nblock, size;
 	uint32_t oblocks;
-	uint8_t digest[HASHSIZE];
+	uint32_t tempout[SHA1WORDS];
+	uint32_t seed[SHA1WORDS];
+	int i;
+	hrtime_t timestamp;
+	uint8_t *src, *dst;
 
-	ASSERT(mutex_owned(&rmp->rm_lock));
+	ASSERT(mutex_owned(&rmp->rm_mag.rm_lock));
 
 	/* Nothing is being asked */
 	if (len == 0) {
-		mutex_exit(&rmp->rm_lock);
+		mutex_exit(&rmp->rm_mag.rm_lock);
 		return (0);
 	}
 
 	nblock = howmany(len, HASHSIZE);
 
-	rmp->rm_oblocks += nblock;
-	oblocks = rmp->rm_oblocks;
+	rmp->rm_mag.rm_oblocks += nblock;
+	oblocks = rmp->rm_mag.rm_oblocks;
 
 	do {
-		if (oblocks >= rmp->rm_olimit) {
-			hrtime_t timestamp;
-			uint8_t key[HMAC_KEYSIZE];
+		if (oblocks >= rmp->rm_mag.rm_olimit) {
 
 			/*
 			 * Contention-avoiding rekey: see if
@@ -650,14 +642,15 @@
 			 * Do an 'exponential back-in' to ensure we don't
 			 * run too long without rekey.
 			 */
-			if (rmp->rm_ofuzz) {
+			if (rmp->rm_mag.rm_ofuzz) {
 				/*
 				 * Decaying exponential back-in for rekey.
 				 */
 				if ((rnbyte_cnt < MINEXTRACTBYTES) ||
 				    (!mutex_tryenter(&rndpool_lock))) {
-					rmp->rm_olimit += rmp->rm_ofuzz;
-					rmp->rm_ofuzz >>= 1;
+					rmp->rm_mag.rm_olimit +=
+					    rmp->rm_mag.rm_ofuzz;
+					rmp->rm_mag.rm_ofuzz >>= 1;
 					goto punt;
 				}
 			} else {
@@ -665,49 +658,71 @@
 			}
 
 			/* Get a new chunk of entropy */
-			(void) rnd_get_bytes(key, HMAC_KEYSIZE,
-			    ALWAYS_EXTRACT, B_FALSE);
-
-			/* Set up key */
-			SET_ENCRYPT_KEY(key, HMAC_KEYSIZE, &rmp->rm_ks);
+			(void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key,
+			    HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE);
 
-			/* Get new counter value by encrypting timestamp */
-			timestamp = gethrtime();
-			HMAC_ENCRYPT(&rmp->rm_ks, &timestamp,
-			    sizeof (timestamp), digest);
-			rmp->rm_olimit = PRNG_MAXOBLOCKS/2;
-			rmp->rm_ofuzz = PRNG_MAXOBLOCKS/4;
-			bcopy(digest, &rmp->rm_counter, sizeof (uint64_t));
+			rmp->rm_mag.rm_olimit = PRNG_MAXOBLOCKS/2;
+			rmp->rm_mag.rm_ofuzz = PRNG_MAXOBLOCKS/4;
 			oblocks = 0;
-			rmp->rm_oblocks = nblock;
+			rmp->rm_mag.rm_oblocks = nblock;
 		}
 punt:
-		/* Hash counter to produce prn stream */
+		timestamp = gethrtime();
+
+		src = (uint8_t *)&timestamp;
+		dst = (uint8_t *)rmp->rm_mag.rm_seed;
+
+		for (i = 0; i < HASHSIZE; i++) {
+			dst[i] ^= src[i % sizeof (timestamp)];
+		}
+
+		bcopy(rmp->rm_mag.rm_seed, seed, HASHSIZE);
+
+		fips_random_inner(rmp->rm_mag.rm_key, tempout,
+		    seed);
+
 		if (bytes >= HASHSIZE) {
 			size = HASHSIZE;
-			HMAC_ENCRYPT(&rmp->rm_ks, &rmp->rm_counter,
-			    sizeof (rmp->rm_counter), ptr);
 		} else {
 			size = min(bytes, HASHSIZE);
-			HMAC_ENCRYPT(&rmp->rm_ks, &rmp->rm_counter,
-			    sizeof (rmp->rm_counter), digest);
-			bcopy(digest, ptr, size);
 		}
+
+		/*
+		 * FIPS 140-2: Continuous RNG test - each generation
+		 * of an n-bit block shall be compared with the previously
+		 * generated block. Test shall fail if any two compared
+		 * n-bit blocks are equal.
+		 */
+		for (i = 0; i < size/BYTES_IN_WORD; i++) {
+			if (tempout[i] != rmp->rm_mag.rm_previous[i])
+				break;
+		}
+		if (i == size/BYTES_IN_WORD)
+			cmn_err(CE_WARN, "kcf_random: The value of 160-bit "
+			    "block random bytes are same as the previous "
+			    "one.\n");
+
+		bcopy(tempout, rmp->rm_mag.rm_previous,
+		    HASHSIZE);
+
+		bcopy(tempout, ptr, size);
 		ptr += size;
 		bytes -= size;
-		rmp->rm_counter++;
 		oblocks++;
 		nblock--;
 	} while (bytes > 0);
 
-	mutex_exit(&rmp->rm_lock);
+	/* Zero out sensitive information */
+	bzero(seed, HASHSIZE);
+	bzero(tempout, HASHSIZE);
+	mutex_exit(&rmp->rm_mag.rm_lock);
 	return (0);
 }
 
 /*
  * Per-CPU Random magazines.
  */
-static rndmag_t *rndmag;
+static rndmag_pad_t *rndmag;
 static uint8_t	*rndbuf;
 static size_t 	rndmag_total;
 /*
@@ -728,7 +743,7 @@
 int
 kcf_rnd_get_pseudo_bytes(uint8_t *ptr, size_t len)
 {
-	rndmag_t *rmp;
+	rndmag_pad_t *rmp;
 	uint8_t *cptr, *eptr;
 
 	/*
@@ -741,7 +756,7 @@
 	 */
 	for (;;) {
 		rmp = &rndmag[CPU->cpu_seqid];
-		mutex_enter(&rmp->rm_lock);
+		mutex_enter(&rmp->rm_mag.rm_lock);
 
 		/*
 		 * Big requests bypass buffer and tail-call the
@@ -752,27 +767,27 @@
 			return (rnd_generate_pseudo_bytes(rmp, ptr, len));
 		}
 
-		cptr = rmp->rm_rptr;
+		cptr = rmp->rm_mag.rm_rptr;
 		eptr = cptr + len;
 
-		if (eptr <= rmp->rm_eptr) {
-			rmp->rm_rptr = eptr;
+		if (eptr <= rmp->rm_mag.rm_eptr) {
+			rmp->rm_mag.rm_rptr = eptr;
 			bcopy(cptr, ptr, len);
 			BUMP_CPU_RND_STATS(rmp, rs_urndOut, len);
-			mutex_exit(&rmp->rm_lock);
+			mutex_exit(&rmp->rm_mag.rm_lock);
 
 			return (0);
 		}
 		/*
 		 * End fast path.
 		 */
-		rmp->rm_rptr = rmp->rm_buffer;
+		rmp->rm_mag.rm_rptr = rmp->rm_mag.rm_buffer;
 		/*
 		 * Note:  We assume the generate routine always succeeds
 		 * in this case (because it does at present..)
 		 * It also always releases rm_lock.
 		 */
-		(void) rnd_generate_pseudo_bytes(rmp, rmp->rm_buffer,
+		(void) rnd_generate_pseudo_bytes(rmp, rmp->rm_mag.rm_buffer,
 		    rndbuf_len);
 	}
 }
@@ -788,8 +803,9 @@
 static void
 rnd_alloc_magazines()
 {
-	rndmag_t *rmp;
+	rndmag_pad_t *rmp;
 	int i;
+	uint8_t discard_buf[HASHSIZE];
 
 	rndbuf_len = roundup(rndbuf_len, HASHSIZE);
 	if (rndmag_size < rndbuf_len)
@@ -800,20 +816,40 @@
 	rndmag_total = rndmag_size * random_max_ncpus;
 
 	rndbuf = kmem_alloc(rndmag_total, KM_SLEEP);
-	rndmag = kmem_zalloc(sizeof (rndmag_t) * random_max_ncpus, KM_SLEEP);
+	rndmag = kmem_zalloc(sizeof (rndmag_pad_t) * random_max_ncpus,
+	    KM_SLEEP);
 
 	for (i = 0; i < random_max_ncpus; i++) {
 		uint8_t *buf;
 
 		rmp = &rndmag[i];
-		mutex_init(&rmp->rm_lock, NULL, MUTEX_DRIVER, NULL);
+		mutex_init(&rmp->rm_mag.rm_lock, NULL, MUTEX_DRIVER, NULL);
 
 		buf = rndbuf + i * rndmag_size;
 
-		rmp->rm_buffer = buf;
-		rmp->rm_eptr = buf + rndbuf_len;
-		rmp->rm_rptr = buf + rndbuf_len;
-		rmp->rm_oblocks = 1;
+		rmp->rm_mag.rm_buffer = buf;
+		rmp->rm_mag.rm_eptr = buf + rndbuf_len;
+		rmp->rm_mag.rm_rptr = buf + rndbuf_len;
+		rmp->rm_mag.rm_oblocks = 1;
+
+		mutex_enter(&rndpool_lock);
+		/*
+		 * FIPS 140-2: the first n-bit (n > 15) block generated
+		 * after power-up, initialization, or reset shall not
+		 * be used, but shall be saved for comparison.
+		 */
+		(void) rnd_get_bytes(discard_buf,
+		    HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE);
+		bcopy(discard_buf, rmp->rm_mag.rm_previous,
+		    HMAC_KEYSIZE);
+		/* rnd_get_bytes() will call mutex_exit(&rndpool_lock) */
+		mutex_enter(&rndpool_lock);
+		(void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key,
+		    HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE);
+		/* rnd_get_bytes() will call mutex_exit(&rndpool_lock) */
+		mutex_enter(&rndpool_lock);
+		(void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_seed,
+		    HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE);
 	}
 }
 
@@ -905,71 +941,6 @@
 	kcf_rnd_schedule_timeout(B_FALSE);
 }
 
-/* Hashing functions */
-
-static void
-hmac_key(uint8_t *key, size_t keylen, void *buf)
-{
-	uint32_t *ip, *op;
-	uint32_t ipad[HMAC_BLOCK_SIZE/sizeof (uint32_t)];
-	uint32_t opad[HMAC_BLOCK_SIZE/sizeof (uint32_t)];
-	HASH_CTX *icontext, *ocontext;
-	int i;
-	int nints;
-
-	icontext = buf;
-	ocontext = (SHA1_CTX *)((uint8_t *)buf + sizeof (HASH_CTX));
-
-	bzero((uchar_t *)ipad, HMAC_BLOCK_SIZE);
-	bzero((uchar_t *)opad, HMAC_BLOCK_SIZE);
-	bcopy(key, (uchar_t *)ipad, keylen);
-	bcopy(key, (uchar_t *)opad, keylen);
-
-	/*
-	 * XOR key with ipad (0x36) and opad (0x5c) as defined
-	 * in RFC 2104.
-	 */
-	ip = ipad;
-	op = opad;
-	nints = HMAC_BLOCK_SIZE/sizeof (uint32_t);
-
-	for (i = 0; i < nints; i++) {
-		ip[i] ^= 0x36363636;
-		op[i] ^= 0x5c5c5c5c;
-	}
-
-	/* Perform hash with ipad */
-	HashInit(icontext);
-	HashUpdate(icontext, (uchar_t *)ipad, HMAC_BLOCK_SIZE);
-
-	/* Perform hash with opad */
-	HashInit(ocontext);
-	HashUpdate(ocontext, (uchar_t *)opad, HMAC_BLOCK_SIZE);
-}
-
-static void
-hmac_encr(void *ctx, uint8_t *ptr, size_t len, uint8_t *digest)
-{
-	HASH_CTX *saved_contexts;
-	HASH_CTX icontext;
-	HASH_CTX ocontext;
-
-	saved_contexts = (HASH_CTX *)ctx;
-	icontext = saved_contexts[0];
-	ocontext = saved_contexts[1];
-
-	HashUpdate(&icontext, ptr, len);
-	HashFinal(digest, &icontext);
-
-	/*
-	 * Perform Hash(K XOR OPAD, DIGEST), where DIGEST is the
-	 * Hash(K XOR IPAD, DATA).
-	 */
-	HashUpdate(&ocontext, digest, HASHSIZE);
-	HashFinal(digest, &ocontext);
-}
-
-
 static void
 rndc_addbytes(uint8_t *ptr, size_t len)
 {
--- a/usr/src/uts/common/crypto/io/swrand.c	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/common/crypto/io/swrand.c	Thu Nov 06 16:52:01 2008 -0800
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Software based random number provider for the Kernel Cryptographic
  * Framework (KCF). This provider periodically collects unpredictable input
@@ -56,6 +54,7 @@
 #include <sys/sunddi.h>
 #include <sys/modctl.h>
 #include <sys/hold_page.h>
+#include <rng/fips_random.h>
 
 #define	RNDPOOLSIZE		1024	/* Pool size in bytes */
 #define	HASHBUFSIZE		64	/* Buffer size used for pool mixing */
@@ -95,7 +94,9 @@
 static int bstart, bindex;		/* Global vars for adding/extracting */
 					/* from the buffer */
 static uint8_t leftover[HASHSIZE];	/* leftover output */
+static uint32_t	swrand_XKEY[6];		/* one extra word for getentropy */
 static int leftover_bytes;		/* leftover length */
+static uint32_t previous_bytes[SHA1WORDS];	/* previous random bytes */
 
 static physmem_entsrc_t entsrc;		/* Physical mem as an entropy source */
 static timeout_id_t rnd_timeout_id;
@@ -253,6 +254,8 @@
 	mutex_enter(&srndpool_lock);
 	swrand_schedule_timeout();
 	mutex_exit(&srndpool_lock);
+	(void) swrand_get_entropy((uint8_t *)swrand_XKEY, HASHSIZE, B_TRUE);
+	bcopy(swrand_XKEY, previous_bytes, HASHSIZE);
 
 	return (0);
 }
@@ -303,7 +306,6 @@
 	return (CRYPTO_SUCCESS);
 }
 
-
 /*
  * Extraction of entropy from the pool.
  *
@@ -318,6 +320,8 @@
 	int i, bytes;
 	HASH_CTX hashctx;
 	uint8_t digest[HASHSIZE], *pool;
+	uint32_t tempout[SHA1WORDS];
+	int size;
 
 	mutex_enter(&srndpool_lock);
 	if (leftover_bytes > 0) {
@@ -379,25 +383,45 @@
 			pindex &= (RNDPOOLSIZE - 1);
 		}
 
-		/*
-		 * Hash the digest again before output to obscure
-		 * what was fed back to the pool.
-		 */
-		HashInit(&hashctx);
-		HashUpdate(&hashctx, digest, HASHSIZE);
-		if (len >= HASHSIZE)
-			HashFinal(ptr, &hashctx);
-		else {
-			HashFinal(digest, &hashctx);
-			bcopy(digest, ptr, bytes);
-			leftover_bytes = HASHSIZE - bytes;
-			bcopy(digest + bytes, leftover, leftover_bytes);
+		/* LINTED E_BAD_PTR_CAST_ALIGN */
+		fips_random_inner(swrand_XKEY, tempout, (uint32_t *)digest);
+
+		if (len >= HASHSIZE) {
+			size = HASHSIZE;
+		} else {
+			size = min(bytes, HASHSIZE);
 		}
 
-		len -= bytes;
-		ptr += bytes;
-		BUMP_SWRAND_STATS(ss_bytesOut, bytes);
+		/*
+		 * FIPS 140-2: Continuous RNG test - each generation
+		 * of an n-bit block shall be compared with the previously
+		 * generated block. Test shall fail if any two compared
+		 * n-bit blocks are equal.
+		 */
+		for (i = 0; i < size/BYTES_IN_WORD; i++) {
+			if (tempout[i] != previous_bytes[i])
+				break;
+		}
+		if (i == size/BYTES_IN_WORD)
+			cmn_err(CE_WARN, "swrand: The value of 160-bit block "
+			    "random bytes are same as the previous one.\n");
+
+		bcopy(tempout, previous_bytes, HASHSIZE);
+
+		bcopy(tempout, ptr, size);
+		if (len < HASHSIZE) {
+			leftover_bytes = HASHSIZE - bytes;
+			bcopy(tempout + bytes, leftover, leftover_bytes);
+		}
+
+		ptr += size;
+		len -= size;
+		BUMP_SWRAND_STATS(ss_bytesOut, size);
 	}
+
+	/* Zero out sensitive information */
+	bzero(digest, HASHSIZE);
+	bzero(tempout, HASHSIZE);
 	mutex_exit(&srndpool_lock);
 	return (0);
 }
--- a/usr/src/uts/common/sys/random.h	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/common/sys/random.h	Thu Nov 06 16:52:01 2008 -0800
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_RANDOM_H
 #define	_SYS_RANDOM_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/atomic.h>
 
@@ -54,7 +52,7 @@
 
 #ifdef	_KERNEL
 
-#define	BUMP_CPU_RND_STATS(rm, x, v)    (((rm)->rm_stats).x += (v))
+#define	BUMP_CPU_RND_STATS(rm, x, v)    (((rm)->rm_mag.rm_stats).x += (v))
 #define	BUMP_RND_STATS(x, v)	atomic_add_64(&(rnd_stats).x, (v))
 #define	BUMP_SWRAND_STATS(x, v)	atomic_add_64(&(swrand_stats).x, (v))
 
--- a/usr/src/uts/intel/swrand/Makefile	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/intel/swrand/Makefile	Thu Nov 06 16:52:01 2008 -0800
@@ -19,10 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 #
 #	This makefile drives the production of the swrand KEF provider.
 #
@@ -33,6 +32,7 @@
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
 #
 UTSBASE	= ../..
+COM_DIR = $(COMMONBASE)/crypto
 
 #
 #	Define the module and object file sets.
@@ -58,7 +58,8 @@
 #
 # lint pass one enforcement
 #
-CFLAGS		+= $(CCVERBOSE)
+CFLAGS		+= $(CCVERBOSE) -I$(COM_DIR)
+LINTFLAGS	+= -I$(COM_DIR)
 
 #
 # Linkage dependencies
--- a/usr/src/uts/sparc/swrand/Makefile	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/sparc/swrand/Makefile	Thu Nov 06 16:52:01 2008 -0800
@@ -19,10 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 #
 #	This makefile drives the production of the swrand KEF provider.
 #
@@ -33,6 +32,7 @@
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
 #
 UTSBASE	= ../..
+COM_DIR = $(COMMONBASE)/crypto
 
 #
 #	Define the module and object file sets.
@@ -57,7 +57,8 @@
 #
 # lint pass one enforcement
 #
-CFLAGS		+= $(CCVERBOSE)
+CFLAGS		+= $(CCVERBOSE) -I$(COM_DIR)
+LINTFLAGS	+= -I$(COM_DIR)
 
 #
 # Linkage dependencies
--- a/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c	Thu Nov 06 16:52:01 2008 -0800
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/sysmacros.h>
 #include <sys/modctl.h>
@@ -45,14 +43,10 @@
 #include <sys/sha1.h>
 #include <sys/ddi.h>  /* near end to get min and max macros right */
 #include <sys/sunddi.h>
+#include <rng/fips_random.h>
 
 /* n must be a power of 2 */
 #define	ROUNDUP(k, n)		(((k) + (n) - 1) & ~((n) - 1))
-#define	SHA1BLOCKBITS		512
-#define	SHA1BLOCKBYTES		(SHA1BLOCKBITS / 8)
-#define	SHA1WORDS		5
-#define	SHA1BYTES		(4 * SHA1WORDS)
-
 
 /*
  * Policy.  ENTROPY_STARVATION is the maximum number of calls each
@@ -68,119 +62,6 @@
  */
 #define	ENTROPY_STARVATION	10000ULL
 
-/*
- * Adds val1 and val2 and stores result into sum.  The various input
- * pointers can be exactly aliased.  (They cannot be offset and
- * overlapping, but no one would ever do that.)  Values are big endian
- * by words and native byte order within words.  The return value's
- * 2-bit is 0 if the result is zero, it's 1 bit is carry out.  (This
- * is reused code.  The return code is not used by n2rng.)  Thus,
- * calling with both carryin and complement_val2 ones does a
- * subtraction.  A null sum pointer parameter is allowed.  The
- * subtraction features were required when this code was orginally
- * written so it could do a mod q operation.
- */
-static int
-add160(uint32_t *sum, uint32_t const *val1, uint32_t const *val2,
-    const unsigned carryin, const int complement_val2)
-{
-	int i;
-	uint32_t partialsum;
-	uint32_t carry = (carryin > 0);
-	uint32_t non_zero = 0;
-
-	for (i = 4; i >= 0; --i) {
-		partialsum = val1[i] + (complement_val2 ? ~val2[i] : val2[i]) +
-		    carry;
-		if (carry) {
-			carry = (partialsum <= val1[i]);
-		} else {
-			carry = (partialsum < val1[i]);
-		}
-		if (sum) {
-			sum[i] = partialsum;
-		}
-		non_zero |= partialsum;
-	}
-
-	return (((non_zero != 0) * 2) | carry);
-}
-
-
-
-/*
- * Computes a new random value, which is stored in x_j; updates XKEY
- * in the *rs.  XSEED_j is additional input.  In principle, we should
- * protect XKEY, perhaps by putting it on a non-pagable page, but we
- * aways clobber XKEY with fresh entropy just before we use it.  And
- * step 3d irreversibly updates it just after we use it.  The only
- * risk is that if an attacker captured the state while the entropy
- * generator was broken, the attacker could predict future values.
- * There are two cases: 1.  The attack gets root access to a live
- * system.  But there is no defense against that.  2.  The attacker
- * gets access to a crash dump.  But by then no values are being
- * generated.
- *
- * Note that XSEEDj is overwritten with sensitive stuff, and must be
- * zeroed by the caller.  We use two separate symbols (XVAL and
- * XSEEDj) to make each step match the notation in FIPS 186-2.
- */
-static void
-fips_random_inner(fipsrandomstruct_t *frsp, uint32_t *x_j,
-    uint32_t *XSEED_j)
-{
-	int		i;
-	SHA1_CTX	sha1_context;
-	/* Alias to preserve terminology from FIPS 186-2 */
-#define	XVAL XSEED_j
-	/*
-	 * K&R section A8.7: If the array has fixed size, the number
-	 * of initializers may not exceed the number of members in the
-	 * array; if there are fewer, the trailing members are
-	 * initialized with 0.
-	 */
-	static const char	zero[SHA1BLOCKBYTES - SHA1BYTES] = {0};
-
-	/*
-	 * Step 3b: XVAL = (XKEY + XSEED_sub_j) mod 2^b.  The mod is
-	 * implicit in the 160 bit representation.  Note that XVAL and
-	 * XSEED_j are actually the same location.
-	 */
-	(void) add160(XVAL, frsp->XKEY, XSEED_j, 0, 0);
-	/*
-	 * Step 3c: x_sub_j = G(t, XVAL)
-	 */
-	SHA1Init(&sha1_context);
-	SHA1Update(&sha1_context, (unsigned char *)XVAL, SHA1BYTES);
-	/*
-	 * Filling to 64 bytes is requried by FIPS 186-2 Appendix 3.3.
-	 * It also triggers SHA1Transform (the steps a-e of the spec).
-	 *
-	 * zero is a const char[], but SHA1update does not declare its
-	 * second parameter const, even though it does not modify it,
-	 * so we cast to suppress a compiler warning.
-	 */
-	SHA1Update(&sha1_context, (unsigned char *)zero,
-	    SHA1BLOCKBYTES - SHA1BYTES);
-	/*
-	 * The code below directly accesses the state field of
-	 * sha1_context, which is of type SHA1_CTX, defined in sha1.h.
-	 * This has been deemed acceptable, because that typedef is
-	 * Consolidation Private, and n2rng is in the same
-	 * consolidation.
-	 */
-	/* copy out to x_j */
-	for (i = 0; i < 5; i++) {
-		x_j[i] = sha1_context.state[i];
-	}
-	/*
-	 * Step 3d: XKEY = (1 + XKEY + x_sub_j) mod 2^b.  b=160.  The
-	 * mod 2^160 is implicit in the 160 bit representation.  The
-	 * one is added via the carry-in flag.
-	 */
-	(void) add160(frsp->XKEY, frsp->XKEY, x_j, 1, 0);
-#undef XVAL
-}
 
 int
 fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes)
@@ -259,7 +140,7 @@
 		}
 
 		/* nbytes - i is bytes to go */
-		fips_random_inner(frsp, tempout, entropy.as32);
+		fips_random_inner(frsp->XKEY, tempout, entropy.as32);
 		bcopy(tempout, &out[i], min(nbytes - i,  SHA1BYTES));
 
 		mutex_exit(&frsp->mtx);
--- a/usr/src/uts/sun4v/n2rng/Makefile	Thu Nov 06 15:40:19 2008 -0800
+++ b/usr/src/uts/sun4v/n2rng/Makefile	Thu Nov 06 16:52:01 2008 -0800
@@ -20,11 +20,10 @@
 #
 # uts/sun4v/n2rng/Makefile
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 #
 #	This makefile drives the production of the n2rng driver kernel module.
 #
@@ -35,6 +34,7 @@
 #	Path to the base of the uts directory tree (usually /usr/src/uts).
 #
 UTSBASE = ../..
+COM_DIR   = $(COMMONBASE)/crypto
 
 #
 #	Define the module and object file sets.
@@ -67,8 +67,13 @@
 #
 # lint pass one enforcement
 #
-CFLAGS += -v -DN2
-LINTFLAGS += -DN2
+CFLAGS += -v -DN2 -I$(COM_DIR)
+LINTFLAGS += -DN2 -I$(COM_DIR)
+
+#
+# module dependencies
+#
+LDFLAGS += -dy -Nmisc/kcf
 
 #
 #	Default build targets.