1 /*******************************************************************************
2 This file is part of LibTMCG.
3
4 Copyright (C) 2002, 2004, 2005, 2007,
5 2016, 2017, 2018, 2019 Heiko Stamer <HeikoStamer@gmx.net>
6
7 LibTMCG is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 LibTMCG is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with LibTMCG; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *******************************************************************************/
21
22 // include headers
23 #ifdef HAVE_CONFIG_H
24 #include "libTMCG_config.h"
25 #endif
26 #include "mpz_srandom.hh"
27
28 // additional headers
29 #include <cstring>
30 #include <cassert>
31 #include <climits>
32 #include <iostream>
33 #include <stdexcept>
34
35 // GNU crypto library
36 #include <gcrypt.h>
37
38 #ifdef BOTAN
39 // Random number generators from Botan cryptographic library
40 #include <botan/auto_rng.h>
41 #include <botan/rng.h>
42 #endif
43
44
tmcg_mpz_grandom_ui(enum gcry_random_level level)45 unsigned long int tmcg_mpz_grandom_ui
46 (enum gcry_random_level level)
47 {
48 unsigned long int tmp = 0;
49 if (level == GCRY_WEAK_RANDOM)
50 gcry_create_nonce((unsigned char*)&tmp, sizeof(tmp));
51 else
52 gcry_randomize((unsigned char*)&tmp, sizeof(tmp), level);
53 #ifdef BOTAN
54 std::unique_ptr<Botan::RandomNumberGenerator>
55 rng(new Botan::AutoSeeded_RNG);
56 unsigned long int botan_tmp = 0;
57 rng->randomize((uint8_t*)&botan_tmp, sizeof(botan_tmp));
58 if (tmp != botan_tmp)
59 tmp ^= botan_tmp; // XOR both random sources
60 #endif
61 return tmp;
62 }
63
tmcg_mpz_grandom_ui_nomodbias(enum gcry_random_level level,const unsigned long int modulo)64 unsigned long int tmcg_mpz_grandom_ui_nomodbias
65 (enum gcry_random_level level, const unsigned long int modulo)
66 {
67 unsigned long int div, max, rnd = 0;
68
69 if ((modulo == 0) || (modulo == 1))
70 throw std::invalid_argument("tmcg_mpz_grandom_ui_nomodbias: bad modulo");
71
72 // Remove ``modulo bias'' by limiting the return values
73 div = (ULONG_MAX - modulo + 1) / modulo;
74 max = ((div + 1) * modulo) - 1;
75 do
76 rnd = tmcg_mpz_grandom_ui(level);
77 while (rnd > max);
78
79 return rnd;
80 }
81
tmcg_mpz_ssrandom_ui()82 unsigned long int tmcg_mpz_ssrandom_ui
83 ()
84 {
85 return tmcg_mpz_grandom_ui(GCRY_VERY_STRONG_RANDOM);
86 }
87
tmcg_mpz_srandom_ui()88 unsigned long int tmcg_mpz_srandom_ui
89 ()
90 {
91 return tmcg_mpz_grandom_ui(GCRY_STRONG_RANDOM);
92 }
93
tmcg_mpz_wrandom_ui()94 unsigned long int tmcg_mpz_wrandom_ui
95 ()
96 {
97 return tmcg_mpz_grandom_ui(GCRY_WEAK_RANDOM);
98 }
99
tmcg_mpz_ssrandom_mod(const unsigned long int modulo)100 unsigned long int tmcg_mpz_ssrandom_mod
101 (const unsigned long int modulo)
102 {
103 unsigned long int t = 0;
104 t = tmcg_mpz_grandom_ui_nomodbias(GCRY_VERY_STRONG_RANDOM, modulo) % modulo;
105 return t;
106 }
107
tmcg_mpz_srandom_mod(const unsigned long int modulo)108 unsigned long int tmcg_mpz_srandom_mod
109 (const unsigned long int modulo)
110 {
111 return tmcg_mpz_grandom_ui_nomodbias(GCRY_STRONG_RANDOM, modulo) % modulo;
112 }
113
tmcg_mpz_wrandom_mod(const unsigned long int modulo)114 unsigned long int tmcg_mpz_wrandom_mod
115 (const unsigned long int modulo)
116 {
117 return tmcg_mpz_grandom_ui_nomodbias(GCRY_WEAK_RANDOM, modulo) % modulo;
118 }
119
tmcg_mpz_grandomb(mpz_ptr r,const unsigned long int size,enum gcry_random_level level)120 void tmcg_mpz_grandomb
121 (mpz_ptr r, const unsigned long int size, enum gcry_random_level level)
122 {
123 if (size > 0)
124 {
125 unsigned char tmp[(size+7)/8];
126 gcry_randomize(tmp, (size+7)/8, level);
127 mpz_import(r, (size+7)/8, 1, 1, 1, 0, (const void*)tmp);
128 #ifdef BOTAN
129 std::unique_ptr<Botan::RandomNumberGenerator>
130 rng(new Botan::AutoSeeded_RNG);
131 rng->randomize((uint8_t*)tmp, (size+7)/8);
132 mpz_t rrr;
133 mpz_init(rrr);
134 mpz_import(rrr, (size+7)/8, 1, 1, 1, 0, (const void*)tmp);
135 mpz_add(r, r, rrr); // ADD number from other random source
136 mpz_clear(rrr);
137 #endif
138 // r mod 2^size, i.e. shift right and bit mask
139 mpz_tdiv_r_2exp(r, r, size);
140 }
141 else
142 throw std::invalid_argument("tmcg_mpz_grandomb: size is zero");
143 }
144
tmcg_mpz_ssrandomb(mpz_ptr r,const unsigned long int size)145 void tmcg_mpz_ssrandomb
146 (mpz_ptr r, const unsigned long int size)
147 {
148 FILE *fhd = fopen("/proc/sys/kernel/random/entropy_avail", "r");
149 if (fhd != NULL)
150 {
151 unsigned long int entropy_avail = 0;
152 if (fscanf(fhd, "%lu", &entropy_avail) != 1)
153 entropy_avail = 0;
154 fclose(fhd);
155 if (entropy_avail < size)
156 {
157 std::cerr << "tmcg_mpz_ssrandomb(): too few entropy (" <<
158 entropy_avail << " bits) available; blocking" << std::endl;
159 }
160 }
161 tmcg_mpz_grandomb(r, size, GCRY_VERY_STRONG_RANDOM);
162 }
163
tmcg_mpz_srandomb(mpz_ptr r,const unsigned long int size)164 void tmcg_mpz_srandomb
165 (mpz_ptr r, const unsigned long int size)
166 {
167 tmcg_mpz_grandomb(r, size, GCRY_STRONG_RANDOM);
168 }
169
tmcg_mpz_wrandomb(mpz_ptr r,const unsigned long int size)170 void tmcg_mpz_wrandomb
171 (mpz_ptr r, const unsigned long int size)
172 {
173 tmcg_mpz_grandomb(r, size, GCRY_WEAK_RANDOM);
174 }
175
tmcg_mpz_grandomm(mpz_ptr r,mpz_srcptr m,enum gcry_random_level level)176 void tmcg_mpz_grandomm
177 (mpz_ptr r, mpz_srcptr m, enum gcry_random_level level)
178 {
179 // make bias negligible cf. BSI TR-02102-1, B.4 Verfahren 2
180 unsigned long int nbytes = (mpz_sizeinbase(m, 2UL) + 64 + 7) / 8;
181 unsigned char tmp[nbytes];
182 gcry_randomize(tmp, nbytes, level);
183 mpz_import(r, nbytes, 1, 1, 1, 0, (const void*)tmp);
184 #ifdef BOTAN
185 std::unique_ptr<Botan::RandomNumberGenerator>
186 rng(new Botan::AutoSeeded_RNG);
187 rng->randomize((uint8_t*)tmp, nbytes);
188 mpz_t rrr;
189 mpz_init(rrr);
190 mpz_import(rrr, nbytes, 1, 1, 1, 0, (const void*)tmp);
191 mpz_add(r, r, rrr); // ADD number from other random source
192 mpz_clear(rrr);
193 #endif
194 mpz_mod(r, r, m); // bias is negligible due to increased size of r
195 }
196
tmcg_mpz_ssrandomm(mpz_ptr r,mpz_srcptr m)197 void tmcg_mpz_ssrandomm
198 (mpz_ptr r, mpz_srcptr m)
199 {
200 FILE *fhd = fopen("/proc/sys/kernel/random/entropy_avail", "r");
201 if (fhd != NULL)
202 {
203 unsigned long int entropy_avail = 0;
204 if (fscanf(fhd, "%lu", &entropy_avail) != 1)
205 entropy_avail = 0;
206 fclose(fhd);
207 if (entropy_avail < mpz_sizeinbase(m, 2UL))
208 {
209 std::cerr << "tmcg_mpz_ssrandomm(): too few entropy (" <<
210 entropy_avail << " bits) available; blocking" << std::endl;
211 }
212 }
213 tmcg_mpz_grandomm(r, m, GCRY_VERY_STRONG_RANDOM);
214 }
215
tmcg_mpz_srandomm(mpz_ptr r,mpz_srcptr m)216 void tmcg_mpz_srandomm
217 (mpz_ptr r, mpz_srcptr m)
218 {
219 tmcg_mpz_grandomm(r, m, GCRY_STRONG_RANDOM);
220 }
221
tmcg_mpz_wrandomm(mpz_ptr r,mpz_srcptr m)222 void tmcg_mpz_wrandomm
223 (mpz_ptr r, mpz_srcptr m)
224 {
225 tmcg_mpz_grandomm(r, m, GCRY_WEAK_RANDOM);
226 }
227
tmcg_mpz_ssrandomm_cache_init(mpz_t ssrandomm_cache[TMCG_MAX_SSRANDOMM_CACHE],mpz_ptr ssrandomm_cache_mod,size_t & ssrandomm_cache_avail,const size_t n,mpz_srcptr m)228 void tmcg_mpz_ssrandomm_cache_init
229 (mpz_t ssrandomm_cache[TMCG_MAX_SSRANDOMM_CACHE],
230 mpz_ptr ssrandomm_cache_mod,
231 size_t &ssrandomm_cache_avail,
232 const size_t n,
233 mpz_srcptr m)
234 {
235 size_t i = 0;
236 if ((n == 0) || (n > TMCG_MAX_SSRANDOMM_CACHE))
237 throw std::invalid_argument("tmcg_mpz_ssrandomm_cache_init: bad n");
238 for (i = 0; i < TMCG_MAX_SSRANDOMM_CACHE; i++)
239 mpz_init(ssrandomm_cache[i]);
240 for (i = 0; i < n; i++)
241 tmcg_mpz_ssrandomm(ssrandomm_cache[i], m);
242 mpz_init_set(ssrandomm_cache_mod, m);
243 ssrandomm_cache_avail = n;
244 }
245
tmcg_mpz_ssrandomm_cache(mpz_t ssrandomm_cache[TMCG_MAX_SSRANDOMM_CACHE],mpz_srcptr ssrandomm_cache_mod,size_t & ssrandomm_cache_avail,mpz_ptr r,mpz_srcptr m)246 void tmcg_mpz_ssrandomm_cache
247 (mpz_t ssrandomm_cache[TMCG_MAX_SSRANDOMM_CACHE],
248 mpz_srcptr ssrandomm_cache_mod,
249 size_t &ssrandomm_cache_avail,
250 mpz_ptr r,
251 mpz_srcptr m)
252 {
253 if (!mpz_cmp(m, ssrandomm_cache_mod) && (ssrandomm_cache_avail > 0))
254 {
255 ssrandomm_cache_avail--; // next cached random value
256 mpz_set(r, ssrandomm_cache[ssrandomm_cache_avail]);
257 }
258 else
259 tmcg_mpz_ssrandomm(r, m);
260 }
261
tmcg_mpz_ssrandomm_cache_done(mpz_t ssrandomm_cache[TMCG_MAX_SSRANDOMM_CACHE],mpz_ptr ssrandomm_cache_mod,size_t & ssrandomm_cache_avail)262 void tmcg_mpz_ssrandomm_cache_done
263 (mpz_t ssrandomm_cache[TMCG_MAX_SSRANDOMM_CACHE],
264 mpz_ptr ssrandomm_cache_mod,
265 size_t &ssrandomm_cache_avail)
266 {
267 size_t i = 0;
268 ssrandomm_cache_avail = 0;
269 mpz_clear(ssrandomm_cache_mod);
270 for (i = 0; i < TMCG_MAX_SSRANDOMM_CACHE; i++)
271 mpz_clear(ssrandomm_cache[i]);
272 }
273
274