New MAC authentication warning, preventing CCAs, but allowing to force-decrypt unauthentic files.

This commit is contained in:
Sebastian Stenzel
2015-07-09 17:16:43 +02:00
parent 9d2d847727
commit 685e347524
27 changed files with 276 additions and 157 deletions
@@ -358,7 +358,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
}
@Override
public Long decryptFile(SeekableByteChannel encryptedFile, OutputStream plaintextFile) throws IOException, DecryptFailedException {
public Long decryptFile(SeekableByteChannel encryptedFile, OutputStream plaintextFile, boolean authenticate) throws IOException, DecryptFailedException {
// read header:
encryptedFile.position(0l);
final ByteBuffer headerBuf = ByteBuffer.allocate(96);
@@ -397,14 +397,14 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
headerBuf.get(storedHeaderMac);
// calculate mac over first 64 bytes of header:
final Mac headerMac = this.hmacSha256(hMacMasterKey);
headerBuf.position(0);
headerBuf.limit(64);
headerMac.update(headerBuf);
// check header integrity:
if (!MessageDigest.isEqual(storedHeaderMac, headerMac.doFinal())) {
throw new MacAuthenticationFailedException("Header MAC authentication failed.");
if (authenticate) {
final Mac headerMac = this.hmacSha256(hMacMasterKey);
headerBuf.position(0);
headerBuf.limit(64);
headerMac.update(headerBuf);
if (!MessageDigest.isEqual(storedHeaderMac, headerMac.doFinal())) {
throw new MacAuthenticationFailedException("Header MAC authentication failed.");
}
}
// content decryption:
@@ -424,12 +424,14 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
}
// check MAC of current block:
contentMac.update(buffer, 0, n - 32);
final byte[] calculatedMac = contentMac.doFinal();
final byte[] storedMac = new byte[32];
System.arraycopy(buffer, n - 32, storedMac, 0, 32);
if (!MessageDigest.isEqual(calculatedMac, storedMac)) {
throw new MacAuthenticationFailedException("Content MAC authentication failed.");
if (authenticate) {
contentMac.update(buffer, 0, n - 32);
final byte[] calculatedMac = contentMac.doFinal();
final byte[] storedMac = new byte[32];
System.arraycopy(buffer, n - 32, storedMac, 0, 32);
if (!MessageDigest.isEqual(calculatedMac, storedMac)) {
throw new MacAuthenticationFailedException("Content MAC authentication failed.");
}
}
// decrypt block:
@@ -444,7 +446,7 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
}
@Override
public Long decryptRange(SeekableByteChannel encryptedFile, OutputStream plaintextFile, long pos, long length) throws IOException, DecryptFailedException {
public Long decryptRange(SeekableByteChannel encryptedFile, OutputStream plaintextFile, long pos, long length, boolean authenticate) throws IOException, DecryptFailedException {
// read header:
encryptedFile.position(0l);
final ByteBuffer headerBuf = ByteBuffer.allocate(96);
@@ -470,14 +472,14 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
headerBuf.get(storedHeaderMac);
// calculate mac over first 64 bytes of header:
final Mac headerMac = this.hmacSha256(hMacMasterKey);
headerBuf.position(0);
headerBuf.limit(64);
headerMac.update(headerBuf);
// check header integrity:
if (!MessageDigest.isEqual(storedHeaderMac, headerMac.doFinal())) {
throw new MacAuthenticationFailedException("Header MAC authentication failed.");
if (authenticate) {
final Mac headerMac = this.hmacSha256(hMacMasterKey);
headerBuf.position(0);
headerBuf.limit(64);
headerMac.update(headerBuf);
if (!MessageDigest.isEqual(storedHeaderMac, headerMac.doFinal())) {
throw new MacAuthenticationFailedException("Header MAC authentication failed.");
}
}
// find first relevant block:
@@ -509,12 +511,14 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration {
}
// check MAC of current block:
contentMac.update(buffer, 0, n - 32);
final byte[] calculatedMac = contentMac.doFinal();
final byte[] storedMac = new byte[32];
System.arraycopy(buffer, n - 32, storedMac, 0, 32);
if (!MessageDigest.isEqual(calculatedMac, storedMac)) {
throw new MacAuthenticationFailedException("Content MAC authentication failed.");
if (authenticate) {
contentMac.update(buffer, 0, n - 32);
final byte[] calculatedMac = contentMac.doFinal();
final byte[] storedMac = new byte[32];
System.arraycopy(buffer, n - 32, storedMac, 0, 32);
if (!MessageDigest.isEqual(calculatedMac, storedMac)) {
throw new MacAuthenticationFailedException("Content MAC authentication failed.");
}
}
// decrypt block:
@@ -99,7 +99,7 @@ public class Aes256CryptorTest {
// decrypt modified content (should fail with DecryptFailedException):
final SeekableByteChannel encryptedIn = new ByteBufferBackedSeekableChannel(encryptedData);
final ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream();
cryptor.decryptFile(encryptedIn, plaintextOut);
cryptor.decryptFile(encryptedIn, plaintextOut, true);
}
@Test
@@ -127,7 +127,7 @@ public class Aes256CryptorTest {
// decrypt:
final ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream();
final Long numDecryptedBytes = cryptor.decryptFile(encryptedIn, plaintextOut);
final Long numDecryptedBytes = cryptor.decryptFile(encryptedIn, plaintextOut, true);
IOUtils.closeQuietly(encryptedIn);
IOUtils.closeQuietly(plaintextOut);
Assert.assertEquals(filesize.longValue(), numDecryptedBytes.longValue());
@@ -162,7 +162,7 @@ public class Aes256CryptorTest {
// decrypt:
final SeekableByteChannel encryptedIn = new ByteBufferBackedSeekableChannel(encryptedData);
final ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream();
final Long numDecryptedBytes = cryptor.decryptRange(encryptedIn, plaintextOut, 260000 * Integer.BYTES, 4000 * Integer.BYTES);
final Long numDecryptedBytes = cryptor.decryptRange(encryptedIn, plaintextOut, 260000 * Integer.BYTES, 4000 * Integer.BYTES, true);
IOUtils.closeQuietly(encryptedIn);
IOUtils.closeQuietly(plaintextOut);
Assert.assertTrue(numDecryptedBytes > 0);