1
2 /***************************************************************************
3 *
4 Copyright 2012 CertiVox IOM Ltd. *
5 *
6 This file is part of CertiVox MIRACL Crypto SDK. *
7 *
8 The CertiVox MIRACL Crypto SDK provides developers with an *
9 extensive and efficient set of cryptographic functions. *
10 For further information about its features and functionalities please *
11 refer to http://www.certivox.com *
12 *
13 * The CertiVox MIRACL Crypto SDK is free software: you can *
14 redistribute it and/or modify it under the terms of the *
15 GNU Affero General Public License as published by the *
16 Free Software Foundation, either version 3 of the License, *
17 or (at your option) any later version. *
18 *
19 * The CertiVox MIRACL Crypto SDK is distributed in the hope *
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the *
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
22 See the GNU Affero General Public License for more details. *
23 *
24 * You should have received a copy of the GNU Affero General Public *
25 License along with CertiVox MIRACL Crypto SDK. *
26 If not, see <http://www.gnu.org/licenses/>. *
27 *
28 You can be released from the requirements of the license by purchasing *
29 a commercial license. Buying such a license is mandatory as soon as you *
30 develop commercial activities involving the CertiVox MIRACL Crypto SDK *
31 without disclosing the source code of your own applications, or shipping *
32 the CertiVox MIRACL Crypto SDK with a closed source product. *
33 *
34 ***************************************************************************/
35 /*
36 * MIRACL cryptographic strong random number generator
37 * mrstrong.c
38 *
39 * Unguessable seed -> SHA -> PRNG internal state -> SHA -> random numbers
40 * Slow - but secure
41 *
42 * See ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf for a justification
43 */
44
45 #include "miracl.h"
46
47 #ifndef MR_NO_RAND
48
sbrand(csprng * rng)49 static mr_unsign32 sbrand(csprng *rng)
50 { /* Marsaglia & Zaman random number generator */
51 int i,k;
52 mr_unsign32 pdiff,t;
53 rng->rndptr++;
54 if (rng->rndptr<NK) return rng->ira[rng->rndptr];
55 rng->rndptr=0;
56 for (i=0,k=NK-NJ;i<NK;i++,k++)
57 { /* calculate next NK values */
58 if (k==NK) k=0;
59 t=rng->ira[k];
60 pdiff=t - rng->ira[i] - rng->borrow;
61 if (pdiff<t) rng->borrow=0;
62 if (pdiff>t) rng->borrow=1;
63 rng->ira[i]=pdiff;
64 }
65 return rng->ira[0];
66 }
67
sirand(csprng * rng,mr_unsign32 seed)68 static void sirand(csprng* rng,mr_unsign32 seed)
69 { /* initialise random number system */
70 /* modified so that a subsequent call "stirs" in another seed value */
71 /* in this way as many seed bits as desired may be used */
72 int i,in;
73 mr_unsign32 t,m=1L;
74 rng->borrow=0L;
75 rng->rndptr=0;
76 rng->ira[0]^=seed;
77 for (i=1;i<NK;i++)
78 { /* fill initialisation vector */
79 in=(NV*i)%NK;
80 rng->ira[in]^=m; /* note XOR */
81 t=m;
82 m=seed-m;
83 seed=t;
84 }
85 for (i=0;i<10000;i++) sbrand(rng ); /* "warm-up" & stir the generator */
86 }
87
fill_pool(csprng * rng)88 static void fill_pool(csprng *rng)
89 { /* hash down output of RNG to re-fill the pool */
90 int i;
91 sha256 sh;
92 shs256_init(&sh);
93 for (i=0;i<128;i++) shs256_process(&sh,sbrand(rng));
94 shs256_hash(&sh,rng->pool);
95 rng->pool_ptr=0;
96 }
97
strong_init(csprng * rng,int rawlen,char * raw,mr_unsign32 tod)98 void strong_init(csprng *rng,int rawlen,char *raw,mr_unsign32 tod)
99 { /* initialise from at least 128 byte string of raw *
100 * random (keyboard?) input, and 32-bit time-of-day */
101 int i;
102 mr_unsign32 hash[MR_HASH_BYTES/4];
103 sha256 sh;
104 rng->pool_ptr=0;
105 for (i=0;i<NK;i++) rng->ira[i]=0;
106 if (rawlen>0)
107 {
108 shs256_init(&sh);
109 for (i=0;i<rawlen;i++)
110 shs256_process(&sh,raw[i]);
111 shs256_hash(&sh,(char *)hash);
112
113 /* initialise PRNG from distilled randomness */
114
115 for (i=0;i<MR_HASH_BYTES/4;i++) sirand(rng,hash[i]);
116 }
117 sirand(rng,tod);
118
119 fill_pool(rng);
120 }
121
strong_kill(csprng * rng)122 void strong_kill(csprng *rng)
123 { /* kill internal state */
124 int i;
125 rng->pool_ptr=rng->rndptr=0;
126 for (i=0;i<MR_HASH_BYTES;i++) rng->pool[i]=0;
127 for (i=0;i<NK;i++) rng->ira[i]=0;
128 rng->borrow=0;
129 }
130
131 /* get random byte */
132
strong_rng(csprng * rng)133 int strong_rng(csprng *rng)
134 {
135 int r;
136 r=rng->pool[rng->pool_ptr++];
137 if (rng->pool_ptr>=MR_HASH_BYTES) fill_pool(rng);
138 return r;
139 }
140
strong_bigrand(_MIPD_ csprng * rng,big w,big x)141 void strong_bigrand(_MIPD_ csprng *rng,big w,big x)
142 {
143 int i, m;
144 mr_small r;
145 unsigned int ran;
146 unsigned int ch;
147
148 #ifdef MR_OS_THREADS
149 miracl *mr_mip=get_mip();
150 #endif
151 if (mr_mip->ERNUM) return;
152 MR_IN(20)
153
154 m = 0;
155 zero(mr_mip->w1);
156
157 do
158 {
159 m++;
160 mr_mip->w1->len=m;
161 for (r = 0, i = 0; i < sizeof(mr_small); i++) {
162 ch=(unsigned char)strong_rng(rng);
163 ran=ch;
164 r = (r << 8) ^ ran;
165 }
166 if (mr_mip->base==0) mr_mip->w1->w[m-1]=r;
167 else mr_mip->w1->w[m-1]=MR_REMAIN(r,mr_mip->base);
168 } while (mr_compare(mr_mip->w1,w)<0);
169 mr_lzero(mr_mip->w1);
170 divide(_MIPP_ mr_mip->w1,w,w);
171
172 copy(mr_mip->w1,x);
173 MR_OUT
174 }
175
strong_bigdig(_MIPD_ csprng * rng,int n,int b,big x)176 void strong_bigdig(_MIPD_ csprng *rng,int n,int b,big x)
177 { /* generate random number n digits long *
178 * to "printable" base b */
179 #ifdef MR_OS_THREADS
180 miracl *mr_mip=get_mip();
181 #endif
182 if (mr_mip->ERNUM) return;
183
184 MR_IN(19)
185
186 if (b<2 || b>256)
187 {
188 mr_berror(_MIPP_ MR_ERR_BASE_TOO_BIG);
189 MR_OUT
190 return;
191 }
192
193 do
194 { /* repeat if x too small */
195 expint(_MIPP_ b,n,mr_mip->w2);
196 strong_bigrand(_MIPP_ rng,mr_mip->w2,x);
197 subdiv(_MIPP_ mr_mip->w2,b,mr_mip->w2);
198 } while (!mr_mip->ERNUM && mr_compare(x,mr_mip->w2)<0);
199
200 MR_OUT
201 }
202
203 #endif
204
205 /* test main program
206
207 #include <stdio.h>
208 #include "miracl.h"
209 #include <time.h>
210
211 void main()
212 {
213 int i;
214 char raw[256];
215 big x,w;
216 time_t seed;
217 csprng rng;
218 miracl *mip=mirsys(200,256);
219 x=mirvar(0);
220 w=mirvar(0);
221 printf("Enter Raw random string= ");
222 scanf("%s",raw);
223 getchar();
224 time(&seed);
225 strong_init(&rng,strlen(raw),raw,(long)seed);
226 mip->IOBASE=16;
227 expint(2,256,w);
228 cotnum(w,stdout);
229 for (i=0;i<20;i++)
230 {
231 strong_bigrand(&rng,w,x);
232 cotnum(x,stdout);
233 }
234 printf("\n");
235 for (i=0;i<20;i++)
236 {
237 strong_bigdig(&rng,128,2,x);
238 cotnum(x,stdout);
239 }
240 }
241
242 */
243
244