Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F31766777
random.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
14 KB
Subscribers
None
random.c
View Options
/* random.c - part of the Libgcrypt test suite.
Copyright (C) 2005 Free Software Foundation, Inc.
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 of the
License, 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA. */
#ifdef HAVE_CONFIG_H
#include
<config.h>
#endif
#include
<assert.h>
#include
<stdio.h>
#include
<string.h>
#include
<stdlib.h>
#include
<errno.h>
#ifndef HAVE_W32_SYSTEM
# include <signal.h>
# include <unistd.h>
# include <sys/wait.h>
#endif
#include
"../src/gcrypt-int.h"
#define PGM "random"
static
int
verbose
;
static
int
debug
;
static
int
with_progress
;
static
void
die
(
const
char
*
format
,
...)
{
va_list
arg_ptr
;
va_start
(
arg_ptr
,
format
);
fputs
(
PGM
": "
,
stderr
);
vfprintf
(
stderr
,
format
,
arg_ptr
);
va_end
(
arg_ptr
);
exit
(
1
);
}
static
void
inf
(
const
char
*
format
,
...)
{
va_list
arg_ptr
;
va_start
(
arg_ptr
,
format
);
fputs
(
PGM
": "
,
stderr
);
vfprintf
(
stderr
,
format
,
arg_ptr
);
va_end
(
arg_ptr
);
}
static
void
print_hex
(
const
char
*
text
,
const
void
*
buf
,
size_t
n
)
{
const
unsigned
char
*
p
=
buf
;
inf
(
"%s"
,
text
);
for
(;
n
;
n
--
,
p
++
)
fprintf
(
stderr
,
"%02X"
,
*
p
);
putc
(
'\n'
,
stderr
);
}
static
void
progress_cb
(
void
*
cb_data
,
const
char
*
what
,
int
printchar
,
int
current
,
int
total
)
{
(
void
)
cb_data
;
inf
(
"progress (%s %c %d %d)
\n
"
,
what
,
printchar
,
current
,
total
);
fflush
(
stderr
);
}
static
int
writen
(
int
fd
,
const
void
*
buf
,
size_t
nbytes
)
{
size_t
nleft
=
nbytes
;
int
nwritten
;
while
(
nleft
>
0
)
{
nwritten
=
write
(
fd
,
buf
,
nleft
);
if
(
nwritten
<
0
)
{
if
(
errno
==
EINTR
)
nwritten
=
0
;
else
return
-1
;
}
nleft
-=
nwritten
;
buf
=
(
const
char
*
)
buf
+
nwritten
;
}
return
0
;
}
static
int
readn
(
int
fd
,
void
*
buf
,
size_t
buflen
,
size_t
*
ret_nread
)
{
size_t
nleft
=
buflen
;
int
nread
;
while
(
nleft
>
0
)
{
nread
=
read
(
fd
,
buf
,
nleft
);
if
(
nread
<
0
)
{
if
(
nread
==
EINTR
)
nread
=
0
;
else
return
-1
;
}
else
if
(
!
nread
)
break
;
/* EOF */
nleft
-=
nread
;
buf
=
(
char
*
)
buf
+
nread
;
}
if
(
ret_nread
)
*
ret_nread
=
buflen
-
nleft
;
return
0
;
}
/* Check that forking won't return the same random. */
static
void
check_forking
(
void
)
{
#ifdef HAVE_W32_SYSTEM
if
(
verbose
)
inf
(
"check_forking skipped: not applicable on Windows
\n
"
);
#else
/*!HAVE_W32_SYSTEM*/
pid_t
pid
;
int
rp
[
2
];
int
i
,
status
;
size_t
nread
;
char
tmp1
[
16
],
tmp1c
[
16
],
tmp1p
[
16
];
if
(
verbose
)
inf
(
"checking that a fork won't cause the same random output
\n
"
);
/* We better make sure that the RNG has been initialzied. */
gcry_randomize
(
tmp1
,
sizeof
tmp1
,
GCRY_STRONG_RANDOM
);
if
(
verbose
)
print_hex
(
"initial random: "
,
tmp1
,
sizeof
tmp1
);
if
(
pipe
(
rp
)
==
-1
)
die
(
"pipe failed: %s
\n
"
,
strerror
(
errno
));
pid
=
fork
();
if
(
pid
==
(
pid_t
)(
-1
))
die
(
"fork failed: %s
\n
"
,
strerror
(
errno
));
if
(
!
pid
)
{
gcry_randomize
(
tmp1c
,
sizeof
tmp1c
,
GCRY_STRONG_RANDOM
);
if
(
writen
(
rp
[
1
],
tmp1c
,
sizeof
tmp1c
))
die
(
"write failed: %s
\n
"
,
strerror
(
errno
));
if
(
verbose
)
{
print_hex
(
" child random: "
,
tmp1c
,
sizeof
tmp1c
);
fflush
(
stdout
);
}
_exit
(
0
);
}
gcry_randomize
(
tmp1p
,
sizeof
tmp1p
,
GCRY_STRONG_RANDOM
);
if
(
verbose
)
print_hex
(
" parent random: "
,
tmp1p
,
sizeof
tmp1p
);
close
(
rp
[
1
]);
if
(
readn
(
rp
[
0
],
tmp1c
,
sizeof
tmp1c
,
&
nread
))
die
(
"read failed: %s
\n
"
,
strerror
(
errno
));
if
(
nread
!=
sizeof
tmp1c
)
die
(
"read too short
\n
"
);
while
(
(
i
=
waitpid
(
pid
,
&
status
,
0
))
==
-1
&&
errno
==
EINTR
)
;
if
(
i
!=
(
pid_t
)(
-1
)
&&
WIFEXITED
(
status
)
&&
!
WEXITSTATUS
(
status
))
;
else
die
(
"child failed
\n
"
);
if
(
!
memcmp
(
tmp1p
,
tmp1c
,
sizeof
tmp1c
))
die
(
"parent and child got the same random number
\n
"
);
#endif
/*!HAVE_W32_SYSTEM*/
}
/* Check that forking won't return the same nonce. */
static
void
check_nonce_forking
(
void
)
{
#ifdef HAVE_W32_SYSTEM
if
(
verbose
)
inf
(
"check_nonce_forking skipped: not applicable on Windows
\n
"
);
#else
/*!HAVE_W32_SYSTEM*/
pid_t
pid
;
int
rp
[
2
];
int
i
,
status
;
size_t
nread
;
char
nonce1
[
10
],
nonce1c
[
10
],
nonce1p
[
10
];
if
(
verbose
)
inf
(
"checking that a fork won't cause the same nonce output
\n
"
);
/* We won't get the same nonce back if we never initialized the
nonce subsystem, thus we get one nonce here and forget about
it. */
gcry_create_nonce
(
nonce1
,
sizeof
nonce1
);
if
(
verbose
)
print_hex
(
"initial nonce: "
,
nonce1
,
sizeof
nonce1
);
if
(
pipe
(
rp
)
==
-1
)
die
(
"pipe failed: %s
\n
"
,
strerror
(
errno
));
pid
=
fork
();
if
(
pid
==
(
pid_t
)(
-1
))
die
(
"fork failed: %s
\n
"
,
strerror
(
errno
));
if
(
!
pid
)
{
gcry_create_nonce
(
nonce1c
,
sizeof
nonce1c
);
if
(
writen
(
rp
[
1
],
nonce1c
,
sizeof
nonce1c
))
die
(
"write failed: %s
\n
"
,
strerror
(
errno
));
if
(
verbose
)
{
print_hex
(
" child nonce: "
,
nonce1c
,
sizeof
nonce1c
);
fflush
(
stdout
);
}
_exit
(
0
);
}
gcry_create_nonce
(
nonce1p
,
sizeof
nonce1p
);
if
(
verbose
)
print_hex
(
" parent nonce: "
,
nonce1p
,
sizeof
nonce1p
);
close
(
rp
[
1
]);
if
(
readn
(
rp
[
0
],
nonce1c
,
sizeof
nonce1c
,
&
nread
))
die
(
"read failed: %s
\n
"
,
strerror
(
errno
));
if
(
nread
!=
sizeof
nonce1c
)
die
(
"read too short
\n
"
);
while
(
(
i
=
waitpid
(
pid
,
&
status
,
0
))
==
-1
&&
errno
==
EINTR
)
;
if
(
i
!=
(
pid_t
)(
-1
)
&&
WIFEXITED
(
status
)
&&
!
WEXITSTATUS
(
status
))
;
else
die
(
"child failed
\n
"
);
if
(
!
memcmp
(
nonce1p
,
nonce1c
,
sizeof
nonce1c
))
die
(
"parent and child got the same nonce
\n
"
);
#endif
/*!HAVE_W32_SYSTEM*/
}
/* Check that a closed random device os re-opened if needed. */
static
void
check_close_random_device
(
void
)
{
#ifdef HAVE_W32_SYSTEM
if
(
verbose
)
inf
(
"check_close_random_device skipped: not applicable on Windows
\n
"
);
#else
/*!HAVE_W32_SYSTEM*/
pid_t
pid
;
int
i
,
status
;
char
buf
[
4
];
if
(
verbose
)
inf
(
"checking that close_random_device works
\n
"
);
gcry_randomize
(
buf
,
sizeof
buf
,
GCRY_STRONG_RANDOM
);
if
(
verbose
)
print_hex
(
"parent random: "
,
buf
,
sizeof
buf
);
pid
=
fork
();
if
(
pid
==
(
pid_t
)(
-1
))
die
(
"fork failed: %s
\n
"
,
strerror
(
errno
));
if
(
!
pid
)
{
gcry_control
(
GCRYCTL_CLOSE_RANDOM_DEVICE
,
0
);
/* The next call will re-open the device. */
gcry_randomize
(
buf
,
sizeof
buf
,
GCRY_STRONG_RANDOM
);
if
(
verbose
)
{
print_hex
(
"child random : "
,
buf
,
sizeof
buf
);
fflush
(
stdout
);
}
_exit
(
0
);
}
while
(
(
i
=
waitpid
(
pid
,
&
status
,
0
))
==
-1
&&
errno
==
EINTR
)
;
if
(
i
!=
(
pid_t
)(
-1
)
&&
WIFEXITED
(
status
)
&&
!
WEXITSTATUS
(
status
))
;
else
die
(
"child failed
\n
"
);
#endif
/*!HAVE_W32_SYSTEM*/
}
static
int
rng_type
(
void
)
{
int
rngtype
;
if
(
gcry_control
(
GCRYCTL_GET_CURRENT_RNG_TYPE
,
&
rngtype
))
die
(
"retrieving RNG type failed
\n
"
);
return
rngtype
;
}
static
void
check_rng_type_switching
(
void
)
{
int
rngtype
,
initial
;
char
tmp1
[
4
];
if
(
verbose
)
inf
(
"checking whether RNG type switching works
\n
"
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
initial
=
rngtype
;
gcry_randomize
(
tmp1
,
sizeof
tmp1
,
GCRY_STRONG_RANDOM
);
if
(
debug
)
print_hex
(
" sample: "
,
tmp1
,
sizeof
tmp1
);
if
(
rngtype
!=
rng_type
())
die
(
"RNG type unexpectedly changed
\n
"
);
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_SYSTEM
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
if
(
rngtype
!=
initial
)
die
(
"switching to System RNG unexpectedly succeeded
\n
"
);
gcry_randomize
(
tmp1
,
sizeof
tmp1
,
GCRY_STRONG_RANDOM
);
if
(
debug
)
print_hex
(
" sample: "
,
tmp1
,
sizeof
tmp1
);
if
(
rngtype
!=
rng_type
())
die
(
"RNG type unexpectedly changed
\n
"
);
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_FIPS
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
if
(
rngtype
!=
initial
)
die
(
"switching to FIPS RNG unexpectedly succeeded
\n
"
);
gcry_randomize
(
tmp1
,
sizeof
tmp1
,
GCRY_STRONG_RANDOM
);
if
(
debug
)
print_hex
(
" sample: "
,
tmp1
,
sizeof
tmp1
);
if
(
rngtype
!=
rng_type
())
die
(
"RNG type unexpectedly changed
\n
"
);
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_STANDARD
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
if
(
rngtype
!=
GCRY_RNG_TYPE_STANDARD
)
die
(
"switching to standard RNG failed
\n
"
);
gcry_randomize
(
tmp1
,
sizeof
tmp1
,
GCRY_STRONG_RANDOM
);
if
(
debug
)
print_hex
(
" sample: "
,
tmp1
,
sizeof
tmp1
);
if
(
rngtype
!=
rng_type
())
die
(
"RNG type unexpectedly changed
\n
"
);
}
static
void
check_early_rng_type_switching
(
void
)
{
int
rngtype
,
initial
;
if
(
verbose
)
inf
(
"checking whether RNG type switching works in the early stage
\n
"
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
initial
=
rngtype
;
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_SYSTEM
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
if
(
initial
>=
GCRY_RNG_TYPE_SYSTEM
&&
rngtype
!=
GCRY_RNG_TYPE_SYSTEM
)
die
(
"switching to System RNG failed
\n
"
);
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_FIPS
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
if
(
initial
>=
GCRY_RNG_TYPE_FIPS
&&
rngtype
!=
GCRY_RNG_TYPE_FIPS
)
die
(
"switching to FIPS RNG failed
\n
"
);
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_STANDARD
);
rngtype
=
rng_type
();
if
(
debug
)
inf
(
"rng type: %d
\n
"
,
rngtype
);
if
(
rngtype
!=
GCRY_RNG_TYPE_STANDARD
)
die
(
"switching to standard RNG failed
\n
"
);
}
/* Because we want to check initialization behaviour, we need to
fork/exec this program with several command line arguments. We use
system, so that these tests work also on Windows. */
static
void
run_all_rng_tests
(
const
char
*
program
)
{
static
const
char
*
options
[]
=
{
"--early-rng-check"
,
"--early-rng-check --prefer-standard-rng"
,
"--early-rng-check --prefer-fips-rng"
,
"--early-rng-check --prefer-system-rng"
,
"--prefer-standard-rng"
,
"--prefer-fips-rng"
,
"--prefer-system-rng"
,
NULL
};
int
idx
;
size_t
len
,
maxlen
;
char
*
cmdline
;
maxlen
=
0
;
for
(
idx
=
0
;
options
[
idx
];
idx
++
)
{
len
=
strlen
(
options
[
idx
]);
if
(
len
>
maxlen
)
maxlen
=
len
;
}
maxlen
+=
strlen
(
program
);
maxlen
+=
strlen
(
" --in-recursion --verbose --debug --progress"
);
maxlen
++
;
cmdline
=
malloc
(
maxlen
+
1
);
if
(
!
cmdline
)
die
(
"out of core
\n
"
);
for
(
idx
=
0
;
options
[
idx
];
idx
++
)
{
if
(
verbose
)
inf
(
"now running with options '%s'
\n
"
,
options
[
idx
]);
strcpy
(
cmdline
,
program
);
strcat
(
cmdline
,
" --in-recursion"
);
if
(
verbose
)
strcat
(
cmdline
,
" --verbose"
);
if
(
debug
)
strcat
(
cmdline
,
" --debug"
);
if
(
with_progress
)
strcat
(
cmdline
,
" --progress"
);
strcat
(
cmdline
,
" "
);
strcat
(
cmdline
,
options
[
idx
]);
if
(
system
(
cmdline
))
die
(
"running '%s' failed
\n
"
,
cmdline
);
}
free
(
cmdline
);
}
int
main
(
int
argc
,
char
**
argv
)
{
int
last_argc
=
-1
;
int
early_rng
=
0
;
int
in_recursion
=
0
;
const
char
*
program
=
NULL
;
if
(
argc
)
{
program
=
*
argv
;
argc
--
;
argv
++
;
}
else
die
(
"argv[0] missing
\n
"
);
while
(
argc
&&
last_argc
!=
argc
)
{
last_argc
=
argc
;
if
(
!
strcmp
(
*
argv
,
"--"
))
{
argc
--
;
argv
++
;
break
;
}
else
if
(
!
strcmp
(
*
argv
,
"--help"
))
{
fputs
(
"usage: random [options]
\n
"
,
stdout
);
exit
(
0
);
}
else
if
(
!
strcmp
(
*
argv
,
"--verbose"
))
{
verbose
=
1
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--debug"
))
{
debug
=
verbose
=
1
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--progress"
))
{
argc
--
;
argv
++
;
with_progress
=
1
;
}
else
if
(
!
strcmp
(
*
argv
,
"--in-recursion"
))
{
in_recursion
=
1
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--early-rng-check"
))
{
early_rng
=
1
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--prefer-standard-rng"
))
{
/* This is anyway the default, but we may want to use it for
debugging. */
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_STANDARD
);
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--prefer-fips-rng"
))
{
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_FIPS
);
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--prefer-system-rng"
))
{
gcry_control
(
GCRYCTL_SET_PREFERRED_RNG_TYPE
,
GCRY_RNG_TYPE_SYSTEM
);
argc
--
;
argv
++
;
}
}
#ifndef HAVE_W32_SYSTEM
signal
(
SIGPIPE
,
SIG_IGN
);
#endif
if
(
early_rng
)
check_early_rng_type_switching
();
gcry_control
(
GCRYCTL_DISABLE_SECMEM
,
0
);
if
(
!
gcry_check_version
(
GCRYPT_VERSION
))
die
(
"version mismatch
\n
"
);
if
(
with_progress
)
gcry_set_progress_handler
(
progress_cb
,
NULL
);
gcry_control
(
GCRYCTL_INITIALIZATION_FINISHED
,
0
);
if
(
debug
)
gcry_control
(
GCRYCTL_SET_DEBUG_FLAGS
,
1u
,
0
);
if
(
!
in_recursion
)
{
check_forking
();
check_nonce_forking
();
check_close_random_device
();
}
check_rng_type_switching
();
if
(
!
in_recursion
)
run_all_rng_tests
(
program
);
return
0
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Nov 6, 3:19 PM (1 d, 1 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f0/3c/264b9fb7a57bbf833d1bac1615a0
Attached To
rC libgcrypt
Event Timeline
Log In to Comment