Kristjan Kelt
Survey of random number generators
on various platforms
University of Luxembourg 2013
Objective
● Investigate random number generation in several open source libraries, frameworks and applications that are based on cryptography
● Investigated– Pure-Python ECDSA
– PyBitmessage
– BitcoinJS
– Bitaddress.org
– CryptoCat
● Part II (if time permits), Trusting random generators (based on Intel RDRAND)
Importance
● Good random generator is cornerstone of good cryptography– Everything that must be hard to predict needs a
good random source
Importance
● Example attack– September 2006, buy commenting out few lines in
OpenSSL library, Debian developers created a bug that rendered OpenSSL random source useless
● Bug was discovered May 2008 by Luciano Bello● All cryptographic keys generated on Debian (or derived
distributions like Ubuntu) with OpenSSL turned out to have only 15 bit entropy provided by process id)
● All keys generated were possible to break with brute force
Importance
● Second attack example– In 2013 vulnerability in Android SecureRandom
class implementation was described by Michaelis, Meyer, Schwenk
– Cascade of bugs reduced entropy to 31 bits making random numbers generated on Android guessable
– Vulnerability was previously used to steal at least 55 BTC from different wallets that used keys generated on Android
What is a good random number?
● Is 7 a good random number?● What about 21299212?● Or 9?
What is a good random number?
● They all can be either good or bad random numbers depending on how they are generated
Entropy
● Entropy is just the size of the pool from where the numbers are randomly picked– Entropy of 1 coin flip is 1 bit – To get more entropy (in bits), we need more flips
(random events)
● Real random numbers are hard to generate (read: slow) both for brain and computer– But entropy can be mixed, combined and distilled– Unfortunately entropy is also consumed fast by
todays cryptographic applications
PRNG (Pseudo random number generator)
● Benefits– Provides statistically good distribution
– Need very low entropy as a source (i.e. current time)
– Fast
● Why are PRNGs not secure?– Predictability
– Linear dependencies
CSPRNG(Cryptographically Secure Pseudo Random Number
Generator)
● Requirements– Forward secrecy
– Backward secrecy
– State security
– Sufficiently large entropy● RFC 1750 Randomness Recommendations for Security,
Schiller, Crocker, Eastlake 1994
● Cryptanalytic Attacks on Pseudorandom Number Generator, Schneier, Kelsey, Wagner, 1998
Generalized CSPRNG, with periodic reseeding
Generalized CSPRNG, with periodic reseeding
Proposed in 1998 by Schneier, Kelsey, Wagner, Hall in Cryptanalytic Attacks on Pseudorandom Number Generators
Presentation of investigated random number generators
● First operation system provided generators were investigated
● Then platform libraries and browsers ● Finally libraries, frameworks and applications in
question
Operating systems
Linux***
Entropy pool
Entropy sources
Non blocking pool
Blockingpool
/dev/urandom /dev/random
ApplicationHardware entropy
source feedback in user space when available
Saved entropy during boot
get_random_bytes
*** without Intel RDRAND
Linux(few comments)
● Entropy estimator seems to be based upon Kolmogorov complexity rather than Shannon entropy (2012 Pousse, Short communication: An interpretation of the Linux entropy estimator)
● Analysis of the Linux Random Number Generator by Gutterman, Pinkas, Reinman 2006
● The Linux Pseudorandom Number Generator Revisited by Lacharme, Röck, Strubel, Videau 2012
Yarrow-160
OSX
Entropy pool(non blocking)
Entropy sources
/dev/random /dev/urandom
Entropy sources
Windows XP
?????
CryptGetRandom
Application
Windows Vista & 7
?????
CryptGetRandom
Application
BCryptGenRandom
?????
?=
Windows 8
?????
CryptGetRandom????
Application
BcryptGenRandomFIPS ?? NIST ??
?????
?=
CryptographicBuffer.GenerateRandom
??
?????
?=
Platform libraries
Windows *Linux, OSX
Python
os.urandom(direct wrapper)
random.SystemRandom
/dev/urandom CryptGetRandom
Application
OpenSSL
Windows *Linux, OSX
RAND_bytes(OpenSSL has different engines but according to documentation
seeds at least once at first call)
/dev/urandom CryptGetRandom
Application
Browsers
Firefoxsince version 21
Windows *Linux, OSX
window.crypto.getRandomValues()
/dev/urandom CryptGetRandom
Application
NIST SP 800-90 - Hash_DRBG (SHA256)(seed length 440 bits, reseeded after 2^48 bytes,
generator is shared between threads)
Internet Explorersince version 11
Windows 7, Windows 8
window.crypto.getRandomValues()
BCryptGetRandom
Application
Webkit(Safari, Chrome, Opera, browser specific)
Windows *Linux, OSX
window.crypto.getRandomValues()
/dev/urandom CryptGetRandom
Application
ARC4 stream cipher based random number generator(seed length 1024 bits, reseeded after 1600000 bytes,
generator is shared between threads)
Libraries, frameworks and applications in question
CryptoCat
window.crypto.getRandomValues
Salsa20/20(seed size 256 bits, reseed never)
Chat Application
Pure-Python ECDSA (library)
os.urandom
ApplicationClass PRNG
Sha256 + counter
Class SigningKey(default NIST192p)
util.randrange(small wrapper around
os.urandom)
OpenSSL library
PyBitmessage (library)
OpenSSL.RAND_bytes
Application
OpenSSL.rand(a library wrapper)
RAND_bytes
addressGenerator
BitcoinJS
● Library crypto.js – contains Crypto.util namespace that with function randomBytes that uses Math.random()
● Library rng.js, provides class SecureRandom– on pool initialization calls window.crypto.random in case of
specific browser version (this interface does not exist) – Then continues to fill pool with Math.random()– Finally adds current time (in ms) to the end of the pool
BitcoinJS
● Library rng.js, prototype SecureRandom– When generating first random byte, creates a ARC4
generator seeded by current pool + current time
– Seed size is 1024 and it is calculated over potentially larger entropy pool
– Generator is never seeded again
BitcoinJS
● At the top of the rng.js is a suggestion to call rng_seed_time() on body.onClick and body.onKeyPress – As generator is never seeded again, it has effect
only till first byte is generated
– Does not suggest mouse movements
– Sample user interface implementation does not follow this suggestion
BitcoinJS
Math.random()
Application
SecureRandom.nextBytes
ARC4(seed size 1024,
from potentially larger entropy pool, never reseeded)
Mouse and keyboard Current time
Bitaddress.org
● Incorporates code from different libraries including BitcoinJS
● Uses similar SecureRandom class but indeed follows the suggestion to fill the pool based on random user generated events
● Uses mouse move event in addition– Uses current time and mouse pointer coordinates
(X*Y)
Bitaddress.org
● Uses seed count to collect enough entropy● Seed count threshold is generated with
Math.random() (from Crypto.util.randomBytes)
Bitaddress.org
● When generating random bytes, checks for existence of window.crypto.getRandomValues– When present, returns bytes using this interface
instead
– In practice this renders seed counting useless as it does not change seed for the window.crypto.getRandomValues
Bitaddress.org
window.crypto.getRandomValues
SecureRandom.nextBytes
ARC4(seed size 1024,
from potentially larger entropy pool, never reseeded)
OR
Application
Full Random Generation Chains
● Pure-Python ECDSA ● PyBitmessage● Bitaddress.org (including parts of BitcoinJS)● CryptoCat
Pure-Python ECDSArandom generation chain
Windows *OSX
/dev/urandom CryptGetRandom
????? ?????
Entropy pool
Linux
/dev/urandom
?????
Entropy pool
Non blocking pool
os.urandom(direct wrapper)
Application
Class SigningKey(default NIST192p)
util.randrange(wrapper around os.urandom)
PyBitmessagerandom generation chain
Windows *OSX
/dev/urandom CryptGetRandom
????? ?????
Entropy pool
Linux
/dev/urandom
?????
Entropy pool
Non blocking pool
OpenSSL.RAND_bytes
Application
addressGenerator
OpenSSL.rand(a library wrapper)
FirefoxNIST SP 800-90 - Hash_DRBG (SHA256)
CryptoCatrandom generation chain
window.crypto.getRandomValues
Salsa20/20
Chat Application
WebkitARC4
Windows *OSX
/dev/urandom CryptGetRandom
window.crypto.getRandomValues
????? ?????
Entropy pool
Linux
/dev/urandom
?????
Entropy pool
Non blocking pool
FirefoxNIST SP 800-90 - Hash_DRBG (SHA256)
Bitaddress.orgrandom generation chain
window.crypto.getRandomValues
WebkitARC4
Windows *OSX
/dev/urandom CryptGetRandom
window.crypto.getRandomValues
????? ?????
Entropy pool
Linux
/dev/urandom
?????
Entropy pool
Non blocking pool
SecureRandom.nextBytes
Application
OR
Math.random()
ARC4
Mouse and keyboard
Current time
Conclusion
● In general most investigated projects got things right– Only really problematic project is
BitcoinJS that can not be used directly out of the box
– Bitaddress.org that extends on BitcoinJS got the things (relatively) right though
●
Conclusion continues
● Random number generation consist very often different linked random number generators
● Cryptography application writer must understand full random generation chain of target platforms
Questions or Part II(if time permits)
Trusting Random Generators
Trusting Random Generators
● Dual_EC_DRBG (Dual Elliptic Curve Deterministic Random Bit Generator)
● Intel RDRAND instruction in Linux
Dual_EC_DRBG(Dual Elliptic Curve Deterministic Random Bit Generator)
● Part of NIST Special Publication 800-90A– National Institute of Standards and Technology
– Recommendation for Random Number Generation Using Deterministic Random Bit Generators
– Contains 4 specifications
● Contains possible backdoor– Showed by Dan Shumow and Niels Ferguson at the
CRYPTO 2007 conference in August
– Still used (after 2007) by RSA security (confirmed) and possibly by Intel and Microsoft (suspected)
– Backdoor somewhat confirmed in 2013
Intel RDRAND in Linux
● Documentation of Linux random driver (comments of random.c) states that hardware random sources are not part of the kernel and entropy from them should be feed back into the pool externally
● 2011 Intel engineers approached Linux and suggested to incorporate Intel RDRAND instruction directly into Linux kernel as an architectural entropy source
Intel RDRAND in Linux
● Everything went (relatively) smoothly and patches went into kernel
● Fast forward to third quarter of 2013 when revelations of Dual_EC_DRBG came out
● Suddenly people noticed that documentation of RDRAND mentions NIST SP 800-90A– But this contains also Dual_EC_DRBG
– But Linux uses RDRAND
Intel RDRAND in Linux
● Linus Torvalds made a statement that– Kernel maintainers actually know what they are doing
– Output of RDRAND is mixed into entropy pool before it is returned to the user
● Theodore Ts said– "I am so glad I resisted pressure from Intel engineers
to let /dev/random rely only on the RDRAND instruction.”
Intel RDRAND in Linux(change history)
void get_random_bytes(void *buf, int nbytes){- extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);+ char *p = buf;++ while (nbytes) {+ unsigned long v;+ int chunk = min(nbytes, (int)sizeof(unsigned long));++ if (!arch_get_random_long(&v))+ break;++ memcpy(buf, &v, chunk);+ p += chunk;+ nbytes -= chunk;+ }++ extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);}EXPORT_SYMBOL(get_random_bytes);
author Linus Torvalds <[email protected]> 2011-10-28 12:29:07 (GMT)committer Linus Torvalds <[email protected]> 2011-10-28 12:29:07 (GMT)
Intel RDRAND in Linux(change history)
static void add_timer_randomness(struct timer_rand_state *state, unsigned num){
struct {- cycles_t cycles;long jiffies;+ unsigned cycles;unsigned num;
} sample;long delta, delta2, delta3;
@@ -637,7 +637,11 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
goto out;
sample.jiffies = jiffies;- sample.cycles = get_cycles();++ /* Use arch random value, fall back to cycles */+ if (!arch_get_random_int(&sample.cycles))+ sample.cycles = get_cycles();+
sample.num = num;mix_pool_bytes(&input_pool, &sample, sizeof(sample));
author Linus Torvalds <[email protected]> 2011-12-22 19:36:22 (GMT)committer H. Peter Anvin <[email protected]> 2011-12-30 00:49:45 (GMT)
Intel RDRAND in Linux(change history)
● Function add_input_randomness is called by– add_input_randomness
– add_disk_randomness
Intel RDRAND in Linux(change history)
author Theodore Ts'o <[email protected]> 2011-12-22 21:28:01 (GMT)committer H. Peter Anvin <[email protected]> 2012-01-16 19:18:21 (GMT)
static void init_std_data(struct entropy_store *r){
+ int i;ktime_t now;unsigned long flags;
@@ -974,6 +975,11 @@ static void init_std_data(struct entropy_store *r)now = ktime_get_real();mix_pool_bytes(r, &now, sizeof(now));
+ for (i = r->poolinfo->poolwords; i; i--) {+ if (!arch_get_random_long(&flags))+ break;+ mix_pool_bytes(r, &flags, sizeof(flags));+ }
mix_pool_bytes(r, utsname(), sizeof(*(utsname())));}
Intel RDRAND in Linux(change history)
author Linus Torvalds <[email protected]> 2012-01-17 02:23:09 (GMT)committer Linus Torvalds <[email protected]> 2012-01-17 02:23:09 (GMT)
static void init_std_data(struct entropy_store *r){+ int i;
ktime_t now;unsigned long flags;
@@ -974,6 +975,11 @@ static void init_std_data(struct entropy_store *r)now = ktime_get_real();
mix_pool_bytes(r, &now, sizeof(now));+ for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof flags) {+ if (!arch_get_random_long(&flags))+ break;+ mix_pool_bytes(r, &flags, sizeof(flags));+ }
mix_pool_bytes(r, utsname(), sizeof(*(utsname())));}
Intel RDRAND in Linux(change history)
● If the CPU supports a hardware random number generator, use it in xfer_secondary_pool(), where it will significantly improve things and where we can afford it.
● Also, remove the use of the arch-specific rng in add_timer_randomness(), since the call is significantly slower than get_cycles(), and we're much better off using it in xfer_secondary_pool() anyway.
author Theodore Ts'o <[email protected]> 2012-07-05 14:21:01 (GMT)committer Theodore Ts'o <[email protected]> 2012-07-15 00:17:46 (GMT)
Intel RDRAND in Linux(change history)
● Mix in any architectural randomness in extract_buf() instead of xfer_secondary_buf(). This allows us to mix in more architectural randomness, and it also makes xfer_secondary_buf() faster, moving a tiny bit of additional CPU overhead to process which is extracting the randomness.
author H. Peter Anvin <[email protected]> 2012-07-28 02:26:08 (GMT)committer Theodore Ts'o <[email protected]> 2012-07-28 02:37:20 (GMT)
Intel RDRAND in Linux(change history)
author H. Peter Anvin <[email protected]> 2012-07-28 02:26:08 (GMT)committer Theodore Ts'o <[email protected]> 2012-07-28 02:37:20 (GMT)
static void extract_buf(struct entropy_store *r, __u8 *out){
[...............]
+ /*+ * If we have a architectural hardware random number+ * generator, mix that in, too.+ */+ for (i = 0; i < LONGS(EXTRACT_SIZE); i++) {+ unsigned long v;+ if (!arch_get_random_long(&v))+ break;+ hash.l[i] ^= v;+ }++ memcpy(out, &hash, EXTRACT_SIZE);+ memset(&hash, 0, sizeof(hash));}
Code of the previous slide
Possible attack of Intel RDRAND in Linux
● Taylor Hornby– At the first sight there is no problem as RANDOM
xor INDEPENDENTLY_BIASED = RANDOM
– What if RDRAND is used as a marker to activate malicious behavior of the CPU?
– Then when it sees the RDRAND followed by XOR, it could bias the RDRAND output according to the second input of the XOR (in this case the state of the entropy buffer)
Intel RDRAND in Linux(change history, current fix of the previous problem)
author Theodore Ts'o <[email protected]> 2013-09-21 22:06:02 (GMT)committer Theodore Ts'o <[email protected]> 2013-10-10 18:32:13 (GMT)
● Previously if CPU chip had a built-in random number generator (i.e., RDRAND on newer x86 chips), we mixed it in at the very end of extract_buf() using an XOR operation.
● We now mix it in right after the calculate a hash across the entire pool. […]
Conclusion
● Random number generator in the CPU can not be trusted