Wednesday, August 14, 2013

Some SecureRandom Thoughts



The Android security team has been investigating the root cause of the compromise of a bitcoin transaction that led to the update of multiple Bitcoin applications on August 11.



We have now determined that applications which use the Java Cryptography Architecture (JCA) for key generation, signing, or random number generation may not receive cryptographically strong values on Android devices due to improper initialization of the underlying PRNG. Applications that directly invoke the system-provided OpenSSL PRNG without explicit initialization on Android are also affected. Applications that establish TLS/SSL connections using the HttpClient and java.net classes are not affected as those classes do seed the OpenSSL PRNG with values from /dev/urandom.



Developers who use JCA for key generation, signing or random number generation should update their applications to explicitly initialize the PRNG with entropy from /dev/urandom or /dev/random. A suggested implementation is provided at the end of this blog post. Also, developers should evaluate whether to regenerate cryptographic keys or other random values previously generated using JCA APIs such as SecureRandom, KeyGenerator, KeyPairGenerator, KeyAgreement, and Signature.



In addition to this developer recommendation, Android has developed patches that ensure that Android’s OpenSSL PRNG is initialized correctly. Those patches have been provided to OHA partners.



We would like to thank Soo Hyeon Kim, Daewan Han of ETRI and Dong Hoon Lee of Korea University who notified Google about the improper initialization of OpenSSL PRNG.



import android.os.Build;
import android.os.Process;

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.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
import java.security.Security;

/**
* Fixes for the output of the default PRNG having low entropy.
*
* The fixes need to be applied via {@link #apply()} before any use of Java
* Cryptography Architecture primitives. A good place to invoke them is in the
* application's {@code onCreate}.
*/
public final class PRNGFixes {

private static final int VERSION_CODE_JELLY_BEAN = 16;
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
getBuildFingerprintAndDeviceSerial();

/** Hidden constructor to prevent instantiation. */
private PRNGFixes() {}

/**
* Applies all fixes.
*
* @throws SecurityException if a fix is needed but could not be applied.
*/
public static void apply() {
applyOpenSSLFix();
installLinuxPRNGSecureRandom();
}

/**
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
* fix is not needed.
*
* @throws SecurityException if the fix is needed but could not be applied.
*/
private static void applyOpenSSLFix() throws SecurityException {
if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
// No need to apply the fix
return;
}

try {
// Mix in the device- and invocation-specific seed.
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_seed", byte[].class)
.invoke(null, generateSeed());

// Mix output of Linux PRNG into OpenSSL's PRNG
int bytesRead = (Integer) Class.forName(
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
.getMethod("RAND_load_file", String.class, long.class)
.invoke(null, "/dev/urandom", 1024);
if (bytesRead != 1024) {
throw new IOException(
"Unexpected number of bytes read from Linux PRNG: "
+ bytesRead);
}
} catch (Exception e) {
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
}
}

/**
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
* default. Does nothing if the implementation is already the default or if
* there is not need to install the implementation.
*
* @throws SecurityException if the fix is needed but could not be applied.
*/
private static void installLinuxPRNGSecureRandom()
throws SecurityException {
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
// No need to apply the fix
return;
}

// Install a Linux PRNG-based SecureRandom implementation as the
// default, if not yet installed.
Provider[] secureRandomProviders =
Security.getProviders("SecureRandom.SHA1PRNG");
if ((secureRandomProviders == null)
|| (secureRandomProviders.length < 1)
|| (!LinuxPRNGSecureRandomProvider.class.equals(
secureRandomProviders[0].getClass()))) {
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
}

// Assert that new SecureRandom() and
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
// by the Linux PRNG-based SecureRandom implementation.
SecureRandom rng1 = new SecureRandom();
if (!LinuxPRNGSecureRandomProvider.class.equals(
rng1.getProvider().getClass())) {
throw new SecurityException(
"new SecureRandom() backed by wrong Provider: "
+ rng1.getProvider().getClass());
}

SecureRandom rng2;
try {
rng2 = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new SecurityException("SHA1PRNG not available", e);
}
if (!LinuxPRNGSecureRandomProvider.class.equals(
rng2.getProvider().getClass())) {
throw new SecurityException(
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
+ " Provider: " + rng2.getProvider().getClass());
}
}

/**
* {@code Provider} of {@code SecureRandom} engines which pass through
* all requests to the Linux PRNG.
*/
private static class LinuxPRNGSecureRandomProvider extends Provider {

public LinuxPRNGSecureRandomProvider() {
super("LinuxPRNG",
1.0,
"A Linux-specific random number provider that uses"
+ " /dev/urandom");
// Although /dev/urandom is not a SHA-1 PRNG, some apps
// explicitly request a SHA1PRNG SecureRandom and we thus need to
// prevent them from getting the default implementation whose output
// may have low entropy.
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
}
}

/**
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
* ({@code /dev/urandom}).
*/
public static 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;

@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 device- and 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;
}
}
}

/**
* Generates a device- and 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.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");
}
}
}

1 comments:

  1. TOKO PUSAT ELETRONIK
    MenawarKan Produk asli dan bergaransi :
    Harga Promo Stok barang terbatas
    ALAMAT TOKO.Jl.Kh.Hasim Asarhi no.125 sentral jkarta10150.
    Kami Melayani pengiriman di seluruh indonesia melalui via TIKI/JNE
    Spesifikasi : Layar 5" TFT Touchscreen, Android 4.1 Jelly Bean, Kamera 8MP, Dual Core 1.2 GHz Cortex A5, RAM 1GB, Dual SIM, Baterei 2100mAh
    Samsung Galaxy Note 3 N900
    Harga Baru Rp 2.550.000

    Spesifikasi : Layar 5.7" Super AMOLED Touchscreen, Android 4.3 Jelly Bean, Kamera 13MP, Quad Core 1.9 GHz Exynos 5 Octa Cortex A15, RAM 3GB, Single SIM, Baterei 3500 mAh
    Samsung Galaxy Note 2 N7100
    Harga Baru Rp 2.250.000

    Spesifikasi : Layar 5.5" Super AMOLED Touchscreen, Android 4.1 Jelly Bean, Kamera 8MP, Quad Core 1.6 GHz Exynos 4412 Cortex A9, RAM 2GB, Single SIM, Baterei 3100 mAh
    Samsung Galaxy S4 Mini I9190
    Harga Baru Rp 2.000.000

    Spesifikasi : Layar 4.3" Super AMOLED Touchscreen, Android 4.2 Jelly Bean, Kamera 8MP, Dual Core 1.7 GHz Snapdragon, RAM 1.5 GB, Single SIM, Baterei 1900 mAh
    Samsung Galaxy S4 Active
    Harga Baru Rp 1.900.000

    Spesifikasi : Layar 4.9" TFT Touchscreen, Android 4.2 Jelly Bean, Kamera 8MP, Quad Core 1.9 GHz Snapdragon, RAM 2 GB, Single SIM, Baterei 2600 mAh
    Samsung Galaxy S4 Zoom SM-C101
    Harga Baru Rp 1.900.000

    Spesifikasi : Layar 4.3" Super AMOLED Touchscreen, Android 4.2 Jelly Bean, Kamera 16MP, Dual Core 1.5 GHz Cortex A9, RAM 1.5 GB, Single SIM, Baterei 2330 mAh
    Samsung Galaxy S4 I9500
    Harga Baru Rp 1.690.000



    Spesifikasi : Layar 3" TFT Touchscreen, Android 4.1 Jelly Bean, Kamera 2MP, Dual Core 1 GHz Cortex A5, RAM 512MB, Dual SIM, Baterei 1200mAh
    Samsung Galaxy Ace 3 GT-S7270
    Harga Baru Rp 950.000

    Spesifikasi : Layar 4" TFT Touchscreen, Android 4.2 Jelly Bean, Kamera 5MP, Dual Core 1 GHz Cortex A9, RAM 1GB, Single SIM, Baterei 1500 mAh
    Samsung Galaxy Core Duos I8262
    Harga Baru Rp 1.159.000

    Spesifikasi : Layar 4.3" TFT Touchscreen, Android 4.1 Jelly Bean, Kamera 5MP, Dual Core 1.2 GHz Cortex A5, RAM 1GB, Dual SIM, Baterei 1800 mAh
    Samsung Galaxy Mega 6.3 I9200
    Harga Baru Rp 1.000.000

    Spesifikasi : Layar 6.3" SC-LCD Touchscreen, Android 4.2 Jelly Bean, Kamera 8MP, Dual Core 1.7 GHz Snapdragon, RAM 1.5GB, Single SIM, Baterei 3200 mAh
    Samsung Galaxy Mega 5.8 I9152
    Harga Baru Rp 990.000

    Spesifikasi : Layar 5.8" TFT Touchscreen, Android 4.2 Jelly Bean, Kamera 8MP, Dual Core 1.4 GHz, RAM 1.5GB, Dual SIM, Baterei 2600 mAh
    Samsung Galaxy Young S6310
    Harga Baru Rp 650.000

    Spesifikasi : Layar 3.27" TFT Touchscreen, Android 4.1 Jelly Bean, Kamera 3.15MP, Dual Core 1 GHz Cortex A5, RAM 768MB, Single SIM, Baterei 1300 mAh
    \ Samsung Galaxy Fame S6810
    Harga Baru Rp 550.000

    Spesifikasi : Layar 3.5" TFT Touchscreen, Android 4.1 Jelly Bean, Kamera 5MP, Dual Core 1 GHz Cortex A5, RAM 512MB, Single SIM, Baterei 1300mAh
    Samsung Galaxy Grand I9082
    Harga Baru Rp 1.150.000

    Spesifikasi : Layar 5" TFT Touchscreen, Android 4.1 Jelly Bean, Kamera 8MP, Dual Core 1.2 GHz Cortex A5, RAM 1GB, Dual SIM, Baterei 2100mAh
    Samsung GALAXY Tab 2 7.0 P3110 Harga Baru Rp.2.150.000
    Samsung Galaxy Tab 3 7.0 T211 Harga Rp 2.550.000
    Samsung Galaxy Tab 3 8.0 T311 Harga Rp 2.250.000

    Blackberry Z10 Hitam Dan Wite Harga Rp.3.299.000
    Blackberry Q5 Full Set Rp.1.450.000
    BLACKBERRY TORCH 9800 WHITE Rp 1.300.000
    BLACKBERRY PORSCHE DESIGN P9981 4.000.000
    BLACKBERRY CURVE 9380 Rp 1.250.000

    APPLE IPHONE 5S 64 GB Rp 2.300.000
    APPLE IPHONE 5S 32 GB Rp 1.950.000
    APPLE IPHONE 5S 16 GB Rp 1,500.000

    CARA Pesan online
    HP. PIN BB:24C19401
    HUB:085310120333

    ReplyDelete