From 6ab3d20d3c2de01a342450d83103e9f5e89e670e Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Thu, 3 Oct 2013 13:23:13 -0700 Subject: [PATCH] Make EntropyMixer mix in output of Hardware RNG into Linux RNG. On devices with Hardware RNG (HW RNG), this makes EntropyMixer periodically (every three hours) read 512 bytes from HW RNG and mix them into the Linux RNG. This is done without increasing Linux RNG's entropy estimates to avoid having to trust the quality of the HW RNG. This approach cannot reduce the quality of the Linux RNG output, but may increase it. Change-Id: Ifde851004301ffd41b2189151a64a0c5989c630f --- .../java/com/android/server/EntropyMixer.java | 37 +++++++++++++++++-- .../com/android/server/EntropyMixerTest.java | 2 +- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/EntropyMixer.java b/services/java/com/android/server/EntropyMixer.java index fbb66f979c5c5..cfdbf7d530cdc 100644 --- a/services/java/com/android/server/EntropyMixer.java +++ b/services/java/com/android/server/EntropyMixer.java @@ -36,7 +36,8 @@ import android.util.Slog; /** * A service designed to load and periodically save "randomness" - * for the Linux kernel. + * 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 @@ -45,6 +46,13 @@ import android.util.Slog; * 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. @@ -57,6 +65,7 @@ public class EntropyMixer extends Binder { private static final long START_NANOTIME = System.nanoTime(); private final String randomDevice; + private final String hwRandomDevice; private final String entropyFile; /** @@ -69,6 +78,7 @@ public class EntropyMixer extends Binder { Slog.e(TAG, "Will not process invalid message"); return; } + addHwRandomEntropy(); writeEntropy(); scheduleEntropyWriter(); } @@ -82,18 +92,25 @@ public class EntropyMixer extends Binder { }; public EntropyMixer(Context context) { - this(context, getSystemDir() + "/entropy.dat", "/dev/urandom"); + this(context, getSystemDir() + "/entropy.dat", "/dev/urandom", "/dev/hw_random"); } /** Test only interface, not for public use */ - public EntropyMixer(Context context, String entropyFile, String randomDevice) { + public EntropyMixer( + Context context, + String entropyFile, + String randomDevice, + String hwRandomDevice) { 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); @@ -168,6 +185,20 @@ public class EntropyMixer extends Binder { } } + /** + * Mixes in the output from HW RNG (if present) into the Linux RNG. + */ + private void addHwRandomEntropy() { + 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 String getSystemDir() { File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); diff --git a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java index 58d6dae1637a6..50e7a0395a2ac 100644 --- a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java +++ b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java @@ -34,7 +34,7 @@ public class EntropyMixerTest extends AndroidTestCase { assertEquals(0, FileUtils.readTextFile(file, 0, null).length()); // The constructor has the side effect of writing to file - new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath()); + new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath(), "/dev/null"); assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0); }