Skip to content

Instantly share code, notes, and snippets.

@tiran
Last active August 16, 2017 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiran/a9ba8c51cc7d1b75d3bc1d3f24411b4c to your computer and use it in GitHub Desktop.
Save tiran/a9ba8c51cc7d1b75d3bc1d3f24411b4c to your computer and use it in GitHub Desktop.
OpenSSL CPRNG RAND_bytes() and pid wrap-around demo
/* Demo for repeated CPRNG output after pid wrap around
*
* Christian Heimes <christian@python.org>
*
*
* $ gcc -lcrypto openssl_rng.c -o openssl_rng
* $ ./openssl_rng
* $ head -n1 rng.txt
* 29104: 76949c6012516ca3
* $ egrep '2920.+:' rng.txt
* 29200: 8328d6d9b0f7a71d
* 29201: a1153ec9674286a3
* ...
* 29200: 8328d6d9b0f7a71d
* 29201: a1153ec9674286a3
*
* Link with OpenSSL git:
* $ gcc -Iinclude -L. -Wl,-rpath,. -lcrypto -DENABLE_ATFORK openssl_rng.c -o openssl_rng
*
*/
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>
#define RNGSIZE 8
int
tohex(char *inbuf, char *outbuf, size_t len)
{
static const char *hexdigits = "0123456789abcdef";
size_t i, j;
for (i=j=0; i < len; i++) {
unsigned char c;
c = (inbuf[i] >> 4) & 0xf;
outbuf[j++] = hexdigits[c];
c = inbuf[i] & 0xf;
outbuf[j++] = hexdigits[c];
}
return 0;
}
int
main(int args, char *argv[])
{
char buf[RNGSIZE];
char hex[2*RNGSIZE];
int i, fd, status;
pid_t pid;
fd = open("rng.txt", O_WRONLY | O_CREAT, 0640);
if (fd < 0) {
perror("rng.txt");
return 1;
}
#if ENABLE_ATFORK
printf("Enabling OPENSSL_INIT_ATFORK\n");
OPENSSL_init_crypto(OPENSSL_INIT_ATFORK, NULL);
#else
printf("OPENSSL_INIT_ATFORK is not enabled\n");
#endif
/* initialize RNG */
RAND_bytes(buf, RNGSIZE);
/* /proc/sys/kernel/pid_max is usually 32768 */
for (i=0; i < 34000; i++) {
if (i && (i % 1000) == 0) {
fprintf(stderr, ".");
}
pid = fork();
if (pid == 0) {
/* child */
RAND_bytes(buf, RNGSIZE);
tohex(buf, hex, sizeof(buf));
dprintf(fd, "%lu: %.*s\n", getpid(), sizeof(hex), hex);
#if 1
if (i < 10) {
fprintf(stderr, "%lu: %.*s\n", getpid(), sizeof(hex), hex);
}
#endif
_exit(0);
} else {
/* wait for child to terminate */
waitpid(pid, &status, 0);
}
}
fprintf(stderr, "\nDone, see rng.txt\n");
close(fd);
return 0;
}
@tiran
Copy link
Author

tiran commented May 3, 2016

$ gcc -lcrypto openssl_rng.c -o openssl_rng
$ ./openssl_rng

$ head -n1 rng.txt
29104: 76949c6012516ca3

$ egrep '2920.+:' rng.txt
29200: 8328d6d9b0f7a71d
29201: a1153ec9674286a3
29202: b0211bc6762561e6
29203: ae9814b39264281d
29204: 647062936ec293dc
29205: 38834f27d8fcf702
29206: 519b28497de9db99
29207: 2d73c41467a4a874
29208: 866ad3c4a7b799ef
29209: eb5ed09fc62c0afc
29200: 8328d6d9b0f7a71d
29201: a1153ec9674286a3
29202: b0211bc6762561e6
29203: ae9814b39264281d
29204: 647062936ec293dc
29205: 38834f27d8fcf702
29206: 519b28497de9db99
29207: 2d73c41467a4a874
29208: 866ad3c4a7b799ef
29209: eb5ed09fc62c0afc

$ wc -l rng.txt
34000 rng.txt

$ sort < rng.txt | uniq | wc -l
31505
$ openssl version
OpenSSL 1.0.2g-fips  1 Mar 2016
$ rpm -qa openssl
openssl-1.0.2g-2.fc23.x86_64
$ gcc --version
gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Copyright (C) 2015 Free Software Foundation, Inc.
$ uname -m
x86_64

@tiran
Copy link
Author

tiran commented Aug 16, 2017

OpenSSL 1.1.1's OPENSSL_INIT_ATFORK fixes the issue, https://www.openssl.org/blog/blog/2017/08/12/random/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment