]> nmode's Git Repositories - signal-cli/commitdiff
Use custom SecureRandom instance
authorAsamK <asamk@gmx.de>
Tue, 20 Nov 2018 23:07:05 +0000 (00:07 +0100)
committerAsamK <asamk@gmx.de>
Sun, 25 Nov 2018 21:07:34 +0000 (22:07 +0100)
- Use NativePRNG algorithm instead of using SHA1PRNG if available
- Register a custom security provider to use the same SecureRandom everywhere

src/main/java/org/asamk/signal/Main.java
src/main/java/org/asamk/signal/manager/KeyUtils.java
src/main/java/org/asamk/signal/util/RandomUtils.java [new file with mode: 0644]
src/main/java/org/asamk/signal/util/SecurityProvider.java [new file with mode: 0644]

index a0820f241b58bbfd3b071b6987cf68ce5c8303bd..df22e63bddce027105444f9944db91e49e73ff15 100644 (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) {
index 225cf68206b7a6b313c5ff79e3cfe5c4bf7b5ee8..617893fc727b7205f2eb86ff8135176a90d4bb61 100644 (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);
-        }
-    }
 }
diff --git a/src/main/java/org/asamk/signal/util/RandomUtils.java b/src/main/java/org/asamk/signal/util/RandomUtils.java
new file mode 100644 (file)
index 0000000..d0463b4
--- /dev/null
@@ -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();
+    }
+}
diff --git a/src/main/java/org/asamk/signal/util/SecurityProvider.java b/src/main/java/org/asamk/signal/util/SecurityProvider.java
new file mode 100644 (file)
index 0000000..9177a78
--- /dev/null
@@ -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);
+        }
+    }
+}