Libcryptorandom Library 2.0 from Intel

ID 777762
Updated 1/26/2016
Version Latest
Public

author-image

By

Downloads

See the downloads section, below.

Libcryptorandom 2.0 Library Use and Implementation

Libcryptorandom is a cross-platform library that allows programmers to obtain cryptographically secure random numbers from the best available entropy source in the underlying system. The intent of the library is to free the programmer from having to code for the various OS-specific implementations of cryptographically secure random number sources and vendor-provided hardware devices. The calling program merely specifies what grade of random bytes are needed, and the library returns a random number provider that will satisfy the request (if available).

The current implementation of libcryptorandom provides support for two random number sources:

Intel® Data Protection Technology with Secure Key. This hardware entropy source is made available to programs via two CPU instructions: RDRAND for generating high-quality random numbers suitable for cryptographic use, and RSEED for seeding software-based pseudorandom number generators (PRNGs). More information about the Digital Random Number Generator (DRNG) in Secure Key is available in the Intel® Digital Random Number Generator (DRNG) Software Implementation Guide.

The Operating System’s software-based pseudorandom number generator. Currently, the Linux*, OS X* and Windows* facilities are supported.

The 2.0 version of the library provides the option to mix the random data from multiple random number providers via XOR, and the ability to specify blocking vs. non-blocking mode when reading from a provider. The former allows programmers to avoid reliance on a single source for entropy and random number generation, where possible. The latter gives the developer more control over the behavior of the library.

This document includes the following sections:

  • Structure of libcryptorand Library
  • Build Requirements
  • API overview and design decisions
  • Sample user code to use libcryptorand library

Structure of libcryptorand Library

The libcryptorand library provides a cross-platform interface to either mix all random numbers from all available providers, or pick the best available provider. The provider list is currently hardcoded to prefer the DRNG over the OS facility when used in the latter mode.

It is compatible with Linux, Windows and OS X, and contains files that make it compatible with multiple platforms as described below:

File or Directory Description
/doc API documentation, as both UNIX man pages and HTML
/lib Directory containing precompiled, static libraries for each platform
/vs

Directory with Microsoft* Visual Studio* solution files for building on Windows.

provider.h cpufeatures.h cpufeatures.c cryptorandom.h cryptorandom.c The core API and support routines.
provider_os.h Header file that defines the API for OS-specific providers
provider_os_unix.c provider_os_unix.h

Implementation of the OS provider for UNIX-based OS’s (Linux and OS X)

provider_os_win.c provider_os_win.h Implementation of the OS provider for Microsoft Windows
provider_drng.c provider_drng.h Implementation of the DRNG provider for all platforms
provider_mix.c provider_mix.h A virtual provider that mixes random numbers from all available providers using XOR.
drng_asm.S drng_win.asm Supplemental assembly routines for the DRNG provider on Windows
vsyasm.props
vsyasm.targets
vsyasm.xml
Configuration files for integrating the YASM assembler into Visual Studio.
Makefile.in config.h.in configure configure.ac install-sh

GNU* autoconf configuration and build support for UNIX systems

testrand.c A demonstration program that checks all providers, including support for the “mix” mode.

Adding a Provider

Additional providers for other random number generators/entropy sources can be added to the library by doing the following:

  1. Implementing the low-level functions for the libcryptorandom API (as defined in provider.h) to interface with the target random number/entropy source
  2. Adding the provider to the hardcoded list of providers

Providers are identified by a unique character string which is defined in that provider’s header file as a C preprocessor symbol. As an example, the OS provider is defined in provider_os.h:

#define PROVIDER_OS        "OS"

The list of providers is defined in cryptorandom.c in two places. The first is in a const char* array of the provider ID strings:

const char *providers[]= {
           PROVIDER_DRNG,
           PROVIDER_OS,
           NULL
};

The order of this array determines the “preference” order for providers, with the first item on the list being tried first and the last item tried last. Note that the list must be NULL-terminated.

The second place providers are defined is in the try_provider() subroutine, which maps each provider ID string to that provider’s random_open() function:

if ( ! strcmp(provider_name, PROVIDER_DRNG) ) {
     rv= drng_random_open(provider, flags);
} else if ( ! strcmp(provider_name, PROVIDER_OS) ) {
     rv= os_random_open(provider, flags);
}

Build Requirements

The library can be built with on Linux and OS X with the Intel compiler (ICC) or the GNU compiler (GCC), and on Microsoft Windows with the Microsoft compiler or the Intel compiler. Builds are supported on both 32-bit and 64-bit architectures.

Linux and OS X

  • If using GCC on Linux or OS X, version 4.8 or later is recommended, though earlier 4.x versions will probably work.
  • If using the Intel compiler, version 15.0 is recommended for any platform though versions 13 and higher should work.

Windows

  • Visual Studio is required to build the library and test program in Windows.
  • If using the Microsoft compiler with Visual Studio, then you need version 2013 or later. The RDRAND intrinsics are available in Visual Studio 2012, but the RDSEED intrinsics are available in Visual Studio 2013. Hence, it is highly recommended to use 2013 or later.
  • If using the Intel compiler, version 15.0 is recommended for any platform though versions 13 and higher should work.
  • The Yasm Modular Assembler* (YASM) is required to build the assembly sources on Windows. YASM must be properly integrated into Visual Studio for this to work, and instructions for doing this can be found in the Yasm documentation (the process for Visual Studio 2013 is the same as that for 2010). You can use the vyasm.xml, vyasm.props, and vyasm.targets files provided in the libcryptorandom distribution. Note: There is a bug in the 1.3.0 version of yasm that causes it to not recognize “Win32” as a valid platform name. This affects 32-bit builds. As of this writing, this bug has been fixed in the source repository but not yet released. Until that happens, use version 1.2.0.

API Overview & Design Decisions

The API includes the following functions:

int random_open(crypto_random_t *providerunsigned int flags);

This function attempts to open a random number provider that meets the requirements that you specify in the flags parameter. If a provider that meets those requirements is not available then an error is returned.

You may have multiple providers open at the same time.

The following flags are supported:

RANDOM_NONBLOCK

Use non-blocking reads. This flag is strongly recommended because 1) not all providers support blocking I/O (specifically, the DRNG), and 2) blocking reads can lead to long hangs, especially when obtaining seed-grade entropy.

Non-blocking reads can lead to short read counts from random_read().

This is not the default mode in order to make the interface to random_open() consistent with that of the POSIX read(2) system call.

RANDOM_CRYPTOGRAPHIC

Request random numbers that are suitable for use in general cryptographic applications, such as key generation, nonces, and IVs. These numbers are compliant to the NIST SP800-90A standard. These random numbers should be assumed to have additive prediction resistance.

This is the default mode and so this parameter is not necessary, but it is provided for completeness or clarity.

RANDOM_SEED

Request random numbers that are of seed grade quality, meaning they are suitable for use as a seed for software-based pseudorandom number generators. These numbers are compliant to the NIST SP800-90B and C standards. These random numbers can be assumed to have multiplicative prediction resistance.

Not all random number providers are capable of generating seed grade random numbers. Some OS facilities, in particular, do not document the operation of their random number generators and as such it is not possible to operate them in a mode that guarantees compliance to the NIST standards for seed grade entropy. The implementations in libcryptorandom are conservative and err on the side of caution.

RANDOM_MIX

Rather than open the best available provider, open a virtual provider that attempts to mix the random sources from all available providers using XOR. If only one provider is capable of meeting the requirements set in flags, however, then the call to random_open() will fail: it is assumed that the request to mix random number sources must be satisfied by having more than one source available to mix.

int random_close(crypto_random_t *provider);

To prevent the library from leaking memory you should close a provider when it is no longer required.

int random_info(crypto_random_t *providerint parametervoid *value);

Obtain information about a provider, or about all known providers.

Information about the provider gets stored in the value variable. Depending upon the parameter argument, the following information about the provider is returned:

RANDOM_INFO_ENGINE_LIST

Used to get a list of all the known providers. The provider argument is ignored and for clarity should be set to NULL. The value argument will be set to the first element of an array of const char pointers, each pointing to the name of a provider. The array is NULL terminated.

RANDOM_INFO_ENGINE

Gets the name of the current provider. The value argument will be set to a const char* containing the name.

ssize_t random_read(crypto_random_t *providervoid *buf, ssize_t len);

Read random bytes from an open provider. The provider parameter must have come from a successful random_open() call.

The generated random bytes will get stored in the buffer pointed to by the buf parameter. Depending upon the provider and type of read requested, random_read() might return fewer bytes than requested by the read length len, including zero. A read size of zero should not be confused for an error.

int random_reseed(crypto_random_t *provider);

Explicitly force a reseed of the underlying random number provider. If the provider cannot be explicitly reseeded then it will return error.

Note that a provider that has been open for seed grade random numbers does not have a reseed capability (by definition, these random number generators are not seeded) and shall always return an error.

const char *random_strerror(int errornum);

Obtain an error string from the error code.

Known Providers

The random number providers known to libcryptorandom are:

OS

The OS facility for obtaining cryptographically secure random numbers. On Linux and OS X this would be the /dev/random and /dev/urandom devices. On Windows, random numbers come from the CryptGenRandom() function defined in Microsoft's CryptoAPI.

Only the Linux OS facility is capable of seed-grade random numbers. The other random number sources are based on pseudorandom number generators that do not provide an interface to reseeding, and hence do not meet the NIS SP800-90B and C requirements.

DRNG

Intel Corporation's digital random number generator, which is marketed under the name Intel® Data Protection Technology with Secure Key. For more information, refer to the DRNG Software Implementation Guide. All systems that support Intel® Data Protection Technology with Secure Key can generate seed-grade random numbers, but processors with support for the RDSEED instruction can do so more efficiently.

Sample User Code

A sample program is included with the library in order to demonstrate the various functions in the libcryptorand API. It takes the following command-line arguments:

- - blocking | -b

By default the test program uses non-blocking reads (the RANDOM_NONBLOCK flag is set). If this argument is passed then it will attempt to open its providers in blocking mode. Note that not all providers support blocking I/O and this mode can result in long hangs on some systems.

- -mix | -m

By default mixing is off. If this command line argument is passed then it will call random_open() with the RANDOM_MIX flag, which attempts to open all available providers and mix their output together via XOR. If only a single provider is available, then the attempt to open the mix provider will fail (you cannot mix only one provider’s output).

The sample application demonstrates the use of both cryptographic grade (the default) and seed grade random numbers. To generate the seed grade random numbers, the RANDOM_SEED flag is passed while opening the provider.

Test program is broadly divided into four parts with detailed description in comments.

Part 1: Provider list

Prints the list of all the providers that are defined in the library, whether or not they are supported or available on the system executing the program.

Part 2: Open a provider for cryptographic grade random numbers

Opens a provider using the random_open() call. This retrieves the best available random number generator on the system. After opening the provider, it prints information about that provider and then runs several tests using random_read() and random_reseed().

Part 3: Open a provider for seed grade random numbers

This is a repeat of Part 2, but for seed grade random numbers. Note that, depending on your system, it may result in a different underlying provider (or no provider at all, i.e. a failure).

Part 4: Iterate through all providers

This part iterates through the providers listed in Part 1, and tests each one for both cryptographic grade and seed grade random numbers.

This makes use of random_open_step() function. After opening first provider in the list, it performs the testing for that provider and then moves to the next provider by calling random_open_step() again with the current provider as the argument. This procedure repeats until no providers are left.

The provider tests

After a provider is successfully opened, it is run through a series of read tests. The first reads into a simple 16 byte buffer, starting with a one byte read, then a two-byte read, and so on until finishing with a 16-byte read.

Uninitialized buffer space is shown as a continuous block of 0xff bytes (though a random read can result in a 0xff byte as well).

1/16 bytes: f6 ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
2/16 bytes: a3 68 ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
3/16 bytes: 0e c1 01 ff ff ff ff ff  ff ff ff ff ff ff ff ff
4/16 bytes: e2 a7 e9 df ff ff ff ff  ff ff ff ff ff ff ff ff
5/16 bytes: ed b0 9f 50 58 ff ff ff  ff ff ff ff ff ff ff ff
6/16 bytes: a8 24 6c 9c 04 08 ff ff  ff ff ff ff ff ff ff ff
7/16 bytes: 35 03 c5 7d 8f 95 0b ff  ff ff ff ff ff ff ff ff
8/16 bytes: 63 d8 81 8b 62 77 38 77  ff ff ff ff ff ff ff ff
…

The next test is a bulk read of 1024 bytes.

1024 bytes:
    0x0000  2f d4 c8 11 69 b5 bd 0a  97 82 38 97 0b 69 87 ff
    0x0010  b0 92 4e 12 59 dd ac f7  76 68 13 9f ba 14 37 7f
    0x0020  60 bd 1f 0f 87 ee ab c8  44 91 59 08 b9 3d 32 a5
    0x0030  f1 c7 1c 5e 58 ed 55 89  d1 0e 8c cd eb d9 0e 86
    0x0040  1d fa 61 0b 5c 20 52 16  8e 1a 24 cd 53 dd 82 98
    0x0050  0d b7 68 16 f5 aa a4 0d  7b 50 d6 a0 3f 35 a6 9a
…

Next, it attempts to force a reseed by calling random_reseed().

Forcing reseed...OK

Last, it reads 383 bytes into the middle of a 1024-byte buffer. This demonstrates reads into an unaligned memory address.

383 bytes (unaligned, offset 19):
    0x0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff
    0x0010  ff ff 06 ee 45 ce 2e 38  bb 9d da 5f 78 71 65 21
    0x0020  90 b9 39 b0 17 ef 0f 53  2b 4c a3 2c 6f a3 92 e3
    0x0030  e1 b0 cb 73 29 16 37 32  a1 75 0a 66 30 7a 82 3f
    0x0040  fe 94 24 ec 5a ab 69 fa  38 1f c5 f0 d2 e7 b0 e6
…

Licensing

Libcryptorandom is an open source library distributed under the terms of the BSD license. The license text is included in the distribution.

Any software source code reprinted in this document is furnished under a software license and may only be used or copied in accordance with the terms of that license. 

Intel and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2016 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.