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