Skip to content

Commit

Permalink
move size calculation methods to FileContentCryptor
Browse files Browse the repository at this point in the history
  • Loading branch information
overheadhunter committed Jun 28, 2021
1 parent deceb0f commit cefd70b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 53 deletions.
42 changes: 0 additions & 42 deletions src/main/java/org/cryptomator/cryptolib/api/Cryptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

import javax.security.auth.Destroyable;

import static com.google.common.base.Preconditions.checkArgument;

public interface Cryptor extends Destroyable, AutoCloseable {

FileContentCryptor fileContentCryptor();
Expand All @@ -31,44 +29,4 @@ default void close() {
destroy();
}

/**
* Calculates the size of the cleartext resulting from the given ciphertext decrypted with the given cryptor.
*
* @param ciphertextSize Length of encrypted payload. Not including the {@link FileHeaderCryptor#headerSize() length of the header}.
* @return Cleartext length of a <code>ciphertextSize</code>-sized ciphertext decrypted with <code>cryptor</code>.
*/
default long cleartextSize(long ciphertextSize) {
checkArgument(ciphertextSize >= 0, "expected ciphertextSize to be positive, but was %s", ciphertextSize);
long cleartextChunkSize = fileContentCryptor().cleartextChunkSize();
long ciphertextChunkSize = fileContentCryptor().ciphertextChunkSize();
long overheadPerChunk = ciphertextChunkSize - cleartextChunkSize;
long numFullChunks = ciphertextSize / ciphertextChunkSize; // floor by int-truncation
long additionalCiphertextBytes = ciphertextSize % ciphertextChunkSize;
if (additionalCiphertextBytes > 0 && additionalCiphertextBytes <= overheadPerChunk) {
throw new IllegalArgumentException("Method not defined for input value " + ciphertextSize);
}
long additionalCleartextBytes = (additionalCiphertextBytes == 0) ? 0 : additionalCiphertextBytes - overheadPerChunk;
assert additionalCleartextBytes >= 0;
return cleartextChunkSize * numFullChunks + additionalCleartextBytes;
}

/**
* Calculates the size of the ciphertext resulting from the given cleartext encrypted with the given cryptor.
*
* @param cleartextSize Length of a unencrypted payload.
* @return Ciphertext length of a <code>cleartextSize</code>-sized cleartext encrypted with <code>cryptor</code>.
* Not including the {@link FileHeader#getFilesize() length of the header}.
*/
default long ciphertextSize(long cleartextSize) {
checkArgument(cleartextSize >= 0, "expected cleartextSize to be positive, but was %s", cleartextSize);
long cleartextChunkSize = fileContentCryptor().cleartextChunkSize();
long ciphertextChunkSize = fileContentCryptor().ciphertextChunkSize();
long overheadPerChunk = ciphertextChunkSize - cleartextChunkSize;
long numFullChunks = cleartextSize / cleartextChunkSize; // floor by int-truncation
long additionalCleartextBytes = cleartextSize % cleartextChunkSize;
long additionalCiphertextBytes = (additionalCleartextBytes == 0) ? 0 : additionalCleartextBytes + overheadPerChunk;
assert additionalCiphertextBytes >= 0;
return ciphertextChunkSize * numFullChunks + additionalCiphertextBytes;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import java.nio.ByteBuffer;

import static com.google.common.base.Preconditions.checkArgument;

public interface FileContentCryptor {

/**
Expand Down Expand Up @@ -73,4 +75,44 @@ public interface FileContentCryptor {
*/
void decryptChunk(ByteBuffer ciphertextChunk, ByteBuffer cleartextChunk, long chunkNumber, FileHeader header, boolean authenticate) throws AuthenticationFailedException;

/**
* Calculates the size of the cleartext resulting from the given ciphertext decrypted with the given cryptor.
*
* @param ciphertextSize Length of encrypted payload. Not including the {@link FileHeaderCryptor#headerSize() length of the header}.
* @return Cleartext length of a <code>ciphertextSize</code>-sized ciphertext decrypted with <code>cryptor</code>.
*/
default long cleartextSize(long ciphertextSize) {
checkArgument(ciphertextSize >= 0, "expected ciphertextSize to be positive, but was %s", ciphertextSize);
long cleartextChunkSize = cleartextChunkSize();
long ciphertextChunkSize = ciphertextChunkSize();
long overheadPerChunk = ciphertextChunkSize - cleartextChunkSize;
long numFullChunks = ciphertextSize / ciphertextChunkSize; // floor by int-truncation
long additionalCiphertextBytes = ciphertextSize % ciphertextChunkSize;
if (additionalCiphertextBytes > 0 && additionalCiphertextBytes <= overheadPerChunk) {
throw new IllegalArgumentException("Method not defined for input value " + ciphertextSize);
}
long additionalCleartextBytes = (additionalCiphertextBytes == 0) ? 0 : additionalCiphertextBytes - overheadPerChunk;
assert additionalCleartextBytes >= 0;
return cleartextChunkSize * numFullChunks + additionalCleartextBytes;
}

/**
* Calculates the size of the ciphertext resulting from the given cleartext encrypted with the given cryptor.
*
* @param cleartextSize Length of a unencrypted payload.
* @return Ciphertext length of a <code>cleartextSize</code>-sized cleartext encrypted with <code>cryptor</code>.
* Not including the {@link FileHeader#getFilesize() length of the header}.
*/
default long ciphertextSize(long cleartextSize) {
checkArgument(cleartextSize >= 0, "expected cleartextSize to be positive, but was %s", cleartextSize);
long cleartextChunkSize = cleartextChunkSize();
long ciphertextChunkSize = ciphertextChunkSize();
long overheadPerChunk = ciphertextChunkSize - cleartextChunkSize;
long numFullChunks = cleartextSize / cleartextChunkSize; // floor by int-truncation
long additionalCleartextBytes = cleartextSize % cleartextChunkSize;
long additionalCiphertextBytes = (additionalCleartextBytes == 0) ? 0 : additionalCleartextBytes + overheadPerChunk;
assert additionalCiphertextBytes >= 0;
return ciphertextChunkSize * numFullChunks + additionalCiphertextBytes;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
public interface FileHeader {

/**
* @deprecated No longer supported since vault version 5. Use {@link org.cryptomator.cryptolib.api.Cryptor#cleartextSize(long)} to calculate the cleartext size from the ciphertext size
* @deprecated No longer supported since vault version 5. Use {@link org.cryptomator.cryptolib.api.FileContentCryptor#cleartextSize(long)} to calculate the cleartext size from the ciphertext size
* @return file size stored in file header
*/
@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;

public class CryptorTest {
public class FileContentCryptorTest {

private final Cryptor cryptor = Mockito.mock(Cryptor.class);
private final FileContentCryptor contentCryptor = Mockito.mock(FileContentCryptor.class);

@BeforeEach
public void setup() {
FileContentCryptor contentCryptor = Mockito.mock(FileContentCryptor.class);
Mockito.when(cryptor.fileContentCryptor()).thenReturn(contentCryptor);
Mockito.when(contentCryptor.cleartextChunkSize()).thenReturn(32);
Mockito.when(contentCryptor.ciphertextChunkSize()).thenReturn(40);
Mockito.doCallRealMethod().when(cryptor).cleartextSize(Mockito.anyLong());
Mockito.doCallRealMethod().when(cryptor).ciphertextSize(Mockito.anyLong());
Mockito.doCallRealMethod().when(contentCryptor).cleartextSize(Mockito.anyLong());
Mockito.doCallRealMethod().when(contentCryptor).ciphertextSize(Mockito.anyLong());
}

@ParameterizedTest(name = "cleartextSize({1}) == {0}")
Expand All @@ -34,14 +32,14 @@ public void setup() {
"65,89"
})
public void testCleartextSize(int cleartextSize, int ciphertextSize) {
Assertions.assertEquals(cleartextSize, cryptor.cleartextSize(ciphertextSize));
Assertions.assertEquals(cleartextSize, contentCryptor.cleartextSize(ciphertextSize));
}

@ParameterizedTest(name = "cleartextSize({0}) == undefined")
@ValueSource(ints = {-1, 1, 8, 41, 48, 81, 88})
public void testCleartextSizeWithInvalidCiphertextSize(int invalidCiphertextSize) {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
cryptor.cleartextSize(invalidCiphertextSize);
contentCryptor.cleartextSize(invalidCiphertextSize);
});
}

Expand All @@ -58,14 +56,14 @@ public void testCleartextSizeWithInvalidCiphertextSize(int invalidCiphertextSize
"65,89"
})
public void testCiphertextSize(int cleartextSize, int ciphertextSize) {
Assertions.assertEquals(ciphertextSize, cryptor.ciphertextSize(cleartextSize));
Assertions.assertEquals(ciphertextSize, contentCryptor.ciphertextSize(cleartextSize));
}

@ParameterizedTest(name = "ciphertextSize({0}) == undefined")
@ValueSource(ints = {-1})
public void testCiphertextSizewithInvalidCleartextSize(int invalidCleartextSize) {
Assertions.assertThrows(IllegalArgumentException.class, () -> {
cryptor.ciphertextSize(invalidCleartextSize);
contentCryptor.ciphertextSize(invalidCleartextSize);
});
}

Expand Down

0 comments on commit cefd70b

Please sign in to comment.