# HG changeset patch # User Carl Byington # Date 1406857420 25200 # Node ID 663637117cf8573c91f95103113ed412b85b0ec2 # Parent b40bc65fa09a4e0da31b2de796bbe53968915081 compensate for SecureRandom bug on older devices diff -r b40bc65fa09a -r 663637117cf8 src/ch/ethz/ssh2/crypto/SecureRandomFix.java --- /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