2011-05-19 16:31 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* src/rtl/Makefile
* src/rtl/hbrandom.c
+ src/rtl/hbrand.c
+ src/rtl/arc4.c
+ src/rtl/arc4.h
+ added C level arc4 API. adapted to Harbour by Tamas Tevesz,
original authors listed in sources
* moved HB_RAND32() function to separate source
* changed HB_RAND32() to use arc4 backend, which means it will
now return properly string random numbers
; arc4 code may need tweaks on some platforms (android f.e.),
pls test
This commit is contained in:
@@ -16,6 +16,20 @@
|
||||
The license applies to all entries newer than 2009-04-28.
|
||||
*/
|
||||
|
||||
2011-05-19 16:31 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
|
||||
* src/rtl/Makefile
|
||||
* src/rtl/hbrandom.c
|
||||
+ src/rtl/hbrand.c
|
||||
+ src/rtl/arc4.c
|
||||
+ src/rtl/arc4.h
|
||||
+ added C level arc4 API. adapted to Harbour by Tamas Tevesz,
|
||||
original authors listed in sources
|
||||
* moved HB_RAND32() function to separate source
|
||||
* changed HB_RAND32() to use arc4 backend, which means it will
|
||||
now return properly string random numbers
|
||||
; arc4 code may need tweaks on some platforms (android f.e.),
|
||||
pls test
|
||||
|
||||
2011-05-19 14:55 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
|
||||
* contrib/hbmzip/mzip.c
|
||||
* formatting
|
||||
|
||||
@@ -16,6 +16,7 @@ C_SOURCES := \
|
||||
abs.c \
|
||||
accept.c \
|
||||
ampm.c \
|
||||
arc4.c \
|
||||
at.c \
|
||||
ati.c \
|
||||
base64c.c \
|
||||
@@ -96,6 +97,7 @@ C_SOURCES := \
|
||||
hbntos.c \
|
||||
hbproces.c \
|
||||
hbprocfn.c \
|
||||
hbrand.c \
|
||||
hbrandom.c \
|
||||
hbregex.c \
|
||||
hbregexc.c \
|
||||
|
||||
656
harbour/src/rtl/arc4.c
Normal file
656
harbour/src/rtl/arc4.c
Normal file
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portable ARC4 PRNG, based on arc4random.c from Libevent.
|
||||
* Harbour adaptation Copyright 2011 Tamas TEVESZ <ice@extreme.hu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portable arc4random.c based on arc4random.c from OpenBSD.
|
||||
* Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
|
||||
* Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Arc4 random number generator for OpenBSD.
|
||||
*
|
||||
* This code is derived from section 17.1 of Applied Cryptography,
|
||||
* second edition, which describes a stream cipher allegedly
|
||||
* compatible with RSA Labs "RC4" cipher (the actual description of
|
||||
* which is a trade secret). The same algorithm is used as a stream
|
||||
* cipher called "arcfour" in Tatu Ylonen's ssh package.
|
||||
*
|
||||
* Here the stream cipher has been modified always to include the time
|
||||
* when initializing the state. That makes it impossible to
|
||||
* regenerate the same random sequence twice, so this can't be used
|
||||
* for encryption, but will generate good random numbers.
|
||||
*
|
||||
* RC4 is a registered trademark of RSA Laboratories.
|
||||
*/
|
||||
|
||||
#include "arc4.h"
|
||||
#include "hbdate.h"
|
||||
#include "hbthread.h"
|
||||
|
||||
|
||||
/* XXX: Check and possibly extend this to other Unix-like platforms */
|
||||
#if defined( HB_OS_BSD ) || defined( HB_OS_LINUX )
|
||||
# define HAVE_SYS_SYSCTL_H
|
||||
# define HAVE_DECL_CTL_KERN
|
||||
# define HAVE_DECL_KERN_RANDOM
|
||||
# if defined( HB_OS_LINUX )
|
||||
# define HAVE_DECL_RANDOM_UUID
|
||||
# else
|
||||
# define HAVE_DECL_KERN_ARND
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined( HB_OS_WIN )
|
||||
# include <wincrypt.h>
|
||||
# include <process.h>
|
||||
#else
|
||||
# include <sys/param.h>
|
||||
# include <sys/time.h>
|
||||
# ifdef HAVE_SYS_SYSCTL_H
|
||||
# include <sys/sysctl.h>
|
||||
# endif
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Add platform entropy 32 bytes (256 bits) at a time. */
|
||||
#define ADD_ENTROPY 32
|
||||
|
||||
/* Re-seed from the platform RNG after generating this many bytes. */
|
||||
#define BYTES_BEFORE_RESEED 1600000
|
||||
|
||||
struct arc4_stream
|
||||
{
|
||||
HB_U8 i;
|
||||
HB_U8 j;
|
||||
HB_U8 s[ 256 ];
|
||||
};
|
||||
|
||||
#if defined( HB_OS_WIN )
|
||||
# define getpid _getpid
|
||||
# define pid_t int
|
||||
#endif
|
||||
|
||||
static int rs_initialized;
|
||||
static struct arc4_stream rs;
|
||||
static pid_t arc4_stir_pid;
|
||||
static HB_I32 arc4_count;
|
||||
|
||||
static HB_CRITICAL_NEW( arc4_lock );
|
||||
#define _ARC4_LOCK() hb_threadEnterCriticalSection( &arc4_lock )
|
||||
#define _ARC4_UNLOCK() hb_threadLeaveCriticalSection( &arc4_lock )
|
||||
|
||||
static _HB_INLINE_ HB_U8 arc4_getbyte( void );
|
||||
|
||||
static _HB_INLINE_ void arc4_init( void )
|
||||
{
|
||||
int n;
|
||||
|
||||
for( n = 0; n < 256; n++ )
|
||||
rs.s[ n ] = n;
|
||||
|
||||
rs.i = rs.j = 0;
|
||||
}
|
||||
|
||||
static _HB_INLINE_ void arc4_addrandom( const HB_U8 * dat, int datlen )
|
||||
{
|
||||
int n;
|
||||
HB_U8 si;
|
||||
|
||||
rs.i--;
|
||||
for( n = 0; n < 256; n++ )
|
||||
{
|
||||
rs.i = ( rs.i + 1 );
|
||||
si = rs.s[ rs.i ];
|
||||
rs.j = rs.j + si + dat[ n % datlen ];
|
||||
rs.s[ rs.i ] = rs.s[ rs.j ];
|
||||
rs.s[ rs.j ] = si;
|
||||
}
|
||||
rs.j = rs.i;
|
||||
}
|
||||
|
||||
#if ! defined( HB_OS_WIN )
|
||||
static HB_ISIZ read_all( int fd, HB_U8 * buf, size_t count )
|
||||
{
|
||||
HB_SIZE numread = 0;
|
||||
HB_ISIZ result;
|
||||
|
||||
while( numread < count )
|
||||
{
|
||||
result = read( fd, buf + numread, count - numread );
|
||||
|
||||
if( result < 0 )
|
||||
return -1;
|
||||
else if( result == 0 )
|
||||
break;
|
||||
|
||||
numread += result;
|
||||
}
|
||||
|
||||
return ( HB_ISIZ ) numread;
|
||||
}
|
||||
#endif /* ! HB_OS_WIN */
|
||||
|
||||
#if defined( HB_OS_WIN )
|
||||
|
||||
#define TRY_SEED_MS_CRYPTOAPI
|
||||
static int arc4_seed_win32( void )
|
||||
{
|
||||
/* This is adapted from Tor's crypto_seed_rng() */
|
||||
static int provider_set = 0;
|
||||
static HCRYPTPROV provider;
|
||||
unsigned char buf[ ADD_ENTROPY ];
|
||||
|
||||
if( ! provider_set &&
|
||||
! CryptAcquireContext( &provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) &&
|
||||
GetLastError() != ( DWORD ) NTE_BAD_KEYSET )
|
||||
return -1;
|
||||
|
||||
provider_set = 1;
|
||||
|
||||
if( ! CryptGenRandom( provider, sizeof( buf ), buf ) )
|
||||
return -1;
|
||||
|
||||
arc4_addrandom( buf, sizeof( buf ) );
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HB_OS_WIN */
|
||||
|
||||
#if defined( HAVE_SYS_SYSCTL_H )
|
||||
|
||||
#if defined( HAVE_DECL_CTL_KERN ) && defined( HAVE_DECL_KERN_RANDOM ) && \
|
||||
defined( HAVE_DECL_RANDOM_UUID )
|
||||
|
||||
#define TRY_SEED_SYSCTL_LINUX
|
||||
static int arc4_seed_sysctl_linux( void )
|
||||
{
|
||||
/*
|
||||
* Based on code by William Ahern, this function tries to use the
|
||||
* RANDOM_UUID sysctl to get entropy from the kernel. This can work
|
||||
* even if /dev/urandom is inaccessible for some reason (e.g., we're
|
||||
* running in a chroot).
|
||||
*/
|
||||
int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
|
||||
HB_U8 buf[ ADD_ENTROPY ];
|
||||
HB_SIZE len, n;
|
||||
unsigned int i;
|
||||
int any_set;
|
||||
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
for( len = 0; len < sizeof( buf ); len += n )
|
||||
{
|
||||
n = sizeof( buf ) - len;
|
||||
|
||||
if( sysctl( mib, 3, &buf[ len ], &n, NULL, 0 ) != 0 )
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make sure that the buffer actually got set. */
|
||||
for( i = 0, any_set = 0; i < sizeof( buf ); ++i )
|
||||
any_set |= buf[ i ];
|
||||
|
||||
if( ! any_set )
|
||||
return -1;
|
||||
|
||||
arc4_addrandom( buf, sizeof( buf ) );
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_DECL_CTL_KERN && HAVE_DECL_KERN_RANDOM && HAVE_DECL_RANDOM_UUID */
|
||||
|
||||
#if defined( HAVE_DECL_CTL_KERN ) && defined( HAVE_DECL_KERN_ARND )
|
||||
|
||||
#define TRY_SEED_SYSCTL_BSD
|
||||
static int arc4_seed_sysctl_bsd( void )
|
||||
{
|
||||
/*
|
||||
* Based on code from William Ahern and from OpenBSD, this function
|
||||
* tries to use the KERN_ARND syscall to get entropy from the kernel.
|
||||
* This can work even if /dev/urandom is inaccessible for some reason
|
||||
* (e.g., we're running in a chroot).
|
||||
*/
|
||||
int mib[] = { CTL_KERN, KERN_ARND };
|
||||
HB_U8 buf[ ADD_ENTROPY ];
|
||||
HB_SIZE len, n;
|
||||
int i, any_set;
|
||||
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
len = sizeof( buf );
|
||||
if( sysctl( mib, 2, buf, &len, NULL, 0 ) == -1 )
|
||||
{
|
||||
for( len = 0; len < sizeof( buf ); len += sizeof( unsigned ) )
|
||||
{
|
||||
n = sizeof( unsigned );
|
||||
|
||||
if( n + len > sizeof( buf ) )
|
||||
n = len - sizeof( buf );
|
||||
|
||||
if( sysctl( mib, 2, &buf[ len ], &n, NULL, 0 ) == -1 )
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure that the buffer actually got set. */
|
||||
for( i = any_set = 0; i < sizeof( buf ); ++i )
|
||||
any_set |= buf[ i ];
|
||||
|
||||
if( ! any_set )
|
||||
return -1;
|
||||
|
||||
arc4_addrandom( buf, sizeof( buf ) );
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_DECL_CTL_KERN && HAVE_DECL_KERN_ARND */
|
||||
|
||||
#endif /* defined( HAVE_SYS_SYSCTL_H ) */
|
||||
|
||||
#if defined( HB_OS_LINUX )
|
||||
|
||||
#define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
|
||||
static _HB_INLINE_ int hex_char_to_int( char c )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case '0': return 0;
|
||||
case '1': return 1;
|
||||
case '2': return 2;
|
||||
case '3': return 3;
|
||||
case '4': return 4;
|
||||
case '5': return 5;
|
||||
case '6': return 6;
|
||||
case '7': return 7;
|
||||
case '8': return 8;
|
||||
case '9': return 9;
|
||||
case 'A': case 'a': return 10;
|
||||
case 'B': case 'b': return 11;
|
||||
case 'C': case 'c': return 12;
|
||||
case 'D': case 'd': return 13;
|
||||
case 'E': case 'e': return 14;
|
||||
case 'F': case 'f': return 15;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int arc4_seed_proc_sys_kernel_random_uuid( void )
|
||||
{
|
||||
/*
|
||||
* Occasionally, somebody will make /proc/sys accessible in a chroot,
|
||||
* but not /dev/urandom. Let's try /proc/sys/kernel/random/uuid.
|
||||
* Its format is stupid, so we need to decode it from hex.
|
||||
*/
|
||||
int fd;
|
||||
char buf[ 128 ];
|
||||
HB_U8 entropy[ 64 ];
|
||||
int bytes, n, i, nybbles;
|
||||
|
||||
for( bytes = 0; bytes < ADD_ENTROPY; )
|
||||
{
|
||||
fd = open( "/proc/sys/kernel/random/uuid", O_RDONLY, 0 );
|
||||
if( fd < 0 )
|
||||
return -1;
|
||||
|
||||
n = read( fd, buf, sizeof( buf ) );
|
||||
close( fd );
|
||||
|
||||
if( n <= 0 )
|
||||
return -1;
|
||||
|
||||
memset( entropy, 0, sizeof( entropy ) );
|
||||
for( i = nybbles = 0; i < n; ++i )
|
||||
{
|
||||
if( HB_ISXDIGIT( buf[ i ] ) )
|
||||
{
|
||||
int nyb = hex_char_to_int( buf[ i ] );
|
||||
|
||||
if( nybbles & 1 )
|
||||
entropy[ nybbles / 2 ] |= nyb;
|
||||
else
|
||||
entropy[ nybbles / 2 ] |= nyb << 4;
|
||||
|
||||
++nybbles;
|
||||
}
|
||||
}
|
||||
if( nybbles < 2 )
|
||||
return -1;
|
||||
|
||||
arc4_addrandom( entropy, nybbles / 2 );
|
||||
bytes += nybbles / 2;
|
||||
}
|
||||
|
||||
memset( entropy, 0, sizeof( entropy ) );
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HB_OS_LINUX */
|
||||
|
||||
#if defined( HB_OS_UNIX )
|
||||
|
||||
#define TRY_SEED_URANDOM
|
||||
static int arc4_seed_urandom( void )
|
||||
{
|
||||
/* This is adapted from Tor's crypto_seed_rng() */
|
||||
static const char * filenames[] = {
|
||||
"/dev/srandom",
|
||||
"/dev/urandom",
|
||||
"/dev/random",
|
||||
NULL
|
||||
};
|
||||
HB_U8 buf[ ADD_ENTROPY ];
|
||||
int fd, i;
|
||||
HB_SIZE n;
|
||||
|
||||
for( i = 0; filenames[ i ]; ++i )
|
||||
{
|
||||
fd = open( filenames[ i ], O_RDONLY, 0 );
|
||||
if( fd < 0 )
|
||||
continue;
|
||||
|
||||
n = read_all( fd, buf, sizeof( buf ) );
|
||||
close( fd );
|
||||
|
||||
if( n != sizeof( buf ) )
|
||||
return -1;
|
||||
|
||||
arc4_addrandom( buf, sizeof( buf ) );
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif /* HB_OS_UNIX */
|
||||
|
||||
static int arc4_seed_rand( void )
|
||||
{
|
||||
HB_SIZE i;
|
||||
HB_U8 buf[ ADD_ENTROPY ];
|
||||
|
||||
srand( ( unsigned ) hb_dateMilliSeconds() );
|
||||
|
||||
for( i = 0; i < sizeof( buf ); i++ )
|
||||
buf[ i ] = ( HB_U8 ) ( rand() % 256 ); /* not biased */
|
||||
|
||||
arc4_addrandom( buf, sizeof( buf ) );
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void arc4_seed( void )
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
/*
|
||||
* We try every method that might work, and don't give up even if one
|
||||
* does seem to work. There's no real harm in over-seeding, and if
|
||||
* one of these sources turns out to be broken, that would be bad.
|
||||
*/
|
||||
|
||||
#if defined( TRY_SEED_MS_CRYPTOAPI )
|
||||
if( arc4_seed_win32() == 0 )
|
||||
ok = 1;
|
||||
#endif
|
||||
|
||||
#if defined( TRY_SEED_URANDOM )
|
||||
if( arc4_seed_urandom() == 0 )
|
||||
ok = 1;
|
||||
#endif
|
||||
|
||||
#if defined( TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID )
|
||||
if( arc4_seed_proc_sys_kernel_random_uuid() == 0 )
|
||||
ok = 1;
|
||||
#endif
|
||||
|
||||
#if defined( TRY_SEED_SYSCTL_LINUX )
|
||||
/*
|
||||
* Apparently Linux is deprecating sysctl, and spewing warning
|
||||
* messages when you try to use it. To avoid dmesg spamming,
|
||||
* only try this if no previous method worked.
|
||||
*/
|
||||
if( ! ok && arc4_seed_sysctl_linux() == 0 )
|
||||
ok = 1;
|
||||
#endif
|
||||
|
||||
#if defined( TRY_SEED_SYSCTL_BSD )
|
||||
if( arc4_seed_sysctl_bsd() == 0 )
|
||||
ok = 1;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If nothing else worked or there is no specific seeding
|
||||
* method for the current platform, fall back to rand().
|
||||
* In case an existing platform-specific method had a
|
||||
* (transient) failure, it will be re-tried at the next
|
||||
* seeding cycle.
|
||||
*/
|
||||
if( ! ok )
|
||||
arc4_seed_rand();
|
||||
}
|
||||
|
||||
static void arc4_stir( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( ! rs_initialized )
|
||||
{
|
||||
arc4_init();
|
||||
rs_initialized = 1;
|
||||
}
|
||||
|
||||
arc4_seed();
|
||||
|
||||
/*
|
||||
* Discard early keystream, as per recommendations in
|
||||
* "Weaknesses in the Key Scheduling Algorithm of RC4" by
|
||||
* Scott Fluhrer, Itsik Mantin, and Adi Shamir.
|
||||
* http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
|
||||
*
|
||||
* Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
|
||||
* we drop at least 2*256 bytes, with 12*256 as a conservative
|
||||
* value.
|
||||
*
|
||||
* RFC4345 says to drop 6*256.
|
||||
*
|
||||
* At least some versions of this code drop 4*256, in a mistaken
|
||||
* belief that "words" in the Fluhrer/Mantin/Shamir paper refers
|
||||
* to processor words.
|
||||
*
|
||||
* We add another sect to the cargo cult, and choose 12*256.
|
||||
*/
|
||||
for( i = 0; i < 12 * 256; i++ )
|
||||
( void ) arc4_getbyte();
|
||||
|
||||
arc4_count = BYTES_BEFORE_RESEED;
|
||||
}
|
||||
|
||||
static void arc4_stir_if_needed( void )
|
||||
{
|
||||
pid_t pid = getpid();
|
||||
|
||||
if( arc4_count <= 0 || ! rs_initialized || arc4_stir_pid != pid )
|
||||
{
|
||||
arc4_stir_pid = pid;
|
||||
arc4_stir();
|
||||
}
|
||||
}
|
||||
|
||||
static _HB_INLINE_ HB_U8 arc4_getbyte( void )
|
||||
{
|
||||
HB_U8 si, sj;
|
||||
|
||||
rs.i = rs.i + 1;
|
||||
si = rs.s[ rs.i ];
|
||||
rs.j = rs.j + si;
|
||||
sj = rs.s[ rs.j ];
|
||||
rs.s[ rs.i ] = sj;
|
||||
rs.s[ rs.j ] = si;
|
||||
|
||||
return rs.s[ ( si + sj ) & 0xff ];
|
||||
}
|
||||
|
||||
static _HB_INLINE_ HB_U32 arc4_getword( void )
|
||||
{
|
||||
HB_U32 val;
|
||||
|
||||
val = arc4_getbyte() << 24;
|
||||
val |= arc4_getbyte() << 16;
|
||||
val |= arc4_getbyte() << 8;
|
||||
val |= arc4_getbyte();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* These two are part of the original arc4random API, but Harbour does not
|
||||
* make use of either of them.
|
||||
*/
|
||||
void arc4random_stir( void )
|
||||
{
|
||||
_ARC4_LOCK();
|
||||
arc4_stir();
|
||||
_ARC4_UNLOCK();
|
||||
}
|
||||
|
||||
void arc4random_addrandom( const unsigned char * dat, int datlen )
|
||||
{
|
||||
int j;
|
||||
|
||||
_ARC4_LOCK();
|
||||
if( ! rs_initialized )
|
||||
arc4_stir();
|
||||
|
||||
for( j = 0; j < datlen; j += 256 )
|
||||
{
|
||||
/*
|
||||
* arc4_addrandom() ignores all but the first 256 bytes of
|
||||
* its input. We want to make sure to look at ALL the
|
||||
* data in 'dat', just in case the user is doing something
|
||||
* crazy like passing us all the files in /var/log.
|
||||
*/
|
||||
arc4_addrandom( dat + j, datlen - j );
|
||||
}
|
||||
_ARC4_UNLOCK();
|
||||
}
|
||||
#endif
|
||||
|
||||
HB_U32 hb_arc4random( void )
|
||||
{
|
||||
HB_U32 val;
|
||||
|
||||
_ARC4_LOCK();
|
||||
|
||||
arc4_count -= 4;
|
||||
arc4_stir_if_needed();
|
||||
val = arc4_getword();
|
||||
|
||||
_ARC4_UNLOCK();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void hb_arc4random_buf( void * _buf, HB_SIZE n )
|
||||
{
|
||||
HB_U8 * buf = ( HB_U8 * ) _buf;
|
||||
|
||||
_ARC4_LOCK();
|
||||
|
||||
arc4_stir_if_needed();
|
||||
|
||||
while( n-- )
|
||||
{
|
||||
if( --arc4_count <= 0 )
|
||||
arc4_stir();
|
||||
|
||||
buf[ n ] = arc4_getbyte();
|
||||
}
|
||||
|
||||
_ARC4_UNLOCK();
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate a uniformly distributed random number less than upper_bound
|
||||
* avoiding "modulo bias".
|
||||
*
|
||||
* Uniformity is achieved by generating new random numbers until the one
|
||||
* returned is outside the range [0, 2**32 % upper_bound). This
|
||||
* guarantees the selected random number will be inside
|
||||
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
|
||||
* after reduction modulo upper_bound.
|
||||
*/
|
||||
HB_U32 hb_arc4random_uniform( HB_U32 upper_bound )
|
||||
{
|
||||
HB_U32 r, min;
|
||||
|
||||
if( upper_bound < 2 )
|
||||
return 0;
|
||||
|
||||
#if ( HB_U32_MAX > 0xffffffffUL )
|
||||
min = 0x100000000UL % upper_bound;
|
||||
#else
|
||||
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
|
||||
if( upper_bound > 0x80000000 )
|
||||
{
|
||||
/* 2**32 - upper_bound */
|
||||
min = 1 + ~upper_bound;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
|
||||
min = ( ( 0xffffffff - ( upper_bound * 2 ) ) + 1 ) % upper_bound;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This could theoretically loop forever but each retry has
|
||||
* p > 0.5 (worst case, usually far better) of selecting a
|
||||
* number inside the range we need, so it should rarely need
|
||||
* to re-roll.
|
||||
*/
|
||||
for( ;; )
|
||||
{
|
||||
r = hb_arc4random();
|
||||
if( r >= min )
|
||||
break;
|
||||
}
|
||||
|
||||
return r % upper_bound;
|
||||
}
|
||||
73
harbour/src/rtl/arc4.h
Normal file
73
harbour/src/rtl/arc4.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portable ARC4 PRNG, based on arc4random.c from Libevent.
|
||||
* Harbour adaptation Copyright 2011 Tamas TEVESZ <ice@extreme.hu>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portable arc4random.c based on arc4random.c from OpenBSD.
|
||||
* Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
|
||||
* Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Arc4 random number generator for OpenBSD.
|
||||
*
|
||||
* This code is derived from section 17.1 of Applied Cryptography,
|
||||
* second edition, which describes a stream cipher allegedly
|
||||
* compatible with RSA Labs "RC4" cipher (the actual description of
|
||||
* which is a trade secret). The same algorithm is used as a stream
|
||||
* cipher called "arcfour" in Tatu Ylonen's ssh package.
|
||||
*
|
||||
* Here the stream cipher has been modified always to include the time
|
||||
* when initializing the state. That makes it impossible to
|
||||
* regenerate the same random sequence twice, so this can't be used
|
||||
* for encryption, but will generate good random numbers.
|
||||
*
|
||||
* RC4 is a registered trademark of RSA Laboratories.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bit of a guesswork; possibly needs to be extended to other platforms,
|
||||
* but on UNIX-ish systems, seeding will fall back to using the
|
||||
* /dev/random-variants.
|
||||
*/
|
||||
|
||||
#ifndef __ARC4_H__
|
||||
#define __ARC4_H__
|
||||
|
||||
#include "hbdefs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HB_U32 hb_arc4random( void );
|
||||
void hb_arc4random_buf( void * _buf, HB_SIZE n );
|
||||
HB_U32 hb_arc4random_uniform( HB_U32 upper_bound );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARC4_H__ */
|
||||
60
harbour/src/rtl/hbrand.c
Normal file
60
harbour/src/rtl/hbrand.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* HB_RAND32() function
|
||||
*
|
||||
* Copyright 2011 Viktor Szakats (harbour.01 syenar.hu)
|
||||
* www - http://harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
||||
*
|
||||
* As a special exception, the Harbour Project gives permission for
|
||||
* additional uses of the text contained in its release of Harbour.
|
||||
*
|
||||
* The exception is that, if you link the Harbour libraries with other
|
||||
* files to produce an executable, this does not by itself cause the
|
||||
* resulting executable to be covered by the GNU General Public License.
|
||||
* Your use of that executable is in no way restricted on account of
|
||||
* linking the Harbour library code into it.
|
||||
*
|
||||
* This exception does not however invalidate any other reasons why
|
||||
* the executable file might be covered by the GNU General Public License.
|
||||
*
|
||||
* This exception applies only to the code released by the Harbour
|
||||
* Project under the name Harbour. If you copy code from other
|
||||
* Harbour Project or Free Software Foundation releases into a copy of
|
||||
* Harbour, as the General Public License permits, the exception does
|
||||
* not apply to the code that you add in this way. To avoid misleading
|
||||
* anyone as to the status of such modified files, you must delete
|
||||
* this exception notice from them.
|
||||
*
|
||||
* If you write modifications of your own for Harbour, it is your choice
|
||||
* whether to permit this exception to apply to your modifications.
|
||||
* If you do not wish that, delete this exception notice.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hbapi.h"
|
||||
|
||||
#include "arc4.h"
|
||||
|
||||
HB_FUNC( HB_RAND32 ) /* returns an integer between 0 and 0xFFFFFFFF (inclusive) */
|
||||
{
|
||||
hb_retnint( hb_arc4random() );
|
||||
}
|
||||
@@ -118,11 +118,6 @@ HB_FUNC( HB_RANDOMINT )
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_RAND32 ) /* returns an integer between 0 and 0xFFFFFFFF (inclusive) */
|
||||
{
|
||||
hb_retnint( ( HB_MAXINT ) ( hb_random_num() * ( HB_MAXINT ) HB_U32_MAX ) );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_RANDOMSEED )
|
||||
{
|
||||
srand( HB_ISNUM( 1 ) ? ( unsigned ) hb_parni( 1 ) : ( unsigned ) hb_dateMilliSeconds() );
|
||||
|
||||
Reference in New Issue
Block a user