From 63f64fae0390f96c05fe2a89597177bcd565ff26 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 23 Feb 2015 14:51:52 +0100 Subject: [PATCH] Fixed performance implications due to slow /dev/random. Now seeding PRNG only once per Cryptor. Fixes #36 --- main/core/pom.xml | 2 +- main/crypto-aes/pom.xml | 2 +- .../crypto/aes256/Aes256Cryptor.java | 48 ++++++------------- .../aes256/AesCryptographicConfiguration.java | 2 +- .../crypto/aes256/Aes256CryptorTest.java | 19 ++++---- main/crypto-api/pom.xml | 2 +- main/pom.xml | 2 +- main/ui/pom.xml | 2 +- 8 files changed, 28 insertions(+), 51 deletions(-) diff --git a/main/core/pom.xml b/main/core/pom.xml index 1e99ac34d..6972d2765 100644 --- a/main/core/pom.xml +++ b/main/core/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.5.0 + 0.5.1 core Cryptomator WebDAV and I/O module diff --git a/main/crypto-aes/pom.xml b/main/crypto-aes/pom.xml index a8b305220..064355cc3 100644 --- a/main/crypto-aes/pom.xml +++ b/main/crypto-aes/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.5.0 + 0.5.1 crypto-aes Cryptomator cryptographic module (AES) diff --git a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java index cc632d720..0f2b3ee44 100644 --- a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java +++ b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java @@ -25,7 +25,6 @@ import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Random; import java.util.UUID; import javax.crypto.BadPaddingException; @@ -58,19 +57,19 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class Aes256Cryptor extends AbstractCryptor implements AesCryptographicConfiguration, FileNamingConventions { - /** - * PRNG for cryptographically secure random numbers. Defaults to SHA1-based number generator. - * - * @see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SecureRandom - */ - private static final SecureRandom SECURE_PRNG; - /** * Defined in static initializer. Defaults to 256, but falls back to maximum value possible, if JCE Unlimited Strength Jurisdiction * Policy Files isn't installed. Those files can be downloaded here: http://www.oracle.com/technetwork/java/javase/downloads/. */ private static final int AES_KEY_LENGTH_IN_BITS; + /** + * PRNG for cryptographically secure random numbers. Defaults to SHA1-based number generator. + * + * @see http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SecureRandom + */ + private final SecureRandom securePrng; + /** * Jackson JSON-Mapper. */ @@ -89,7 +88,6 @@ public class Aes256Cryptor extends AbstractCryptor implements AesCryptographicCo static { try { - SECURE_PRNG = SecureRandom.getInstance(PRNG_ALGORITHM); final int maxKeyLength = Cipher.getMaxAllowedKeyLength(AES_KEY_ALGORITHM); AES_KEY_LENGTH_IN_BITS = (maxKeyLength >= PREF_MASTER_KEY_LENGTH_IN_BITS) ? PREF_MASTER_KEY_LENGTH_IN_BITS : maxKeyLength; } catch (NoSuchAlgorithmException e) { @@ -101,33 +99,16 @@ public class Aes256Cryptor extends AbstractCryptor implements AesCryptographicCo * Creates a new Cryptor with a newly initialized PRNG. */ public Aes256Cryptor() { - SECURE_PRNG.setSeed(SECURE_PRNG.generateSeed(PRNG_SEED_LENGTH)); byte[] bytes = new byte[AES_KEY_LENGTH_IN_BITS / Byte.SIZE]; try { - SECURE_PRNG.nextBytes(bytes); + securePrng = SecureRandom.getInstance(PRNG_ALGORITHM); + securePrng.setSeed(securePrng.generateSeed(PRNG_SEED_LENGTH)); + securePrng.nextBytes(bytes); this.primaryMasterKey = new SecretKeySpec(bytes, AES_KEY_ALGORITHM); - - SECURE_PRNG.nextBytes(bytes); - this.hMacMasterKey = new SecretKeySpec(bytes, HMAC_KEY_ALGORITHM); - } finally { - Arrays.fill(bytes, (byte) 0); - } - } - - /** - * Creates a new Cryptor with the given PRNG.
- * DO NOT USE IN PRODUCTION. This constructor must only be used in in unit tests. Do not change method visibility. - * - * @param prng Fast, possibly insecure PRNG. - */ - Aes256Cryptor(Random prng) { - byte[] bytes = new byte[AES_KEY_LENGTH_IN_BITS / Byte.SIZE]; - try { - prng.nextBytes(bytes); - this.primaryMasterKey = new SecretKeySpec(bytes, AES_KEY_ALGORITHM); - - prng.nextBytes(bytes); + securePrng.nextBytes(bytes); this.hMacMasterKey = new SecretKeySpec(bytes, HMAC_KEY_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("PRNG algorithm should exist.", e); } finally { Arrays.fill(bytes, (byte) 0); } @@ -266,8 +247,7 @@ public class Aes256Cryptor extends AbstractCryptor implements AesCryptographicCo private byte[] randomData(int length) { final byte[] result = new byte[length]; - SECURE_PRNG.setSeed(SECURE_PRNG.generateSeed(PRNG_SEED_LENGTH)); - SECURE_PRNG.nextBytes(result); + securePrng.nextBytes(result); return result; } diff --git a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/AesCryptographicConfiguration.java b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/AesCryptographicConfiguration.java index 7cdf319ec..4bd81f93f 100644 --- a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/AesCryptographicConfiguration.java +++ b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/AesCryptographicConfiguration.java @@ -33,7 +33,7 @@ interface AesCryptographicConfiguration { /** * Number of bytes used as seed for the PRNG. */ - int PRNG_SEED_LENGTH = 16; + int PRNG_SEED_LENGTH = 32; /** * Algorithm used for random number generation. diff --git a/main/crypto-aes/src/test/java/org/cryptomator/crypto/aes256/Aes256CryptorTest.java b/main/crypto-aes/src/test/java/org/cryptomator/crypto/aes256/Aes256CryptorTest.java index 668250e80..7d486c8c8 100644 --- a/main/crypto-aes/src/test/java/org/cryptomator/crypto/aes256/Aes256CryptorTest.java +++ b/main/crypto-aes/src/test/java/org/cryptomator/crypto/aes256/Aes256CryptorTest.java @@ -17,7 +17,6 @@ import java.nio.channels.SeekableByteChannel; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.Random; import org.apache.commons.io.IOUtils; import org.cryptomator.crypto.CryptorIOSupport; @@ -29,17 +28,15 @@ import org.junit.Test; public class Aes256CryptorTest { - private static final Random TEST_PRNG = new Random(); - @Test public void testCorrectPassword() throws IOException, WrongPasswordException, DecryptFailedException, UnsupportedKeyLengthException { final String pw = "asd"; - final Aes256Cryptor cryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor cryptor = new Aes256Cryptor(); final ByteArrayOutputStream out = new ByteArrayOutputStream(); cryptor.encryptMasterKey(out, pw); cryptor.swipeSensitiveData(); - final Aes256Cryptor decryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor decryptor = new Aes256Cryptor(); final InputStream in = new ByteArrayInputStream(out.toByteArray()); decryptor.decryptMasterKey(in, pw); @@ -50,7 +47,7 @@ public class Aes256CryptorTest { @Test public void testWrongPassword() throws IOException, DecryptFailedException, WrongPasswordException, UnsupportedKeyLengthException { final String pw = "asd"; - final Aes256Cryptor cryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor cryptor = new Aes256Cryptor(); final ByteArrayOutputStream out = new ByteArrayOutputStream(); cryptor.encryptMasterKey(out, pw); cryptor.swipeSensitiveData(); @@ -58,7 +55,7 @@ public class Aes256CryptorTest { // all these passwords are expected to fail. final String[] wrongPws = {"a", "as", "asdf", "sdf", "das", "dsa", "foo", "bar", "baz"}; - final Aes256Cryptor decryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor decryptor = new Aes256Cryptor(); for (final String wrongPw : wrongPws) { final InputStream in = new ByteArrayInputStream(out.toByteArray()); try { @@ -79,7 +76,7 @@ public class Aes256CryptorTest { final InputStream plaintextIn = new ByteArrayInputStream(plaintextData); // init cryptor: - final Aes256Cryptor cryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor cryptor = new Aes256Cryptor(); // encrypt: final ByteBuffer encryptedData = ByteBuffer.allocate(96); @@ -111,7 +108,7 @@ public class Aes256CryptorTest { final InputStream plaintextIn = new ByteArrayInputStream(plaintextData); // init cryptor: - final Aes256Cryptor cryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor cryptor = new Aes256Cryptor(); // encrypt: final ByteBuffer encryptedData = ByteBuffer.allocate(96); @@ -150,7 +147,7 @@ public class Aes256CryptorTest { final InputStream plaintextIn = new ByteArrayInputStream(plaintextData); // init cryptor: - final Aes256Cryptor cryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor cryptor = new Aes256Cryptor(); // encrypt: final ByteBuffer encryptedData = ByteBuffer.allocate((int) (64 + plaintextData.length * 1.2)); @@ -178,7 +175,7 @@ public class Aes256CryptorTest { @Test public void testEncryptionOfFilenames() throws IOException, DecryptFailedException { final CryptorIOSupport ioSupportMock = new CryptoIOSupportMock(); - final Aes256Cryptor cryptor = new Aes256Cryptor(TEST_PRNG); + final Aes256Cryptor cryptor = new Aes256Cryptor(); // short path components final String originalPath1 = "foo/bar/baz"; diff --git a/main/crypto-api/pom.xml b/main/crypto-api/pom.xml index 362175477..498a7523a 100644 --- a/main/crypto-api/pom.xml +++ b/main/crypto-api/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.5.0 + 0.5.1 crypto-api Cryptomator cryptographic module API diff --git a/main/pom.xml b/main/pom.xml index 57f9ee613..63ffe9d48 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.cryptomator main - 0.5.0 + 0.5.1 pom Cryptomator diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 85204c920..c123b5ae0 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -12,7 +12,7 @@ org.cryptomator main - 0.5.0 + 0.5.1 ui Cryptomator GUI