Sebastian Stenzel 9 سال پیش
والد
کامیت
951a02a9a5
14فایلهای تغییر یافته به همراه42 افزوده شده و 95 حذف شده
  1. 1 1
      main/filesystem-api/src/main/java/org/cryptomator/filesystem/ReadableBytes.java
  2. 6 5
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentCryptor.java
  3. 1 1
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentDecryptor.java
  4. 1 1
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentEncryptor.java
  5. 1 3
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FilenameCryptor.java
  6. 14 16
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/CryptorImpl.java
  7. 2 15
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentCryptorImpl.java
  8. 0 13
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FilenameCryptorImpl.java
  9. 0 28
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/TheDestroyer.java
  10. 7 6
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/fs/CryptoReadableFile.java
  11. 1 1
      main/filesystem-crypto/src/main/java/org/cryptomator/crypto/fs/CryptoWritableFile.java
  12. 2 2
      main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/NoFileContentCryptor.java
  13. 5 2
      main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryFile.java
  14. 1 1
      main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/NioFile.java

+ 1 - 1
main/filesystem-api/src/main/java/org/cryptomator/filesystem/ReadableBytes.java

@@ -41,6 +41,6 @@ public interface ReadableBytes {
 	 *             if an {@link IOException} occurs while reading from this
 	 *             {@code ReadableBytes}
 	 */
-	void read(ByteBuffer target, int position) throws UncheckedIOException;
+	void read(ByteBuffer target, long position) throws UncheckedIOException;
 
 }

+ 6 - 5
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentCryptor.java

@@ -3,9 +3,10 @@ package org.cryptomator.crypto.engine;
 import java.nio.ByteBuffer;
 import java.util.Optional;
 
-import javax.security.auth.Destroyable;
-
-public interface FileContentCryptor extends Destroyable {
+/**
+ * Factory for stateful {@link FileContentEncryptor Encryptor}/{@link FileContentDecryptor Decryptor} instances, that are capable of processing data exactly once.
+ */
+public interface FileContentCryptor {
 
 	/**
 	 * @return The fixed number of bytes of the file header. The header length is implementation-specific.
@@ -16,13 +17,13 @@ public interface FileContentCryptor extends Destroyable {
 	 * @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()}.
 	 * @return A possibly new FileContentDecryptor instance which is capable of decrypting ciphertexts associated with the given file header.
 	 */
-	FileContentDecryptor getFileContentDecryptor(ByteBuffer header);
+	FileContentDecryptor createFileContentDecryptor(ByteBuffer header);
 
 	/**
 	 * @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()}.
 	 *            If the header is empty, a new one will be created by the returned encryptor.
 	 * @return A possibly new FileContentEncryptor instance which is capable of encrypting cleartext associated with the given file header.
 	 */
-	FileContentEncryptor getFileContentEncryptor(Optional<ByteBuffer> header);
+	FileContentEncryptor createFileContentEncryptor(Optional<ByteBuffer> header);
 
 }

+ 1 - 1
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentDecryptor.java

@@ -4,7 +4,7 @@ import java.nio.ByteBuffer;
 import java.util.concurrent.BlockingQueue;
 
 /**
- * Not necessarily thread-safe.
+ * Stateful, thus not thread-safe.
  */
 public interface FileContentDecryptor {
 

+ 1 - 1
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentEncryptor.java

@@ -4,7 +4,7 @@ import java.nio.ByteBuffer;
 import java.util.concurrent.BlockingQueue;
 
 /**
- * Not necessarily thread-safe.
+ * Stateful, thus not thread-safe.
  */
 public interface FileContentEncryptor {
 

+ 1 - 3
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FilenameCryptor.java

@@ -8,15 +8,13 @@
  *******************************************************************************/
 package org.cryptomator.crypto.engine;
 
-import javax.security.auth.Destroyable;
-
 /**
  * Provides deterministic encryption capabilities as filenames must not change on subsequent encryption attempts,
  * otherwise each change results in major directory structure changes which would be a terrible idea for cloud storage encryption.
  * 
  * @see <a href="https://en.wikipedia.org/wiki/Deterministic_encryption">Wikipedia on deterministic encryption</a>
  */
-public interface FilenameCryptor extends Destroyable {
+public interface FilenameCryptor {
 
 	/**
 	 * @return constant length string, that is unlikely to collide with any other name.

+ 14 - 16
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/CryptorImpl.java

@@ -18,6 +18,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Destroyable;
 
 import org.cryptomator.crypto.engine.Cryptor;
 import org.cryptomator.crypto.engine.FileContentCryptor;
@@ -52,12 +53,11 @@ public class CryptorImpl implements Cryptor {
 		if (existingCryptor != null) {
 			return existingCryptor;
 		} else {
-			final FilenameCryptorImpl newCryptor = new FilenameCryptorImpl(encryptionKey, macKey);
+			final FilenameCryptor newCryptor = new FilenameCryptorImpl(encryptionKey, macKey);
 			if (filenameCryptor.compareAndSet(null, newCryptor)) {
 				return newCryptor;
 			} else {
 				// CAS failed: other thread set an object
-				newCryptor.destroy();
 				return filenameCryptor.get();
 			}
 		}
@@ -70,12 +70,11 @@ public class CryptorImpl implements Cryptor {
 		if (existingCryptor != null) {
 			return existingCryptor;
 		} else {
-			final FileContentCryptorImpl newCryptor = new FileContentCryptorImpl(encryptionKey, macKey);
+			final FileContentCryptor newCryptor = new FileContentCryptorImpl(encryptionKey, macKey);
 			if (fileContentCryptor.compareAndSet(null, newCryptor)) {
 				return newCryptor;
 			} else {
 				// CAS failed: other thread set an object
-				newCryptor.destroy();
 				return fileContentCryptor.get();
 			}
 		}
@@ -162,22 +161,21 @@ public class CryptorImpl implements Cryptor {
 
 	@Override
 	public void destroy() throws DestroyFailedException {
-		TheDestroyer.destroyQuietly(encryptionKey);
-		TheDestroyer.destroyQuietly(macKey);
-		if (filenameCryptor.get() != null) {
-			TheDestroyer.destroyQuietly(getFilenameCryptor());
-		}
-		if (fileContentCryptor.get() != null) {
-			TheDestroyer.destroyQuietly(getFileContentCryptor());
-		}
+		destroyQuietly(encryptionKey);
+		destroyQuietly(macKey);
 	}
 
 	@Override
 	public boolean isDestroyed() {
-		return encryptionKey.isDestroyed() //
-				&& macKey.isDestroyed() //
-				&& (filenameCryptor.get() == null || filenameCryptor.get().isDestroyed()) //
-				&& (fileContentCryptor.get() == null || fileContentCryptor.get().isDestroyed());
+		return encryptionKey.isDestroyed() && macKey.isDestroyed();
+	}
+
+	private void destroyQuietly(Destroyable d) {
+		try {
+			d.destroy();
+		} catch (DestroyFailedException e) {
+			// ignore
+		}
 	}
 
 }

+ 2 - 15
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentCryptorImpl.java

@@ -28,26 +28,13 @@ class FileContentCryptorImpl implements FileContentCryptor {
 	}
 
 	@Override
-	public FileContentDecryptor getFileContentDecryptor(ByteBuffer header) {
+	public FileContentDecryptor createFileContentDecryptor(ByteBuffer header) {
 		throw new UnsupportedOperationException("Method not implemented");
 	}
 
 	@Override
-	public FileContentEncryptor getFileContentEncryptor(Optional<ByteBuffer> header) {
+	public FileContentEncryptor createFileContentEncryptor(Optional<ByteBuffer> header) {
 		throw new UnsupportedOperationException("Method not implemented");
 	}
 
-	/* ======================= destruction ======================= */
-
-	@Override
-	public void destroy() {
-		TheDestroyer.destroyQuietly(encryptionKey);
-		TheDestroyer.destroyQuietly(macKey);
-	}
-
-	@Override
-	public boolean isDestroyed() {
-		return encryptionKey.isDestroyed() && macKey.isDestroyed();
-	}
-
 }

+ 0 - 13
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FilenameCryptorImpl.java

@@ -84,17 +84,4 @@ class FilenameCryptorImpl implements FilenameCryptor {
 		}
 	}
 
-	/* ======================= destruction ======================= */
-
-	@Override
-	public void destroy() {
-		TheDestroyer.destroyQuietly(encryptionKey);
-		TheDestroyer.destroyQuietly(macKey);
-	}
-
-	@Override
-	public boolean isDestroyed() {
-		return encryptionKey.isDestroyed() && macKey.isDestroyed();
-	}
-
 }

+ 0 - 28
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/TheDestroyer.java

@@ -1,28 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.crypto.engine.impl;
-
-import javax.security.auth.DestroyFailedException;
-import javax.security.auth.Destroyable;
-
-final class TheDestroyer {
-
-	private TheDestroyer() {
-
-	}
-
-	public static void destroyQuietly(Destroyable d) {
-		try {
-			d.destroy();
-		} catch (DestroyFailedException e) {
-			// ignore
-		}
-	}
-
-}

+ 7 - 6
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/fs/CryptoReadableFile.java

@@ -15,19 +15,20 @@ import org.cryptomator.io.ByteBuffers;
 class CryptoReadableFile implements ReadableFile {
 
 	private static final int READ_BUFFER_SIZE = 32 * 1024 + 32; // aligned with encrypted chunk size + MAC size
+	private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
 
 	private final ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
 	private final FileContentDecryptor decryptor;
 	private final ReadableFile file;
 	private Future<Void> readAheadTask;
-	private ByteBuffer bufferedCleartext;
+	private ByteBuffer bufferedCleartext = EMPTY_BUFFER;
 
 	public CryptoReadableFile(FileContentCryptor cryptor, ReadableFile file) {
 		final int headerSize = cryptor.getHeaderSize();
 		final ByteBuffer header = ByteBuffer.allocate(headerSize);
 		file.read(header, 0);
 		header.flip();
-		this.decryptor = cryptor.getFileContentDecryptor(header);
+		this.decryptor = cryptor.createFileContentDecryptor(header);
 		this.file = file;
 		this.prepareReadAtPhysicalPosition(headerSize + 0);
 	}
@@ -35,6 +36,7 @@ class CryptoReadableFile implements ReadableFile {
 	private void prepareReadAtPhysicalPosition(long pos) {
 		if (readAheadTask != null) {
 			readAheadTask.cancel(true);
+			bufferedCleartext = EMPTY_BUFFER;
 			decryptor.cleartext().clear();
 		}
 		readAheadTask = executorService.submit(new Reader(pos));
@@ -53,7 +55,7 @@ class CryptoReadableFile implements ReadableFile {
 	}
 
 	private void bufferCleartext() throws InterruptedException {
-		if (bufferedCleartext == null || !bufferedCleartext.hasRemaining()) {
+		if (!bufferedCleartext.hasRemaining()) {
 			bufferedCleartext = decryptor.cleartext().take();
 		}
 	}
@@ -64,7 +66,7 @@ class CryptoReadableFile implements ReadableFile {
 	}
 
 	@Override
-	public void read(ByteBuffer target, int position) {
+	public void read(ByteBuffer target, long position) {
 		throw new UnsupportedOperationException("Partial read not implemented yet.");
 	}
 
@@ -89,8 +91,7 @@ class CryptoReadableFile implements ReadableFile {
 
 		@Override
 		public Void call() {
-			// TODO change to file.read(ByteBuffer, long)
-			file.read(ByteBuffer.allocate(0), (int) startpos);
+			file.read(EMPTY_BUFFER, startpos);
 			int bytesRead = -1;
 			do {
 				ByteBuffer ciphertext = ByteBuffer.allocate(READ_BUFFER_SIZE);

+ 1 - 1
main/filesystem-crypto/src/main/java/org/cryptomator/crypto/fs/CryptoWritableFile.java

@@ -23,7 +23,7 @@ class CryptoWritableFile implements WritableFile {
 	private final Future<Void> writeTask;
 
 	public CryptoWritableFile(FileContentCryptor cryptor, WritableFile file) {
-		this.encryptor = cryptor.getFileContentEncryptor(Optional.empty());
+		this.encryptor = cryptor.createFileContentEncryptor(Optional.empty());
 		this.file = file;
 		writeHeader();
 		this.writeTask = executorService.submit(new Writer());

+ 2 - 2
main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/NoFileContentCryptor.java

@@ -13,7 +13,7 @@ class NoFileContentCryptor implements FileContentCryptor {
 	}
 
 	@Override
-	public FileContentDecryptor getFileContentDecryptor(ByteBuffer header) {
+	public FileContentDecryptor createFileContentDecryptor(ByteBuffer header) {
 		if (header.remaining() != getHeaderSize()) {
 			throw new IllegalArgumentException("Invalid header size.");
 		}
@@ -21,7 +21,7 @@ class NoFileContentCryptor implements FileContentCryptor {
 	}
 
 	@Override
-	public FileContentEncryptor getFileContentEncryptor(Optional<ByteBuffer> header) {
+	public FileContentEncryptor createFileContentEncryptor(Optional<ByteBuffer> header) {
 		return new Encryptor();
 	}
 

+ 5 - 2
main/filesystem-inmemory/src/main/java/org/cryptomator/filesystem/inmem/InMemoryFile.java

@@ -57,8 +57,11 @@ class InMemoryFile extends InMemoryNode implements File, ReadableFile, WritableF
 	}
 
 	@Override
-	public void read(ByteBuffer target, int position) {
-		content.position(position);
+	public void read(ByteBuffer target, long position) {
+		if (position > Integer.MAX_VALUE) {
+			throw new IllegalArgumentException("Can not keep files of virtually unlimited size in memory.");
+		}
+		content.position((int) position);
 		ByteBuffers.copy(content, target);
 	}
 

+ 1 - 1
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/NioFile.java

@@ -44,7 +44,7 @@ class NioFile extends NioNode implements File {
 		}
 
 		@Override
-		public void read(ByteBuffer target, int position) throws UncheckedIOException {
+		public void read(ByteBuffer target, long position) throws UncheckedIOException {
 		}
 
 		@Override