From 525ad3504d6751aa9d61075fefd1e0f478ce9ac8 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Mon, 8 Dec 2014 22:29:21 +0100 Subject: [PATCH] Move LinuxSecureRandom from Bitcoin Wallet to bitcoinj. This class is in use since August 2013 without any signs of RNG issues. --- .../bitcoinj/crypto/LinuxSecureRandom.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 core/src/main/java/org/bitcoinj/crypto/LinuxSecureRandom.java diff --git a/core/src/main/java/org/bitcoinj/crypto/LinuxSecureRandom.java b/core/src/main/java/org/bitcoinj/crypto/LinuxSecureRandom.java new file mode 100644 index 00000000..57919ef3 --- /dev/null +++ b/core/src/main/java/org/bitcoinj/crypto/LinuxSecureRandom.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoinj.crypto; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.Provider; +import java.security.SecureRandomSpi; +import java.security.Security; + +/** + * A SecureRandom implementation that is able to override the standard JVM provided implementation, and which simply + * serves random numbers by reading /dev/urandom. That is, it delegates to the kernel on UNIX systems and is unusable on + * other platforms. Attempts to manually set the seed are ignored. There is no difference between seed bytes and + * non-seed bytes, they are all from the same source. + */ +public class LinuxSecureRandom extends SecureRandomSpi { + private static final FileInputStream urandom; + + private static class LinuxSecureRandomProvider extends Provider { + public LinuxSecureRandomProvider() { + super("LinuxSecureRandom", 1.0, "A Linux specific random number provider that uses /dev/urandom"); + put("SecureRandom.LinuxSecureRandom", LinuxSecureRandom.class.getName()); + } + } + + static { + try { + File file = new File("/dev/urandom"); + if (file.exists()) { + // This stream is deliberately leaked. + urandom = new FileInputStream(file); + // Now override the default SecureRandom implementation with this one. + Security.insertProviderAt(new LinuxSecureRandomProvider(), 1); + } else { + urandom = null; + } + } catch (FileNotFoundException e) { + // Should never happen. + throw new RuntimeException(e); + } + } + + private final DataInputStream dis; + + public LinuxSecureRandom() { + // DataInputStream is not thread safe, so each random object has its own. + dis = new DataInputStream(urandom); + } + + @Override + protected void engineSetSeed(byte[] bytes) { + // Ignore. + } + + @Override + protected void engineNextBytes(byte[] bytes) { + try { + dis.readFully(bytes); // This will block until all the bytes can be read. + } catch (IOException e) { + throw new RuntimeException(e); // Fatal error. Do not attempt to recover from this. + } + } + + @Override + protected byte[] engineGenerateSeed(int i) { + byte[] bits = new byte[i]; + engineNextBytes(bits); + return bits; + } +}