xref: /minix3/crypto/external/bsd/openssl/dist/MacOS/Randomizer.cpp (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
1*ebfedea0SLionel Sambuc /*
2*ebfedea0SLionel Sambuc ------- Strong random data generation on a Macintosh (pre - OS X) ------
3*ebfedea0SLionel Sambuc 
4*ebfedea0SLionel Sambuc --	GENERAL: We aim to generate unpredictable bits without explicit
5*ebfedea0SLionel Sambuc 	user interaction. A general review of the problem may be found
6*ebfedea0SLionel Sambuc 	in RFC 1750, "Randomness Recommendations for Security", and some
7*ebfedea0SLionel Sambuc 	more discussion, of general and Mac-specific issues has appeared
8*ebfedea0SLionel Sambuc 	in "Using and Creating Cryptographic- Quality Random Numbers" by
9*ebfedea0SLionel Sambuc 	Jon Callas (www.merrymeet.com/jon/usingrandom.html).
10*ebfedea0SLionel Sambuc 
11*ebfedea0SLionel Sambuc 	The data and entropy estimates provided below are based on my
12*ebfedea0SLionel Sambuc 	limited experimentation and estimates, rather than by any
13*ebfedea0SLionel Sambuc 	rigorous study, and the entropy estimates tend to be optimistic.
14*ebfedea0SLionel Sambuc 	They should not be considered absolute.
15*ebfedea0SLionel Sambuc 
16*ebfedea0SLionel Sambuc 	Some of the information being collected may be correlated in
17*ebfedea0SLionel Sambuc 	subtle ways. That includes mouse positions, timings, and disk
18*ebfedea0SLionel Sambuc 	size measurements. Some obvious correlations will be eliminated
19*ebfedea0SLionel Sambuc 	by the programmer, but other, weaker ones may remain. The
20*ebfedea0SLionel Sambuc 	reliability of the code depends on such correlations being
21*ebfedea0SLionel Sambuc 	poorly understood, both by us and by potential interceptors.
22*ebfedea0SLionel Sambuc 
23*ebfedea0SLionel Sambuc 	This package has been planned to be used with OpenSSL, v. 0.9.5.
24*ebfedea0SLionel Sambuc 	It requires the OpenSSL function RAND_add.
25*ebfedea0SLionel Sambuc 
26*ebfedea0SLionel Sambuc --	OTHER WORK: Some source code and other details have been
27*ebfedea0SLionel Sambuc 	published elsewhere, but I haven't found any to be satisfactory
28*ebfedea0SLionel Sambuc 	for the Mac per se:
29*ebfedea0SLionel Sambuc 
30*ebfedea0SLionel Sambuc 	* The Linux random number generator (by Theodore Ts'o, in
31*ebfedea0SLionel Sambuc 	  drivers/char/random.c), is a carefully designed open-source
32*ebfedea0SLionel Sambuc 	  crypto random number package. It collects data from a variety
33*ebfedea0SLionel Sambuc 	  of sources, including mouse, keyboard and other interrupts.
34*ebfedea0SLionel Sambuc 	  One nice feature is that it explicitly estimates the entropy
35*ebfedea0SLionel Sambuc 	  of the data it collects. Some of its features (e.g. interrupt
36*ebfedea0SLionel Sambuc 	  timing) cannot be reliably exported to the Mac without using
37*ebfedea0SLionel Sambuc 	  undocumented APIs.
38*ebfedea0SLionel Sambuc 
39*ebfedea0SLionel Sambuc 	* Truerand by Don P. Mitchell and Matt Blaze uses variations
40*ebfedea0SLionel Sambuc 	  between different timing mechanisms on the same system. This
41*ebfedea0SLionel Sambuc 	  has not been tested on the Mac, but requires preemptive
42*ebfedea0SLionel Sambuc 	  multitasking, and is hardware-dependent, and can't be relied
43*ebfedea0SLionel Sambuc 	  on to work well if only one oscillator is present.
44*ebfedea0SLionel Sambuc 
45*ebfedea0SLionel Sambuc 	* Cryptlib's RNG for the Mac (RNDMAC.C by Peter Gutmann),
46*ebfedea0SLionel Sambuc 	  gathers a lot of information about the machine and system
47*ebfedea0SLionel Sambuc 	  environment. Unfortunately, much of it is constant from one
48*ebfedea0SLionel Sambuc 	  startup to the next. In other words, the random seed could be
49*ebfedea0SLionel Sambuc 	  the same from one day to the next. Some of the APIs are
50*ebfedea0SLionel Sambuc 	  hardware-dependent, and not all are compatible with Carbon (OS
51*ebfedea0SLionel Sambuc 	  X). Incidentally, the EGD library is based on the UNIX entropy
52*ebfedea0SLionel Sambuc 	  gathering methods in cryptlib, and isn't suitable for MacOS
53*ebfedea0SLionel Sambuc 	  either.
54*ebfedea0SLionel Sambuc 
55*ebfedea0SLionel Sambuc 	* Mozilla (and perhaps earlier versions of Netscape) uses the
56*ebfedea0SLionel Sambuc 	  time of day (in seconds) and an uninitialized local variable
57*ebfedea0SLionel Sambuc 	  to seed the random number generator. The time of day is known
58*ebfedea0SLionel Sambuc 	  to an outside interceptor (to within the accuracy of the
59*ebfedea0SLionel Sambuc 	  system clock). The uninitialized variable could easily be
60*ebfedea0SLionel Sambuc 	  identical between subsequent launches of an application, if it
61*ebfedea0SLionel Sambuc 	  is reached through the same path.
62*ebfedea0SLionel Sambuc 
63*ebfedea0SLionel Sambuc 	* OpenSSL provides the function RAND_screen(), by G. van
64*ebfedea0SLionel Sambuc 	  Oosten, which hashes the contents of the screen to generate a
65*ebfedea0SLionel Sambuc 	  seed. This is not useful for an extension or for an
66*ebfedea0SLionel Sambuc 	  application which launches at startup time, since the screen
67*ebfedea0SLionel Sambuc 	  is likely to look identical from one launch to the next. This
68*ebfedea0SLionel Sambuc 	  method is also rather slow.
69*ebfedea0SLionel Sambuc 
70*ebfedea0SLionel Sambuc 	* Using variations in disk drive seek times has been proposed
71*ebfedea0SLionel Sambuc 	  (Davis, Ihaka and Fenstermacher, world.std.com/~dtd/;
72*ebfedea0SLionel Sambuc 	  Jakobsson, Shriver, Hillyer and Juels,
73*ebfedea0SLionel Sambuc 	  www.bell-labs.com/user/shriver/random.html). These variations
74*ebfedea0SLionel Sambuc 	  appear to be due to air turbulence inside the disk drive
75*ebfedea0SLionel Sambuc 	  mechanism, and are very strongly unpredictable. Unfortunately
76*ebfedea0SLionel Sambuc 	  this technique is slow, and some implementations of it may be
77*ebfedea0SLionel Sambuc 	  patented (see Shriver's page above.) It of course cannot be
78*ebfedea0SLionel Sambuc 	  used with a RAM disk.
79*ebfedea0SLionel Sambuc 
80*ebfedea0SLionel Sambuc --	TIMING: On the 601 PowerPC the time base register is guaranteed
81*ebfedea0SLionel Sambuc 	to change at least once every 10 addi instructions, i.e. 10
82*ebfedea0SLionel Sambuc 	cycles. On a 60 MHz machine (slowest PowerPC) this translates to
83*ebfedea0SLionel Sambuc 	a resolution of 1/6 usec. Newer machines seem to be using a 10
84*ebfedea0SLionel Sambuc 	cycle resolution as well.
85*ebfedea0SLionel Sambuc 
86*ebfedea0SLionel Sambuc 	For 68K Macs, the Microseconds() call may be used. See Develop
87*ebfedea0SLionel Sambuc 	issue 29 on the Apple developer site
88*ebfedea0SLionel Sambuc 	(developer.apple.com/dev/techsupport/develop/issue29/minow.html)
89*ebfedea0SLionel Sambuc 	for information on its accuracy and resolution. The code below
90*ebfedea0SLionel Sambuc 	has been tested only on PowerPC based machines.
91*ebfedea0SLionel Sambuc 
92*ebfedea0SLionel Sambuc 	The time from machine startup to the launch of an application in
93*ebfedea0SLionel Sambuc 	the startup folder has a variance of about 1.6 msec on a new G4
94*ebfedea0SLionel Sambuc 	machine with a defragmented and optimized disk, most extensions
95*ebfedea0SLionel Sambuc 	off and no icons on the desktop. This can be reasonably taken as
96*ebfedea0SLionel Sambuc 	a lower bound on the variance. Most of this variation is likely
97*ebfedea0SLionel Sambuc 	due to disk seek time variability. The distribution of startup
98*ebfedea0SLionel Sambuc 	times is probably not entirely even or uncorrelated. This needs
99*ebfedea0SLionel Sambuc 	to be investigated, but I am guessing that it not a majpor
100*ebfedea0SLionel Sambuc 	problem. Entropy = log2 (1600/0.166) ~= 13 bits on a 60 MHz
101*ebfedea0SLionel Sambuc 	machine, ~16 bits for a 450 MHz machine.
102*ebfedea0SLionel Sambuc 
103*ebfedea0SLionel Sambuc 	User-launched application startup times will have a variance of
104*ebfedea0SLionel Sambuc 	a second or more relative to machine startup time. Entropy >~22
105*ebfedea0SLionel Sambuc 	bits.
106*ebfedea0SLionel Sambuc 
107*ebfedea0SLionel Sambuc 	Machine startup time is available with a 1-second resolution. It
108*ebfedea0SLionel Sambuc 	is predictable to no better a minute or two, in the case of
109*ebfedea0SLionel Sambuc 	people who show up punctually to work at the same time and
110*ebfedea0SLionel Sambuc 	immediately start their computer. Using the scheduled startup
111*ebfedea0SLionel Sambuc 	feature (when available) will cause the machine to start up at
112*ebfedea0SLionel Sambuc 	the same time every day, making the value predictable. Entropy
113*ebfedea0SLionel Sambuc 	>~7 bits, or 0 bits with scheduled startup.
114*ebfedea0SLionel Sambuc 
115*ebfedea0SLionel Sambuc 	The time of day is of course known to an outsider and thus has 0
116*ebfedea0SLionel Sambuc 	entropy if the system clock is regularly calibrated.
117*ebfedea0SLionel Sambuc 
118*ebfedea0SLionel Sambuc --	KEY TIMING: A  very fast typist (120 wpm) will have a typical
119*ebfedea0SLionel Sambuc 	inter-key timing interval of 100 msec. We can assume a variance
120*ebfedea0SLionel Sambuc 	of no less than 2 msec -- maybe. Do good typists have a constant
121*ebfedea0SLionel Sambuc 	rhythm, like drummers? Since what we measure is not the
122*ebfedea0SLionel Sambuc 	key-generated interrupt but the time at which the key event was
123*ebfedea0SLionel Sambuc 	taken off the event queue, our resolution is roughly the time
124*ebfedea0SLionel Sambuc 	between process switches, at best 1 tick (17 msec). I  therefore
125*ebfedea0SLionel Sambuc 	consider this technique questionable and not very useful for
126*ebfedea0SLionel Sambuc 	obtaining high entropy data on the Mac.
127*ebfedea0SLionel Sambuc 
128*ebfedea0SLionel Sambuc --	MOUSE POSITION AND TIMING: The high bits of the mouse position
129*ebfedea0SLionel Sambuc 	are far from arbitrary, since the mouse tends to stay in a few
130*ebfedea0SLionel Sambuc 	limited areas of the screen. I am guessing that the position of
131*ebfedea0SLionel Sambuc 	the mouse is arbitrary within a 6 pixel square. Since the mouse
132*ebfedea0SLionel Sambuc 	stays still for long periods of time, it should be sampled only
133*ebfedea0SLionel Sambuc 	after it was moved, to avoid correlated data. This gives an
134*ebfedea0SLionel Sambuc 	entropy of log2(6*6) ~= 5 bits per measurement.
135*ebfedea0SLionel Sambuc 
136*ebfedea0SLionel Sambuc 	The time during which the mouse stays still can vary from zero
137*ebfedea0SLionel Sambuc 	to, say, 5 seconds (occasionally longer). If the still time is
138*ebfedea0SLionel Sambuc 	measured by sampling the mouse during null events, and null
139*ebfedea0SLionel Sambuc 	events are received once per tick, its resolution is 1/60th of a
140*ebfedea0SLionel Sambuc 	second, giving an entropy of log2 (60*5) ~= 8 bits per
141*ebfedea0SLionel Sambuc 	measurement. Since the distribution of still times is uneven,
142*ebfedea0SLionel Sambuc 	this estimate is on the high side.
143*ebfedea0SLionel Sambuc 
144*ebfedea0SLionel Sambuc 	For simplicity and compatibility across system versions, the
145*ebfedea0SLionel Sambuc 	mouse is to be sampled explicitly (e.g. in the event loop),
146*ebfedea0SLionel Sambuc 	rather than in a time manager task.
147*ebfedea0SLionel Sambuc 
148*ebfedea0SLionel Sambuc --	STARTUP DISK TOTAL FILE SIZE: Varies typically by at least 20k
149*ebfedea0SLionel Sambuc 	from one startup to the next, with 'minimal' computer use. Won't
150*ebfedea0SLionel Sambuc 	vary at all if machine is started again immediately after
151*ebfedea0SLionel Sambuc 	startup (unless virtual memory is on), but any application which
152*ebfedea0SLionel Sambuc 	uses the web and caches information to disk is likely to cause
153*ebfedea0SLionel Sambuc 	this much variation or more. The variation is probably not
154*ebfedea0SLionel Sambuc 	random, but I don't know in what way. File sizes tend to be
155*ebfedea0SLionel Sambuc 	divisible by 4 bytes since file format fields are often
156*ebfedea0SLionel Sambuc 	long-aligned. Entropy > log2 (20000/4) ~= 12 bits.
157*ebfedea0SLionel Sambuc 
158*ebfedea0SLionel Sambuc --	STARTUP DISK FIRST AVAILABLE ALLOCATION BLOCK: As the volume
159*ebfedea0SLionel Sambuc 	gets fragmented this could be anywhere in principle. In a
160*ebfedea0SLionel Sambuc 	perfectly unfragmented volume this will be strongly correlated
161*ebfedea0SLionel Sambuc 	with the total file size on the disk. With more fragmentation
162*ebfedea0SLionel Sambuc 	comes less certainty. I took the variation in this value to be
163*ebfedea0SLionel Sambuc 	1/8 of the total file size on the volume.
164*ebfedea0SLionel Sambuc 
165*ebfedea0SLionel Sambuc --	SYSTEM REQUIREMENTS: The code here requires System 7.0 and above
166*ebfedea0SLionel Sambuc 	(for Gestalt and Microseconds calls). All the calls used are
167*ebfedea0SLionel Sambuc 	Carbon-compatible.
168*ebfedea0SLionel Sambuc */
169*ebfedea0SLionel Sambuc 
170*ebfedea0SLionel Sambuc /*------------------------------ Includes ----------------------------*/
171*ebfedea0SLionel Sambuc 
172*ebfedea0SLionel Sambuc #include "Randomizer.h"
173*ebfedea0SLionel Sambuc 
174*ebfedea0SLionel Sambuc // Mac OS API
175*ebfedea0SLionel Sambuc #include <Files.h>
176*ebfedea0SLionel Sambuc #include <Folders.h>
177*ebfedea0SLionel Sambuc #include <Events.h>
178*ebfedea0SLionel Sambuc #include <Processes.h>
179*ebfedea0SLionel Sambuc #include <Gestalt.h>
180*ebfedea0SLionel Sambuc #include <Resources.h>
181*ebfedea0SLionel Sambuc #include <LowMem.h>
182*ebfedea0SLionel Sambuc 
183*ebfedea0SLionel Sambuc // Standard C library
184*ebfedea0SLionel Sambuc #include <stdlib.h>
185*ebfedea0SLionel Sambuc #include <math.h>
186*ebfedea0SLionel Sambuc 
187*ebfedea0SLionel Sambuc /*---------------------- Function declarations -----------------------*/
188*ebfedea0SLionel Sambuc 
189*ebfedea0SLionel Sambuc // declared in OpenSSL/crypto/rand/rand.h
190*ebfedea0SLionel Sambuc extern "C" void RAND_add (const void *buf, int num, double entropy);
191*ebfedea0SLionel Sambuc 
192*ebfedea0SLionel Sambuc unsigned long GetPPCTimer (bool is601);	// Make it global if needed
193*ebfedea0SLionel Sambuc 					// elsewhere
194*ebfedea0SLionel Sambuc 
195*ebfedea0SLionel Sambuc /*---------------------------- Constants -----------------------------*/
196*ebfedea0SLionel Sambuc 
197*ebfedea0SLionel Sambuc #define kMouseResolution 6		// Mouse position has to differ
198*ebfedea0SLionel Sambuc 					// from the last one by this
199*ebfedea0SLionel Sambuc 					// much to be entered
200*ebfedea0SLionel Sambuc #define kMousePositionEntropy 5.16	// log2 (kMouseResolution**2)
201*ebfedea0SLionel Sambuc #define kTypicalMouseIdleTicks 300.0	// I am guessing that a typical
202*ebfedea0SLionel Sambuc 					// amount of time between mouse
203*ebfedea0SLionel Sambuc 					// moves is 5 seconds
204*ebfedea0SLionel Sambuc #define kVolumeBytesEntropy 12.0	// about log2 (20000/4),
205*ebfedea0SLionel Sambuc 					// assuming a variation of 20K
206*ebfedea0SLionel Sambuc 					// in total file size and
207*ebfedea0SLionel Sambuc 					// long-aligned file formats.
208*ebfedea0SLionel Sambuc #define kApplicationUpTimeEntropy 6.0	// Variance > 1 second, uptime
209*ebfedea0SLionel Sambuc 					// in ticks
210*ebfedea0SLionel Sambuc #define kSysStartupEntropy 7.0		// Entropy for machine startup
211*ebfedea0SLionel Sambuc 					// time
212*ebfedea0SLionel Sambuc 
213*ebfedea0SLionel Sambuc 
214*ebfedea0SLionel Sambuc /*------------------------ Function definitions ----------------------*/
215*ebfedea0SLionel Sambuc 
CRandomizer(void)216*ebfedea0SLionel Sambuc CRandomizer::CRandomizer (void)
217*ebfedea0SLionel Sambuc {
218*ebfedea0SLionel Sambuc 	long	result;
219*ebfedea0SLionel Sambuc 
220*ebfedea0SLionel Sambuc 	mSupportsLargeVolumes =
221*ebfedea0SLionel Sambuc 		(Gestalt(gestaltFSAttr, &result) == noErr) &&
222*ebfedea0SLionel Sambuc 		((result & (1L << gestaltFSSupports2TBVols)) != 0);
223*ebfedea0SLionel Sambuc 
224*ebfedea0SLionel Sambuc 	if (Gestalt (gestaltNativeCPUtype, &result) != noErr)
225*ebfedea0SLionel Sambuc 	{
226*ebfedea0SLionel Sambuc 		mIsPowerPC = false;
227*ebfedea0SLionel Sambuc 		mIs601 = false;
228*ebfedea0SLionel Sambuc 	}
229*ebfedea0SLionel Sambuc 	else
230*ebfedea0SLionel Sambuc 	{
231*ebfedea0SLionel Sambuc 		mIs601 = (result == gestaltCPU601);
232*ebfedea0SLionel Sambuc 		mIsPowerPC = (result >= gestaltCPU601);
233*ebfedea0SLionel Sambuc 	}
234*ebfedea0SLionel Sambuc 	mLastMouse.h = mLastMouse.v = -10;	// First mouse will
235*ebfedea0SLionel Sambuc 						// always be recorded
236*ebfedea0SLionel Sambuc 	mLastPeriodicTicks = TickCount();
237*ebfedea0SLionel Sambuc 	GetTimeBaseResolution ();
238*ebfedea0SLionel Sambuc 
239*ebfedea0SLionel Sambuc 	// Add initial entropy
240*ebfedea0SLionel Sambuc 	AddTimeSinceMachineStartup ();
241*ebfedea0SLionel Sambuc 	AddAbsoluteSystemStartupTime ();
242*ebfedea0SLionel Sambuc 	AddStartupVolumeInfo ();
243*ebfedea0SLionel Sambuc 	AddFiller ();
244*ebfedea0SLionel Sambuc }
245*ebfedea0SLionel Sambuc 
PeriodicAction(void)246*ebfedea0SLionel Sambuc void CRandomizer::PeriodicAction (void)
247*ebfedea0SLionel Sambuc {
248*ebfedea0SLionel Sambuc 	AddCurrentMouse ();
249*ebfedea0SLionel Sambuc 	AddNow (0.0);	// Should have a better entropy estimate here
250*ebfedea0SLionel Sambuc 	mLastPeriodicTicks = TickCount();
251*ebfedea0SLionel Sambuc }
252*ebfedea0SLionel Sambuc 
253*ebfedea0SLionel Sambuc /*------------------------- Private Methods --------------------------*/
254*ebfedea0SLionel Sambuc 
AddCurrentMouse(void)255*ebfedea0SLionel Sambuc void CRandomizer::AddCurrentMouse (void)
256*ebfedea0SLionel Sambuc {
257*ebfedea0SLionel Sambuc 	Point mouseLoc;
258*ebfedea0SLionel Sambuc 	unsigned long lastCheck;	// Ticks since mouse was last
259*ebfedea0SLionel Sambuc 					// sampled
260*ebfedea0SLionel Sambuc 
261*ebfedea0SLionel Sambuc #if TARGET_API_MAC_CARBON
262*ebfedea0SLionel Sambuc 	GetGlobalMouse (&mouseLoc);
263*ebfedea0SLionel Sambuc #else
264*ebfedea0SLionel Sambuc 	mouseLoc = LMGetMouseLocation();
265*ebfedea0SLionel Sambuc #endif
266*ebfedea0SLionel Sambuc 
267*ebfedea0SLionel Sambuc 	if (labs (mLastMouse.h - mouseLoc.h) > kMouseResolution/2 &&
268*ebfedea0SLionel Sambuc 	    labs (mLastMouse.v - mouseLoc.v) > kMouseResolution/2)
269*ebfedea0SLionel Sambuc 		AddBytes (&mouseLoc, sizeof (mouseLoc),
270*ebfedea0SLionel Sambuc 				kMousePositionEntropy);
271*ebfedea0SLionel Sambuc 
272*ebfedea0SLionel Sambuc 	if (mLastMouse.h == mouseLoc.h && mLastMouse.v == mouseLoc.v)
273*ebfedea0SLionel Sambuc 		mMouseStill ++;
274*ebfedea0SLionel Sambuc 	else
275*ebfedea0SLionel Sambuc 	{
276*ebfedea0SLionel Sambuc 		double entropy;
277*ebfedea0SLionel Sambuc 
278*ebfedea0SLionel Sambuc 		// Mouse has moved. Add the number of measurements for
279*ebfedea0SLionel Sambuc 		// which it's been still. If the resolution is too
280*ebfedea0SLionel Sambuc 		// coarse, assume the entropy is 0.
281*ebfedea0SLionel Sambuc 
282*ebfedea0SLionel Sambuc 		lastCheck = TickCount() - mLastPeriodicTicks;
283*ebfedea0SLionel Sambuc 		if (lastCheck <= 0)
284*ebfedea0SLionel Sambuc 			lastCheck = 1;
285*ebfedea0SLionel Sambuc 		entropy = log2l
286*ebfedea0SLionel Sambuc 			(kTypicalMouseIdleTicks/(double)lastCheck);
287*ebfedea0SLionel Sambuc 		if (entropy < 0.0)
288*ebfedea0SLionel Sambuc 			entropy = 0.0;
289*ebfedea0SLionel Sambuc 		AddBytes (&mMouseStill, sizeof (mMouseStill), entropy);
290*ebfedea0SLionel Sambuc 		mMouseStill = 0;
291*ebfedea0SLionel Sambuc 	}
292*ebfedea0SLionel Sambuc 	mLastMouse = mouseLoc;
293*ebfedea0SLionel Sambuc }
294*ebfedea0SLionel Sambuc 
AddAbsoluteSystemStartupTime(void)295*ebfedea0SLionel Sambuc void CRandomizer::AddAbsoluteSystemStartupTime (void)
296*ebfedea0SLionel Sambuc {
297*ebfedea0SLionel Sambuc 	unsigned long	now;		// Time in seconds since
298*ebfedea0SLionel Sambuc 					// 1/1/1904
299*ebfedea0SLionel Sambuc 	GetDateTime (&now);
300*ebfedea0SLionel Sambuc 	now -= TickCount() / 60;	// Time in ticks since machine
301*ebfedea0SLionel Sambuc 					// startup
302*ebfedea0SLionel Sambuc 	AddBytes (&now, sizeof (now), kSysStartupEntropy);
303*ebfedea0SLionel Sambuc }
304*ebfedea0SLionel Sambuc 
AddTimeSinceMachineStartup(void)305*ebfedea0SLionel Sambuc void CRandomizer::AddTimeSinceMachineStartup (void)
306*ebfedea0SLionel Sambuc {
307*ebfedea0SLionel Sambuc 	AddNow (1.5);			// Uncertainty in app startup
308*ebfedea0SLionel Sambuc 					// time is > 1.5 msec (for
309*ebfedea0SLionel Sambuc 					// automated app startup).
310*ebfedea0SLionel Sambuc }
311*ebfedea0SLionel Sambuc 
AddAppRunningTime(void)312*ebfedea0SLionel Sambuc void CRandomizer::AddAppRunningTime (void)
313*ebfedea0SLionel Sambuc {
314*ebfedea0SLionel Sambuc 	ProcessSerialNumber PSN;
315*ebfedea0SLionel Sambuc 	ProcessInfoRec		ProcessInfo;
316*ebfedea0SLionel Sambuc 
317*ebfedea0SLionel Sambuc 	ProcessInfo.processInfoLength = sizeof (ProcessInfoRec);
318*ebfedea0SLionel Sambuc 	ProcessInfo.processName = nil;
319*ebfedea0SLionel Sambuc 	ProcessInfo.processAppSpec = nil;
320*ebfedea0SLionel Sambuc 
321*ebfedea0SLionel Sambuc 	GetCurrentProcess (&PSN);
322*ebfedea0SLionel Sambuc 	GetProcessInformation (&PSN, &ProcessInfo);
323*ebfedea0SLionel Sambuc 
324*ebfedea0SLionel Sambuc 	// Now add the amount of time in ticks that the current process
325*ebfedea0SLionel Sambuc 	// has been active
326*ebfedea0SLionel Sambuc 
327*ebfedea0SLionel Sambuc 	AddBytes (&ProcessInfo, sizeof (ProcessInfoRec),
328*ebfedea0SLionel Sambuc 			kApplicationUpTimeEntropy);
329*ebfedea0SLionel Sambuc }
330*ebfedea0SLionel Sambuc 
AddStartupVolumeInfo(void)331*ebfedea0SLionel Sambuc void CRandomizer::AddStartupVolumeInfo (void)
332*ebfedea0SLionel Sambuc {
333*ebfedea0SLionel Sambuc 	short			vRefNum;
334*ebfedea0SLionel Sambuc 	long			dirID;
335*ebfedea0SLionel Sambuc 	XVolumeParam	pb;
336*ebfedea0SLionel Sambuc 	OSErr			err;
337*ebfedea0SLionel Sambuc 
338*ebfedea0SLionel Sambuc 	if (!mSupportsLargeVolumes)
339*ebfedea0SLionel Sambuc 		return;
340*ebfedea0SLionel Sambuc 
341*ebfedea0SLionel Sambuc 	FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder,
342*ebfedea0SLionel Sambuc 			&vRefNum, &dirID);
343*ebfedea0SLionel Sambuc 	pb.ioVRefNum = vRefNum;
344*ebfedea0SLionel Sambuc 	pb.ioCompletion = 0;
345*ebfedea0SLionel Sambuc 	pb.ioNamePtr = 0;
346*ebfedea0SLionel Sambuc 	pb.ioVolIndex = 0;
347*ebfedea0SLionel Sambuc 	err = PBXGetVolInfoSync (&pb);
348*ebfedea0SLionel Sambuc 	if (err != noErr)
349*ebfedea0SLionel Sambuc 		return;
350*ebfedea0SLionel Sambuc 
351*ebfedea0SLionel Sambuc 	// Base the entropy on the amount of space used on the disk and
352*ebfedea0SLionel Sambuc 	// on the next available allocation block. A lot else might be
353*ebfedea0SLionel Sambuc 	// unpredictable, so might as well toss the whole block in. See
354*ebfedea0SLionel Sambuc 	// comments for entropy estimate justifications.
355*ebfedea0SLionel Sambuc 
356*ebfedea0SLionel Sambuc 	AddBytes (&pb, sizeof (pb),
357*ebfedea0SLionel Sambuc 		kVolumeBytesEntropy +
358*ebfedea0SLionel Sambuc 		log2l (((pb.ioVTotalBytes.hi - pb.ioVFreeBytes.hi)
359*ebfedea0SLionel Sambuc 				* 4294967296.0D +
360*ebfedea0SLionel Sambuc 			(pb.ioVTotalBytes.lo - pb.ioVFreeBytes.lo))
361*ebfedea0SLionel Sambuc 				/ pb.ioVAlBlkSiz - 3.0));
362*ebfedea0SLionel Sambuc }
363*ebfedea0SLionel Sambuc 
364*ebfedea0SLionel Sambuc /*
365*ebfedea0SLionel Sambuc 	On a typical startup CRandomizer will come up with about 60
366*ebfedea0SLionel Sambuc 	bits of good, unpredictable data. Assuming no more input will
367*ebfedea0SLionel Sambuc 	be available, we'll need some more lower-quality data to give
368*ebfedea0SLionel Sambuc 	OpenSSL the 128 bits of entropy it desires. AddFiller adds some
369*ebfedea0SLionel Sambuc 	relatively predictable data into the soup.
370*ebfedea0SLionel Sambuc */
371*ebfedea0SLionel Sambuc 
AddFiller(void)372*ebfedea0SLionel Sambuc void CRandomizer::AddFiller (void)
373*ebfedea0SLionel Sambuc {
374*ebfedea0SLionel Sambuc 	struct
375*ebfedea0SLionel Sambuc 	{
376*ebfedea0SLionel Sambuc 		ProcessSerialNumber psn;	// Front process serial
377*ebfedea0SLionel Sambuc 						// number
378*ebfedea0SLionel Sambuc 		RGBColor	hiliteRGBValue;	// User-selected
379*ebfedea0SLionel Sambuc 						// highlight color
380*ebfedea0SLionel Sambuc 		long		processCount;	// Number of active
381*ebfedea0SLionel Sambuc 						// processes
382*ebfedea0SLionel Sambuc 		long		cpuSpeed;	// Processor speed
383*ebfedea0SLionel Sambuc 		long		totalMemory;	// Total logical memory
384*ebfedea0SLionel Sambuc 						// (incl. virtual one)
385*ebfedea0SLionel Sambuc 		long		systemVersion;	// OS version
386*ebfedea0SLionel Sambuc 		short		resFile;	// Current resource file
387*ebfedea0SLionel Sambuc 	} data;
388*ebfedea0SLionel Sambuc 
389*ebfedea0SLionel Sambuc 	GetNextProcess ((ProcessSerialNumber*) kNoProcess);
390*ebfedea0SLionel Sambuc 	while (GetNextProcess (&data.psn) == noErr)
391*ebfedea0SLionel Sambuc 		data.processCount++;
392*ebfedea0SLionel Sambuc 	GetFrontProcess (&data.psn);
393*ebfedea0SLionel Sambuc 	LMGetHiliteRGB (&data.hiliteRGBValue);
394*ebfedea0SLionel Sambuc 	Gestalt (gestaltProcClkSpeed, &data.cpuSpeed);
395*ebfedea0SLionel Sambuc 	Gestalt (gestaltLogicalRAMSize, &data.totalMemory);
396*ebfedea0SLionel Sambuc 	Gestalt (gestaltSystemVersion, &data.systemVersion);
397*ebfedea0SLionel Sambuc 	data.resFile = CurResFile ();
398*ebfedea0SLionel Sambuc 
399*ebfedea0SLionel Sambuc 	// Here we pretend to feed the PRNG completely random data. This
400*ebfedea0SLionel Sambuc 	// is of course false, as much of the above data is predictable
401*ebfedea0SLionel Sambuc 	// by an outsider. At this point we don't have any more
402*ebfedea0SLionel Sambuc 	// randomness to add, but with OpenSSL we must have a 128 bit
403*ebfedea0SLionel Sambuc 	// seed before we can start. We just add what we can, without a
404*ebfedea0SLionel Sambuc 	// real entropy estimate, and hope for the best.
405*ebfedea0SLionel Sambuc 
406*ebfedea0SLionel Sambuc 	AddBytes (&data, sizeof(data), 8.0 * sizeof(data));
407*ebfedea0SLionel Sambuc 	AddCurrentMouse ();
408*ebfedea0SLionel Sambuc 	AddNow (1.0);
409*ebfedea0SLionel Sambuc }
410*ebfedea0SLionel Sambuc 
411*ebfedea0SLionel Sambuc //-------------------  LOW LEVEL ---------------------
412*ebfedea0SLionel Sambuc 
AddBytes(void * data,long size,double entropy)413*ebfedea0SLionel Sambuc void CRandomizer::AddBytes (void *data, long size, double entropy)
414*ebfedea0SLionel Sambuc {
415*ebfedea0SLionel Sambuc 	RAND_add (data, size, entropy * 0.125);	// Convert entropy bits
416*ebfedea0SLionel Sambuc 						// to bytes
417*ebfedea0SLionel Sambuc }
418*ebfedea0SLionel Sambuc 
AddNow(double millisecondUncertainty)419*ebfedea0SLionel Sambuc void CRandomizer::AddNow (double millisecondUncertainty)
420*ebfedea0SLionel Sambuc {
421*ebfedea0SLionel Sambuc 	long time = SysTimer();
422*ebfedea0SLionel Sambuc 	AddBytes (&time, sizeof (time), log2l (millisecondUncertainty *
423*ebfedea0SLionel Sambuc 			mTimebaseTicksPerMillisec));
424*ebfedea0SLionel Sambuc }
425*ebfedea0SLionel Sambuc 
426*ebfedea0SLionel Sambuc //----------------- TIMING SUPPORT ------------------
427*ebfedea0SLionel Sambuc 
GetTimeBaseResolution(void)428*ebfedea0SLionel Sambuc void CRandomizer::GetTimeBaseResolution (void)
429*ebfedea0SLionel Sambuc {
430*ebfedea0SLionel Sambuc #ifdef __powerc
431*ebfedea0SLionel Sambuc 	long speed;
432*ebfedea0SLionel Sambuc 
433*ebfedea0SLionel Sambuc 	// gestaltProcClkSpeed available on System 7.5.2 and above
434*ebfedea0SLionel Sambuc 	if (Gestalt (gestaltProcClkSpeed, &speed) != noErr)
435*ebfedea0SLionel Sambuc 		// Only PowerPCs running pre-7.5.2 are 60-80 MHz
436*ebfedea0SLionel Sambuc 		// machines.
437*ebfedea0SLionel Sambuc 		mTimebaseTicksPerMillisec =  6000.0D;
438*ebfedea0SLionel Sambuc 	// Assume 10 cycles per clock update, as in 601 spec. Seems true
439*ebfedea0SLionel Sambuc 	// for later chips as well.
440*ebfedea0SLionel Sambuc 	mTimebaseTicksPerMillisec = speed / 1.0e4D;
441*ebfedea0SLionel Sambuc #else
442*ebfedea0SLionel Sambuc 	// 68K VIA-based machines (see Develop Magazine no. 29)
443*ebfedea0SLionel Sambuc 	mTimebaseTicksPerMillisec = 783.360D;
444*ebfedea0SLionel Sambuc #endif
445*ebfedea0SLionel Sambuc }
446*ebfedea0SLionel Sambuc 
SysTimer(void)447*ebfedea0SLionel Sambuc unsigned long CRandomizer::SysTimer (void)	// returns the lower 32
448*ebfedea0SLionel Sambuc 						// bit of the chip timer
449*ebfedea0SLionel Sambuc {
450*ebfedea0SLionel Sambuc #ifdef __powerc
451*ebfedea0SLionel Sambuc 	return GetPPCTimer (mIs601);
452*ebfedea0SLionel Sambuc #else
453*ebfedea0SLionel Sambuc 	UnsignedWide usec;
454*ebfedea0SLionel Sambuc 	Microseconds (&usec);
455*ebfedea0SLionel Sambuc 	return usec.lo;
456*ebfedea0SLionel Sambuc #endif
457*ebfedea0SLionel Sambuc }
458*ebfedea0SLionel Sambuc 
459*ebfedea0SLionel Sambuc #ifdef __powerc
460*ebfedea0SLionel Sambuc // The timebase is available through mfspr on 601, mftb on later chips.
461*ebfedea0SLionel Sambuc // Motorola recommends that an 601 implementation map mftb to mfspr
462*ebfedea0SLionel Sambuc // through an exception, but I haven't tested to see if MacOS actually
463*ebfedea0SLionel Sambuc // does this. We only sample the lower 32 bits of the timer (i.e. a
464*ebfedea0SLionel Sambuc // few minutes of resolution)
465*ebfedea0SLionel Sambuc 
GetPPCTimer(register bool is601)466*ebfedea0SLionel Sambuc asm unsigned long GetPPCTimer (register bool is601)
467*ebfedea0SLionel Sambuc {
468*ebfedea0SLionel Sambuc 	cmplwi	is601, 0	// Check if 601
469*ebfedea0SLionel Sambuc 	bne	_601		// if non-zero goto _601
470*ebfedea0SLionel Sambuc 	mftb  	r3		// Available on 603 and later.
471*ebfedea0SLionel Sambuc 	blr			// return with result in r3
472*ebfedea0SLionel Sambuc _601:
473*ebfedea0SLionel Sambuc 	mfspr r3, spr5  	// Available on 601 only.
474*ebfedea0SLionel Sambuc 				// blr inserted automatically
475*ebfedea0SLionel Sambuc }
476*ebfedea0SLionel Sambuc #endif
477