FileDocCategorySizeDatePackage
EntropyMixer.javaAPI DocAndroid 5.1 API8185Thu Mar 12 22:22:42 GMT 2015com.android.server

EntropyMixer

public class EntropyMixer extends android.os.Binder
A service designed to load and periodically save "randomness" for the Linux kernel RNG and to mix in data from Hardware RNG (if present) into the Linux RNG.

When a Linux system starts up, the entropy pool associated with {@code /dev/random} may be in a fairly predictable state. Applications which depend strongly on randomness may find {@code /dev/random} or {@code /dev/urandom} returning predictable data. In order to counteract this effect, it's helpful to carry the entropy pool information across shutdowns and startups.

On systems with Hardware RNG (/dev/hw_random), a block of output from HW RNG is mixed into the Linux RNG on EntropyMixer's startup and whenever EntropyMixer periodically runs to save a block of output from Linux RNG on disk. This mixing is done in a way that does not increase the Linux RNG's entropy estimate is not increased. This is to avoid having to trust/verify the quality and authenticity of the "randomness" of the HW RNG.

This class was modeled after the script in man 4 random.

Fields Summary
private static final String
TAG
private static final int
ENTROPY_WHAT
private static final int
ENTROPY_WRITE_PERIOD
private static final long
START_TIME
private static final long
START_NANOTIME
private final String
randomDevice
private final String
hwRandomDevice
private final String
entropyFile
private final android.os.Handler
mHandler
Handler that periodically updates the entropy on disk.
private final android.content.BroadcastReceiver
mBroadcastReceiver
Constructors Summary
public EntropyMixer(android.content.Context context)


       
        this(context, getSystemDir() + "/entropy.dat", "/dev/urandom", "/dev/hw_random");
    
public EntropyMixer(android.content.Context context, String entropyFile, String randomDevice, String hwRandomDevice)
Test only interface, not for public use

        if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
        if (hwRandomDevice == null) { throw new NullPointerException("hwRandomDevice"); }
        if (entropyFile == null) { throw new NullPointerException("entropyFile"); }

        this.randomDevice = randomDevice;
        this.hwRandomDevice = hwRandomDevice;
        this.entropyFile = entropyFile;
        loadInitialEntropy();
        addDeviceSpecificEntropy();
        addHwRandomEntropy();
        writeEntropy();
        scheduleEntropyWriter();
        IntentFilter broadcastFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
        broadcastFilter.addAction(Intent.ACTION_POWER_CONNECTED);
        broadcastFilter.addAction(Intent.ACTION_REBOOT);
        context.registerReceiver(mBroadcastReceiver, broadcastFilter);
    
Methods Summary
private voidaddDeviceSpecificEntropy()
Add additional information to the kernel entropy pool. The information isn't necessarily "random", but that's ok. Even sending non-random information to {@code /dev/urandom} is useful because, while it doesn't increase the "quality" of the entropy pool, it mixes more bits into the pool, which gives us a higher degree of uncertainty in the generated randomness. Like nature, writes to the random device can only cause the quality of the entropy in the kernel to stay the same or increase.

For maximum effect, we try to target information which varies on a per-device basis, and is not easily observable to an attacker.

        PrintWriter out = null;
        try {
            out = new PrintWriter(new FileOutputStream(randomDevice));
            out.println("Copyright (C) 2009 The Android Open Source Project");
            out.println("All Your Randomness Are Belong To Us");
            out.println(START_TIME);
            out.println(START_NANOTIME);
            out.println(SystemProperties.get("ro.serialno"));
            out.println(SystemProperties.get("ro.bootmode"));
            out.println(SystemProperties.get("ro.baseband"));
            out.println(SystemProperties.get("ro.carrier"));
            out.println(SystemProperties.get("ro.bootloader"));
            out.println(SystemProperties.get("ro.hardware"));
            out.println(SystemProperties.get("ro.revision"));
            out.println(SystemProperties.get("ro.build.fingerprint"));
            out.println(new Object().hashCode());
            out.println(System.currentTimeMillis());
            out.println(System.nanoTime());
        } catch (IOException e) {
            Slog.w(TAG, "Unable to add device specific data to the entropy pool", e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    
private voidaddHwRandomEntropy()
Mixes in the output from HW RNG (if present) into the Linux RNG.

        try {
            RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false);
            Slog.i(TAG, "Added HW RNG output to entropy pool");
        } catch (FileNotFoundException ignored) {
            // HW RNG not present/exposed -- ignore
        } catch (IOException e) {
            Slog.w(TAG, "Failed to add HW RNG output to entropy pool", e);
        }
    
private static java.lang.StringgetSystemDir()

        File dataDir = Environment.getDataDirectory();
        File systemDir = new File(dataDir, "system");
        systemDir.mkdirs();
        return systemDir.toString();
    
private voidloadInitialEntropy()

        try {
            RandomBlock.fromFile(entropyFile).toFile(randomDevice, false);
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "No existing entropy file -- first boot?");
        } catch (IOException e) {
            Slog.w(TAG, "Failure loading existing entropy file", e);
        }
    
private voidscheduleEntropyWriter()

        mHandler.removeMessages(ENTROPY_WHAT);
        mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
    
private voidwriteEntropy()

        try {
            Slog.i(TAG, "Writing entropy...");
            RandomBlock.fromFile(randomDevice).toFile(entropyFile, true);
        } catch (IOException e) {
            Slog.w(TAG, "Unable to write entropy", e);
        }