mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 18:21:26 +00:00
added test to check authentication errors in file headers
This commit is contained in:
@@ -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()}.
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user