mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-25 06:01:31 +00:00
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:
@@ -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();
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user