Use custom SecureRandom instance

- Use NativePRNG algorithm instead of using SHA1PRNG if available
- Register a custom security provider to use the same SecureRandom everywhere
This commit is contained in:
AsamK 2018-11-21 00:07:05 +01:00
parent cf972e5b6c
commit 5f2190713a
4 changed files with 88 additions and 14 deletions

View file

@ -24,6 +24,8 @@ import org.asamk.Signal;
import org.asamk.signal.commands.*;
import org.asamk.signal.manager.BaseConfig;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.util.SecurityProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
@ -35,8 +37,9 @@ import java.util.Map;
public class Main {
public static void main(String[] args) {
// Workaround for BKS truststore
Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 1);
// Register our own security provider
Security.insertProviderAt(new SecurityProvider(), 1);
Security.addProvider(new BouncyCastleProvider());
Namespace ns = parseArgs(args);
if (ns == null) {

View file

@ -1,10 +1,8 @@
package org.asamk.signal.manager;
import org.asamk.signal.util.RandomUtils;
import org.whispersystems.signalservice.internal.util.Base64;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
class KeyUtils {
private KeyUtils() {
@ -33,15 +31,7 @@ class KeyUtils {
private static byte[] getSecretBytes(int size) {
byte[] secret = new byte[size];
getSecureRandom().nextBytes(secret);
RandomUtils.getSecureRandom().nextBytes(secret);
return secret;
}
private static SecureRandom getSecureRandom() {
try {
return SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
}

View file

@ -0,0 +1,37 @@
package org.asamk.signal.util;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class RandomUtils {
private static final ThreadLocal<SecureRandom> LOCAL_RANDOM = new ThreadLocal<SecureRandom>() {
@Override
protected SecureRandom initialValue() {
SecureRandom rand = getSecureRandomUnseeded();
// Let the SecureRandom seed it self initially
rand.nextBoolean();
return rand;
}
};
private static SecureRandom getSecureRandomUnseeded() {
try {
return SecureRandom.getInstance("NativePRNG");
} catch (NoSuchAlgorithmException e) {
// Fallback to SHA1PRNG if NativePRNG is not available (e.g. on windows)
try {
return SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e1) {
// Fallback to default
return new SecureRandom();
}
}
}
public static SecureRandom getSecureRandom() {
return LOCAL_RANDOM.get();
}
}

View file

@ -0,0 +1,44 @@
package org.asamk.signal.util;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
public class SecurityProvider extends Provider {
private static final String PROVIDER_NAME = "SSP";
private static final String info = "Security Provider v1.0";
public SecurityProvider() {
super(PROVIDER_NAME, 1.0, info);
put("SecureRandom.DEFAULT", DefaultRandom.class.getName());
// Workaround for BKS truststore
put("KeyStore.BKS", "org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$Std");
put("KeyStore.BKS-V1", "org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$Version1");
put("KeyStore.BouncyCastle", "org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$BouncyCastleStore");
put("KeyFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory");
put("CertificateFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory");
}
public static class DefaultRandom extends SecureRandomSpi {
private static final SecureRandom random = RandomUtils.getSecureRandom();
public DefaultRandom() {
}
protected void engineSetSeed(byte[] bytes) {
random.setSeed(bytes);
}
protected void engineNextBytes(byte[] bytes) {
random.nextBytes(bytes);
}
protected byte[] engineGenerateSeed(int numBytes) {
return random.generateSeed(numBytes);
}
}
}