diff --git a/doc/crypto-rng.dox b/doc/crypto-rng.dox new file mode 100644 index 00000000..0f846ad6 --- /dev/null +++ b/doc/crypto-rng.dox @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2015 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** +\file crypto-rng.dox +\page crypto_rng Generating random numbers + +Random numbers are one of the most important aspects of secure cryptography. +Without a good source of random numbers it may be possible for an attacker +to predict the encryption and authentication keys that are used to protect a +session, or to predict the private component of a public/private key pair. +This is especially difficult in embedded environments that do not have +input sources like keystrokes, mouse movements, disk drive write times, etc +to collect entropy from the user. + +\section crypto_rng_features Features of the random number generator + +This library provides the \link RNGClass RNG\endlink class to manage the +global random number pool. It has the following features: + +\li Provision for plug-in environmental noise sources and entropy estimation. +\li Whitening of noise values to scatter the input noise across the entire + random number pool. +\li Support for mixing in static values like serial numbers and MAC + addresses so that otherwise identical devices do not generate the + same sequence of random numbers upon first boot. +\li Cryptographically secure pseudo random number generator (PRNG) for + expanding the noise-based seed into an arbitrary amount of random material + for the application. +\li Periodic saving of the random seed into EEPROM so that the accumulated + entropy is not lost across a power restart. +\li Built-in protection so that if an attacker captures the seed, it cannot + be used to predict past outputs. And after mixing in a modest amount + of new noise, cannot be used to predict future outputs. + +The whitening function and the PRNG are based on ChaCha::hashCore() +with 20 rounds. The structure of the PRNG is very similar to OpenBSD's +ChaCha20-based arc4random() implementation. + +\section crypto_rng_noise_sources Standard noise sources + +The library provides two standard noise sources: + +\li TransistorNoiseSource for collecting avalanche noise from a transistor. + This is based on the work of + Rob Seward. +\li RingOscillatorNoiseSource for collecting entropy from the jitter of a + \ref crypto_rng_ring "ring oscillator". This is a design of my own. + +The transistor design needs an input voltage of 10 to 15 VDC to trigger +the avalanche effect, which can sometimes be difficult in a 5V Arduino +environment. The ring oscillator design can run at 5V but the quality +of the noise is less than for the transistor design. The +RingOscillatorNoiseSource class attempts to make up for this by collecting +more input bits for the same amount of output entropy. +See \ref crypto_rng_ring "this page" for more information on ring oscillators. + +For both of the standard noise sources, the system should have enough entropy +to safely generate 256 bits of key material about 3 to 4 seconds after startup. +This is sufficient to create a private key for Curve25519 for example. + +If you are unsure which noise source to use, then I suggest +TransistorNoiseSource as Rob's design has had more review. Another +approach is to mix multiple noise sources together to get the best +of both worlds. + +\section crypto_rng_init Initializing the random number generator + +To use the random number generator, both \link RNGClass RNG\endlink and a +noise source must first be initialized. We start by including the necessary +libraries: + +\code +#include +#include +#include +\endcode + +Next we create a global variable for the noise source and specify the +I/O pin that the noise circuit is connected to: + +\code +TransistorNoiseSource noise(A1); +\endcode + +Then in the setup() function we call \link RNGClass::begin() RNG.begin()\endlink +to start the random number generator running: + +\code +void setup() { + // Initialize the random number generator with the application tag + // "MyApp 1.0" and load the previous seed from EEPROM address 500. + RNG.begin("MyApp 1.0", 500); + + // ... +} +\endcode + +The begin() function is passed two arguments: a tag string that should +be different for every application and an EEPROM address to use to +load and save the random number seed. The tag string ensures that +different applications and versions will generate different random numbers +upon first boot before the noise source has collected any entropy. +If the device also has a unique serial number or a MAC address, then +those can be mixed in during the setup() function after calling begin(): + +\code +void setup() { + RNG.begin("MyApp 1.0", 500); + RNG.stir(serial_number, sizeof(serial_number)); + RNG.stir(mac_address, sizeof(mac_address)); + ... +} +\endcode + +The random number generator needs 49 bytes of EEPROM space at the +specified address to store the previous seed. When the system is started +next time, the previous saved seed is loaded and then deliberately +overwritten with a new seed. This ensures that the device will not +accidentally generate the same sequence of random numbers if it is +restarted before a new seed can be saved. + +By default the seed is saved once an hour, although this can be changed +with \link RNGClass::setAutoSaveTime() RNG.setAutoSaveTime()\endlink. +Because the device may be restarted before the first hour expires, there +is a special case in the code: the first time that the entropy pool +fills up, a save will be automatically forced. + +To use the random number generator properly, there are some regular tasks +that must be performed every time around the application's main loop(). +Newly accumulated noise must be mixed in with +\link RNGClass::stir() RNG.stir()\endlink and the +\link RNGClass::loop() RNG.loop()\endlink function must be called to +perform auto-saves: + +\code +void loop() { + // ... + + // If the noise source has accumulated new entropy, then stir it in. + RNG.stir(noise); + + // Perform regular housekeeping on the random number generator. + RNG.loop(); + + // ... +} +\endcode + +The random number generator is now ready to generate data. + +\section crypto_rng_using Generating data with the random number generator + +Whenever the application needs random data, it calls +\link RNGClass::rand() RNG.rand()\endlink with a buffer to fill. +The following example generates a 256-bit encryption key and a 128-bit +initialization vector; e.g. for use with AES256 in CTR mode: + +\code +byte key[32]; +byte iv[16]; + +void generateKeys() { + RNG.rand(key, sizeof(key)); + RNG.rand(iv, sizeof(iv)); +} +\endcode + +The data will be generated immediately, using whatever entropy happens to +be in the global random number pool at the time. In Linux terms, the +rand() function acts like the /dev/urandom device. + +If the system has been running for a while then this should be safe as +the noise source would have already permuted the pool with noise-based entropy. +However, when the system first starts up there may not be much entropy +available other than that from the saved seed (which could have been +compromised). + +In Linux terms we want the effect of the /dev/random device which +blocks until sufficient entropy is available to service the request. +Blocking isn't compatible with the Arduino way of doing things, +so the library instead provides the +\link RNGClass::available() RNG.available()\endlink function to poll +how much entropy is in the global random number pool: + +\code +byte key[32]; +byte iv[16]; +bool haveKeys = false; + +void generateKeys() { + if (!haveKeys && RNG.available(sizeof(key) + sizeof(iv))) { + RNG.rand(key, sizeof(key)); + RNG.rand(iv, sizeof(iv)); + haveKeys = true; + } +} +\endcode + +This feature should allow applications to generate secret material safely +at startup. The application may want to implement a timeout: if the +application has to wait too long to generate a key then the noise source +may be disconnected or faulty. + +The global random number pool can hold up to 48 bytes, or 384 bits, of entropy. +Requests for more than 384 bits will be allowed if the entropy is at +maximum. That is, a request for 64 bytes (512 bits) of data will be +allowed when there is only 384 bits of entropy in the pool. This behaviour +prevents the application from waiting indefinitely if the request is +too large. + +If the application truly needs more than 384 bits of real entropy (e.g. to +generate a public/private key pair for an algorithm like RSA), then it +should break the request up into smaller chunks and poll available() +for each chunk. + +\section crypto_rng_secret Destroying secret data + +When the application is finished with the secret key material and plaintext, +it should destroy the data to remove it from RAM permanently. The memset() +function can be used for this purpose: + +\code +memset(key, 0, sizeof(key)); +memset(iv, 0, sizeof(iv)); +\endcode + +However, this may not be safe. Optimizing compilers have been known to +optimize away memset() calls if the compiler thinks that the value won't be +used again. A safer method is to use the clean() function in the library: + +\code +clean(key); +clean(iv); +\endcode + +The clean() function attempts to implement the memory clear in a way +that the compiler shouldn't optimize away. By default the clean() +function figures out the size of the buffer itself at compile time. +In some cases (e.g. buffers that are passed by pointer), it may +be necessary to specify the size manually: + +\code +clean(key, 32); +clean(iv, 16); +\endcode + +*/ diff --git a/doc/crypto.dox b/doc/crypto.dox index 1cd2fa74..63158c47 100644 --- a/doc/crypto.dox +++ b/doc/crypto.dox @@ -50,6 +50,10 @@ hashing, with 256-bit and 512-bit hash outputs respectively. They are intended as high performance replacements for SHA256 and SHA512 for when speed is critical but exact bit-compatibility of hash values is not. +\section crypto_other Examples and other topics + +\li \ref crypto_rng "Generating random numbers" + \section crypto_performance Performance All figures are for the Arduino Uno running at 16 MHz. Figures for the