EntropyMixerpublic 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 | mHandlerHandler 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 void | addDeviceSpecificEntropy()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 void | addHwRandomEntropy()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.String | getSystemDir()
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
return systemDir.toString();
| private void | loadInitialEntropy()
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 void | scheduleEntropyWriter()
mHandler.removeMessages(ENTROPY_WHAT);
mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
| private void | writeEntropy()
try {
Slog.i(TAG, "Writing entropy...");
RandomBlock.fromFile(randomDevice).toFile(entropyFile, true);
} catch (IOException e) {
Slog.w(TAG, "Unable to write entropy", e);
}
|
|