📄 randomizer.cpp
字号:
/* ------- Strong random data generation on a Macintosh (pre - OS X) ------ -- GENERAL: We aim to generate unpredictable bits without explicit user interaction. A general review of the problem may be found in RFC 1750, "Randomness Recommendations for Security", and some more discussion, of general and Mac-specific issues has appeared in "Using and Creating Cryptographic- Quality Random Numbers" by Jon Callas (www.merrymeet.com/jon/usingrandom.html). The data and entropy estimates provided below are based on my limited experimentation and estimates, rather than by any rigorous study, and the entropy estimates tend to be optimistic. They should not be considered absolute. Some of the information being collected may be correlated in subtle ways. That includes mouse positions, timings, and disk size measurements. Some obvious correlations will be eliminated by the programmer, but other, weaker ones may remain. The reliability of the code depends on such correlations being poorly understood, both by us and by potential interceptors. This package has been planned to be used with OpenSSL, v. 0.9.5. It requires the OpenSSL function RAND_add. -- OTHER WORK: Some source code and other details have been published elsewhere, but I haven't found any to be satisfactory for the Mac per se: * The Linux random number generator (by Theodore Ts'o, in drivers/char/random.c), is a carefully designed open-source crypto random number package. It collects data from a variety of sources, including mouse, keyboard and other interrupts. One nice feature is that it explicitly estimates the entropy of the data it collects. Some of its features (e.g. interrupt timing) cannot be reliably exported to the Mac without using undocumented APIs. * Truerand by Don P. Mitchell and Matt Blaze uses variations between different timing mechanisms on the same system. This has not been tested on the Mac, but requires preemptive multitasking, and is hardware-dependent, and can't be relied on to work well if only one oscillator is present. * Cryptlib's RNG for the Mac (RNDMAC.C by Peter Gutmann), gathers a lot of information about the machine and system environment. Unfortunately, much of it is constant from one startup to the next. In other words, the random seed could be the same from one day to the next. Some of the APIs are hardware-dependent, and not all are compatible with Carbon (OS X). Incidentally, the EGD library is based on the UNIX entropy gathering methods in cryptlib, and isn't suitable for MacOS either. * Mozilla (and perhaps earlier versions of Netscape) uses the time of day (in seconds) and an uninitialized local variable to seed the random number generator. The time of day is known to an outside interceptor (to within the accuracy of the system clock). The uninitialized variable could easily be identical between subsequent launches of an application, if it is reached through the same path. * OpenSSL provides the function RAND_screen(), by G. van Oosten, which hashes the contents of the screen to generate a seed. This is not useful for an extension or for an application which launches at startup time, since the screen is likely to look identical from one launch to the next. This method is also rather slow. * Using variations in disk drive seek times has been proposed (Davis, Ihaka and Fenstermacher, world.std.com/~dtd/; Jakobsson, Shriver, Hillyer and Juels, www.bell-labs.com/user/shriver/random.html). These variations appear to be due to air turbulence inside the disk drive mechanism, and are very strongly unpredictable. Unfortunately this technique is slow, and some implementations of it may be patented (see Shriver's page above.) It of course cannot be used with a RAM disk.-- TIMING: On the 601 PowerPC the time base register is guaranteed to change at least once every 10 addi instructions, i.e. 10 cycles. On a 60 MHz machine (slowest PowerPC) this translates to a resolution of 1/6 usec. Newer machines seem to be using a 10 cycle resolution as well. For 68K Macs, the Microseconds() call may be used. See Develop issue 29 on the Apple developer site (developer.apple.com/dev/techsupport/develop/issue29/minow.html) for information on its accuracy and resolution. The code below has been tested only on PowerPC based machines. The time from machine startup to the launch of an application in the startup folder has a variance of about 1.6 msec on a new G4 machine with a defragmented and optimized disk, most extensions off and no icons on the desktop. This can be reasonably taken as a lower bound on the variance. Most of this variation is likely due to disk seek time variability. The distribution of startup times is probably not entirely even or uncorrelated. This needs to be investigated, but I am guessing that it not a majpor problem. Entropy = log2 (1600/0.166) ~= 13 bits on a 60 MHz machine, ~16 bits for a 450 MHz machine. User-launched application startup times will have a variance of a second or more relative to machine startup time. Entropy >~22 bits. Machine startup time is available with a 1-second resolution. It is predictable to no better a minute or two, in the case of people who show up punctually to work at the same time and immediately start their computer. Using the scheduled startup feature (when available) will cause the machine to start up at the same time every day, making the value predictable. Entropy >~7 bits, or 0 bits with scheduled startup. The time of day is of course known to an outsider and thus has 0 entropy if the system clock is regularly calibrated.-- KEY TIMING: A very fast typist (120 wpm) will have a typical inter-key timing interval of 100 msec. We can assume a variance of no less than 2 msec -- maybe. Do good typists have a constant rhythm, like drummers? Since what we measure is not the key-generated interrupt but the time at which the key event was taken off the event queue, our resolution is roughly the time between process switches, at best 1 tick (17 msec). I therefore consider this technique questionable and not very useful for obtaining high entropy data on the Mac.-- MOUSE POSITION AND TIMING: The high bits of the mouse position are far from arbitrary, since the mouse tends to stay in a few limited areas of the screen. I am guessing that the position of the mouse is arbitrary within a 6 pixel square. Since the mouse stays still for long periods of time, it should be sampled only after it was moved, to avoid correlated data. This gives an entropy of log2(6*6) ~= 5 bits per measurement. The time during which the mouse stays still can vary from zero to, say, 5 seconds (occasionally longer). If the still time is measured by sampling the mouse during null events, and null events are received once per tick, its resolution is 1/60th of a second, giving an entropy of log2 (60*5) ~= 8 bits per measurement. Since the distribution of still times is uneven, this estimate is on the high side. For simplicity and compatibility across system versions, the mouse is to be sampled explicitly (e.g. in the event loop), rather than in a time manager task.-- STARTUP DISK TOTAL FILE SIZE: Varies typically by at least 20k from one startup to the next, with 'minimal' computer use. Won't vary at all if machine is started again immediately after startup (unless virtual memory is on), but any application which uses the web and caches information to disk is likely to cause this much variation or more. The variation is probably not random, but I don't know in what way. File sizes tend to be divisible by 4 bytes since file format fields are often long-aligned. Entropy > log2 (20000/4) ~= 12 bits. -- STARTUP DISK FIRST AVAILABLE ALLOCATION BLOCK: As the volume gets fragmented this could be anywhere in principle. In a perfectly unfragmented volume this will be strongly correlated with the total file size on the disk. With more fragmentation comes less certainty. I took the variation in this value to be 1/8 of the total file size on the volume.-- SYSTEM REQUIREMENTS: The code here requires System 7.0 and above (for Gestalt and Microseconds calls). All the calls used are Carbon-compatible.*//*------------------------------ Includes ----------------------------*/#include "Randomizer.h"// Mac OS API#include <Files.h>#include <Folders.h>#include <Events.h>#include <Processes.h>#include <Gestalt.h>#include <Resources.h>#include <LowMem.h>// Standard C library#include <stdlib.h>#include <math.h>/*---------------------- Function declarations -----------------------*/// declared in OpenSSL/crypto/rand/rand.hextern "C" void RAND_add (const void *buf, int num, double entropy);unsigned long GetPPCTimer (bool is601); // Make it global if needed // elsewhere/*---------------------------- Constants -----------------------------*/#define kMouseResolution 6 // Mouse position has to differ // from the last one by this // much to be entered#define kMousePositionEntropy 5.16 // log2 (kMouseResolution**2)#define kTypicalMouseIdleTicks 300.0 // I am guessing that a typical // amount of time between mouse // moves is 5 seconds#define kVolumeBytesEntropy 12.0 // about log2 (20000/4), // assuming a variation of 20K // in total file size and // long-aligned file formats.#define kApplicationUpTimeEntropy 6.0 // Variance > 1 second, uptime // in ticks #define kSysStartupEntropy 7.0 // Entropy for machine startup // time/*------------------------ Function definitions ----------------------*/CRandomizer::CRandomizer (void){ long result; mSupportsLargeVolumes = (Gestalt(gestaltFSAttr, &result) == noErr) && ((result & (1L << gestaltFSSupports2TBVols)) != 0); if (Gestalt (gestaltNativeCPUtype, &result) != noErr) { mIsPowerPC = false; mIs601 = false; } else { mIs601 = (result == gestaltCPU601); mIsPowerPC = (result >= gestaltCPU601); } mLastMouse.h = mLastMouse.v = -10; // First mouse will // always be recorded mLastPeriodicTicks = TickCount(); GetTimeBaseResolution (); // Add initial entropy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -