December 6, 2017

Cryptographically Secure Pseudo-Random Number Generator (CSPRNG) in Linux and Java

Introduction

What is random? Example is the below bits randomly generated?

0100 1101 1101 0011

The probability for that is 1/2^16.

And to measure the uncertainty we introduce the notion entropy. And in Linux you can get the current entropy by:

$ cat /proc/sys/kernel/random/entropy_avail 
942

And in Linux there are two way to get random data

/dev/urandom (non-blocking)
/dev/random  (blocking)

So to get 128 bits from /dev/urandom you can do

$ dd if=/dev/urandom bs=128 count=1 2> /dev/null | od -t x1 -An
 fa 17 5c ae d2 6a 3f 82 8b 42 41 d9 72 bb 64 a1
 86 62 bc 04 65 e6 df 45 ce cb 24 fe 97 8f 14 25
 43 a2 0f 8a 43 07 b0 e4 b8 97 7f fe 24 32 b0 26
 6f 4e 12 d3 9b bc b4 40 e8 74 9e 03 6d cc 2f 02
 6f 54 dc 98 6a c8 fa 12 6c ed de 0e cd 89 16 d6
 2b b7 14 07 a9 c4 75 21 8e 79 04 48 c2 a9 7e b2
 1e a5 43 41 63 5a 82 01 ae 19 87 d2 06 d1 49 be
 5f ab 0d 0e 75 15 f1 50 b6 ba f6 40 c3 5e 0f 30

So the randomness in the Linux Kernel can be illustrated as

Entropy Sources:
 - Keyboard                                |--> Blocking entropy pool     --> /dev/random (blocking)
 - Interrupts   --> Primary Entropy Pool --|
 - Disk                                    |--> Non-blocking entropy pool --> /dev/urandom (non-blocking)
 - Mouse

Java

In Java things are more simple, always use java.security.SecureRandom.

// blocking random
SecureRandom nonBlockingSecureRandom = new SecureRandom();
System.out.println("Provider : " + nonBlockingSecureRandom.getProvider());
System.out.println("Algorithm : " + nonBlockingSecureRandom.getAlgorithm());
byte[] nonBlockingRandomBytes = new byte[20];
// SecureRandom randomizer should always be self-seeded
nonBlockingSecureRandom.nextBytes(nonBlockingRandomBytes);
System.out.println("Bytes : " + Arrays.toString(nonBlockingRandomBytes)
);

// blocking random
SecureRandom blockingSecureRandom = SecureRandom.getInstanceStrong();
System.out.println("Provider : " + blockingSecureRandom.getProvider());
System.out.println("Algorithm : " + blockingSecureRandom.getAlgorithm());
byte[] blockingRandomBytes = new byte[20];
// SecureRandom randomizer should always be self-seeded
blockingSecureRandom.nextBytes(blockingRandomBytes);
System.out.println("Bytes : " + Arrays.toString(blockingRandomBytes));

And produces when run on Linux.

Provider : SUN version 1.8
Algorithm : NativePRNG
Bytes : [114, -84, -57, -60, 76, -75, 49, -122, -12, 108, -3, 126, -29, -9, 81, 117, -108, -27, -14, 13]
Provider : SUN version 1.8
Algorithm : NativePRNGBlocking
Bytes : [55, 90, -125, 46, 18, 29, 51, 54, 10, 90, -57, 68, 30, -56, 32, -99, 43, 98, -113, -46]

You can also configure the default behaviour for SecureRandom in

$JAVA_HOME/lib/security/java.security
...
#
# Sun Provider SecureRandom seed source.
#
# Select the primary source of seed data for the "SHA1PRNG" and
# "NativePRNG" SecureRandom implementations in the "Sun" provider.
# (Other SecureRandom implementations might also use this property.)
#
# On Unix-like systems (for example, Solaris/Linux/MacOS), the
# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
# special device files such as file:/dev/random.
#
# On Windows systems, specifying the URLs "file:/dev/random" or
# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
# mechanism for SHA1PRNG.
#
# By default, an attempt is made to use the entropy gathering device
# specified by the "securerandom.source" Security property.  If an
# exception occurs while accessing the specified URL:
#
#     SHA1PRNG:
#         the traditional system/thread activity algorithm will be used.
#
#     NativePRNG:
#         a default value of /dev/random will be used.  If neither
#         are available, the implementation will be disabled.
#         "file" is the only currently supported protocol type.
#
# The entropy gathering device can also be specified with the System
# property "java.security.egd". For example:
#
#   % java -Djava.security.egd=file:/dev/random MainClass
#
# Specifying this System property will override the
# "securerandom.source" Security property.
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be more preferred than
# SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random

#
# A list of known strong SecureRandom implementations.
#
# To help guide applications in selecting a suitable strong
# java.security.SecureRandom implementation, Java distributions should
# indicate a list of known strong implementations using the property.
#
# This is a comma-separated list of algorithm and/or algorithm:provider
# entries.
#
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
...

No comments: