randomizing masterkeys is now a explicit task, so random numbers are not needed when loading a masterkey file from disk. trying to use an uninitialized cryptor results in runtime exceptions

This commit is contained in:
Sebastian Stenzel
2015-11-23 15:09:39 +01:00
parent 2fca4629b9
commit a7c19624ce
7 changed files with 36 additions and 15 deletions

View File

@@ -49,6 +49,7 @@ public class RangeRequestTest {
@BeforeClass
public static void startServer() throws URISyntaxException {
CRYPTOR.randomizeMasterKey();
SERVER.start();
SERVLET = SERVER.createServlet(TMP_VAULT.toPath(), CRYPTOR, new ArrayList<String>(), new ArrayList<String>(), "JUnitTestVault");
SERVLET.start();

View File

@@ -39,7 +39,7 @@
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>siv-mode</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>
</dependency>
<!-- Commons -->

View File

@@ -103,25 +103,30 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
* Creates a new Cryptor with a newly initialized PRNG.
*/
public Aes256Cryptor() {
byte[] bytes = new byte[AES_KEY_LENGTH_IN_BITS / Byte.SIZE];
try {
securePrng = SecureRandom.getInstanceStrong();
// No setSeed needed. See SecureRandom.getInstance(String):
// The first call to nextBytes will force the SecureRandom object to seed itself
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("PRNG algorithm should exist.", e);
}
}
@Override
public void randomizeMasterKey() {
byte[] bytes = new byte[AES_KEY_LENGTH_IN_BITS / Byte.SIZE];
try {
// No setSeed needed. See SecureRandom.getInstance(String):
// The first call to nextBytes will force the SecureRandom object to seed itself
securePrng.nextBytes(bytes);
this.primaryMasterKey = new SecretKeySpec(bytes, AES_KEY_ALGORITHM);
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);
}
}
/**
* Encrypts the current masterKey with the given password and writes the result to the given output stream.
*/
@Override
public void encryptMasterKey(OutputStream out, CharSequence password) throws IOException {
try {
@@ -149,14 +154,6 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
}
}
/**
* Reads the encrypted masterkey from the given input stream and decrypts it with the given password.
*
* @throws DecryptFailedException If the decryption failed for various reasons (including wrong password).
* @throws WrongPasswordException If the provided password was wrong. Note: Sometimes the algorithm itself fails due to a wrong password. In this case a DecryptFailedException will be thrown.
* @throws UnsupportedKeyLengthException If the masterkey has been encrypted with a higher key length than supported by the system. In this case Java JCE needs to be installed.
* @throws UnsupportedVaultException If the masterkey file is too old or too modern.
*/
@Override
public void decryptMasterKey(InputStream in, CharSequence password) throws DecryptFailedException, WrongPasswordException, UnsupportedKeyLengthException, IOException, UnsupportedVaultException {
try {
@@ -194,6 +191,10 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
@Override
public boolean isDestroyed() {
if (primaryMasterKey == null || hMacMasterKey == null) {
// master keys have not been set yet, so there is nothing sensitive
return true;
}
return primaryMasterKey.isDestroyed() && hMacMasterKey.isDestroyed();
}

View File

@@ -33,6 +33,8 @@ public class Aes256CryptorTest {
public void testCorrectPassword() throws IOException, WrongPasswordException, DecryptFailedException, UnsupportedKeyLengthException, DestroyFailedException, UnsupportedVaultException {
final String pw = "asd";
final Aes256Cryptor cryptor = new Aes256Cryptor();
cryptor.randomizeMasterKey();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
cryptor.encryptMasterKey(out, pw);
cryptor.destroy();
@@ -49,6 +51,8 @@ public class Aes256CryptorTest {
public void testWrongPassword() throws IOException, DecryptFailedException, WrongPasswordException, UnsupportedKeyLengthException, DestroyFailedException, UnsupportedVaultException {
final String pw = "asd";
final Aes256Cryptor cryptor = new Aes256Cryptor();
cryptor.randomizeMasterKey();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
cryptor.encryptMasterKey(out, pw);
cryptor.destroy();
@@ -78,6 +82,7 @@ public class Aes256CryptorTest {
// init cryptor:
final Aes256Cryptor cryptor = new Aes256Cryptor();
cryptor.randomizeMasterKey();
// encrypt:
final ByteBuffer encryptedData = ByteBuffer.allocate(104 + plaintextData.length + 4096);
@@ -110,6 +115,7 @@ public class Aes256CryptorTest {
// init cryptor:
final Aes256Cryptor cryptor = new Aes256Cryptor();
cryptor.randomizeMasterKey();
// encrypt:
final ByteBuffer encryptedData = ByteBuffer.allocate(104 + plaintextData.length + 4096 + 32); // header + content + maximum possible size obfuscation padding + 32 bytes mac (per each 32k)
@@ -149,6 +155,7 @@ public class Aes256CryptorTest {
// init cryptor:
final Aes256Cryptor cryptor = new Aes256Cryptor();
cryptor.randomizeMasterKey();
// encrypt:
final ByteBuffer encryptedData = ByteBuffer.allocate((int) (104 + plaintextData.length * 1.2));
@@ -176,6 +183,7 @@ public class Aes256CryptorTest {
@Test
public void testEncryptionOfFilenames() throws IOException, DecryptFailedException {
final Aes256Cryptor cryptor = new Aes256Cryptor();
cryptor.randomizeMasterKey();
// directory paths
final String originalPath1 = "foo/bar/baz";

View File

@@ -22,6 +22,11 @@ public class AbstractCryptorDecorator implements Cryptor {
this.cryptor = cryptor;
}
@Override
public void randomizeMasterKey() {
cryptor.randomizeMasterKey();
}
@Override
public void encryptMasterKey(OutputStream out, CharSequence password) throws IOException {
cryptor.encryptMasterKey(out, password);

View File

@@ -27,6 +27,11 @@ import org.cryptomator.crypto.exceptions.WrongPasswordException;
*/
public interface Cryptor extends Destroyable {
/**
* Assigns new random bytes to the keys in this Cryptor instance.
*/
void randomizeMasterKey();
/**
* Encrypts the current masterKey with the given password and writes the result to the given output stream.
*/

View File

@@ -93,6 +93,7 @@ public class InitializeController extends AbstractFXMLViewController {
final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
final CharSequence password = passwordField.getCharacters();
try (OutputStream masterKeyOutputStream = Files.newOutputStream(masterKeyPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)) {
vault.getCryptor().randomizeMasterKey();
vault.getCryptor().encryptMasterKey(masterKeyOutputStream, password);
final String dataRootDir = vault.getCryptor().encryptDirectoryPath("", FileSystems.getDefault().getSeparator());
final Path dataRootPath = vault.getPath().resolve("d").resolve(dataRootDir);