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