added test to check authentication errors in file headers

This commit is contained in:
Sebastian Stenzel
2016-02-22 13:08:58 +01:00
parent 5df9f35065
commit c8df03a085
5 changed files with 22 additions and 7 deletions

View File

@@ -35,7 +35,7 @@ public interface FileContentCryptor {
* @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, 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()}.

View File

@@ -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.");
}

View File

@@ -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<Mac> hmacSha256Factory, ByteBuffer header) throws IllegalArgumentException {
public static FileHeader decrypt(SecretKey headerKey, Supplier<Mac> 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.");
}
}

View File

@@ -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");

View File

@@ -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() {