Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34109955
random.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
25 KB
Subscribers
None
random.c
View Options
/* random.c - random number generator
* Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/****************
* This random number generator is modelled after the one described
* in Peter Gutmann's Paper: "Software Generation of Practically
* Strong Random Numbers".
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<assert.h>
#include
<errno.h>
#include
<string.h>
#include
<sys/time.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<unistd.h>
#include
<fcntl.h>
#include
<time.h>
#ifdef HAVE_GETHRTIME
#include
<sys/times.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
#include
<sys/times.h>
#endif
#ifdef HAVE_GETRUSAGE
#include
<sys/resource.h>
#endif
#ifdef __MINGW32__
#include
<process.h>
#endif
#include
"g10lib.h"
#include
"rmd.h"
#include
"random.h"
#include
"rand-internal.h"
//#include "dynload.h"
#include
"cipher.h"
/* only used for the rmd160_hash_buffer() prototype */
#include
"ath.h"
#ifndef RAND_MAX
/* for SunOS */
#define RAND_MAX 32767
#endif
#if SIZEOF_UNSIGNED_LONG == 8
#define ADD_VALUE 0xa5a5a5a5a5a5a5a5
#elif SIZEOF_UNSIGNED_LONG == 4
#define ADD_VALUE 0xa5a5a5a5
#else
#error weird size for an unsigned long
#endif
#define BLOCKLEN 64
/* hash this amount of bytes */
#define DIGESTLEN 20
/* into a digest of this length (rmd160) */
/* poolblocks is the number of digests which make up the pool
* and poolsize must be a multiple of the digest length
* to make the AND operations faster, the size should also be
* a multiple of ulong
*/
#define POOLBLOCKS 30
#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
#error Please make sure that poolsize is a multiple of ulong
#endif
#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
static
int
is_initialized
;
#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
static
char
*
rndpool
;
/* allocated size is POOLSIZE+BLOCKLEN */
static
char
*
keypool
;
/* allocated size is POOLSIZE+BLOCKLEN */
static
size_t
pool_readpos
;
static
size_t
pool_writepos
;
static
int
pool_filled
;
static
int
pool_balance
;
static
int
just_mixed
;
static
int
did_initial_extra_seeding
;
static
char
*
seed_file_name
;
static
int
allow_seed_file_update
;
static
unsigned
char
failsafe_digest
[
DIGESTLEN
];
static
int
failsafe_digest_valid
;
static
int
secure_alloc
;
static
int
quick_test
;
static
int
faked_rng
;
static
ath_mutex_t
pool_lock
=
ATH_MUTEX_INITIALIZER
;
static
int
pool_is_locked
;
/* only used for assertion */
static
byte
*
get_random_bytes
(
size_t
nbytes
,
int
level
,
int
secure
);
static
void
read_pool
(
byte
*
buffer
,
size_t
length
,
int
level
);
static
void
add_randomness
(
const
void
*
buffer
,
size_t
length
,
int
source
);
static
void
random_poll
(
void
);
static
void
do_fast_random_poll
(
void
);
static
void
read_random_source
(
int
requester
,
size_t
length
,
int
level
);
static
int
gather_faked
(
void
(
*
add
)(
const
void
*
,
size_t
,
int
),
int
requester
,
size_t
length
,
int
level
);
static
struct
{
ulong
mixrnd
;
ulong
mixkey
;
ulong
slowpolls
;
ulong
fastpolls
;
ulong
getbytes1
;
ulong
ngetbytes1
;
ulong
getbytes2
;
ulong
ngetbytes2
;
ulong
addbytes
;
ulong
naddbytes
;
}
rndstats
;
static
void
(
*
progress_cb
)
(
void
*
,
const
char
*
,
int
,
int
,
int
);
static
void
*
progress_cb_data
;
/* Note, we assume that this function is used before any concurrent
access happens */
static
void
initialize
(
void
)
{
int
err
;
err
=
ath_mutex_init
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to create the pool lock: %s
\n
"
,
strerror
(
err
)
);
/* The data buffer is allocated somewhat larger, so that we can use
this extra space (which is allocated in secure memory) as a
temporary hash buffer */
rndpool
=
secure_alloc
?
gcry_xcalloc_secure
(
1
,
POOLSIZE
+
BLOCKLEN
)
:
gcry_xcalloc
(
1
,
POOLSIZE
+
BLOCKLEN
);
keypool
=
secure_alloc
?
gcry_xcalloc_secure
(
1
,
POOLSIZE
+
BLOCKLEN
)
:
gcry_xcalloc
(
1
,
POOLSIZE
+
BLOCKLEN
);
is_initialized
=
1
;
//_gcry_cipher_modules_constructor ();
}
/* Used to register a progress callback. */
void
_gcry_register_random_progress
(
void
(
*
cb
)(
void
*
,
const
char
*
,
int
,
int
,
int
),
void
*
cb_data
)
{
progress_cb
=
cb
;
progress_cb_data
=
cb_data
;
}
/* This progress function is currently used by the random modules to give hint
on how much more entropy is required. */
void
_gcry_random_progress
(
const
char
*
what
,
int
printchar
,
int
current
,
int
total
)
{
if
(
progress_cb
)
progress_cb
(
progress_cb_data
,
what
,
printchar
,
current
,
total
);
}
/* Initialize this random subsystem. This function memrely calls the
initialzies and does not do anything more. Doing this is not
really required but when running in a threaded environment we might
get a race condition otherwise. */
void
_gcry_random_initialize
()
{
if
(
!
is_initialized
)
initialize
();
}
void
_gcry_random_dump_stats
()
{
log_info
(
"random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu
\n
"
" outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu
\n
"
,
POOLSIZE
,
rndstats
.
mixrnd
,
rndstats
.
slowpolls
,
rndstats
.
fastpolls
,
rndstats
.
naddbytes
,
rndstats
.
addbytes
,
rndstats
.
mixkey
,
rndstats
.
ngetbytes1
,
rndstats
.
getbytes1
,
rndstats
.
ngetbytes2
,
rndstats
.
getbytes2
);
}
void
_gcry_secure_random_alloc
()
{
secure_alloc
=
1
;
}
int
_gcry_quick_random_gen
(
int
onoff
)
{
int
last
;
/* No need to lock it here because we are only initializing. A
prerequisite of the entire code is that it has already been
initialized before any possible concurrent access */
read_random_source
(
0
,
0
,
0
);
/* init */
last
=
quick_test
;
if
(
onoff
!=
-1
)
quick_test
=
onoff
;
return
faked_rng
?
1
:
last
;
}
int
_gcry_random_is_faked
()
{
if
(
!
is_initialized
)
initialize
();
return
faked_rng
||
quick_test
;
}
/****************
* Return a pointer to a randomized buffer of level 0 and LENGTH bits
* caller must free the buffer.
* Note: The returned value is rounded up to bytes.
*/
static
byte
*
get_random_bytes
(
size_t
nbytes
,
int
level
,
int
secure
)
{
byte
*
buf
,
*
p
;
int
err
;
if
(
quick_test
&&
level
>
1
)
level
=
1
;
MASK_LEVEL
(
level
);
err
=
ath_mutex_lock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to acquire the pool lock: %s
\n
"
,
strerror
(
err
));
pool_is_locked
=
1
;
if
(
level
==
1
)
{
rndstats
.
getbytes1
+=
nbytes
;
rndstats
.
ngetbytes1
++
;
}
else
if
(
level
>=
2
)
{
rndstats
.
getbytes2
+=
nbytes
;
rndstats
.
ngetbytes2
++
;
}
buf
=
secure
&&
secure_alloc
?
gcry_xmalloc_secure
(
nbytes
)
:
gcry_xmalloc
(
nbytes
);
for
(
p
=
buf
;
nbytes
>
0
;
)
{
size_t
n
=
nbytes
>
POOLSIZE
?
POOLSIZE
:
nbytes
;
read_pool
(
p
,
n
,
level
);
nbytes
-=
n
;
p
+=
n
;
}
pool_is_locked
=
0
;
err
=
ath_mutex_unlock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to release the pool lock: %s
\n
"
,
strerror
(
err
));
return
buf
;
}
/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
should be in the range of 0..100 to indicate the goodness of the
entropy added, or -1 for goodness not known.
Note, that this fucntion currently does nothing.
*/
int
gcry_random_add_bytes
(
const
void
*
buf
,
size_t
buflen
,
int
quality
)
{
if
(
!
buf
||
quality
<
-1
||
quality
>
100
)
return
GCRYERR_INV_ARG
;
if
(
!
buflen
)
return
0
;
/* Shortcut this dummy case. */
/* Before we actuall enbale this code, we need to lock the pool,
have a look at the quality and find a way to add them without
disturbing the real entropy (we have estimated). */
/*add_randomness( buf, buflen, 1 );*/
return
0
;
}
void
*
gcry_random_bytes
(
size_t
nbytes
,
enum
gcry_random_level
level
)
{
if
(
!
is_initialized
)
initialize
();
return
get_random_bytes
(
nbytes
,
level
,
0
);
}
void
*
gcry_random_bytes_secure
(
size_t
nbytes
,
enum
gcry_random_level
level
)
{
if
(
!
is_initialized
)
initialize
();
return
get_random_bytes
(
nbytes
,
level
,
1
);
}
/* Fill the buffer with LENGTH bytes of cryptographically strong
random bytes. level 0 is not very strong, 1 is strong enough for
most usage, 2 is good for key generation stuff but may be very
slow. */
void
gcry_randomize
(
byte
*
buffer
,
size_t
length
,
enum
gcry_random_level
level
)
{
byte
*
p
;
int
err
;
if
(
!
is_initialized
)
initialize
();
if
(
quick_test
&&
level
>
1
)
level
=
1
;
MASK_LEVEL
(
level
);
err
=
ath_mutex_lock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to acquire the pool lock: %s
\n
"
,
strerror
(
err
));
pool_is_locked
=
1
;
if
(
level
==
1
)
{
rndstats
.
getbytes1
+=
length
;
rndstats
.
ngetbytes1
++
;
}
else
if
(
level
>=
2
)
{
rndstats
.
getbytes2
+=
length
;
rndstats
.
ngetbytes2
++
;
}
for
(
p
=
buffer
;
length
>
0
;)
{
size_t
n
=
length
>
POOLSIZE
?
POOLSIZE
:
length
;
read_pool
(
p
,
n
,
level
);
length
-=
n
;
p
+=
n
;
}
pool_is_locked
=
0
;
err
=
ath_mutex_unlock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to release the pool lock: %s
\n
"
,
strerror
(
err
));
}
/*
Mix the pool:
|........blocks*20byte........|20byte|..44byte..|
<..44byte..> <20byte>
| |
| +------+
+---------------------------|----------+
v v
|........blocks*20byte........|20byte|..44byte..|
<.....64bytes.....>
|
+----------------------------------+
Hash
v
|.............................|20byte|..44byte..|
<20byte><20byte><..44byte..>
| |
| +---------------------+
+-----------------------------+ |
v v
|.............................|20byte|..44byte..|
<.....64byte......>
|
+-------------------------+
Hash
v
|.............................|20byte|..44byte..|
<20byte><20byte><..44byte..>
and so on until we did this for all blocks.
*/
static
void
mix_pool
(
byte
*
pool
)
{
char
*
hashbuf
=
pool
+
POOLSIZE
;
char
*
p
,
*
pend
;
int
i
,
n
;
RMD160_CONTEXT
md
;
assert
(
pool_is_locked
);
_gcry_rmd160_init
(
&
md
);
#if DIGESTLEN != 20
# error must have a digest length of 20 for ripe-md-160
#endif
/* loop over the pool */
pend
=
pool
+
POOLSIZE
;
memcpy
(
hashbuf
,
pend
-
DIGESTLEN
,
DIGESTLEN
);
memcpy
(
hashbuf
+
DIGESTLEN
,
pool
,
BLOCKLEN
-
DIGESTLEN
);
_gcry_rmd160_mixblock
(
&
md
,
hashbuf
);
memcpy
(
pool
,
hashbuf
,
20
);
if
(
failsafe_digest_valid
&&
(
char
*
)
pool
==
rndpool
)
{
for
(
i
=
0
;
i
<
20
;
i
++
)
pool
[
i
]
^=
failsafe_digest
[
i
];
}
p
=
pool
;
for
(
n
=
1
;
n
<
POOLBLOCKS
;
n
++
)
{
memcpy
(
hashbuf
,
p
,
DIGESTLEN
);
p
+=
DIGESTLEN
;
if
(
p
+
DIGESTLEN
+
BLOCKLEN
<
pend
)
memcpy
(
hashbuf
+
DIGESTLEN
,
p
+
DIGESTLEN
,
BLOCKLEN
-
DIGESTLEN
);
else
{
char
*
pp
=
p
+
DIGESTLEN
;
for
(
i
=
DIGESTLEN
;
i
<
BLOCKLEN
;
i
++
)
{
if
(
pp
>=
pend
)
pp
=
pool
;
hashbuf
[
i
]
=
*
pp
++
;
}
}
_gcry_rmd160_mixblock
(
&
md
,
hashbuf
);
memcpy
(
p
,
hashbuf
,
20
);
}
/* Hmmm: our hash implementation does only leave small parts (64
bytes) of the pool on the stack, so I thnik it ios okay not to
require secure memory here. Before we use this pool, it gets
copied to the help buffer anyway. */
if
(
(
char
*
)
pool
==
rndpool
)
{
_gcry_rmd160_hash_buffer
(
failsafe_digest
,
pool
,
POOLSIZE
);
failsafe_digest_valid
=
1
;
}
_gcry_burn_stack
(
384
);
/* for the rmd160_mixblock(), rmd160_hash_buffer */
}
void
_gcry_set_random_seed_file
(
const
char
*
name
)
{
if
(
seed_file_name
)
BUG
();
seed_file_name
=
gcry_xstrdup
(
name
);
}
/****************
* Read in a seed form the random_seed file
* and return true if this was successful
*/
static
int
read_seed_file
()
{
int
fd
;
struct
stat
sb
;
unsigned
char
buffer
[
POOLSIZE
];
int
n
;
assert
(
pool_is_locked
);
if
(
!
seed_file_name
)
return
0
;
#ifdef HAVE_DOSISH_SYSTEM
fd
=
open
(
seed_file_name
,
O_RDONLY
|
O_BINARY
);
#else
fd
=
open
(
seed_file_name
,
O_RDONLY
);
#endif
if
(
fd
==
-1
&&
errno
==
ENOENT
)
{
allow_seed_file_update
=
1
;
return
0
;
}
if
(
fd
==
-1
)
{
log_info
(
_
(
"can't open `%s': %s
\n
"
),
seed_file_name
,
strerror
(
errno
)
);
return
0
;
}
if
(
fstat
(
fd
,
&
sb
)
)
{
log_info
(
_
(
"can't stat `%s': %s
\n
"
),
seed_file_name
,
strerror
(
errno
)
);
close
(
fd
);
return
0
;
}
if
(
!
S_ISREG
(
sb
.
st_mode
)
)
{
log_info
(
_
(
"`%s' is not a regular file - ignored
\n
"
),
seed_file_name
);
close
(
fd
);
return
0
;
}
if
(
!
sb
.
st_size
)
{
log_info
(
_
(
"note: random_seed file is empty
\n
"
)
);
close
(
fd
);
allow_seed_file_update
=
1
;
return
0
;
}
if
(
sb
.
st_size
!=
POOLSIZE
)
{
log_info
(
_
(
"warning: invalid size of random_seed file - not used
\n
"
)
);
close
(
fd
);
return
0
;
}
do
{
n
=
read
(
fd
,
buffer
,
POOLSIZE
);
}
while
(
n
==
-1
&&
errno
==
EINTR
);
if
(
n
!=
POOLSIZE
)
{
log_fatal
(
_
(
"can't read `%s': %s
\n
"
),
seed_file_name
,
strerror
(
errno
)
);
close
(
fd
);
return
0
;
}
close
(
fd
);
add_randomness
(
buffer
,
POOLSIZE
,
0
);
/* add some minor entropy to the pool now (this will also force a mixing) */
{
pid_t
x
=
getpid
();
add_randomness
(
&
x
,
sizeof
(
x
),
0
);
}
{
time_t
x
=
time
(
NULL
);
add_randomness
(
&
x
,
sizeof
(
x
),
0
);
}
{
clock_t
x
=
clock
();
add_randomness
(
&
x
,
sizeof
(
x
),
0
);
}
/* And read a few bytes from our entropy source. By using
* a level of 0 this will not block and might not return anything
* with some entropy drivers, however the rndlinux driver will use
* /dev/urandom and return some stuff - Do not read to much as we
* want to be friendly to the scare system entropy resource. */
read_random_source
(
0
,
16
,
0
);
allow_seed_file_update
=
1
;
return
1
;
}
void
_gcry_update_random_seed_file
()
{
ulong
*
sp
,
*
dp
;
int
fd
,
i
;
int
err
;
if
(
!
seed_file_name
||
!
is_initialized
||
!
pool_filled
)
return
;
if
(
!
allow_seed_file_update
)
{
log_info
(
_
(
"note: random_seed file not updated
\n
"
));
return
;
}
err
=
ath_mutex_lock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to acquire the pool lock: %s
\n
"
,
strerror
(
err
));
pool_is_locked
=
1
;
/* copy the entropy pool to a scratch pool and mix both of them */
for
(
i
=
0
,
dp
=
(
ulong
*
)
keypool
,
sp
=
(
ulong
*
)
rndpool
;
i
<
POOLWORDS
;
i
++
,
dp
++
,
sp
++
)
{
*
dp
=
*
sp
+
ADD_VALUE
;
}
mix_pool
(
rndpool
);
rndstats
.
mixrnd
++
;
mix_pool
(
keypool
);
rndstats
.
mixkey
++
;
#ifdef HAVE_DOSISH_SYSTEM
fd
=
open
(
seed_file_name
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
|
O_BINARY
,
S_IRUSR
|
S_IWUSR
);
#else
fd
=
open
(
seed_file_name
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
,
S_IRUSR
|
S_IWUSR
);
#endif
if
(
fd
==
-1
)
log_info
(
_
(
"can't create `%s': %s
\n
"
),
seed_file_name
,
strerror
(
errno
)
);
else
{
do
{
i
=
write
(
fd
,
keypool
,
POOLSIZE
);
}
while
(
i
==
-1
&&
errno
==
EINTR
);
if
(
i
!=
POOLSIZE
)
log_info
(
_
(
"can't write `%s': %s
\n
"
),
seed_file_name
,
strerror
(
errno
)
);
if
(
close
(
fd
))
log_info
(
_
(
"can't close `%s': %s
\n
"
),
seed_file_name
,
strerror
(
errno
)
);
}
pool_is_locked
=
0
;
err
=
ath_mutex_unlock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to release the pool lock: %s
\n
"
,
strerror
(
err
));
}
static
void
read_pool
(
byte
*
buffer
,
size_t
length
,
int
level
)
{
int
i
;
ulong
*
sp
,
*
dp
;
assert
(
pool_is_locked
);
if
(
length
>
POOLSIZE
)
{
log_bug
(
"too many random bits requested
\n
"
);
}
if
(
!
pool_filled
)
{
if
(
read_seed_file
()
)
pool_filled
=
1
;
}
/* For level 2 quality (key generation) we always make
* sure that the pool has been seeded enough initially */
if
(
level
==
2
&&
!
did_initial_extra_seeding
)
{
size_t
needed
;
pool_balance
=
0
;
needed
=
length
-
pool_balance
;
if
(
needed
<
POOLSIZE
/
2
)
needed
=
POOLSIZE
/
2
;
else
if
(
needed
>
POOLSIZE
)
BUG
();
read_random_source
(
3
,
needed
,
2
);
pool_balance
+=
needed
;
did_initial_extra_seeding
=
1
;
}
/* for level 2 make sure that there is enough random in the pool */
if
(
level
==
2
&&
pool_balance
<
length
)
{
size_t
needed
;
if
(
pool_balance
<
0
)
pool_balance
=
0
;
needed
=
length
-
pool_balance
;
if
(
needed
>
POOLSIZE
)
BUG
();
read_random_source
(
3
,
needed
,
2
);
pool_balance
+=
needed
;
}
/* make sure the pool is filled */
while
(
!
pool_filled
)
random_poll
();
/* always do a fast random poll - we have to use the unlocked version*/
do_fast_random_poll
();
if
(
!
level
)
{
/* no need for cryptographic strong random */
/* create a new pool */
for
(
i
=
0
,
dp
=
(
ulong
*
)
keypool
,
sp
=
(
ulong
*
)
rndpool
;
i
<
POOLWORDS
;
i
++
,
dp
++
,
sp
++
)
*
dp
=
*
sp
+
ADD_VALUE
;
/* must mix both pools */
mix_pool
(
rndpool
);
rndstats
.
mixrnd
++
;
mix_pool
(
keypool
);
rndstats
.
mixkey
++
;
memcpy
(
buffer
,
keypool
,
length
);
}
else
{
/* mix the pool (if add_randomness() didn't it) */
if
(
!
just_mixed
)
{
mix_pool
(
rndpool
);
rndstats
.
mixrnd
++
;
}
/* create a new pool */
for
(
i
=
0
,
dp
=
(
ulong
*
)
keypool
,
sp
=
(
ulong
*
)
rndpool
;
i
<
POOLWORDS
;
i
++
,
dp
++
,
sp
++
)
*
dp
=
*
sp
+
ADD_VALUE
;
/* and mix both pools */
mix_pool
(
rndpool
);
rndstats
.
mixrnd
++
;
mix_pool
(
keypool
);
rndstats
.
mixkey
++
;
/* read the required data
* we use a readpoiter to read from a different postion each
* time */
while
(
length
--
)
{
*
buffer
++
=
keypool
[
pool_readpos
++
];
if
(
pool_readpos
>=
POOLSIZE
)
pool_readpos
=
0
;
pool_balance
--
;
}
if
(
pool_balance
<
0
)
pool_balance
=
0
;
/* and clear the keypool */
memset
(
keypool
,
0
,
POOLSIZE
);
}
}
/****************
* Add LENGTH bytes of randomness from buffer to the pool.
* source may be used to specify the randomness source.
* Source is:
* 0 - used ony for initialization
* 1 - fast random poll function
* 2 - normal poll function
* 3 - used when level 2 random quality has been requested
* to do an extra pool seed.
*/
static
void
add_randomness
(
const
void
*
buffer
,
size_t
length
,
int
source
)
{
const
byte
*
p
=
buffer
;
assert
(
pool_is_locked
);
if
(
!
is_initialized
)
initialize
();
rndstats
.
addbytes
+=
length
;
rndstats
.
naddbytes
++
;
while
(
length
--
)
{
rndpool
[
pool_writepos
++
]
^=
*
p
++
;
if
(
pool_writepos
>=
POOLSIZE
)
{
if
(
source
>
1
)
pool_filled
=
1
;
pool_writepos
=
0
;
mix_pool
(
rndpool
);
rndstats
.
mixrnd
++
;
just_mixed
=
!
length
;
}
}
}
static
void
random_poll
()
{
rndstats
.
slowpolls
++
;
read_random_source
(
2
,
POOLSIZE
/
5
,
1
);
}
static
int
(
*
getfnc_gather_random
(
void
))(
void
(
*
)(
const
void
*
,
size_t
,
int
),
int
,
size_t
,
int
)
{
#if USE_RNDLINUX
int
rndlinux_gather_random
(
void
(
*
add
)
(
const
void
*
,
size_t
,
int
),
int
requester
,
size_t
length
,
int
level
);
#endif
#if USE_RNDUNIX
int
rndunix_gather_random
(
void
(
*
add
)
(
const
void
*
,
size_t
,
int
),
int
requester
,
size_t
length
,
int
level
);
#endif
#if USE_RNDEGD
int
rndegd_gather_random
(
void
(
*
add
)
(
const
void
*
,
size_t
,
int
),
int
requester
,
size_t
length
,
int
level
);
int
rndegd_connect_socket
(
int
nofail
);
#endif
#if USE_RNDW32
int
rndw32_gather_random
(
void
(
*
add
)
(
const
void
*
,
size_t
,
int
),
int
requester
,
size_t
length
,
int
level
);
#endif
#ifdef USE_ALL_RANDOM_MODULES
static
int
(
*
fnc
)(
void
(
*
)(
const
void
*
,
size_t
,
int
),
int
,
size_t
,
int
);
if
(
fnc
)
return
fnc
;
# if USE_RNDLINUX
if
(
!
access
(
NAME_OF_DEV_RANDOM
,
R_OK
)
&&
!
access
(
NAME_OF_DEV_RANDOM
,
R_OK
))
{
fnc
=
rndlinux_gather_random
;
return
fnc
;
}
# endif
# if USE_RNDEGD
if
(
rndegd_connect_socket
(
1
)
!=
-1
)
{
fnc
=
rndegd_gather_random
;
return
fnc
;
}
# endif
# if USE_RNDUNIX
fnc
=
rndunix_gather_random
;
return
fnc
;
# endif
log_fatal
(
_
(
"no entropy gathering module detected
\n
"
));
#else
# if USE_RNDLINUX
return
rndlinux_gather_random
;
# endif
# if USE_RNDUNIX
return
rndunix_gather_random
;
# endif
# if USE_RNDEGD
return
rndegd_gather_random
;
# endif
# if USE_RNDW32
return
rndw32_gather_random
;
# endif
# if USE_RNDRISCOS
return
rndriscos_gather_random
;
# endif
#endif
return
NULL
;
}
static
void
(
*
getfnc_fast_random_poll
(
void
))(
void
(
*
)(
const
void
*
,
size_t
,
int
),
int
)
{
#if USE_RNDW32
int
rndw32_gather_random_fast
(
void
(
*
add
)
(
const
void
*
,
size_t
,
int
),
int
requester
);
return
rndw32_gather_random_fast
;
#endif
return
NULL
;
}
static
void
do_fast_random_poll
()
{
static
void
(
*
fnc
)(
void
(
*
)(
const
void
*
,
size_t
,
int
),
int
)
=
NULL
;
static
int
initialized
=
0
;
assert
(
pool_is_locked
);
rndstats
.
fastpolls
++
;
if
(
!
initialized
)
{
if
(
!
is_initialized
)
initialize
();
initialized
=
1
;
fnc
=
getfnc_fast_random_poll
();
}
if
(
fnc
)
{
(
*
fnc
)(
add_randomness
,
1
);
return
;
}
/* fall back to the generic function */
#if HAVE_GETHRTIME
{
hrtime_t
tv
;
tv
=
gethrtime
();
add_randomness
(
&
tv
,
sizeof
(
tv
),
1
);
}
#elif HAVE_GETTIMEOFDAY
{
struct
timeval
tv
;
if
(
gettimeofday
(
&
tv
,
NULL
)
)
BUG
();
add_randomness
(
&
tv
.
tv_sec
,
sizeof
(
tv
.
tv_sec
),
1
);
add_randomness
(
&
tv
.
tv_usec
,
sizeof
(
tv
.
tv_usec
),
1
);
}
#elif HAVE_CLOCK_GETTIME
{
struct
timespec
tv
;
if
(
clock_gettime
(
CLOCK_REALTIME
,
&
tv
)
==
-1
)
BUG
();
add_randomness
(
&
tv
.
tv_sec
,
sizeof
(
tv
.
tv_sec
),
1
);
add_randomness
(
&
tv
.
tv_nsec
,
sizeof
(
tv
.
tv_nsec
),
1
);
}
#else
/* use times */
#ifndef HAVE_DOSISH_SYSTEM
{
struct
tms
buf
;
times
(
&
buf
);
add_randomness
(
&
buf
,
sizeof
buf
,
1
);
}
#endif
#endif
#ifdef HAVE_GETRUSAGE
#ifndef RUSAGE_SELF
#ifdef __GCC__
#warning There is no RUSAGE_SELF on this system
#endif
#else
{
struct
rusage
buf
;
/* QNX/Neutrino does return ENOSYS - so we just ignore it and
* add whatever is in buf. In a chroot environment it might not
* work at all (i.e. because /proc/ is not accessible), so we better
* ugnore all error codes and hope for the best
*/
getrusage
(
RUSAGE_SELF
,
&
buf
);
add_randomness
(
&
buf
,
sizeof
buf
,
1
);
memset
(
&
buf
,
0
,
sizeof
buf
);
}
#endif
#endif
/* time and clock are availabe on all systems - so
* we better do it just in case one of the above functions
* didn't work */
{
time_t
x
=
time
(
NULL
);
add_randomness
(
&
x
,
sizeof
(
x
),
1
);
}
{
clock_t
x
=
clock
();
add_randomness
(
&
x
,
sizeof
(
x
),
1
);
}
}
void
_gcry_fast_random_poll
()
{
int
err
;
/* We have to make sure that the intialization is done because this
gatherer might be called before any other functions and it is not
sufficient to initialize it within do_fast_random_pool becuase we
want to use the mutex here. FIXME: Whe should initialize the mutex
using a global constructor independent from the initialization
of the pool. */
if
(
!
is_initialized
)
initialize
();
err
=
ath_mutex_lock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to acquire the pool lock: %s
\n
"
,
strerror
(
err
));
pool_is_locked
=
1
;
do_fast_random_poll
();
pool_is_locked
=
0
;
err
=
ath_mutex_unlock
(
&
pool_lock
);
if
(
err
)
log_fatal
(
"failed to acquire the pool lock: %s
\n
"
,
strerror
(
err
));
}
static
void
read_random_source
(
int
requester
,
size_t
length
,
int
level
)
{
static
int
(
*
fnc
)(
void
(
*
)(
const
void
*
,
size_t
,
int
),
int
,
size_t
,
int
)
=
NULL
;
if
(
!
fnc
)
{
if
(
!
is_initialized
)
initialize
();
fnc
=
getfnc_gather_random
();
//fnc = ((GcryRandomSpec *) randoms_registered->spec)->add;
//fnc = _gcry_dynload_getfnc_gather_random();
if
(
!
fnc
)
{
faked_rng
=
1
;
fnc
=
gather_faked
;
}
if
(
!
requester
&&
!
length
&&
!
level
)
return
;
/* init only */
}
if
(
(
*
fnc
)(
add_randomness
,
requester
,
length
,
level
)
<
0
)
log_fatal
(
"No way to gather entropy for the RNG
\n
"
);
}
static
int
gather_faked
(
void
(
*
add
)(
const
void
*
,
size_t
,
int
),
int
requester
,
size_t
length
,
int
level
)
{
static
int
initialized
=
0
;
size_t
n
;
char
*
buffer
,
*
p
;
if
(
!
initialized
)
{
log_info
(
_
(
"WARNING: using insecure random number generator!!
\n
"
));
/* we can't use tty_printf here - do we need this function at
all - does it really make sense or canit be viewed as a potential
security problem ? wk 17.11.99 */
#if 0
tty_printf(_("The random number generator is only a kludge to let\n"
"it run - it is in no way a strong RNG!\n\n"
"DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
#endif
initialized
=
1
;
#ifdef HAVE_RAND
srand
(
time
(
NULL
)
*
getpid
());
#else
srandom
(
time
(
NULL
)
*
getpid
());
#endif
}
p
=
buffer
=
gcry_xmalloc
(
length
);
n
=
length
;
#ifdef HAVE_RAND
while
(
n
--
)
*
p
++
=
((
unsigned
)(
1
+
(
int
)
(
256.0
*
rand
()
/
(
RAND_MAX
+
1.0
)))
-1
);
#else
while
(
n
--
)
*
p
++
=
((
unsigned
)(
1
+
(
int
)
(
256.0
*
random
()
/
(
RAND_MAX
+
1.0
)))
-1
);
#endif
add_randomness
(
buffer
,
length
,
requester
);
gcry_free
(
buffer
);
return
0
;
/* okay */
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Dec 5, 5:41 AM (1 d, 23 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
7d/dc/3f52cdb255702b1d66cb8351e786
Attached To
rC libgcrypt
Event Timeline
Log In to Comment