xref: /illumos-gate/usr/src/common/crypto/rng/fips_random.c (revision 6cefaae1e90a413ba01560575bb3998e1a3df40e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <rng/fips_random.h>
28 #include <sys/sha1.h>
29 
30 /*
31  * Adds val1 and val2 and stores result into sum.  The various input
32  * pointers can be exactly aliased.  (They cannot be offset and
33  * overlapping, but no one would ever do that.)  Values are big endian
34  * by words and native byte order within words.  The return value's
35  * 2-bit is 0 if the result is zero, it's 1 bit is carry out.  (This
36  * is reused code.  The return code is not used by n2rng.)  Thus,
37  * calling with both carryin and complement_val2 ones does a
38  * subtraction.  A null sum pointer parameter is allowed.  The
39  * subtraction features were required when this code was orginally
40  * written so it could do a mod q operation.
41  */
42 static int
43 fips_add160(uint32_t *sum, uint32_t const *val1, uint32_t const *val2,
44     const unsigned carryin, const int complement_val2)
45 {
46 	int i;
47 	uint32_t partialsum;
48 	uint32_t carry = (carryin > 0);
49 	uint32_t non_zero = 0;
50 
51 	for (i = 4; i >= 0; --i) {
52 		partialsum = val1[i] + (complement_val2 ? ~val2[i] : val2[i]) +
53 		    carry;
54 		if (carry) {
55 			carry = (partialsum <= val1[i]);
56 		} else {
57 			carry = (partialsum < val1[i]);
58 		}
59 		if (sum) {
60 			sum[i] = partialsum;
61 		}
62 		non_zero |= partialsum;
63 	}
64 
65 	return (((non_zero != 0) * 2) | carry);
66 }
67 
68 /*
69  * Computes a new random value, which is stored in x_j; updates
70  * XKEY.  XSEED_j is additional input.  In principle, we should
71  * protect XKEY, perhaps by putting it on a non-pagable page, but we
72  * aways clobber XKEY with fresh entropy just before we use it.  And
73  * step 3d irreversibly updates it just after we use it.  The only
74  * risk is that if an attacker captured the state while the entropy
75  * generator was broken, the attacker could predict future values.
76  * There are two cases: 1.  The attack gets root access to a live
77  * system.  But there is no defense against that.  2.  The attacker
78  * gets access to a crash dump.  But by then no values are being
79  * generated.
80  *
81  * Note that XSEEDj is overwritten with sensitive stuff, and must be
82  * zeroed by the caller.  We use two separate symbols (XVAL and
83  * XSEEDj) to make each step match the notation in FIPS 186-2.
84  */
85 void
86 fips_random_inner(uint32_t *key, uint32_t *x_j,
87     uint32_t *XSEED_j)
88 {
89 	int		i;
90 	SHA1_CTX	sha1_context;
91 	/* Alias to preserve terminology from FIPS 186-2 */
92 #define	XVAL XSEED_j
93 	/*
94 	 * K&R section A8.7: If the array has fixed size, the number
95 	 * of initializers may not exceed the number of members in the
96 	 * array; if there are fewer, the trailing members are
97 	 * initialized with 0.
98 	 */
99 	static const char	zero[SHA1BLOCKBYTES - SHA1BYTES] = {0};
100 
101 	/*
102 	 * Step 3b: XVAL = (XKEY + XSEED_sub_j) mod 2^b.  The mod is
103 	 * implicit in the 160 bit representation.  Note that XVAL and
104 	 * XSEED_j are actually the same location.
105 	 */
106 	(void) fips_add160(XVAL, key, XSEED_j, 0, 0);
107 	/*
108 	 * Step 3c: x_sub_j = G(t, XVAL).
109 	 */
110 	SHA1Init(&sha1_context);
111 	SHA1Update(&sha1_context, (unsigned char *)XVAL, SHA1BYTES);
112 	/*
113 	 * Filling to 64 bytes is requried by FIPS 186-2 Appendix 3.3.
114 	 * It also triggers SHA1Transform (the steps a-e of the spec).
115 	 *
116 	 * zero is a const char[], but SHA1update does not declare its
117 	 * second parameter const, even though it does not modify it,
118 	 * so we cast to suppress a compiler warning.
119 	 */
120 	SHA1Update(&sha1_context, (unsigned char *)zero,
121 	    SHA1BLOCKBYTES - SHA1BYTES);
122 	/*
123 	 * The code below directly accesses the state field of
124 	 * sha1_context, which is of type SHA1_CTX, defined in sha1.h.
125 	 */
126 	/* copy out to x_j */
127 	for (i = 0; i < 5; i++) {
128 		x_j[i] = sha1_context.state[i];
129 	}
130 	/*
131 	 * Step 3d: XKEY = (1 + XKEY + x_sub_j) mod 2^b.  b=160.  The
132 	 * mod 2^160 is implicit in the 160 bit representation.  The
133 	 * one is added via the carry-in flag.
134 	 */
135 	(void) fips_add160(key, key, x_j, 1, 0);
136 #undef XVAL
137 }
138