diff options
author | Ricardo Cerqueira <cyanogenmod@cerqueira.org> | 2013-08-31 02:21:14 +0100 |
---|---|---|
committer | Ricardo Cerqueira <cyanogenmod@cerqueira.org> | 2013-09-04 15:01:50 +0100 |
commit | ebe07a6dca6ea821a23847c30c376180c6a54765 (patch) | |
tree | 6c5709016befce74dd855ca4d586736d45bb862c | |
parent | 35d2187f72e95136574ead9323fb4fb7d4feb4dc (diff) | |
download | libcore-ebe07a6dca6ea821a23847c30c376180c6a54765.zip libcore-ebe07a6dca6ea821a23847c30c376180c6a54765.tar.gz libcore-ebe07a6dca6ea821a23847c30c376180c6a54765.tar.bz2 |
Apply a variation of the suggested app-level patch to SecureRandom
http://android-developers.blogspot.pt/2013/08/some-securerandom-thoughts.html
for more details. This isn't an ideal solution, but until a proper patch
comes up it'll do
Change-Id: Ib6bf4478fc1ae3d16eefa4eb2ad90f1f3e9de021
-rw-r--r-- | luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java | 179 | ||||
-rw-r--r-- | luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java | 25 |
2 files changed, 203 insertions, 1 deletions
diff --git a/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java b/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java index 2420fbe..de6d853 100644 --- a/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java +++ b/luni/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java @@ -27,6 +27,164 @@ import java.security.SecureRandomSpi; import libcore.io.Streams; import libcore.util.EmptyArray; + + +// HAX +// +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.Security; + +/** + * {@link SecureRandomSpi} which passes all requests to the Linux PRNG + * ({@code /dev/urandom}). + */ +class LinuxPRNGSecureRandom extends SecureRandomSpi { + + /* + * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed + * are passed through to the Linux PRNG (/dev/urandom). Instances of + * this class seed themselves by mixing in the current time, PID, UID, + * build fingerprint, and hardware serial number (where available) into + * Linux PRNG. + * + * Concurrency: Read requests to the underlying Linux PRNG are + * serialized (on sLock) to ensure that multiple threads do not get + * duplicated PRNG output. + */ + + private static final File URANDOM_FILE = new File("/dev/urandom"); + + private static final Object sLock = new Object(); + + /** + * Input stream for reading from Linux PRNG or {@code null} if not yet + * opened. + * + * @GuardedBy("sLock") + */ + private static DataInputStream sUrandomIn; + + /** + * Output stream for writing to Linux PRNG or {@code null} if not yet + * opened. + * + * @GuardedBy("sLock") + */ + private static OutputStream sUrandomOut; + + /** + * Whether this engine instance has been seeded. This is needed because + * each instance needs to seed itself if the client does not explicitly + * seed it. + */ + private boolean mSeeded; + + /** + * Generates a invocation-specific seed to be mixed into the + * Linux PRNG. + */ + private static byte[] generateSeed() { + try { + ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream(); + DataOutputStream seedBufferOut = + new DataOutputStream(seedBuffer); + seedBufferOut.writeLong(System.currentTimeMillis()); + seedBufferOut.writeLong(System.nanoTime()); + seedBufferOut.close(); + return seedBuffer.toByteArray(); + } catch (IOException e) { + throw new SecurityException("Failed to generate seed", e); + } + } + @Override + protected void engineSetSeed(byte[] bytes) { + try { + OutputStream out; + synchronized (sLock) { + out = getUrandomOutputStream(); + } + out.write(bytes); + out.flush(); + mSeeded = true; + } catch (IOException e) { + throw new SecurityException( + "Failed to mix seed into " + URANDOM_FILE, e); + } + } + + @Override + protected void engineNextBytes(byte[] bytes) { + if (!mSeeded) { + // Mix in the invocation-specific seed. + engineSetSeed(generateSeed()); + } + + try { + DataInputStream in; + synchronized (sLock) { + in = getUrandomInputStream(); + } + synchronized (in) { + in.readFully(bytes); + } + } catch (IOException e) { + throw new SecurityException( + "Failed to read from " + URANDOM_FILE, e); + } + } + + @Override + protected byte[] engineGenerateSeed(int size) { + byte[] seed = new byte[size]; + engineNextBytes(seed); + return seed; + } + + private DataInputStream getUrandomInputStream() { + synchronized (sLock) { + if (sUrandomIn == null) { + // NOTE: Consider inserting a BufferedInputStream between + // DataInputStream and FileInputStream if you need higher + // PRNG output performance and can live with future PRNG + // output being pulled into this process prematurely. + try { + sUrandomIn = new DataInputStream( + new FileInputStream(URANDOM_FILE)); + } catch (IOException e) { + throw new SecurityException("Failed to open " + + URANDOM_FILE + " for reading", e); + } + } + return sUrandomIn; + } + } + + private OutputStream getUrandomOutputStream() { + synchronized (sLock) { + if (sUrandomOut == null) { + try { + sUrandomOut = new FileOutputStream(URANDOM_FILE); + } catch (IOException e) { + throw new SecurityException("Failed to open " + + URANDOM_FILE + " for writing", e); + } + } + return sUrandomOut; + } + } +} +// --HAX + + + + /** * This class extends the SecureRandomSpi class implementing all its abstract methods. <BR> * <BR> @@ -37,7 +195,14 @@ import libcore.util.EmptyArray; * The class implements the Serializable interface. */ -public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serializable, SHA1_Data { +/* TEMPORARY: This now derives from LinuxPRNGSecureRandom and does NOT + * override the SecureRandomSpi methods in there + * + * Pending Google's real fix for the PRNG problem, this is a system-wide + * application of the patch from + * http://android-developers.blogspot.pt/2013/08/some-securerandom-thoughts.html + */ +public class SHA1PRNG_SecureRandomImpl extends LinuxPRNGSecureRandom implements Serializable, SHA1_Data { private static final long serialVersionUID = 283736797212159675L; @@ -199,6 +364,9 @@ public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serial * @throws * NullPointerException - if null is passed to the "seed" argument */ + + /* Blocked while LinuxPRNGSecureRandom is in use + protected synchronized void engineSetSeed(byte[] seed) { if (seed == null) { @@ -216,6 +384,8 @@ public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serial } } + */ + /** * Returns a required number of random bytes. <BR> * @@ -228,6 +398,8 @@ public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serial * @throws * InvalidParameterException - if numBytes < 0 */ + + /* Blocked while LinuxPRNGSecureRandom is in use protected synchronized byte[] engineGenerateSeed(int numBytes) { byte[] myBytes; // byte[] for bytes returned by "nextBytes()" @@ -250,6 +422,8 @@ public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serial return myBytes; } + */ + /** * Writes random bytes into an array supplied. * Bits in a byte are from left to right. <BR> @@ -266,6 +440,8 @@ public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serial * @throws * NullPointerException - if null is passed to the "bytes" argument */ + + /* Blocked while LinuxPRNGSecureRandom is in use protected synchronized void engineNextBytes(byte[] bytes) { int i, n; @@ -403,6 +579,7 @@ public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements Serial } } } + */ private void writeObject(ObjectOutputStream oos) throws IOException { diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java index fd011f0..28b8c02 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRandom.java @@ -19,9 +19,32 @@ package org.apache.harmony.xnet.provider.jsse; import java.io.Serializable; import java.security.SecureRandomSpi; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + public class OpenSSLRandom extends SecureRandomSpi implements Serializable { private static final long serialVersionUID = 8506210602917522860L; + /** + * Generates a invocation-specific seed to be mixed into the + * Linux PRNG. + */ + private static void generateSeed() { + try { + ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream(); + DataOutputStream seedBufferOut = + new DataOutputStream(seedBuffer); + seedBufferOut.writeLong(System.currentTimeMillis()); + seedBufferOut.writeLong(System.nanoTime()); + seedBufferOut.close(); + NativeCrypto.RAND_seed(seedBuffer.toByteArray()); + NativeCrypto.RAND_load_file("/dev/urandom", 1024); + } catch (IOException e) { + throw new SecurityException("Failed to generate seed", e); + } + } + @Override protected void engineSetSeed(byte[] seed) { NativeCrypto.RAND_seed(seed); @@ -29,12 +52,14 @@ public class OpenSSLRandom extends SecureRandomSpi implements Serializable { @Override protected void engineNextBytes(byte[] bytes) { + generateSeed(); NativeCrypto.RAND_bytes(bytes); } @Override protected byte[] engineGenerateSeed(int numBytes) { byte[] output = new byte[numBytes]; + generateSeed(); NativeCrypto.RAND_bytes(output); return output; } |