1 /*
2 *
3 * Copyright (C) 2018, OFFIS e.V.
4 * All rights reserved. See COPYRIGHT file for details.
5 *
6 * This software and supporting documentation were developed by
7 *
8 * OFFIS e.V.
9 * R&D Division Health
10 * Escherweg 2
11 * D-26121 Oldenburg, Germany
12 *
13 *
14 * Module: ofstd
15 *
16 * Author: Marco Eichelberg, based on the reference implementation
17 * of the ISAAC PRNG by Bob Jenkins (Public Domain).
18 *
19 * Purpose: Cryptographically secure PRNG based on Bob Jenkins's ISAAC algorithm
20 *
21 */
22
23 #include "dcmtk/config/osconfig.h"
24 #include "dcmtk/ofstd/ofrand.h"
25 #include "dcmtk/ofstd/ofcast.h"
26 #include "dcmtk/ofstd/ofstd.h"
27
28 #define INCLUDE_CSTDIO
29 #define INCLUDE_CSTDDEF
30 #define INCLUDE_CTIME
31 #include "dcmtk/ofstd/ofstdinc.h"
32
33 BEGIN_EXTERN_C
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #endif
37 END_EXTERN_C
38
39 #ifdef HAVE_WINDOWS_H
40 #define WIN32_LEAN_AND_MEAN
41 #include <windows.h>
42 #endif
43
44 #define ind(mm,x) ((mm)[(x>>2)&(OFRandom_SIZ-1)])
45
46 #define rngstep(mix,a,b,mm,m,m2,r,x) \
47 { \
48 x = *m; \
49 a = ((a^(mix)) + *(m2++)); \
50 *(m++) = y = (ind(mm,x) + a + b); \
51 *(r++) = b = (ind(mm,y>>OFRandom_SIZL) + x) & 0xffffffff; \
52 }
53
54 #define mix(a,b,c,d,e,f,g,h) \
55 { \
56 a^=b<<11; d+=a; b+=c; \
57 b^=(c&0xffffffff)>>2; e+=b; c+=d; \
58 c^=d<<8; f+=c; d+=e; \
59 d^=(e&0xffffffff)>>16; g+=d; e+=f; \
60 e^=f<<10; h+=e; f+=g; \
61 f^=(g&0xffffffff)>>4; a+=f; g+=h; \
62 g^=h<<8; b+=g; h+=a; \
63 h^=(a&0xffffffff)>>9; c+=h; a+=b; \
64 }
65
OFRandom()66 OFRandom::OFRandom()
67 : randcnt(OFRandom_SIZ)
68 , randrsl()
69 , randmem()
70 , randa(0)
71 , randb(0)
72 , randc(0)
73 {
74 /* initialize randrsl based on the current time, CPU clock count, and process ID */
75 Uint32 tm = OFstatic_cast(Uint32, time(NULL));
76 Uint32 cl = OFstatic_cast(Uint32, clock());
77 Uint32 pi = OFstatic_cast(Uint32, OFStandard::getProcessID());
78
79 #ifdef _WIN32
80 ULARGE_INTEGER wintm;
81 /* tm is number of 100ns ticks since Jan 01 1601.
82 * We only use the lowest 32 bits of this number.
83 */
84 GetSystemTimeAsFileTime(OFreinterpret_cast(FILETIME *, &wintm));
85 Uint32 tm2 = OFstatic_cast(Uint32, wintm.LowPart);
86 #else
87 struct timeval posixtm;
88 gettimeofday(&posixtm, NULL);
89 /* sub-second part of current time in microseconds */
90 Uint32 tm2 = OFstatic_cast(Uint32, posixtm.tv_usec);
91 #endif
92
93 for (int i=0; i<OFRandom_SIZ; i += 4) // OFRandom_SIZ is dividable by 4
94 {
95 randrsl[i] = tm++;
96 randrsl[i+1] = cl++;
97 randrsl[i+2] = pi++;
98 randrsl[i+3] = tm2++;
99 }
100
101 mixSeed();
102 }
103
mixSeed()104 void OFRandom::mixSeed()
105 {
106 int i;
107 Uint32 a,b,c,d,e,f,g,h;
108 a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */
109
110 for (i=0; i<4; ++i) /* scramble it */
111 {
112 mix(a,b,c,d,e,f,g,h);
113 }
114
115 /* initialize using the contents of randrsl[] as the seed */
116 for (i=0; i<OFRandom_SIZ; i+=8)
117 {
118 a+=randrsl[i ]; b+=randrsl[i+1];
119 c+=randrsl[i+2]; d+=randrsl[i+3];
120 e+=randrsl[i+4]; f+=randrsl[i+5];
121 g+=randrsl[i+6]; h+=randrsl[i+7];
122 mix(a,b,c,d,e,f,g,h);
123 randmem[i ]=a; randmem[i+1]=b; randmem[i+2]=c; randmem[i+3]=d;
124 randmem[i+4]=e; randmem[i+5]=f; randmem[i+6]=g; randmem[i+7]=h;
125 }
126 /* do a second pass to make all of the seed affect all of m */
127 for (i=0; i<OFRandom_SIZ; i+=8)
128 {
129 a+=randmem[i ]; b+=randmem[i+1];
130 c+=randmem[i+2]; d+=randmem[i+3];
131 e+=randmem[i+4]; f+=randmem[i+5];
132 g+=randmem[i+6]; h+=randmem[i+7];
133 mix(a,b,c,d,e,f,g,h);
134 randmem[i ]=a; randmem[i+1]=b; randmem[i+2]=c; randmem[i+3]=d;
135 randmem[i+4]=e; randmem[i+5]=f; randmem[i+6]=g; randmem[i+7]=h;
136 }
137
138 isaac(); /* fill in the first set of results */}
139
seed(Uint32 sval)140 void OFRandom::seed(Uint32 sval)
141 {
142 for (int i=0; i<OFRandom_SIZ; i++)
143 {
144 randrsl[i] = sval;
145 }
146 randa = 0;
147 randb = 0;
148 randc = 0;
149 mixSeed();
150 }
151
isaac()152 void OFRandom::isaac()
153 {
154 Uint32 x,y,*m,*m2,*mend;
155 Uint32 *r = randrsl;
156 Uint32 a = randa;
157 Uint32 b = randb + (++randc);
158 for (m = randmem, mend = m2 = m+(OFRandom_SIZ/2); m<mend; )
159 {
160 rngstep( a<<13, a, b, randmem, m, m2, r, x);
161 rngstep( (a & 0xffffffff) >>6 , a, b, randmem, m, m2, r, x);
162 rngstep( a<<2 , a, b, randmem, m, m2, r, x);
163 rngstep( (a & 0xffffffff) >>16, a, b, randmem, m, m2, r, x);
164 }
165 for (m2 = randmem; m2<mend; )
166 {
167 rngstep( a<<13, a, b, randmem, m, m2, r, x);
168 rngstep( (a & 0xffffffff) >>6 , a, b, randmem, m, m2, r, x);
169 rngstep( a<<2 , a, b, randmem, m, m2, r, x);
170 rngstep( (a & 0xffffffff) >>16, a, b, randmem, m, m2, r, x);
171 }
172 randb = b; randa = a;
173 randcnt = OFRandom_SIZ;
174 }
175
getRND32()176 Uint32 OFRandom::getRND32()
177 {
178 // check if we still have random numbers left
179 if (randcnt == 0) isaac();
180
181 // we use the random numbers from last to first
182 return randrsl[--randcnt];
183 }
184
getRND16()185 Uint16 OFRandom::getRND16()
186 {
187 // use one 32-bit random number and ignore the extra bits
188 return OFstatic_cast(Uint16, getRND32());
189 }
190
191 #ifndef OF_NO_UINT64
getRND64()192 Uint64 OFRandom::getRND64()
193 {
194 // get a 32-bit random number
195 Uint64 result = getRND32();
196 // shift into upper 32 bits of the 64-bit word
197 result <<= 32;
198 // get a second 32-bit random number
199 result |= getRND32();
200 return result;
201 }
202 #endif
203