2 * Copyright (C) 2008, 2010 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 /* Here is the libgcrypt random generator layer.
28 #include <gnutls_int.h>
29 #include <gnutls_errors.h>
30 #include <gnutls_num.h>
31 #include <nettle/yarrow.h>
34 #include <sys/types.h>
42 static void* rnd_mutex
;
44 #define RND_LOCK if (gnutls_mutex_lock(rnd_mutex)!=0) abort()
45 #define RND_UNLOCK if (gnutls_mutex_unlock(rnd_mutex)!=0) abort()
48 RANDOM_SOURCE_TRIVIA
=0,
52 static struct yarrow256_ctx yctx
;
53 static struct yarrow_source ysources
[SOURCES
];
54 static time_t device_last_read
= 0;
57 static time_t trivia_previous_time
= 0;
58 static time_t trivia_time_count
= 0;
60 static int do_trivia_source(int init
)
73 if (gettimeofday(&event
.now
, NULL
) < 0) {
74 _gnutls_debug_log("gettimeofday failed: %s\n", strerror(errno
));
78 if (getrusage(RUSAGE_SELF
, &event
.rusage
) < 0) {
79 _gnutls_debug_log("getrusage failed: %s\n", strerror(errno
));
86 trivia_time_count
= 0;
88 event
.count
= trivia_time_count
++;
90 if (event
.now
.tv_sec
!= trivia_previous_time
) {
91 /* Count one bit of entropy if we either have more than two
92 * invocations in one second, or more than two seconds
93 * between invocations. */
94 if ((trivia_time_count
> 2)
95 || ((event
.now
.tv_sec
- trivia_previous_time
) > 2))
98 trivia_time_count
= 0;
101 trivia_previous_time
= event
.now
.tv_sec
;
102 event
.pid
= getpid();
104 return yarrow256_update(&yctx
, RANDOM_SOURCE_TRIVIA
, entropy
,
105 sizeof(event
), (const uint8_t *) &event
);
108 #define DEVICE_READ_SIZE 16
109 #define DEVICE_READ_SIZE_MAX 32
110 #define DEVICE_READ_INTERVAL 360
111 static int do_device_source(int init
)
113 time_t now
= time(NULL
);
114 int read_size
= DEVICE_READ_SIZE
;
119 device_fd
= open("/dev/urandom", O_RDONLY
);
121 _gnutls_debug_log("Cannot open urandom!\n");
125 old
= fcntl(device_fd
, F_GETFD
);
126 fcntl(device_fd
, F_SETFD
, old
| 1);
127 device_last_read
= now
;
129 read_size
= DEVICE_READ_SIZE_MAX
; /* initially read more data */
133 && (init
|| ((now
- device_last_read
) > DEVICE_READ_INTERVAL
))) {
135 /* More than a minute since we last read the device */
136 uint8_t buf
[DEVICE_READ_SIZE_MAX
];
139 for (done
= 0; done
< read_size
;) {
143 read(device_fd
, buf
+ done
, sizeof(buf
) - done
);
144 while (res
< 0 && errno
== EINTR
);
148 _gnutls_debug_log("Failed to read /dev/urandom: %s\n",
152 ("Failed to read /dev/urandom: end of file\n");
161 device_last_read
= now
;
162 return yarrow256_update(&yctx
, RANDOM_SOURCE_DEVICE
, read_size
*8/3 /* be more conservative */,
168 static void wrap_nettle_rnd_deinit(void* ctx
)
175 static int wrap_nettle_rnd_init(void **ctx
)
179 if (gnutls_mutex_init
)
181 ret
= gnutls_mutex_init(&rnd_mutex
);
189 yarrow256_init(&yctx
, SOURCES
, ysources
);
193 yarrow256_slow_reseed(&yctx
);
201 wrap_nettle_rnd(void *_ctx
, int level
, void *data
, size_t datasize
)
204 do_trivia_source( 0);
205 do_device_source( 0);
207 yarrow256_random(&yctx
, datasize
, data
);
212 int crypto_rnd_prio
= INT_MAX
;
214 gnutls_crypto_rnd_st _gnutls_rnd_ops
= {
215 .init
= wrap_nettle_rnd_init
,
216 .deinit
= wrap_nettle_rnd_deinit
,
217 .rnd
= wrap_nettle_rnd
,