mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-20 19:51:27 +00:00
support for forced decryption ignoring failed authentication
This commit is contained in:
@@ -32,9 +32,10 @@ public interface FileContentCryptor {
|
||||
* @param header The full fixed-length header of an encrypted file. The caller is required to pass the exact amount of bytes returned by {@link #getHeaderSize()}.
|
||||
* @param firstCiphertextByte Position of the first ciphertext byte passed to the decryptor. If the decryptor can not fast-forward to the requested byte, an exception is thrown.
|
||||
* If firstCiphertextByte is an invalid starting point, i.e. doesn't align with the decryptors internal block size, an IllegalArgumentException will be thrown.
|
||||
* @param authenticate Skip authentication by setting this flag to <code>false</code>. Should be <code>true</code> by default.
|
||||
* @return A possibly new FileContentDecryptor instance which is capable of decrypting ciphertexts associated with the given file header.
|
||||
*/
|
||||
FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte) throws IllegalArgumentException;
|
||||
FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte, boolean authenticate) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* @param header The full fixed-length header of an encrypted file or {@link Optional#empty()}. The caller is required to pass the exact amount of bytes returned by {@link #getHeaderSize()}.
|
||||
|
||||
@@ -50,14 +50,14 @@ public class FileContentCryptorImpl implements FileContentCryptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte) {
|
||||
public FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte, boolean authenticate) {
|
||||
if (header.remaining() != getHeaderSize()) {
|
||||
throw new IllegalArgumentException("Invalid header.");
|
||||
}
|
||||
if (firstCiphertextByte % (CHUNK_SIZE + MAC_SIZE) != 0) {
|
||||
throw new IllegalArgumentException("Invalid starting point for decryption.");
|
||||
}
|
||||
return new FileContentDecryptorImpl(encryptionKey, macKey, header, firstCiphertextByte);
|
||||
return new FileContentDecryptorImpl(encryptionKey, macKey, header, firstCiphertextByte, authenticate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,13 +41,15 @@ class FileContentDecryptorImpl implements FileContentDecryptor {
|
||||
private final FifoParallelDataProcessor<ByteBuffer> dataProcessor = new FifoParallelDataProcessor<>(NUM_THREADS, NUM_THREADS + READ_AHEAD);
|
||||
private final ThreadLocal<Mac> hmacSha256;
|
||||
private final FileHeader header;
|
||||
private final boolean authenticate;
|
||||
private ByteBuffer ciphertextBuffer = ByteBuffer.allocate(CHUNK_SIZE + MAC_SIZE);
|
||||
private long chunkNumber = 0;
|
||||
|
||||
public FileContentDecryptorImpl(SecretKey headerKey, SecretKey macKey, ByteBuffer header, long firstCiphertextByte) {
|
||||
public FileContentDecryptorImpl(SecretKey headerKey, SecretKey macKey, ByteBuffer header, long firstCiphertextByte, boolean authenticate) {
|
||||
final ThreadLocalMac hmacSha256 = new ThreadLocalMac(macKey, HMAC_SHA256);
|
||||
this.hmacSha256 = hmacSha256;
|
||||
this.header = FileHeader.decrypt(headerKey, hmacSha256, header);
|
||||
this.authenticate = authenticate;
|
||||
this.chunkNumber = firstCiphertextByte / CHUNK_SIZE; // floor() by int-truncation
|
||||
}
|
||||
|
||||
@@ -141,10 +143,12 @@ class FileContentDecryptorImpl implements FileContentDecryptor {
|
||||
@Override
|
||||
public ByteBuffer call() {
|
||||
try {
|
||||
Mac mac = hmacSha256.get();
|
||||
mac.update(ciphertextChunk.asReadOnlyBuffer());
|
||||
if (!MessageDigest.isEqual(expectedMac, mac.doFinal())) {
|
||||
throw new AuthenticationFailedException();
|
||||
if (authenticate) {
|
||||
Mac mac = hmacSha256.get();
|
||||
mac.update(ciphertextChunk.asReadOnlyBuffer());
|
||||
if (!MessageDigest.isEqual(expectedMac, mac.doFinal())) {
|
||||
throw new AuthenticationFailedException();
|
||||
}
|
||||
}
|
||||
|
||||
Cipher cipher = ThreadLocalAesCtrCipher.get();
|
||||
|
||||
@@ -40,7 +40,8 @@ public class CryptoFile extends CryptoNode implements File {
|
||||
|
||||
@Override
|
||||
public ReadableFile openReadable() {
|
||||
return new CryptoReadableFile(cryptor.getFileContentCryptor(), physicalFile().openReadable());
|
||||
boolean authenticate = !fileSystem().delegate().shouldSkipAuthentication(toString());
|
||||
return new CryptoReadableFile(cryptor.getFileContentCryptor(), physicalFile().openReadable(), authenticate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,10 +27,12 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
|
||||
private static final String MASTERKEY_BACKUP_FILENAME = "masterkey.cryptomator.bkup";
|
||||
|
||||
private final Folder physicalRoot;
|
||||
private final CryptoFileSystemDelegate delegate;
|
||||
|
||||
public CryptoFileSystem(Folder physicalRoot, Cryptor cryptor, CharSequence passphrase) throws InvalidPassphraseException {
|
||||
public CryptoFileSystem(Folder physicalRoot, Cryptor cryptor, CryptoFileSystemDelegate delegate, CharSequence passphrase) throws InvalidPassphraseException {
|
||||
super(null, "", cryptor);
|
||||
this.physicalRoot = physicalRoot;
|
||||
this.delegate = delegate;
|
||||
final File masterkeyFile = physicalRoot.file(MASTERKEY_FILENAME);
|
||||
if (masterkeyFile.exists()) {
|
||||
final boolean unlocked = decryptMasterKeyFile(cryptor, masterkeyFile, passphrase);
|
||||
@@ -68,6 +70,10 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
CryptoFileSystemDelegate delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File physicalFile() {
|
||||
return physicalDataRoot().file(ROOT_DIR_FILE);
|
||||
@@ -107,7 +113,7 @@ public class CryptoFileSystem extends CryptoFolder implements FileSystem {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return physicalRoot + ":::/";
|
||||
return "/";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.cryptomator.filesystem.crypto;
|
||||
|
||||
public interface CryptoFileSystemDelegate {
|
||||
|
||||
/**
|
||||
* Reports the path for resources, that could not be decrypted due to authentication errors.
|
||||
*
|
||||
* @param cleartextPath Unix-style vault-relative path
|
||||
*/
|
||||
void authenticationFailed(String cleartextPath);
|
||||
|
||||
/**
|
||||
* Allows the delegate to deactivate authentication during decryption.
|
||||
* This bears the risk of CCAs, thus this method should only return <code>true</code> for data recovery purposes.
|
||||
*
|
||||
* @param cleartextPath Unix-style vault-relative path
|
||||
* @return Must always <b>default to <code>false</code></b>, except when authentication should be skipped.
|
||||
*/
|
||||
boolean shouldSkipAuthentication(String cleartextPath);
|
||||
|
||||
}
|
||||
@@ -24,9 +24,9 @@ public class CryptoFileSystemFactory {
|
||||
this.blockAlignedFileSystemFactory = blockAlignedFileSystemFactory;
|
||||
}
|
||||
|
||||
public FileSystem get(Folder root, CharSequence passphrase) {
|
||||
public FileSystem get(Folder root, CharSequence passphrase, CryptoFileSystemDelegate delegate) {
|
||||
final FileSystem nameShorteningFs = shorteningFileSystemFactory.get(root);
|
||||
final FileSystem cryptoFs = new CryptoFileSystem(nameShorteningFs, cryptorProvider.get(), passphrase);
|
||||
final FileSystem cryptoFs = new CryptoFileSystem(nameShorteningFs, cryptorProvider.get(), delegate, passphrase);
|
||||
return blockAlignedFileSystemFactory.get(cryptoFs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ abstract class CryptoNode implements Node {
|
||||
return parent.physicalFolder().file(encryptedName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CryptoFileSystem fileSystem() {
|
||||
return (CryptoFileSystem) Node.super.fileSystem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CryptoFolder> parent() {
|
||||
return Optional.of(parent);
|
||||
@@ -74,4 +79,12 @@ abstract class CryptoNode implements Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unix-style cleartext path rooted at the vault's top-level directory.
|
||||
*
|
||||
* @return Vault-relative cleartext path.
|
||||
*/
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
}
|
||||
|
||||
@@ -29,14 +29,16 @@ class CryptoReadableFile implements ReadableFile {
|
||||
private final ByteBuffer header;
|
||||
private final FileContentCryptor cryptor;
|
||||
private final ReadableFile file;
|
||||
private final boolean authenticate;
|
||||
private FileContentDecryptor decryptor;
|
||||
private Future<Void> readAheadTask;
|
||||
private ByteBuffer bufferedCleartext = EMPTY_BUFFER;
|
||||
|
||||
public CryptoReadableFile(FileContentCryptor cryptor, ReadableFile file) {
|
||||
public CryptoReadableFile(FileContentCryptor cryptor, ReadableFile file, boolean authenticate) {
|
||||
this.header = ByteBuffer.allocate(cryptor.getHeaderSize());
|
||||
this.cryptor = cryptor;
|
||||
this.file = file;
|
||||
this.authenticate = authenticate;
|
||||
file.position(0);
|
||||
file.read(header);
|
||||
header.flip();
|
||||
@@ -73,7 +75,7 @@ class CryptoReadableFile implements ReadableFile {
|
||||
bufferedCleartext = EMPTY_BUFFER;
|
||||
}
|
||||
long ciphertextPos = cryptor.toCiphertextPos(position);
|
||||
decryptor = cryptor.createFileContentDecryptor(header.asReadOnlyBuffer(), ciphertextPos);
|
||||
decryptor = cryptor.createFileContentDecryptor(header.asReadOnlyBuffer(), ciphertextPos, authenticate);
|
||||
readAheadTask = executorService.submit(new CiphertextReader(file, decryptor, header.remaining() + ciphertextPos));
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class NoFileContentCryptor implements FileContentCryptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte) {
|
||||
public FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte, boolean authenticate) {
|
||||
if (header.remaining() != getHeaderSize()) {
|
||||
throw new IllegalArgumentException("Invalid header size.");
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class FileContentCryptorImplTest {
|
||||
FileContentCryptor cryptor = new FileContentCryptorImpl(encryptionKey, macKey, RANDOM_MOCK);
|
||||
|
||||
ByteBuffer tooShortHeader = ByteBuffer.allocate(63);
|
||||
cryptor.createFileContentDecryptor(tooShortHeader, 0);
|
||||
cryptor.createFileContentDecryptor(tooShortHeader, 0, true);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -75,7 +75,7 @@ public class FileContentCryptorImplTest {
|
||||
FileContentCryptor cryptor = new FileContentCryptorImpl(encryptionKey, macKey, RANDOM_MOCK);
|
||||
|
||||
ByteBuffer header = ByteBuffer.allocate(cryptor.getHeaderSize());
|
||||
cryptor.createFileContentDecryptor(header, 3);
|
||||
cryptor.createFileContentDecryptor(header, 3, true);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -110,7 +110,7 @@ public class FileContentCryptorImplTest {
|
||||
ciphertext.flip();
|
||||
|
||||
ByteBuffer plaintext = ByteBuffer.allocate(100);
|
||||
try (FileContentDecryptor decryptor = cryptor.createFileContentDecryptor(header, 0)) {
|
||||
try (FileContentDecryptor decryptor = cryptor.createFileContentDecryptor(header, 0, true)) {
|
||||
decryptor.append(ciphertext);
|
||||
decryptor.append(FileContentCryptor.EOF);
|
||||
ByteBuffer buf;
|
||||
@@ -163,7 +163,7 @@ public class FileContentCryptorImplTest {
|
||||
|
||||
final Thread fileReader;
|
||||
final long decStart = System.nanoTime();
|
||||
try (FileContentDecryptor decryptor = cryptor.createFileContentDecryptor(header, 0)) {
|
||||
try (FileContentDecryptor decryptor = cryptor.createFileContentDecryptor(header, 0, true)) {
|
||||
fileReader = new Thread(() -> {
|
||||
try (FileChannel fc = FileChannel.open(tmpFile, StandardOpenOption.READ)) {
|
||||
ByteBuffer ciphertext = ByteBuffer.allocate(654321);
|
||||
|
||||
@@ -19,6 +19,7 @@ import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
import org.cryptomator.crypto.engine.AuthenticationFailedException;
|
||||
import org.cryptomator.crypto.engine.FileContentCryptor;
|
||||
import org.cryptomator.crypto.engine.FileContentDecryptor;
|
||||
import org.cryptomator.crypto.engine.FileContentEncryptor;
|
||||
@@ -47,7 +48,51 @@ public class FileContentDecryptorImplTest {
|
||||
final byte[] header = Base64.decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwN74OFIGKQKgsI7bakfCYm1VXJZiKFLyhZkQCz0Ye/il0PmdZOYsSYEH9h6S00RsdHL3wLtB1FJsb9QLTtP00H8M2theZaZdlKTmjhXsmbc=");
|
||||
final byte[] content = Base64.decode("tPCsFM1g/ubfJMa+AocdPh/WPHfXMFRJdIz6PkLuRijSIIXvxn7IUwVzHQ==");
|
||||
|
||||
try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0)) {
|
||||
try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0, true)) {
|
||||
decryptor.append(ByteBuffer.wrap(Arrays.copyOfRange(content, 0, 15)));
|
||||
decryptor.append(ByteBuffer.wrap(Arrays.copyOfRange(content, 15, 43)));
|
||||
decryptor.append(FileContentCryptor.EOF);
|
||||
|
||||
ByteBuffer result = ByteBuffer.allocate(11); // we just care about the first 11 bytes, as this is the ciphertext.
|
||||
ByteBuffer buf;
|
||||
while ((buf = decryptor.cleartext()) != FileContentCryptor.EOF) {
|
||||
ByteBuffers.copy(buf, result);
|
||||
}
|
||||
|
||||
Assert.assertArrayEquals("hello world".getBytes(), result.array());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationFailedException.class)
|
||||
public void testManipulatedDecryption() throws InterruptedException {
|
||||
final byte[] keyBytes = new byte[32];
|
||||
final SecretKey headerKey = new SecretKeySpec(keyBytes, "AES");
|
||||
final SecretKey macKey = new SecretKeySpec(keyBytes, "HmacSHA256");
|
||||
final byte[] header = Base64.decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwN74OFIGKQKgsI7bakfCYm1VXJZiKFLyhZkQCz0Ye/il0PmdZOYsSYEH9h6S00RsdHL3wLtB1FJsb9QLTtP00H8M2theZaZdlKTmjhXsmbc=");
|
||||
final byte[] content = Base64.decode("tPCsFM1g/ubfJMa+AocdPh/WPHfXMFRJdIz6PkLuRijSIIXvxn7IUwVzHq==");
|
||||
|
||||
try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0, true)) {
|
||||
decryptor.append(ByteBuffer.wrap(Arrays.copyOfRange(content, 0, 15)));
|
||||
decryptor.append(ByteBuffer.wrap(Arrays.copyOfRange(content, 15, 43)));
|
||||
decryptor.append(FileContentCryptor.EOF);
|
||||
|
||||
ByteBuffer result = ByteBuffer.allocate(11); // we just care about the first 11 bytes, as this is the ciphertext.
|
||||
ByteBuffer buf;
|
||||
while ((buf = decryptor.cleartext()) != FileContentCryptor.EOF) {
|
||||
ByteBuffers.copy(buf, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManipulatedDecryptionWithSuppressedAuthentication() throws InterruptedException {
|
||||
final byte[] keyBytes = new byte[32];
|
||||
final SecretKey headerKey = new SecretKeySpec(keyBytes, "AES");
|
||||
final SecretKey macKey = new SecretKeySpec(keyBytes, "HmacSHA256");
|
||||
final byte[] header = Base64.decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwN74OFIGKQKgsI7bakfCYm1VXJZiKFLyhZkQCz0Ye/il0PmdZOYsSYEH9h6S00RsdHL3wLtB1FJsb9QLTtP00H8M2theZaZdlKTmjhXsmbc=");
|
||||
final byte[] content = Base64.decode("tPCsFM1g/ubfJMa+AocdPh/WPHfXMFRJdIz6PkLuRijSIIXvxn7IUwVzHq==");
|
||||
|
||||
try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0, false)) {
|
||||
decryptor.append(ByteBuffer.wrap(Arrays.copyOfRange(content, 0, 15)));
|
||||
decryptor.append(ByteBuffer.wrap(Arrays.copyOfRange(content, 15, 43)));
|
||||
decryptor.append(FileContentCryptor.EOF);
|
||||
@@ -69,7 +114,7 @@ public class FileContentDecryptorImplTest {
|
||||
final SecretKey macKey = new SecretKeySpec(keyBytes, "AES");
|
||||
final byte[] header = Base64.decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwN74OFIGKQKgsI7bakfCYm1VXJZiKFLyhZkQCz0Ye/il0PmdZOYsSYEH9h6S00RsdHL3wLtB1FJsb9QLTtP00H8M2theZaZdlKTmjhXsmbc=");
|
||||
|
||||
try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0)) {
|
||||
try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0, true)) {
|
||||
decryptor.cancelWithException(new IOException("can not do"));
|
||||
decryptor.cleartext();
|
||||
}
|
||||
@@ -113,7 +158,7 @@ public class FileContentDecryptorImplTest {
|
||||
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
final int ciphertextPos = (int) cryptor.toCiphertextPos(i * 32768);
|
||||
try (FileContentDecryptor decryptor = cryptor.createFileContentDecryptor(header, ciphertextPos)) {
|
||||
try (FileContentDecryptor decryptor = cryptor.createFileContentDecryptor(header, ciphertextPos, true)) {
|
||||
final Thread ciphertextReader = new Thread(() -> {
|
||||
try {
|
||||
ciphertext.position(ciphertextPos);
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -24,13 +25,15 @@ public class CryptoFileSystemComponentIntegrationTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CryptoFileSystemComponentIntegrationTest.class);
|
||||
|
||||
private CryptoFileSystemDelegate cryptoDelegate;
|
||||
private FileSystem ciphertextFs;
|
||||
private FileSystem cleartextFs;
|
||||
|
||||
@Before
|
||||
public void setupFileSystems() {
|
||||
cryptoDelegate = Mockito.mock(CryptoFileSystemDelegate.class);
|
||||
ciphertextFs = new InMemoryFileSystem();
|
||||
cleartextFs = cryptoFsComp.cryptoFileSystemFactory().get(ciphertextFs, "TopSecret");
|
||||
cleartextFs = cryptoFsComp.cryptoFileSystemFactory().get(ciphertextFs, "TopSecret", cryptoDelegate);
|
||||
cleartextFs.create();
|
||||
}
|
||||
|
||||
@@ -77,7 +80,38 @@ public class CryptoFileSystemComponentIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 2000000) // assuming a minimum speed of 10mb/s during encryption and decryption 20s should be enough
|
||||
@Test
|
||||
public void testForcedDecryptionOfManipulatedFile() {
|
||||
// write test content to encrypted file
|
||||
try (WritableFile writable = cleartextFs.file("test1.txt").openWritable()) {
|
||||
writable.write(ByteBuffer.wrap("Hello World".getBytes()));
|
||||
}
|
||||
|
||||
File physicalFile = ciphertextFs.folder("d").folders().findAny().get().folders().findAny().get().files().findAny().get();
|
||||
Assert.assertTrue(physicalFile.exists());
|
||||
|
||||
// toggle last bit
|
||||
try (WritableFile writable = physicalFile.openWritable(); ReadableFile readable = physicalFile.openReadable()) {
|
||||
ByteBuffer buf = ByteBuffer.allocate((int) readable.size());
|
||||
readable.read(buf);
|
||||
buf.array()[buf.limit() - 1] ^= 0x01;
|
||||
buf.flip();
|
||||
writable.write(buf);
|
||||
}
|
||||
|
||||
// whitelist
|
||||
Mockito.when(cryptoDelegate.shouldSkipAuthentication("/test1.txt")).thenReturn(true);
|
||||
|
||||
// read test content from decrypted file
|
||||
try (ReadableFile readable = cleartextFs.file("test1.txt").openReadable()) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(11);
|
||||
readable.read(buf);
|
||||
buf.flip();
|
||||
Assert.assertArrayEquals("Hello World".getBytes(), buf.array());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 20000) // assuming a minimum speed of 10mb/s during encryption and decryption 20s should be enough
|
||||
public void testEncryptionAndDecryptionSpeed() throws InterruptedException, IOException {
|
||||
File file = cleartextFs.file("benchmark.test");
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.cryptomator.filesystem.WritableFile;
|
||||
import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class CryptoFileSystemTest {
|
||||
|
||||
@@ -45,7 +46,7 @@ public class CryptoFileSystemTest {
|
||||
Assert.assertFalse(physicalDataRoot.exists());
|
||||
|
||||
// init crypto fs:
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
Assert.assertTrue(masterkeyFile.exists());
|
||||
Assert.assertTrue(masterkeyBkupFile.exists());
|
||||
fs.create();
|
||||
@@ -66,7 +67,7 @@ public class CryptoFileSystemTest {
|
||||
Assert.assertFalse(masterkeyBkupFile.exists());
|
||||
|
||||
// first initialization:
|
||||
new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
Assert.assertTrue(masterkeyBkupFile.exists());
|
||||
final Instant bkupDateT0 = masterkeyBkupFile.lastModified();
|
||||
|
||||
@@ -75,7 +76,7 @@ public class CryptoFileSystemTest {
|
||||
Thread.sleep(1);
|
||||
|
||||
// second initialization:
|
||||
new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
Assert.assertTrue(masterkeyBkupFile.exists());
|
||||
final Instant bkupDateT1 = masterkeyBkupFile.lastModified();
|
||||
|
||||
@@ -88,7 +89,7 @@ public class CryptoFileSystemTest {
|
||||
final Cryptor cryptor = new NoCryptor();
|
||||
final FileSystem physicalFs = new InMemoryFileSystem();
|
||||
final Folder physicalDataRoot = physicalFs.folder("d");
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
fs.create();
|
||||
|
||||
// add another encrypted folder:
|
||||
@@ -108,7 +109,7 @@ public class CryptoFileSystemTest {
|
||||
// mock stuff and prepare crypto FS:
|
||||
final Cryptor cryptor = new NoCryptor();
|
||||
final FileSystem physicalFs = new InMemoryFileSystem();
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
fs.create();
|
||||
|
||||
// create foo/bar/ and then move foo/ to baz/:
|
||||
@@ -131,7 +132,7 @@ public class CryptoFileSystemTest {
|
||||
// mock stuff and prepare crypto FS:
|
||||
final Cryptor cryptor = new NoCryptor();
|
||||
final FileSystem physicalFs = new InMemoryFileSystem();
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
fs.create();
|
||||
|
||||
// create foo/bar/ and then try to move foo/bar/ to foo/
|
||||
@@ -141,12 +142,12 @@ public class CryptoFileSystemTest {
|
||||
fooBarFolder.moveTo(fooFolder);
|
||||
}
|
||||
|
||||
@Test(timeout = 10000000)
|
||||
@Test(timeout = 10000)
|
||||
public void testWriteAndReadEncryptedFile() {
|
||||
// mock stuff and prepare crypto FS:
|
||||
final Cryptor cryptor = new NoCryptor();
|
||||
final FileSystem physicalFs = new InMemoryFileSystem();
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, "foo");
|
||||
final FileSystem fs = new CryptoFileSystem(physicalFs, cryptor, Mockito.mock(CryptoFileSystemDelegate.class), "foo");
|
||||
fs.create();
|
||||
|
||||
// write test content to file
|
||||
|
||||
@@ -30,7 +30,7 @@ public class CryptoReadableFileTest {
|
||||
}).thenThrow(new UncheckedIOException(new IOException("failed.")));
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
ReadableFile cryptoReadableFile = new CryptoReadableFile(fileContentCryptor, underlyingFile);
|
||||
ReadableFile cryptoReadableFile = new CryptoReadableFile(fileContentCryptor, underlyingFile, true);
|
||||
cryptoReadableFile.read(ByteBuffer.allocate(1));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@ import java.util.List;
|
||||
import org.cryptomator.crypto.engine.impl.CryptorImpl;
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystem;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemDelegate;
|
||||
import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
|
||||
import org.cryptomator.filesystem.invariants.FileSystemFactories.FileSystemFactory;
|
||||
import org.cryptomator.filesystem.nio.NioFileSystem;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
class FileSystemFactories implements Iterable<FileSystemFactory> {
|
||||
|
||||
@@ -48,11 +50,11 @@ class FileSystemFactories implements Iterable<FileSystemFactory> {
|
||||
}
|
||||
|
||||
private FileSystem createCryptoFileSystemInMemory() {
|
||||
return new CryptoFileSystem(createInMemoryFileSystem(), new CryptorImpl(RANDOM_MOCK), "aPassphrase");
|
||||
return new CryptoFileSystem(createInMemoryFileSystem(), new CryptorImpl(RANDOM_MOCK), Mockito.mock(CryptoFileSystemDelegate.class), "aPassphrase");
|
||||
}
|
||||
|
||||
private FileSystem createCryptoFileSystemNio() {
|
||||
return new CryptoFileSystem(createNioFileSystem(), new CryptorImpl(RANDOM_MOCK), "aPassphrase");
|
||||
return new CryptoFileSystem(createNioFileSystem(), new CryptorImpl(RANDOM_MOCK), Mockito.mock(CryptoFileSystemDelegate.class), "aPassphrase");
|
||||
}
|
||||
|
||||
private void add(String name, FileSystemFactory factory) {
|
||||
|
||||
Reference in New Issue
Block a user