14fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich/*
24fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * Copyright (C) 2009 The Android Open Source Project
34fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich *
44fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * Licensed under the Apache License, Version 2.0 (the "License");
54fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * you may not use this file except in compliance with the License.
64fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * You may obtain a copy of the License at
74fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich *
84fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich *      http://www.apache.org/licenses/LICENSE-2.0
94fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich *
104fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * Unless required by applicable law or agreed to in writing, software
114fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * distributed under the License is distributed on an "AS IS" BASIS,
124fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * See the License for the specific language governing permissions and
144fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * limitations under the License.
154fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich */
164fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
174fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichpackage com.android.server;
184fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
194fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichimport java.io.File;
2013579ed3305bf89b41a9fa88e1347f0e0769d279Dianne Hackbornimport java.io.FileNotFoundException;
21b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevichimport java.io.FileOutputStream;
224fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichimport java.io.IOException;
23b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevichimport java.io.OutputStream;
24b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevichimport java.io.PrintWriter;
254fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
2679619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevichimport android.content.BroadcastReceiver;
2779619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevichimport android.content.Context;
2879619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevichimport android.content.Intent;
2979619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevichimport android.content.IntentFilter;
304fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichimport android.os.Binder;
314fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichimport android.os.Environment;
324fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichimport android.os.Handler;
334fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevichimport android.os.Message;
34b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevichimport android.os.SystemProperties;
358a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
364fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
374fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich/**
384fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * A service designed to load and periodically save "randomness"
394fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * for the Linux kernel.
404fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich *
414fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * <p>When a Linux system starts up, the entropy pool associated with
424fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * {@code /dev/random} may be in a fairly predictable state.  Applications which
434fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * depend strongly on randomness may find {@code /dev/random} or
444fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * {@code /dev/urandom} returning predictable data.  In order to counteract
454fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * this effect, it's helpful to carry the entropy pool information across
464fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * shutdowns and startups.
474fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich *
484fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * <p>This class was modeled after the script in
494fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">man
504fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich * 4 random</a>.
514fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich */
526967cbc959b079fa7e4411360e40e2a0ed65da29Nick Kralevichpublic class EntropyMixer extends Binder {
536967cbc959b079fa7e4411360e40e2a0ed65da29Nick Kralevich    private static final String TAG = "EntropyMixer";
544fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private static final int ENTROPY_WHAT = 1;
554fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private static final int ENTROPY_WRITE_PERIOD = 3 * 60 * 60 * 1000;  // 3 hrs
56b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich    private static final long START_TIME = System.currentTimeMillis();
57b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich    private static final long START_NANOTIME = System.nanoTime();
584fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
5993a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich    private final String randomDevice;
6093a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich    private final String entropyFile;
6193a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich
624fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    /**
634fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich     * Handler that periodically updates the entropy on disk.
644fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich     */
654fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private final Handler mHandler = new Handler() {
664fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        @Override
674fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        public void handleMessage(Message msg) {
684fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich            if (msg.what != ENTROPY_WHAT) {
698a9b22056b13477f59df934928c00c58b5871c95Joe Onorato                Slog.e(TAG, "Will not process invalid message");
704fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich                return;
714fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich            }
724fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich            writeEntropy();
734fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich            scheduleEntropyWriter();
744fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        }
754fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    };
764fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
7779619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
7879619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        @Override
7979619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        public void onReceive(Context context, Intent intent) {
8079619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich            writeEntropy();
8179619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        }
8279619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich    };
8379619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich
8479619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich    public EntropyMixer(Context context) {
8579619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        this(context, getSystemDir() + "/entropy.dat", "/dev/urandom");
8693a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich    }
8793a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich
8893a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich    /** Test only interface, not for public use */
8979619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich    public EntropyMixer(Context context, String entropyFile, String randomDevice) {
9093a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich        if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
9193a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich        if (entropyFile == null) { throw new NullPointerException("entropyFile"); }
9293a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich
9393a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich        this.randomDevice = randomDevice;
9493a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich        this.entropyFile = entropyFile;
954fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        loadInitialEntropy();
96b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich        addDeviceSpecificEntropy();
974fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        writeEntropy();
984fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        scheduleEntropyWriter();
9979619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        IntentFilter broadcastFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
10079619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        broadcastFilter.addAction(Intent.ACTION_POWER_CONNECTED);
10179619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        broadcastFilter.addAction(Intent.ACTION_REBOOT);
10279619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich        context.registerReceiver(mBroadcastReceiver, broadcastFilter);
1034fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    }
1044fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
1054fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private void scheduleEntropyWriter() {
1064fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        mHandler.removeMessages(ENTROPY_WHAT);
1074fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD);
1084fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    }
1094fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
1104fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private void loadInitialEntropy() {
1114fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        try {
1126907891b1f2d706fa2bd6c40b986f73e5666e00eElliott Hughes            RandomBlock.fromFile(entropyFile).toFile(randomDevice, false);
11313579ed3305bf89b41a9fa88e1347f0e0769d279Dianne Hackborn        } catch (FileNotFoundException e) {
11413579ed3305bf89b41a9fa88e1347f0e0769d279Dianne Hackborn            Slog.w(TAG, "No existing entropy file -- first boot?");
1154fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        } catch (IOException e) {
11613579ed3305bf89b41a9fa88e1347f0e0769d279Dianne Hackborn            Slog.w(TAG, "Failure loading existing entropy file", e);
1174fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        }
1184fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    }
1194fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
1204fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private void writeEntropy() {
1214fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        try {
12279619ddbfe7367e11dd17d848b179877350b7b8eNick Kralevich            Slog.i(TAG, "Writing entropy...");
1236907891b1f2d706fa2bd6c40b986f73e5666e00eElliott Hughes            RandomBlock.fromFile(randomDevice).toFile(entropyFile, true);
1244fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        } catch (IOException e) {
12513579ed3305bf89b41a9fa88e1347f0e0769d279Dianne Hackborn            Slog.w(TAG, "Unable to write entropy", e);
126b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich        }
127b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich    }
128b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich
129b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich    /**
130b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * Add additional information to the kernel entropy pool.  The
131b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * information isn't necessarily "random", but that's ok.  Even
132b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * sending non-random information to {@code /dev/urandom} is useful
133b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * because, while it doesn't increase the "quality" of the entropy pool,
134b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * it mixes more bits into the pool, which gives us a higher degree
135b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * of uncertainty in the generated randomness.  Like nature, writes to
136b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * the random device can only cause the quality of the entropy in the
137b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * kernel to stay the same or increase.
138b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     *
139b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * <p>For maximum effect, we try to target information which varies
140b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * on a per-device basis, and is not easily observable to an
141b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     * attacker.
142b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich     */
143b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich    private void addDeviceSpecificEntropy() {
144b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich        PrintWriter out = null;
145b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich        try {
14693a68398b661c02d6c417a2a04e64a6750a9a119Nick Kralevich            out = new PrintWriter(new FileOutputStream(randomDevice));
147b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println("Copyright (C) 2009 The Android Open Source Project");
148b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println("All Your Randomness Are Belong To Us");
149b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(START_TIME);
150b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(START_NANOTIME);
151b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.serialno"));
152b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.bootmode"));
153b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.baseband"));
154b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.carrier"));
155b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.bootloader"));
156b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.hardware"));
157b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(SystemProperties.get("ro.revision"));
15803ce76081c29ecd30697fbb827ed45444b4a5f38Nick Kralevich            out.println(SystemProperties.get("ro.build.fingerprint"));
159b91ec410c8ecd09390e7122115e2ab6b7aafefb8Nick Kralevich            out.println(new Object().hashCode());
160b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(System.currentTimeMillis());
161b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            out.println(System.nanoTime());
162b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich        } catch (IOException e) {
1638a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, "Unable to add device specific data to the entropy pool", e);
164b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich        } finally {
165b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            if (out != null) {
166b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich                out.close();
167b8cba95ffd4d9be0edace7a9eb42286e668ef3e3Nick Kralevich            }
1684fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        }
1694fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    }
1704fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich
1714fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    private static String getSystemDir() {
1724fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        File dataDir = Environment.getDataDirectory();
1734fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        File systemDir = new File(dataDir, "system");
1744fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        systemDir.mkdirs();
1754fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich        return systemDir.toString();
1764fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich    }
1774fb256117ca271e3e37284a19b663d116f6ec20cNick Kralevich}
178