Fortuna: Cryptographically Secure Pseudo-Random Number Generation In Software And Hardware Robert McEvoy† , James Curran, Paul Cotter, and Colin Murphy‡ Department of Electrical and Electronic Engineering University College Cork IRELAND † E-mail:
[email protected] ‡
[email protected] Abstract — Fortuna is a pseudo-random number generation algorithm, recently published by Ferguson and Schneier [1]. The algorithm is specifically designed to be cryptographically secure from known attacks. This paper presents a software implementation of Fortuna on a PC, including acquisition of entropy from commonly available sources, and statistical analysis of the results. Using an FPGA, which offers increased security, hardware implementation aspects are also studied and contrasted with the software version. Keywords — Fortuna, CSPRNG, Entropy, AES, SHA, FPGA
I
Introduction
Random numbers are widespread in modern cryptography. Practically every cryptographic protocol requires the use of a random number. For example, when generating a key stream used in one-time-pads or stream ciphers, a pseudo-random bit stream of the same size as the message is used to encrypt/decrypt the message [2]. Random numbers are also used to generate digital signatures, keys for the AES encryption algorithm, large primes for the RSA algorithm, and are used in challenge-response identification systems. Random Number Generators (RNGs) fall into three categories. True RNGs produce random data based on unpredictable physical sources, such as electrical resistor noise, or oscillator phase noise [3]. However, TRNGs produce random data at relatively low rates (e.g. 20 kbps). Pseudorandom Number Generators (PRNGs) use a deterministic method to generate random numbers, employing a (truly random) seed to initialise the algorithm. Cryptographically Secure PRNGs (CSPRNGs) are PRNGs which have been specially designed to be resilient to certain cryptographic attacks. Given a sequence of k bits generated by a CSPRNG, it should be computationally infeasible to predict bit k + 1 with confidence greater than 1 2 . Furthermore, if all or part of the internal state of the CSPRNG is revealed, it should not be possible to deduce the numbers previously generated. Fortuna [1] is one such CSPRNG algorithm. In this paper, a software-based implementa-
tion of Fortuna using C++ is investigated. The implementation uses sources of true randomness (entropy) which are readily available from PCs. An FPGA-based hardware design is also demonstrated, giving increased throughput and security compared to the software-based design. FPGAs are suitable for use as cryptographic accelerators due to their low cost (relative to ASICs), and their flexibility when adopting security protocol upgrades. To the best of the authors’ knowledge, this is the first hardware-based implementation of the Fortuna algorithm in the literature. The rest of this paper is organised as follows. The following section gives an overview of the Fortuna algorithm, as described in [1]. Details of the truly random sources used to seed Fortuna are given in Section III. Section IV describes the software implementation of the algorithm, and notes some of the design choices that were necessary. The FPGA implementation is discussed in Section V, and timing and statistical analyses of the generators’ outputs are presented in Section VI. II
The Fortuna Algorithm
A full description of Fortuna can be found in Chapter 10 of [1], where the purpose of each aspect of the algorithm is explained in detail. Essentially, Fortuna comprises three parts: an entropy accumulator, a random number generator, and a system for seed file management.
Pool P0 Pool P31
128−bit counter
Reseed? Pool P1
Random Seed from Accumulator 1
Random Key
AES−256
Pseudo−random Data
0
Entropy Source
Next Key
Fig. 2: Fortuna’s Generator Core
Pool P15
Fig. 1: Fortuna’s 32 Entropy Pools
a)
Entropy Accumulator
Fortuna’s accumulator gathers truly random data from various external entropy sources, and uses it to seed (and reseed) the generator. The algorithm allows the use of up to 256 sources of entropy. In this implementation, three entropy sources were utilised (see Section III). Fortuna is designed so that the system will remain secure if an attacker gains control of some, but not all, of the entropy sources. This resilience is achieved through use of entropy ‘pools’, as illustrated in Figure 1. Random events from the external sources are uniformly and cyclically distributed amongst 32 pools, labelled P0 , P1 , . . . , P31 respectively. Therefore, each pool can contain random data of (theoretically) unbounded length. In order to cope with this storage problem, data in a particular pool is incrementally compressed, each time an event is added to that pool. The compression function used is the SHA-256 hash function [4], thereby maintaining a constant pool size of 32 bytes. When pool P0 has accumulated ‘enough’ random data (as defined in Section IV below), the generator can be reseeded. A counter r tracks the number of times the generator has been reseeded from the pools. This counter determines which pools will be used in the current reseed, i.e. pool Pi will be included in the reseed if 2i divides r. Hence, P0 is included in every reseed, P1 in every second reseed, etc. Consequently, whilst higher numbered pools contribute less frequently to reseedings, they do, however, collect a larger amount of entropy between reseedings. Reseeding is performed by hashing the specified entropy pools together, using two iterations of SHA-256, henceforth denoted SHAd -256, where d denotes ‘double’. Once a pool has been used in a reseed, it is then reset to zero. Provided there is at least one source of entropy over which an attacker has no control, she will be unable to predict the contents of at least one pool, and therefore will be unable to break the RNG in this way.
b)
Generator
The generator takes a fixed size random seed from the entropy accumulator and produces arbitrarily long sequences of pseudo-random data. The generator consists of a block cipher in counter encryption mode, as shown in Figure 2. In this implementation, AES-256 [5] was chosen as the block cipher. The plaintext input to the block cipher is simply a counter, and the 256-bit keys come from the accumulator. Since AES is a 128-bit block cipher, it generates 16 bytes of data at a time. Once it has generated this data, it generates two further blocks, which will be used as a new key the next time it is required to generate data. This satisfies the requirement that knowledge of the current state of the generator does not reveal the past data generated. If the generator were to generate very long sequences of random data in one call, the data would have a period of 2128 . Since periodic data is not secure, the generated data is limited to 220 bytes per request. The generator will then change the key, or check for a reseed, before continuing. c)
Seed File Manager
Upon initialisation of Fortuna, a ‘seed file’ provides a seed to the generator . This initial seed allows the generator to produce random data, even before enough entropy has been gathered by the accumulator. The seed file is read at start-up, and a new seed is immediately generated and written to the file. While Fortuna accumulates entropy, this data is used to create a better quality seed. It is recommended [1] that a new seed file be generated approximately every ten minutes, but this depends heavily on the application, and on the rate of accumulation of entropy. III
Entropy Sources
As noted in Section II, Fortuna can accommodate up to 256 sources of entropy. In reality, however, it is unlikely that so many sources of unpredictable information would be available to a generator. In the designs presented in this paper, one of the aims was to use sources that would be readily available to the average PC user1 . Therefore, three sources 1 In this implementation, a Dell Optiplex GX270 PC was R 4 CPU, and 768 MB RAM. used, with 2.4 GHz Pentium
4000
of entropy were investigated: mouse movement, keystroke timing, and noise on the microphone input of the PC’s soundcard.
5000
3500
3000
a)
4000
Mouse Movement
b)
Keystroke Timing
Timing between keystrokes is measured by sampling the keyboard every millisecond. This yields a byte of data representing the key struck, and a 32-bit integer representing the timing. Similar to the mouse, the four least significant bits from each number are used to give the truly random data. This source will only produce data as the keys are used, as in the case of the mouse. When both keyboard and mouse sources are running and the computer is being used in a normal fashion, the sources produce an average of 100–200 bits per second. This data-rate depends on typing speed and the particular applications being used, however. c)
Soundcard Noise
Although keystroke timings and mouse movements make reasonable entropy sources, they require the presence of a user in order to generate the data. One could argue that an attacker could easily gain control of these sources, and force them to behave in a predictable way. Therefore, it was decided to add soundcard noise to the Fortuna implementation, as a constant source of randomness which would be more difficult to attack. Recall that it is not a problem if the attacker can predict or copy data from some of the sources, as long as she does not obtain control of them all. The soundcard noise also ensures that some amount of random data is always input to the entropy pools, even if the keyboard and mouse are not being used. In this implementation, an Analog Devices Inc. SoundMAX Integrated Digital Audio soundcard was used. Sixteen-bit samples were taken at
Frequency
2500
Movement of a mouse is considered truly random, as it is operated by a user. Although the general position of the cursor at any one time can be estimated by an attacker, and will most likely have a pattern, the least significant denominations of its position cannot be guessed [6]. The position of the cursor is defined in the Windows API as a structure of two long integers, x and y. These values range (depending on the display resolution) from 0–640/480 for a 15-inch monitor to 0–1280/1024 for a 19-inch monitor. Taking the least significant four bits of the x and y position as true random data is thought to be safe, as no test to date has concluded that this information is not usable. Mouse movement is monitored, and if the mouse has not been moved for a number of samples, data is not gathered from it until such time as the mouse has been moved again.
3000 2000
1500
2000
1000 1000 500
0
0
50
100
150
200
250
Integer value of 8 x 1-bit samples
0
0
50
100
150
200
250
Integer value of 2 x 4-bit samples
Fig. 3: Histograms of sound card samples
44.1 kHz from the unconnected microphone input of the soundcard. In order to obtain truly random data, the least significant bits (LSBs) of these samples were taken in groups of 1, 2, and 4 LSBs, concatenated respectively into bytes, and analysed using histograms (see Figure 3). It is clear from the histograms that taking only the last LSB of each sound card sample provides the most uniform spread of random data. Therefore, in the implementation, 8 samples from the sound card are taken, each giving 1 bit of true random data. These 8 bits are then concatenated into a byte and added to one of the accumulator’s pools. IV
Software Implementation
The software implementation of Fortuna was written using a C++ class structure, and compiled with Microsoft Visual C++ 6.0. A flow diagram of the software implementation is shown in Figure 4. A GUI, written using MFC functions in Visual C++, provides the user interface to Fortuna. C++ routines were also designed to gather random data from the entropy sources, and to perform the well-known SHAd -256 and AES-256 cryptographic algorithms [4, 5]. A typical flow of functions used in Fortuna would be: 1. Call the InitialisePRNG function at PC boot-up, to initialise the pools and the generator variables. 2. Call the UpdateSeed function to create a new key for the generator from the seed file, and call WriteSeed. 3. Call StartSources to begin accumulating entropy from the sources, as described in Section III. 4. Call WriteSeed periodically to ensure that the generator will have a fresh seed file for the
Seed File InitialisePRNG StartSources Reseed GenerateData StopSources
Entropy Sources
WriteSeed UpdateSeed
Pools P0 P1 P2
PoolManager AddEvent CheckPoolSize GetPoolData
SeedFileManager
128−bit counter Update Seed?
Reseed?
True True
SHAd -256
False
SHAd -256
Random Key
AES−256
False
Pseudo-random Data
Next Key
P31
Fig. 4: Software Flow Diagram of Fortuna Implementation
next start-up, in case the computer crashes or is powered down unexpectedly. 5. Call GenerateData when the user requests the generation of a specified amount of pseudorandom data. At this high level of operation, the reseeding from the entropy pools is done automatically. 6. Call StopSources before exiting the program. 7. Call WriteSeed to write a new seed file for the next start-up. Throughout the development of the software for Fortuna, a number of design choices were necessary. Addition of data to the pools is controlled by the PoolManager program, which contains functions AddEvent, CheckPoolSize, and GetPoolData. In order to avoid conflicts if two or more data sources try to access the same pool at the same time (via AddEvent), it was necessary to define a shared data segment. This flag is set when a pool is in use, allowing only one process access to the pool at any one time. The flag also prevents conflicts when the generator is being seeded from the pools (via GetPoolData). Secondly, the generator should only be reseeded from the pools when ‘enough’ random data has been added to them. Since the seed is used as a 256-bit AES key, it is desirable that the key is completely random, i.e. that this key contains 256 bits of entropy. With each call to AddEvent, the sources add one byte of random data to the pools. Although one might assume that each of these bytes contains 8 bits of entropy, in this implementation a more conservative estimate of the entropy was chosen. Specifically, here it is assumed that each call to AddEvent adds 4 bits of entropy to one of the pools. Hence 256 4 = 64 events have to be added to pool P0 before it can be used in a reseed. The function CheckPoolSize monitors this total. The Fortuna algorithm [1] recommends that the random data be incrementally compressed
(hashed) as it is added to the pools. This would require 32 running hash calculations for the 32 pools, utilising substantial memory resources to store the state variables for each of the 32 instances of the SHA-256 algorithm. Instead, upon receiving an event from one of the entropy sources, this implementation uses AddEvent to take existing data from the active pool. This data is concatenated with the new random byte, producing a 264-bit string which is hashed again and returned to the same pool. Therefore, the size of each pool is kept to 256 bits, and extra memory is not required. There is one other difference between the specification in [1] and this software implementation of Fortuna. When adding random data to the pools, a string specifying the length of the data should also be included. However, in this design, the size of the random event is always one byte. Because this information is invariant, it contains no randomness. Consequently, it was decided to omit the insertion of this string from the implementation. A possible weakness can be noted with this method of implementing Fortuna’s accumulator. If an attacker was capable of detecting the existence of a PoolManager process and its CPU usage, she could deduce the particular member function being performed. This could be used to estimate how much data was being added to the pools, and hence the pool size could be estimated. The attacker could potentially deduce when, or more importantly, when not, the generator had been freshly reseeded. In effect, the state of the generator could, with some level of confidence, be deduced by monitoring the CPU. Although many algorithms are susceptible to this type of sidechannel attack [1], it is still worthy of note. V a)
Hardware Implementation
Motivation
The motivation for moving the Fortuna design to a hardware-based implementation was threefold. Firstly, dedicated hardware architectures for SHA-256 and AES-256 encryption allow these operations to be performed much more quickly than
HASH TO POOL
RESEED FROM POOLS
ADD EVENT TO POOL
RESET POOLS
HASH TO KEY
GENERATE BLOCK
OUTPUT BLOCK
READY
CLR SHA
CLR SHA
REGEN 1
RST AES
REGEN 2
REGENERATE KEY
Fig. 5: Hardware State Machine for Fortuna
on an ordinary microprocessor. Since SHA-256 and AES-256 are used extensively in Fortuna, far greater throughputs are attainable from the hardware design compared to the software design (see Section VI). Increased security is another advantage of implementing Fortuna in hardware. Since all of the entropy pools and the generator states are stored in RAM within the FPGA, the information is much more difficult for an attacker to access. Furthermore, the power consumption of the board is not as easily remotely attained as CPU usage, meaning side channel attacks (such as discussed above) are more difficult to mount. A possible disadvantage of the hardware implementation is that the communication channels to the FPGA must be secured, so that seed files or data from the external entropy sources are not intercepted. However, these channels must also be kept similarly secure in the software implementation. Thirdly, an integrated System-on-a-Chip (SoC) solution to cryptographically secure random number generation such as this could be particularly useful in constrained secure computing environments. For example, the system could be used to provide security for transactions using mobile phones or PDAs. Alternative sources of entropy would be necessary in such embedded systems, such as local oscillator phase noise, or packet arrival timing information. A further advantage of using Fortuna as the CSPRNG is that it can reuse cryptographic hardware that may already be in place to perform AES-256 or SHA-256 operations. b)
Implementation Details
The FPGA used in the hardware implementation was a Xilinx Virtex IITM xc2v6000-4ff1152, mounted on a ADM-XRC-II PCI Card. The Fortuna design was captured at the RTL level using VHDL. High-performance designs were chosen to perform the main cryptographic algorithms; an inhouse design for SHA-256 from [7], and an AES256 encryption/decryption core from Algotronix Ltd. [8]. A state machine was designed in VHDL
to control the dataflow to/from RAM, and to automate the RNG process, as illustrated in Figure 5. PC communication with the FPGA was over a 128-bit bidirectional data bus, 32-bit control bus and 32-bit status bus, and was handled by a C++ wrapper (provided by Alpha Data). A C++ application was designed which provided the following four user operations: (i) write a seed file to the FPGA; (ii) request random data (iii) request random data, using a specified seed file; and (iv) add variable length random events from the entropy sources. The functionality of the user interface is therefore restricted, as recommended in the model of [9]. The design utilises 5, 399 FPGA CLB slices (15%), and 8 block RAMs (5%). The maximum operating clock frequency of the design is 65 MHz, corresponding to a critical path of 15.3 ns. The state machine also includes modes (not shown above) whereby the RNG hardware can be re-used for accelerated encryption/decryption or hashing. VI
Results
Speed and area results attained from the hardware and software implementations of Fortuna are compared in Table 1 below. Clearly, the hardware implementation far outperforms the software, achieving throughputs of up to 3.4 times greater. Given the added security afforded by the hardware, it is clearly the implementation of choice for highperformance embedded security systems. Table 1: Fortuna Size/Throughput Results Design Software Hardware
Area 2.14MB executable 15% Virtex II FPGA
Throughput 7.2 Mbps 24.6 Mbps
In order to evaluate the statistical qualities of the random data generated by the software and hardware implementations of Fortuna, the publically available Diehard test suite [10] was used. Diehard consists of a battery of 19 statistical tests of randomness, performed on (at least) 12MB of data. Each test returns P-values ([11],
Section 8.4), measuring the probability that a sample of the test data disagrees with the Null Hypothesis H0 . In this case H0 is that the test data has a particular distribution D. If the P-value is zero for all tests, then it is clear that the data is not random, as no sample has the distribution D. On the other hand, if the P-value is one for any test, the data is not random either, as all samples have the same distribution D. In the case of random data generated by Fortuna, it is desirable that the P-values returned by Diehard have a uniform distribution over (0,1). Diehard will return a ‘fail’ result if any of the 219 P-values generated are equal to one but, apart from this, there are no other pass criteria. In order to analyse the P-values more fully, a scoring scheme by Johnson [12] was used, as chosen also by [13]. The scheme assigns a score to each of the 219 P-values returned by Diehard, according to Table 2. Table 2: Diehard Scoring System [12] P-value Label Score 0 < p < 0.95 Good 0 0.95 ≤ p < 0.998 Suspect 2 p ≥ 0.998 Bad 4 Both the hardware and software implementations of Fortuna were used to generate fifty 12MB files each, while the entropy sources were running. The Diehard tests were performed on these files, and scores given to the results. The average scores are presented in Table 3, along with scores from other RNGs [13]. The hardware and software implementations of Fortuna presented here produce random numbers of similar statistical quality to other high-performance RNGs in the literature. Table 3: Comparison of RNG Diehard Scores RNG Score ‘Mother’ 20 True (TRNG) 22 Fortuna (hardware) 24 Fortuna (software) 24 32-bit LFSR 162 EQG 288 LFSR 756 Maximum (worst) possible score 876 VII
Conclusion
In this paper, the Fortuna algorithm was employed as a solution to the problem of cryptographically secure pseudo-random number generation. A software implementation of Fortuna was presented that utilised sources of entropy which are commonly available to the average PC user.
The Fortuna algorithm was also implemented on an FPGA, in order to attain increased throughput and security. Results from this hardware implementation show the usefulness of Fortuna as a dedicated RNG module, in a secure embedded computing system. Both hardware and software designs were shown to produce very high quality random data, which compares favourably with other CSPRNG designs in the literature. Acknowledgements The authors would like to thank Algotronix Ltd. for providing access to VHDL code for their AES module. This work was supported in part by the Embark Initiative, operated by the Irish Research Council for Science, Engineering and Technology (IRCSET). References [1] N. Ferguson and B. Schneier, Practical Cryptography, Wiley Publishing, Inc., 2003. [2] A. J. Menezes, P. van Oorschot, and S. Vanstone, Handbook of Applied Cryptography, CRC Press, 1996. [3] K. H. Tsoi, K. H. Leung, and P. H. W. Leong, “Compact FPGA-based True and Pseudo Random Number Generators.”, in FCCM. 2003, pp. 51–61, IEEE Computer Society. [4] NIST, “Secure Hash Standard, FIPS PUB 180-2”, 2002. [5] NIST, “Advanced Encryption Standard, FIPS PUB 197”, 2001. [6] T. Matthews, Suggestions for Random Number Generation in Software, RSA Laboratories Bulletin #1. RSA Labs, Jan. 1996. [7] R. McEvoy, F. Crowe, C. Murphy, and W. Marnane, “Optimisation of the SHA-2 Family of Hash Functions on FPGAs”, in ISVLSI. 2006, pp. 317– 322, IEEE Computer Society. [8] Algotronix Ltd., “Advanced Encryption Standard (AES) Core”, http://www.algotronix.com /engineering/aes1.html. [9] B. Barak and S. Halevi, “A model and architecture for pseudo-random generation with applications to /dev/random.”, in ACM Conference on Computer and Communications Security. 2005, pp. 203–212, ACM. [10] G. Marsaglia, “Diehard Battery of Tests of Randomness”, http://stat.fsu.edu/pub/diehard/. [11] J. L. Devore, Probability and Statistics for Engineering and the Sciences, Duxbury, 2000. [12] B. C. Johnson, “Radix-b-extensions to some common empirical tests for pseudorandom number generators.”, ACM Trans. Model. Comput. Simul., vol. 6, no. 4, pp. 261–273, 1996. [13] P. Martin, “An Analysis of Random Number Generators for a Hardware Implementation of Genetic Programming using FPGAs and Handel-C, Technical Report CSM-358”, Jan. 2002.