Skip to content

Commit

Permalink
- added file integrity check (#17) - not yet visible to the user
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Stenzel committed Jan 6, 2015
1 parent e19cf1c commit 2e67910
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 12 deletions.
Expand Up @@ -41,6 +41,7 @@

import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.crypto.generators.SCrypt;
Expand Down Expand Up @@ -403,7 +404,30 @@ private void storeMetadata(CryptorIOSupport ioSupport, String metadataFile, Long

@Override
public boolean authenticateContent(SeekableByteChannel encryptedFile) throws IOException {
throw new UnsupportedOperationException("Not yet implemented.");
// read file size:
final Long fileSize = decryptedContentLength(encryptedFile);

// init mac:
final Mac mac = this.hmacSha256(hMacMasterKey);

// read stored mac:
encryptedFile.position(16);
final ByteBuffer macBuffer = ByteBuffer.allocate(mac.getMacLength());
final int numMacBytesRead = encryptedFile.read(macBuffer);

// check validity of header:
if (numMacBytesRead != mac.getMacLength() || fileSize == null) {
throw new IOException("Failed to read file header.");
}

// read all encrypted data and calculate mac:
encryptedFile.position(64);
final InputStream in = new SeekableByteChannelInputStream(encryptedFile);
final InputStream macIn = new MacInputStream(in, mac);
IOUtils.copyLarge(macIn, new NullOutputStream(), 0, fileSize);

// compare:
return Arrays.equals(macBuffer.array(), mac.doFinal());
}

@Override
Expand Down Expand Up @@ -517,18 +541,18 @@ public Long encryptFile(InputStream plaintextFile, SeekableByteChannel encrypted
final OutputStream cipheredOut = new CipherOutputStream(macOut, cipher);
final Long actualSize = IOUtils.copyLarge(plaintextFile, cipheredOut);

// copy MAC:
macBuffer.position(0);
macBuffer.put(mac.doFinal());

// append fake content:
final int randomContentLength = (int) Math.ceil(Math.random() * actualSize / 10.0);
final int randomContentLength = (int) Math.ceil((Math.random() + 1.0) * actualSize / 20.0);
final byte[] emptyBytes = new byte[AES_BLOCK_LENGTH];
for (int i = 0; i < randomContentLength; i += AES_BLOCK_LENGTH) {
cipheredOut.write(emptyBytes);
}
cipheredOut.flush();

// copy MAC:
macBuffer.position(0);
macBuffer.put(mac.doFinal());

// encrypt actualSize
try {
final ByteBuffer fileSizeBuffer = ByteBuffer.allocate(Long.BYTES);
Expand Down
Expand Up @@ -32,7 +32,7 @@ public int read() throws IOException {
@Override
public int read(byte[] b, int off, int len) throws IOException {
int read = in.read(b, off, len);
mac.update(b);
mac.update(b, off, len);
return read;
}

Expand Down
Expand Up @@ -25,7 +25,6 @@
import org.cryptomator.crypto.exceptions.UnsupportedKeyLengthException;
import org.cryptomator.crypto.exceptions.WrongPasswordException;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

public class Aes256CryptorTest {
Expand Down Expand Up @@ -73,7 +72,6 @@ public void testWrongPassword() throws IOException, DecryptFailedException, Wron
}
}

@Ignore
@Test
public void testIntegrityAuthentication() throws IOException {
// our test plaintext data:
Expand All @@ -93,9 +91,22 @@ public void testIntegrityAuthentication() throws IOException {
encryptedData.position(0);

// authenticate unmodified content:
final SeekableByteChannel encryptedIn = new ByteBufferBackedSeekableChannel(encryptedData);
final boolean unmodifiedContent = cryptor.authenticateContent(encryptedIn);
Assert.assertTrue(unmodifiedContent);
final SeekableByteChannel encryptedIn1 = new ByteBufferBackedSeekableChannel(encryptedData);
final boolean isContentUnmodified1 = cryptor.authenticateContent(encryptedIn1);
Assert.assertTrue(isContentUnmodified1);

// toggle one bit inf first content byte:
encryptedData.position(64);
final byte fifthByte = encryptedData.get();
encryptedData.position(64);
encryptedData.put((byte) (fifthByte ^ 0x01));

encryptedData.position(0);

// authenticate modified content:
final SeekableByteChannel encryptedIn2 = new ByteBufferBackedSeekableChannel(encryptedData);
final boolean isContentUnmodified2 = cryptor.authenticateContent(encryptedIn2);
Assert.assertFalse(isContentUnmodified2);
}

@Test
Expand Down

0 comments on commit 2e67910

Please sign in to comment.