The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/libkern/arc4random.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: arc4random.c,v 1.11.2.1 2004/09/11 10:40:10 he Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Thor Lancelot Simon.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*-
   40  * THE BEER-WARE LICENSE
   41  *
   42  * <dan@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
   43  * can do whatever you want with this stuff.  If we meet some day, and you
   44  * think this stuff is worth it, you can buy me a beer in return.
   45  *
   46  * Dan Moschuk
   47  *
   48  * $FreeBSD: src/sys/libkern/arc4random.c,v 1.9 2001/08/30 12:30:58 bde Exp $
   49  */
   50 
   51 #ifdef _KERNEL
   52 #include "rnd.h"
   53 #else
   54 #define NRND 0
   55 #endif
   56 
   57 #include <sys/types.h>
   58 #include <sys/time.h>
   59 #include <sys/param.h>
   60 #ifdef _KERNEL
   61 #include <sys/kernel.h>
   62 #endif
   63 #include <sys/systm.h>
   64 
   65 #include <lib/libkern/libkern.h>
   66 
   67 #if NRND > 0
   68 #include <sys/rnd.h>
   69 #endif
   70 
   71 #define ARC4_MAXRUNS 16384
   72 #define ARC4_RESEED_SECONDS 300
   73 #define ARC4_KEYBYTES 32 /* 256 bit key */
   74 
   75 static u_int8_t arc4_i, arc4_j;
   76 static int arc4_initialized = 0;
   77 static int arc4_numruns = 0;
   78 static u_int8_t arc4_sbox[256];
   79 static struct timeval arc4_tv_nextreseed;
   80 #ifndef _KERNEL
   81 extern struct timeval mono_time;
   82 #endif
   83 
   84 static inline u_int8_t arc4_randbyte(void);
   85 
   86 static __inline void
   87 arc4_swap(u_int8_t *a, u_int8_t *b)
   88 {
   89         u_int8_t c;
   90 
   91         c = *a;
   92         *a = *b;
   93         *b = c;
   94 }       
   95 
   96 /*
   97  * Stir our S-box.
   98  */
   99 static void
  100 arc4_randrekey(void)
  101 {
  102         u_int8_t key[256];
  103         static int cur_keybytes;
  104         int n, byteswanted;
  105 #if NRND > 0
  106         int r;
  107 #endif
  108 
  109         if(!arc4_initialized)
  110                 /* The first time through, we must take what we can get */
  111                 byteswanted = 0;
  112         else
  113                 /* Don't rekey with less entropy than we already have */
  114                 byteswanted = cur_keybytes;
  115 
  116 #if NRND > 0    /* XXX without rnd, we will key from the stack, ouch! */
  117         r = rnd_extract_data(key, ARC4_KEYBYTES, RND_EXTRACT_GOOD);
  118 
  119         if (r < ARC4_KEYBYTES) {
  120                 if (r >= byteswanted) {
  121                         (void)rnd_extract_data(key + r,
  122                                                ARC4_KEYBYTES - r,
  123                                                RND_EXTRACT_ANY);
  124                 } else {
  125                         /* don't replace a good key with a bad one! */
  126                         arc4_tv_nextreseed = mono_time;
  127                         arc4_tv_nextreseed.tv_sec += ARC4_RESEED_SECONDS;
  128                         arc4_numruns = 0;
  129                         /* we should just ask rnd(4) to rekey us when
  130                            it can, but for now, we'll just try later. */
  131                         return;
  132                 }
  133         }
  134 
  135         cur_keybytes = r;
  136 
  137         for (n = ARC4_KEYBYTES; n < sizeof(key); n++)
  138                         key[n] = key[n % ARC4_KEYBYTES];
  139 #endif
  140         for (n = 0; n < 256; n++) {
  141                 arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256;
  142                 arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]);
  143         }
  144 
  145         /* Reset for next reseed cycle. */
  146         arc4_tv_nextreseed = mono_time;
  147         arc4_tv_nextreseed.tv_sec += ARC4_RESEED_SECONDS;
  148         arc4_numruns = 0;
  149 
  150         /*
  151          * Throw away the first N words of output, as suggested in the
  152          * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
  153          * by Fluher, Mantin, and Shamir.  (N = 256 in our case.)
  154          */
  155         for (n = 0; n < 256 * 4; n++)
  156                 arc4_randbyte();
  157 }
  158 
  159 /*
  160  * Initialize our S-box to its beginning defaults.
  161  */
  162 static void
  163 arc4_init(void)
  164 {
  165         int n;
  166 
  167         arc4_i = arc4_j = 0;
  168         for (n = 0; n < 256; n++)
  169                 arc4_sbox[n] = (u_int8_t) n;
  170 
  171         arc4_randrekey();
  172         arc4_initialized = 1;
  173 }
  174 
  175 /*
  176  * Generate a random byte.
  177  */
  178 static __inline u_int8_t
  179 arc4_randbyte(void)
  180 {
  181         u_int8_t arc4_t;
  182 
  183         arc4_i = (arc4_i + 1) % 256;
  184         arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256;
  185 
  186         arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]);
  187 
  188         arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256;
  189         return arc4_sbox[arc4_t];
  190 }
  191 
  192 u_int32_t
  193 arc4random(void)
  194 {
  195         u_int32_t ret;
  196         int i;
  197 
  198         /* Initialize array if needed. */
  199         if (!arc4_initialized)
  200                 arc4_init();
  201 
  202         if ((++arc4_numruns > ARC4_MAXRUNS) || 
  203             (mono_time.tv_sec > arc4_tv_nextreseed.tv_sec)) {
  204                 arc4_randrekey();
  205         }
  206 
  207         for (i = 0, ret = 0; i <= 24; ret |= arc4_randbyte() << i, i += 8)
  208                 ;
  209         return ret;
  210 }
  211 
  212 void
  213 arc4randbytes(void *p, size_t len)
  214 {
  215         u_int8_t *buf;
  216         size_t i;
  217 
  218         buf = (u_int8_t *)p;
  219 
  220         for (i = 0; i < len; buf[i] = arc4_randbyte(), i++);
  221                 arc4_numruns += len / sizeof(u_int32_t);
  222         if ((arc4_numruns > ARC4_MAXRUNS) ||
  223             (mono_time.tv_sec > arc4_tv_nextreseed.tv_sec)) {
  224                 arc4_randrekey();
  225         }
  226 }

Cache object: acb082565b82933beb6cc9c2f056b28b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.