Praveen> Lutz thanks . Your guess is right. I tried with error option
 Praveen> and I got this printed.

 Praveen> "RSA key error: PRNG not seeded"

You must modify rand_win32.c or whatever you are using to seed the
PRNG.  This is found at the end of the file.  I have written a
"DEV_RANDOM" for vxWorks.  It is attached.  I would appreciate it if
anyone with mathematical skills could look at the function `bitShaker'
and my simple RNG for default data [providing it is interesting ;-].
I tried to follow some FreeBSD entropy code.  I also hope that the bit
time accumulation that I have done with the driver is `random enough'.

vxWorks has a driver model that is much like `simple Unix'.  The
functions open, close, write, read and ioctl are returned from a
create function.  For this driver, the data sent to the `write'
function doesn't matter.  It just accumulates a time delta since the
last call.  It attempt to determine the number of bits difference
between the calls and adds these bits to the entropy data.  This data
is then shuffled with the `bitShaker' function.  The entropy data is
stored to a file occasionally (DEV_RANDOM_DEFAULT).  This file is read
when the driver initializes.  If the file is empty a simple RNG with
primes and seeds are used.  A device can also be distributed with
different DEV_RANDOM_DEFAULT upon distribution.

I am not 100% sure that the buffer sizes that I have chosen provide
enough data to seed SSL.  It is currently 1k of data.  I believe that
this was the same amount that was provided by the support code that
generated a random file.

For use with openSSL, a driver that receives user input or some other
source of random time events, writes to the device.  The RAND_poll()
function then just reads this device.  In my device, I have made calls
in a keyboard and touch screen driver.

If anyone else uses this driver, I would appreciate *INFORMED* feed
back on errors in it's operation.

Regards,
Bill Pringlemeir.

[modified rand_win32.c to rand_vx.c]

#include <random.h>
#define DEVRANDOM DEV_RANDOM

int RAND_poll(void)
{
    FILE *fh;

    /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD
     * have this. Use /dev/urandom if you can as /dev/random may block
     * if it runs out of random entries.  */

    if ((fh = fopen(DEVRANDOM, "r")) != NULL)
    {
        unsigned char tmpbuf[ENTROPY_NEEDED];
        int n;
                
        setvbuf(fh, NULL, _IONBF, 0);
        n=fread((unsigned char *)tmpbuf,1,ENTROPY_NEEDED,fh);
        fclose(fh);
        RAND_add(tmpbuf,sizeof tmpbuf,n);
        memset(tmpbuf,0,n);
    }

    return 1;
}

[end modified rand_win32.c to rand_vx.c]

[start random.h]
#ifndef __RANDOM_H__
#define __RANDOM_H__

/* Size of the random buffer size (power of two). */
#define RANDOM_SIZE 256

/* The entropy acumulated size. */
typedef u_long ENTROPY;
#define EBITS (sizeof(ENTROPY)*8)

/* Name of the Random file. */
#define DEV_RANDOM "/random"

/* Random seed file. */
#define DEV_RANDOM_DEFAULT "/SSL/Client.rnd"

/* Ioctl options */
#define RANDOM_SET_DATA          (15007)
#define RANDOM_GET_DATA          (15008)
#define RANDOM_GET_OUT           (15009)

#ifdef __cplusplus
extern "C" {
#endif

    /* Prototypes. */
    int randomDevCreate(char *name);

#ifdef __cplusplus
}
#endif /*__cplusplus */
    

#endif /*__RANDOM_H__ */
[end random.h]

[start random.c]
/*
modification history
--------------------
01a,08feb01,wjp  Created
*/

/* 
 * DESCRIPTION: This module gets time values when some unpredictable
 * event happens, for instance keyboard or touch screen presses.  The
 * time is used by the SSL library to generate random keys.  It is up
 * to the unpredictable data sources to open this file and write bytes
 * when the data is received.
 *
 * The data is hashed/shaken to spread any non-random data that might
 * be received from these sources.
 *
 */

/* Includes */
#include <vxWorks.h>
#include <config.h>
#include <ioLib.h>
#include <iosLib.h>
#include <errnoLib.h>
#include <selectLib.h>
#include <string.h>
#include <intLib.h>
#include <tickLib.h>
#include <assert.h>
#include <tickLib.h>

#include "random.h"

#define RAND_DEBUG(x, args...)
#ifndef RAND_DEBUG
#include <logLib.h>

#define RAND_DEBUG ptr_rand_debug
void rand_debug(char * fmt, int a, int b, int c, int d, int e, int f)
{
    logMsg(fmt,a,b,c,d,e,f);
}
void (*ptr_rand_debug)() = (void(*)())rand_debug;

#undef LOCAL
#define LOCAL

#endif

/* Forward declarations */
typedef struct
{
    DEV_HDR         devHdr;                /* device super class. */
    size_t          in;                    /* incoming randomness. */
    size_t          out;                   /* outgoing randomness for reads. */
    size_t          bit;                   /* bits of incoming randomness. */
    int             clean;                 /* Wrote out new file? */
    ENTROPY         shaker[4];             /* mixes the random data. */
    ENTROPY         random[RANDOM_SIZE];   /* random data. */
    SEM_ID          read_sem;              /* single read at a time. */
    SEM_ID          write_sem;             /* single write at a time. */
    SEL_WAKEUP_LIST selWakeupList;         /* for select() mechanism. */
} RANDOM_DEVICE;

LOCAL int randomOpen (DEV_HDR* dev, char* name, int mode);
LOCAL int randomClose (DEV_HDR* dev);
LOCAL int randomWrite (DEV_HDR* dev, char* pBuf, unsigned int nBytes);
LOCAL int randomRead (DEV_HDR* dev, char* pBuf, unsigned int nBytes);
LOCAL STATUS randomIoctl (DEV_HDR* dev, int cmd, int arg);

/* locals */
LOCAL int randomDrvNum = 0;
LOCAL RANDOM_DEVICE randomDev;

/*****************************************************************************
*
* deviceIsPresent - check if the device is present
*
* This routine checks if the device <name> is installed.
*
* RETURNS: TRUE when device is present; otherwise FALSE
*
* name - Name of device   
* ppHdr - Place to return header
*
*/
LOCAL BOOL deviceIsPresent(char *name, DEV_HDR **ppHdr)
{
    DEV_HDR * pHdr;
    char *pName;

    pHdr = iosDevFind (name, &pName);
    if ((pHdr != NULL) && (strcmp (name, pHdr->name) == 0))
    {
        *ppHdr = pHdr;
        return TRUE;
    }
    return FALSE;
}

/*****************************************************************************
*
* randomDevCreate - Initialize the random device.
*
*/
int randomDevCreate(char *name)
{
    DEV_HDR * pHdr;
    int fd;

    RAND_DEBUG("randomDevCreate\n");

    /* if device is already present, do not create again */
    if (deviceIsPresent (name, &pHdr))
        return OK;

    if (randomDrvNum != 0)
        return ERROR;

    /* Gaurds read loop */
    randomDev.read_sem = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
    if(randomDev.read_sem == NULL)
        return ERROR;

    /* Gaurds write code */
    randomDev.write_sem = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
    if(randomDev.write_sem == NULL)
    {
        semDelete(randomDev.read_sem);
        return ERROR;
    }
        
    selWakeupListInit(&randomDev.selWakeupList);

    /* mark the driver as created, and add the device to the I/O system */
    randomDrvNum = iosDrvInstall((FUNCPTR) NULL, (FUNCPTR) NULL, 
                                      randomOpen, randomClose, 
                                      randomRead, randomWrite, 
                                      randomIoctl);
    if(randomDrvNum == ERROR)
    {
        errno = S_ioLib_NO_DRIVER;
        semDelete(randomDev.read_sem);
        semDelete(randomDev.write_sem);
        return ERROR;
    }

    if (iosDevAdd(&randomDev.devHdr, name, randomDrvNum) == ERROR)
    {
        iosDrvRemove(randomDrvNum, TRUE);
        randomDrvNum = ERROR;
        semDelete(randomDev.read_sem);
        semDelete(randomDev.write_sem);
        return ERROR;
    }

    /* Retrieve previously stored state. */
    fd = open(DEV_RANDOM_DEFAULT,O_RDONLY,0);
    if(fd > 0)
    {
        read(fd, (char*)randomDev.random, sizeof(randomDev.random));
        close(fd);
    }
    else /* congruential random number generator. */
    {
        unsigned int i;
        ENTROPY seed = 0x3a8694bUL;
        
        for(i = 0; i < NELEMENTS(randomDev.random); i++)
        {
            randomDev.random[i] = seed;
            seed = 104729 * seed + 68147;
        }
    }

    randomDev.in = RANDOM_SIZE/2;
    randomDev.clean = TRUE;
    
    return randomDrvNum;
}

/*****************************************************************************
*
* findBitsSet - calculate the highest bit set.
*
* RETURNS: 0x1f0-> 9, 0x7-> 3, 0x1->1, 0->1.
*/

LOCAL int findBitsSet(ENTROPY mask)
{
    int i;

    for(i = EBITS; i > 1; i--)
    {
        if(mask & 0x80000000UL)
            break;
        mask = mask << 1;
    }
    return i;
}

/*****************************************************************************
*
*  randomWrite 
*/
LOCAL int randomWrite(DEV_HDR* dev, char * pBuf, unsigned int nBytes)
{
    RANDOM_DEVICE *pRand = (RANDOM_DEVICE *)dev;
    static ENTROPY prev_tick;
    ENTROPY current_tick;
    ENTROPY diff;
    ENTROPY mask;
    ENTROPY new_data;
    size_t bits;

    RAND_DEBUG("randomWrite, %p, %d\n", pBuf, nBytes);

    current_tick = tickGet();
    diff = current_tick ^ prev_tick;
    bits = findBitsSet(diff);

    /* insert some new bits?. */
    mask = ((1<<bits) - 1);
    current_tick &= mask;

    /* Write semaphore to prevent duplicate reads. */
    semTake(pRand->write_sem, WAIT_FOREVER);

    new_data = pRand->random[pRand->in];
    new_data |= current_tick << pRand->bit;
    pRand->random[pRand->in] = new_data;

    /* new word? */
    if(bits + pRand->bit > EBITS)
    {
        /* don't overflow. */
        if((pRand->in+1) % RANDOM_SIZE != pRand->out)
        {
            pRand->in = (pRand->in + 1) % RANDOM_SIZE;
        }
        else if(pRand->clean)
        {
            int fd;
            fd = open(DEV_RANDOM_DEFAULT, O_WRONLY|O_CREAT, 0644);
            if(fd > 0)
            {
                write(fd, (char*)&pRand->random[RANDOM_SIZE/2],
                      sizeof(pRand->random)/2);
                write(fd, (char*)&pRand->random[0],
                      sizeof(pRand->random)/2);
                close(fd);
                pRand->clean = FALSE;
            }
        }
        current_tick = current_tick >> (EBITS - pRand->bit);
        pRand->random[pRand->in] = current_tick;
        pRand->bit = bits + pRand->bit - EBITS;
    }
    else
    {
        pRand->bit += bits;
    }

    semGive(pRand->write_sem);
    
    prev_tick = current_tick;
    
    return OK;
}

/* 
 *   Bit shaking function, four entropy elements are interleaved in a
 * fashion that preserves the number of ones and zeros.  It will
 * distribute runs Ie, errors in entropy gathering.  Similar
 * transform/hashing functions exist if a buffer larger than four is
 * needed.  The idea is that a buffer of all zeros or all ones will
 * not return a buffer of all zeros or all ones.  Similarily, runs of
 * ones or zeros will be distributed throughout.  It is still possible
 * for a value of all ones or zeros to be generated.  It is very
 * unlikely.  With four elements of 32 bits it is 1 in 2^(4*32).  The
 * values are XORd with constants to gaurd against all of zeroes or
 * ones.  This does not preserve the ones and zeros, but is just as
 * random.  The main point is that addition, subtraction, shifts etc
 * are not good operation for these functions.  f1,f2,... should not
 * use rotations in the macro.  Perserve bit positions in these
 * functions.
 */
#define f1(x,y,z) (((x) & (y)) | ((~x) & (z)))  /* x ? y : z */
#define f2(x,y,z) (((x) & (z)) | ((y) & (~z)))  /* z ? x : y */
#define f3(x,y,z) (x ^ y ^ z)                   /* XOR */
#define f4(x,y,z) ((x & y) | (x & z) | (y & z)) /* majority */

/* Constants used by SHA. */
#define K1  0x5A827999L         /* sqrt(2) * 2^30 */
#define K2  0x6ED9EBA1L         /* sqrt(3) * 2^30 */
#define K3  0x8F1BBCDCL         /* sqrt(5) * 2^30 */
#define K4  0xCA62C1D6L         /* sqrt(10) * 2^30 */

/* shifts relative prime to 32 are {1,3,7,11,13,15,17,19,25,29,31} */
extern __inline__ ENTROPY rotateRight(const int i, ENTROPY word)
{
    __asm__(" mov %0,%1,ROR %2"
        :"=r" (word)
        :"r" (word), "r" (i));
    return word;
}

LOCAL void bitShaker(RANDOM_DEVICE *pRand)
{

    ENTROPY *s = &pRand->random[pRand->out];
    ENTROPY *d = pRand->shaker;
    
    d[0] = K1; d[1] = K2; d[2] = K3; d[3] = K4;

    d[0] ^= f1(rotateRight(1,s[1]),rotateRight(17,s[0]),rotateRight(31,s[2]));
    d[1] ^= f2(rotateRight(3,s[2]),rotateRight(19,s[3]),rotateRight(29,s[1]));
    d[2] ^= f3(rotateRight(7,s[0]),rotateRight(11,s[2]),rotateRight(15,s[3]));
    d[3] ^= f4(rotateRight(1,s[3]),rotateRight(25,s[1]),rotateRight(13,s[0]));
}
#undef K1
#undef K2
#undef K3
#undef K4

#undef f1
#undef f2
#undef f3
#undef f4

/*****************************************************************************
*
*  randomRead - assumes that pBuf is aligned to ENTROPY size. 
*
*/
LOCAL int randomRead(DEV_HDR* dev, char* pBuf, unsigned int nBytes)
{
    RANDOM_DEVICE *pRand = (RANDOM_DEVICE *)dev;
    unsigned int i;
    ENTROPY *alias = (void *)pBuf;
 
    RAND_DEBUG("randomRead %p, %d\n", pBuf, nBytes);

    /* Read semaphore to prevent duplicate reads. */
    semTake(pRand->read_sem, WAIT_FOREVER);
   
    if(pRand->in == pRand->out)
    {
        semGive(pRand->read_sem);
        return 0;
    }

    /* Keep the shaker full. */
    /* Fixme, handle zero? */
    for(i = 0; i < nBytes/sizeof(ENTROPY); i++)
    {
        /* shake the bits. */
        if(!(pRand->out % NELEMENTS(pRand->shaker)))
        {
            bitShaker(pRand);
        }
            
        alias[i] = pRand->shaker[pRand->out % NELEMENTS(pRand->shaker)];
        pRand->out = (pRand->out + 1) % RANDOM_SIZE;
        if(pRand->in == pRand->out)
            break;
    }

    /* for any extra bytes of data. */
    if(nBytes % sizeof(ENTROPY))
    {
        char buffer[sizeof(ENTROPY)];

        /* shake the bits? */
        if(!(pRand->out % NELEMENTS(pRand->shaker)))
        {
            bitShaker(pRand);
        }

        /* take a word and possibly waste some bytes. */
        *((ENTROPY*)buffer) = pRand->shaker[pRand->out];
        pRand->out = (pRand->out + 1) % RANDOM_SIZE;
        if(pRand->in == pRand->out)
        {
            semGive(pRand->read_sem);
            return nBytes & ~(sizeof(ENTROPY) - 1);
        }

        /* one to three remaining bytes. */
        for(i = nBytes & ~(sizeof(ENTROPY)-1); i < nBytes; i++)
        {
            pBuf[i] = buffer[i];
        }
    }
        
    semGive(pRand->read_sem);

    return nBytes;
}

/*****************************************************************************
*
* randomIoctl - select support.  seeding support.
*/
LOCAL STATUS randomIoctl(DEV_HDR* dev, int cmd, int arg)
{
    RANDOM_DEVICE *pRand = (RANDOM_DEVICE *)dev;
    STATUS status = ERROR;
 
    RAND_DEBUG("randomIoctl %d, %x\n", cmd, arg);
   
    switch(cmd)
    {
        case FIOSELECT:
            if(selWakeupType((SEL_WAKEUP_NODE *) arg) == SELREAD)
            {
                selNodeAdd(&pRand->selWakeupList,
                           (SEL_WAKEUP_NODE *)arg);
                status = OK;
                break;
            }
            break;

        case FIOUNSELECT:
            if(selWakeupType((SEL_WAKEUP_NODE *) arg) == SELREAD)
            {
                selNodeDelete(&pRand->selWakeupList,
                              (SEL_WAKEUP_NODE *)arg);
                status = OK;
            }
            break;

        /* copy random `seed' data. */
        case RANDOM_SET_DATA:
            if(arg)
            {
                ENTROPY *p = (ENTROPY *) arg;

                /* Read semaphore to prevent duplicate reads. */
                semTake(pRand->read_sem, WAIT_FOREVER);

                memcpy(pRand->random, p, sizeof(pRand->random));
                pRand->out = 0;
                pRand->in = RANDOM_SIZE - 1;

                /* Release semaphore. */
                semGive(pRand->read_sem);

                status = OK;
            }
            break;

        /* Retreive random data (for restoration when rebooting). */
        case RANDOM_GET_DATA:
            if(arg)
            {
                ENTROPY *p = (ENTROPY *) arg;
                semTake(pRand->read_sem, WAIT_FOREVER);
                memcpy(p, pRand->random, sizeof(pRand->random));
                semGive(pRand->read_sem);
                status = OK;
            }
            break;

        /* In conjunction with RANDOM_GET_DATA, allows saving state. */
        case RANDOM_GET_OUT:
            if(arg)
            {
                size_t *outArg = (size_t *)arg;
                *outArg = pRand->out;
                status = OK;
            }
        default:
            break;
    }

    return status;
}

/******************************************************************************
*
* randomOpen - open file
*
* This routine opens the random device.
* 
* RETURNS device structure
*
*/
LOCAL int randomOpen(DEV_HDR *dev, char *name, int mode)
{
    return (int)dev;
}

/*****************************************************************************
*
* randomClose - close device
*
*  This routine closes the random device
*
*/
LOCAL int randomClose(DEV_HDR *dev)
{
    return (int)dev;
}
[end random.c]

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to