mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Overview documentation for random number generation
This commit is contained in:
parent
f2f8ed28ea
commit
e0803c01fc
267
doc/crypto-rng.dox
Normal file
267
doc/crypto-rng.dox
Normal file
@ -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
|
||||
<a href="http://robseward.com/misc/RNG2/">Rob Seward</a>.
|
||||
\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 <Crypto.h>
|
||||
#include <RNG.h>
|
||||
#include <TransistorNoiseSource.h>
|
||||
\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 <tt>/dev/urandom</tt> 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 <tt>/dev/random</tt> 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
|
||||
|
||||
*/
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user