Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / security / cryptography

How Random is TPM Random Generator in Windows10 Laptop?

2.67/5 (4 votes)
5 Mar 2018CPOL2 min read 13.9K   166  
This article is about generating random data using Trusted Platform Module in Windows 10 and testing its randomness using dieharder test suite.

Introduction

Now a days, most of the systems servers, laptops and mobiles include TPM (Trusted Platform Module). These hardware modules can be used to store, generate cryptographic keys. Apart from these, there is a hardware random number generator. This RNG mostly uses a combination of thermal noise / shot noise clock jitter for its entropy source and sends to a one way hash function to guarantee randomness. This article details in using TPM module to generate random data and test with standard test suite Dieharder. Even though Dieharder test suite is not meant to test binary file, this is the next best thing. Do check out this Microsoft article to know more about TPM...

You can learn more about Dieharder random number generator test suite here...

Things to check before fetching random numbers...

In your Windows 10 machine, check if TPM is enabled and working, this can be done by running TPM.msc.

Code to Generate Random Data from TPM in Windows...

The following small snippet is used to generate file with random data from TPM module. This uses Cryptographic Next Generation (CNG) functions to access TPM random number generator. VS project is added if anyone wants to play around with it...

C++
#include<fstream>
#include<iostream>
#include<Windows.h>
#include<bcrypt.h>
#include<string>
#define BLOCK_SIZE 1024
#define ONE_MB 1024 * 1024
using namespace std;
// Usage1: tpm_randomgen <size of file in MB>
// Usage2: tpm_randomgen <filename> <size of file in MB>
// Ex tpm_randomgen randbinary 1024
int main(int argc, char *argv[]) {
    UCHAR buf[BLOCK_SIZE];
    BCRYPT_ALG_HANDLE pHandle = NULL;
    long filesize = 1; // default 1 MB unit size
    string filename = "randgen";
    if (argc == 3) {
        filename = string(argv[1]);
        filesize = stol(string(argv[2]));
    } else if (argc == 2) {
        filesize = stol(string(argv[1]));
    }
    filesize = (filesize * ONE_MB) / _countof(buf); // this will convert into MB
    ofstream outfile(filename.c_str(), std::ios::binary);
    // MS_PLATFORM_CRYPTO_PROVIDER will make sure random data is fetched from TPM
    // if TPM not installed it defaults to windows default provided
    if (0 == BCryptOpenAlgorithmProvider(
        &pHandle,
        BCRYPT_RNG_ALGORITHM,
        MS_PLATFORM_CRYPTO_PROVIDER, 
        NULL)) {
        for (long i = 0; i < filesize; i++) {
            BCryptGenRandom(pHandle, buf, sizeof(buf), NULL);
            outfile.write((char *)&buf[0], _countof(buf));
        }
        BCryptCloseAlgorithmProvider(pHandle, NULL);
    }
    return (0);
}

Dieharder test suite requires lot of data to correctly run the tests. If data is less, tests may not provide the desired results. After running the above code for about three hours, I could generate around 2.6GB of random data in a binary file. This file is then copied to a Linux machine where Dieharder is convenient to run.

Using the binary to generate random data in binary format...

TPM_randomgen <size of file in MB>

Example:

TPM_randomgen 1024

would generate default binary file "randgen" with 1GB of data.

TPM_randomgen <filename> <size of file in MB>

Example:

TPM_randomgen randomdata.bin 5120

The above run would create a randomdata.bin file with 5GB random data fetched from TPM, 5120 is filesize in MB.

After generating random data, it's time to test the results...

dieharder -g 201 -f randgen -a > report.txt

-g 201 specifies file_input_raw to the test suite.

Test Results...

The attached report.zip where a comprehensive test result is captured. Overall 90 tests passed, 11 tests failed, 10 tests turned out weak. Even though few tests failed and few are weak, benefit of doubt can be given to the TPM RNG generator to be good.

Creating a Greyscale Image Out of Random Data...

The human eye can easily detect any patterns in an image. So to check if generated data is really random, one more check is to create an image out of random data and inspect it for any patterns...

Small python snippet to accomplish this...

Python
import matplotlib.pyplot as plt
import numpy as np
randfile = open("randgen", "r")
arr = np.fromfile(randfile, dtype=np.uint16)
#To derive n of n * n  matrix
dim = int((arr.size)**(1/2.0))
#To make it exact n * n matrix
arr = arr[:(dim * dim)] 
arr = arr.reshape(dim, dim)
plt.imshow(arr, cmap="gray")
plt.show()

Greyscale image of generated data

Conclusion

After generating random numbers from TPM and testing, it was found that it is quite a decent generator...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)