blob: 28f09f53ff146e0ef774b2b872217b1e848429c8 [file] [log] [blame]
Nick Kralevich4fb25612009-06-17 16:03:22 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import java.io.File;
Nick Kralevichb8cba952009-06-19 09:45:35 -070020import java.io.FileOutputStream;
Nick Kralevich4fb25612009-06-17 16:03:22 -070021import java.io.IOException;
Nick Kralevichb8cba952009-06-19 09:45:35 -070022import java.io.OutputStream;
23import java.io.PrintWriter;
Nick Kralevich4fb25612009-06-17 16:03:22 -070024
25import android.os.Binder;
26import android.os.Environment;
27import android.os.Handler;
28import android.os.Message;
Nick Kralevichb8cba952009-06-19 09:45:35 -070029import android.os.SystemProperties;
Nick Kralevich4fb25612009-06-17 16:03:22 -070030import android.util.Log;
31
32/**
33 * A service designed to load and periodically save "randomness"
34 * for the Linux kernel.
35 *
36 * <p>When a Linux system starts up, the entropy pool associated with
37 * {@code /dev/random} may be in a fairly predictable state. Applications which
38 * depend strongly on randomness may find {@code /dev/random} or
39 * {@code /dev/urandom} returning predictable data. In order to counteract
40 * this effect, it's helpful to carry the entropy pool information across
41 * shutdowns and startups.
42 *
43 * <p>This class was modeled after the script in
44 * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">man
45 * 4 random</a>.
46 *
47 * <p>TODO: Investigate attempting to write entropy data at shutdown time
48 * instead of periodically.
49 */
50public class EntropyService extends Binder {
51 private static final String ENTROPY_FILENAME = getSystemDir() + "/entropy.dat";
52 private static final String TAG = "EntropyService";
53 private static final int ENTROPY_WHAT = 1;
54 private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000; // 3 hrs
55 private static final String RANDOM_DEV = "/dev/urandom";
Nick Kralevichb8cba952009-06-19 09:45:35 -070056 private static final long START_TIME = System.currentTimeMillis();
57 private static final long START_NANOTIME = System.nanoTime();
Nick Kralevich4fb25612009-06-17 16:03:22 -070058
59 /**
60 * Handler that periodically updates the entropy on disk.
61 */
62 private final Handler mHandler = new Handler() {
63 @Override
64 public void handleMessage(Message msg) {
65 if (msg.what != ENTROPY_WHAT) {
66 Log.e(TAG, "Will not process invalid message");
67 return;
68 }
69 writeEntropy();
70 scheduleEntropyWriter();
71 }
72 };
73
74 public EntropyService() {
75 loadInitialEntropy();
Nick Kralevichb8cba952009-06-19 09:45:35 -070076 addDeviceSpecificEntropy();
Nick Kralevich4fb25612009-06-17 16:03:22 -070077 writeEntropy();
78 scheduleEntropyWriter();
79 }
80
81 private void scheduleEntropyWriter() {
82 mHandler.removeMessages(ENTROPY_WHAT);
83 mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
84 }
85
86 private void loadInitialEntropy() {
87 try {
88 RandomBlock.fromFile(ENTROPY_FILENAME).toFile(RANDOM_DEV);
89 } catch (IOException e) {
90 Log.w(TAG, "unable to load initial entropy (first boot?)", e);
91 }
92 }
93
94 private void writeEntropy() {
95 try {
96 RandomBlock.fromFile(RANDOM_DEV).toFile(ENTROPY_FILENAME);
97 } catch (IOException e) {
Nick Kralevichb8cba952009-06-19 09:45:35 -070098 Log.w(TAG, "unable to write entropy", e);
99 }
100 }
101
102 /**
103 * Add additional information to the kernel entropy pool. The
104 * information isn't necessarily "random", but that's ok. Even
105 * sending non-random information to {@code /dev/urandom} is useful
106 * because, while it doesn't increase the "quality" of the entropy pool,
107 * it mixes more bits into the pool, which gives us a higher degree
108 * of uncertainty in the generated randomness. Like nature, writes to
109 * the random device can only cause the quality of the entropy in the
110 * kernel to stay the same or increase.
111 *
112 * <p>For maximum effect, we try to target information which varies
113 * on a per-device basis, and is not easily observable to an
114 * attacker.
115 */
116 private void addDeviceSpecificEntropy() {
117 PrintWriter out = null;
118 try {
119 out = new PrintWriter(new FileOutputStream(RANDOM_DEV));
120 out.println("Copyright (C) 2009 The Android Open Source Project");
121 out.println("All Your Randomness Are Belong To Us");
122 out.println(START_TIME);
123 out.println(START_NANOTIME);
124 out.println(SystemProperties.get("ro.serialno"));
125 out.println(SystemProperties.get("ro.bootmode"));
126 out.println(SystemProperties.get("ro.baseband"));
127 out.println(SystemProperties.get("ro.carrier"));
128 out.println(SystemProperties.get("ro.bootloader"));
129 out.println(SystemProperties.get("ro.hardware"));
130 out.println(SystemProperties.get("ro.revision"));
131 out.println(System.currentTimeMillis());
132 out.println(System.nanoTime());
133 } catch (IOException e) {
134 Log.w(TAG, "Unable to add device specific data to the entropy pool", e);
135 } finally {
136 if (out != null) {
137 out.close();
138 }
Nick Kralevich4fb25612009-06-17 16:03:22 -0700139 }
140 }
141
142 private static String getSystemDir() {
143 File dataDir = Environment.getDataDirectory();
144 File systemDir = new File(dataDir, "system");
145 systemDir.mkdirs();
146 return systemDir.toString();
147 }
148}