diff src/ch/ethz/ssh2/crypto/SecureRandomFix.java @ 345:663637117cf8

compensate for SecureRandom bug on older devices
author Carl Byington <carl@five-ten-sg.com>
date Thu, 31 Jul 2014 18:43:40 -0700
parents
children d6ab7b606a50
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ch/ethz/ssh2/crypto/SecureRandomFix.java	Thu Jul 31 18:43:40 2014 -0700
@@ -0,0 +1,75 @@
+//
+// Copyright (C) 2014 by 510 Software Group
+// licensed under the GPLv3 or later
+
+package ch.ethz.ssh2.crypto;
+
+import java.security.SecureRandom;
+
+
+class SecureRandomFix extends SecureRandom {
+
+    // http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
+
+    private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
+    private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
+        getBuildFingerprintAndDeviceSerial();
+
+    private static byte[] generateReasonableSeed() {
+        try {
+            ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
+            DataOutputStream seedBufferOut =
+                    new DataOutputStream(seedBuffer);
+            seedBufferOut.writeLong(System.currentTimeMillis());
+            seedBufferOut.writeLong(System.nanoTime());
+            seedBufferOut.writeInt(Process.myPid());
+            seedBufferOut.writeInt(Process.myUid());
+            seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
+            seedBufferOut.close();
+            return seedBuffer.toByteArray();
+        } catch (IOException e) {
+            throw new SecurityException("Failed to generate seed", e);
+        }
+    }
+
+    /**
+     * Gets the hardware serial number of this device.
+     *
+     * @return serial number or {@code null} if not available.
+     */
+    private static String getDeviceSerialNumber() {
+        // We're using the Reflection API because Build.SERIAL is only available
+        // since API Level 9 (Gingerbread, Android 2.3).
+        try {
+            return (String) Build.class.getField("SERIAL").get(null);
+        } catch (Exception ignored) {
+            return null;
+        }
+    }
+
+    private static byte[] getBuildFingerprintAndDeviceSerial() {
+        StringBuilder result = new StringBuilder();
+        String fingerprint = Build.FINGERPRINT;
+        if (fingerprint != null) {
+            result.append(fingerprint);
+        }
+        String serial = getDeviceSerialNumber();
+        if (serial != null) {
+            result.append(serial);
+        }
+        try {
+            return result.toString().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("UTF-8 encoding not supported");
+        }
+    }
+
+    public SecureRandomFix() {
+        super();
+        if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
+            // No need to apply the fix
+            return;
+        }
+        setSeed(generateReasonableSeed());
+    }
+}
\ No newline at end of file