From c8df03a08535b87125586e5373f77eb3e4eca347 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 22 Feb 2016 13:08:58 +0100 Subject: [PATCH] added test to check authentication errors in file headers --- .../crypto/engine/FileContentCryptor.java | 2 +- .../crypto/engine/impl/FileContentCryptorImpl.java | 3 ++- .../cryptomator/crypto/engine/impl/FileHeader.java | 8 +++++--- .../engine/impl/FileContentDecryptorImplTest.java | 14 +++++++++++++- .../webdav/jackrabbitservlet/NullInputContext.java | 2 +- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentCryptor.java b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentCryptor.java index 0d5d2553d..ec151a314 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentCryptor.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FileContentCryptor.java @@ -35,7 +35,7 @@ public interface FileContentCryptor { * @param authenticate Skip authentication by setting this flag to false. Should be true 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, boolean authenticate) throws IllegalArgumentException; + FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte, boolean authenticate) throws IllegalArgumentException, AuthenticationFailedException; /** * @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()}. diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentCryptorImpl.java b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentCryptorImpl.java index 1aadd94e6..2551ddbce 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentCryptorImpl.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentCryptorImpl.java @@ -14,6 +14,7 @@ import java.util.Optional; import javax.crypto.SecretKey; +import org.cryptomator.crypto.engine.AuthenticationFailedException; import org.cryptomator.crypto.engine.FileContentCryptor; import org.cryptomator.crypto.engine.FileContentDecryptor; import org.cryptomator.crypto.engine.FileContentEncryptor; @@ -52,7 +53,7 @@ public class FileContentCryptorImpl implements FileContentCryptor { } @Override - public FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte, boolean authenticate) { + public FileContentDecryptor createFileContentDecryptor(ByteBuffer header, long firstCiphertextByte, boolean authenticate) throws IllegalArgumentException, AuthenticationFailedException { if (header.remaining() != getHeaderSize()) { throw new IllegalArgumentException("Invalid header."); } diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileHeader.java b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileHeader.java index c6ab7bc9b..18accc34b 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileHeader.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileHeader.java @@ -17,6 +17,8 @@ import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.security.auth.Destroyable; +import org.cryptomator.crypto.engine.AuthenticationFailedException; + class FileHeader implements Destroyable { static final int HEADER_SIZE = 88; @@ -77,7 +79,7 @@ class FileHeader implements Destroyable { payload.destroy(); } - public static FileHeader decrypt(SecretKey headerKey, Supplier hmacSha256Factory, ByteBuffer header) throws IllegalArgumentException { + public static FileHeader decrypt(SecretKey headerKey, Supplier hmacSha256Factory, ByteBuffer header) throws IllegalArgumentException, AuthenticationFailedException { if (header.remaining() != HEADER_SIZE) { throw new IllegalArgumentException("Invalid header size."); } @@ -97,7 +99,7 @@ class FileHeader implements Destroyable { return new FileHeader(iv, payload); } - private static void checkHeaderMac(ByteBuffer header, Mac mac) throws IllegalArgumentException { + private static void checkHeaderMac(ByteBuffer header, Mac mac) throws AuthenticationFailedException { assert mac.getMacLength() == MAC_LEN; ByteBuffer headerData = header.asReadOnlyBuffer(); headerData.position(0).limit(MAC_POS); @@ -108,7 +110,7 @@ class FileHeader implements Destroyable { headerMac.get(expectedMac); if (!MessageDigest.isEqual(expectedMac, mac.doFinal())) { - throw new IllegalArgumentException("Corrupt header."); + throw new AuthenticationFailedException("Corrupt header."); } } diff --git a/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/impl/FileContentDecryptorImplTest.java b/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/impl/FileContentDecryptorImplTest.java index 885c453db..173d13348 100644 --- a/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/impl/FileContentDecryptorImplTest.java +++ b/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/impl/FileContentDecryptorImplTest.java @@ -64,7 +64,19 @@ public class FileContentDecryptorImplTest { } @Test(expected = AuthenticationFailedException.class) - public void testManipulatedDecryption() throws InterruptedException { + public void testManipulatedHeaderDecryption() 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("AAAAAAAAAAAAAAAAAAAAANyVwHiiQImjrUiiFJKEIIdTD4r7x0U2ualjtPHEy3OLzqdAPU1ga26lJzstK9RUv1hj5zDC4wC9FgMfoVE1mD0HnuENuYXkJa=="); + + try (FileContentDecryptor decryptor = new FileContentDecryptorImpl(headerKey, macKey, ByteBuffer.wrap(header), 0, true)) { + + } + } + + @Test(expected = AuthenticationFailedException.class) + public void testManipulatedContentDecryption() throws InterruptedException { final byte[] keyBytes = new byte[32]; final SecretKey headerKey = new SecretKeySpec(keyBytes, "AES"); final SecretKey macKey = new SecretKeySpec(keyBytes, "HmacSHA256"); diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/NullInputContext.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/NullInputContext.java index 058421dcf..94503155d 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/NullInputContext.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/NullInputContext.java @@ -5,7 +5,7 @@ import java.io.InputStream; import org.apache.jackrabbit.webdav.io.InputContext; -public class NullInputContext implements InputContext { +class NullInputContext implements InputContext { @Override public boolean hasStream() {