root/usr/src/common/crypto/rng/fips_random.c
/*
 * 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 <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);
}

#ifdef _LITTLE_ENDIAN
#define SWAP16(value)  \
        ((((value) & 0xff) << 8) | ((value) >> 8))

#define SWAP32(value)   \
        (((uint32_t)SWAP16((uint16_t)((value) & 0xffff)) << 16) | \
        (uint32_t)SWAP16((uint16_t)((value) >> 16)))

static void
xvalconv(uint32_t *dest, uint32_t *src, int len)
{
        int i;

        for (i = 0; i < len; i++) {
                dest [i] = SWAP32(src[i]);
        }
}
#endif /* _LITTLE_ENDIAN */

/*
 * 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)
{
        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 */

#ifdef _BIG_ENDIAN
        {
                int i;
                for (i = 0; i < 5; i++) {
                        x_j[i] = sha1_context.state[i];
                }
        }
#else
        xvalconv(x_j, sha1_context.state, SHA1BYTES/4);
#endif

        /*
         * 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
}