From d32856f2b21f7ea88aed62d8245093fd18294f37 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 14 Jun 2021 12:22:23 +0200 Subject: [PATCH] remove legacy FileNameCryptor.encrypt/decryptFilename methods without explicit encoding --- .../cryptolib/api/FileNameCryptor.java | 15 --------- .../cryptomator/cryptolib/package-info.java | 4 +-- .../cryptolib/v1/FileNameCryptorImpl.java | 10 ------ .../cryptolib/v2/FileNameCryptorImpl.java | 10 ------ .../cryptolib/v1/FileNameCryptorImplTest.java | 33 ++++++++++--------- .../cryptolib/v2/FileNameCryptorImplTest.java | 32 +++++++++--------- 6 files changed, 36 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptolib/api/FileNameCryptor.java b/src/main/java/org/cryptomator/cryptolib/api/FileNameCryptor.java index 50b6181..e20cd87 100644 --- a/src/main/java/org/cryptomator/cryptolib/api/FileNameCryptor.java +++ b/src/main/java/org/cryptomator/cryptolib/api/FileNameCryptor.java @@ -24,13 +24,6 @@ public interface FileNameCryptor { */ String hashDirectoryId(String cleartextDirectoryId); - /** - * @param cleartextName original filename including cleartext file extension - * @param associatedData optional associated data, that will not get encrypted but needs to be provided during decryption - * @return encrypted filename without any file extension, encoded in BASE32 - */ - String encryptFilename(String cleartextName, byte[]... associatedData); - /** * @param encoding Encoding to use to encode the returned ciphertext * @param cleartextName original filename including cleartext file extension @@ -39,14 +32,6 @@ public interface FileNameCryptor { */ String encryptFilename(BaseEncoding encoding, String cleartextName, byte[]... associatedData); - /** - * @param ciphertextName Ciphertext only, with any additional strings like file extensions stripped first, encoded in BASE32 - * @param associatedData the same associated data used during encryption, otherwise and {@link AuthenticationFailedException} will be thrown - * @return cleartext filename, probably including its cleartext file extension. - * @throws AuthenticationFailedException if the ciphertext is malformed - */ - String decryptFilename(String ciphertextName, byte[]... associatedData) throws AuthenticationFailedException; - /** * @param encoding Encoding to use to decode ciphertextName * @param ciphertextName Ciphertext only, with any additional strings like file extensions stripped first. diff --git a/src/main/java/org/cryptomator/cryptolib/package-info.java b/src/main/java/org/cryptomator/cryptolib/package-info.java index 16c444b..c7b856a 100644 --- a/src/main/java/org/cryptomator/cryptolib/package-info.java +++ b/src/main/java/org/cryptomator/cryptolib/package-info.java @@ -23,8 +23,8 @@ * * // Encrypt and decrypt file name: * String cleartextFileName = "foo.txt"; - * String encryptedName = cryptor.{@link org.cryptomator.cryptolib.api.Cryptor#fileNameCryptor() fileNameCryptor()}.{@link org.cryptomator.cryptolib.api.FileNameCryptor#encryptFilename(String, byte[][]) encryptFilename(cleartextFileName, uniqueIdOfDirectory.getBytes())}; - * String decryptedName = cryptor.fileNameCryptor().{@link org.cryptomator.cryptolib.api.FileNameCryptor#decryptFilename(String, byte[][]) decryptFilename(encryptedName, uniqueIdOfDirectory.getBytes())}; + * String encryptedName = cryptor.{@link org.cryptomator.cryptolib.api.Cryptor#fileNameCryptor() fileNameCryptor()}.{@link org.cryptomator.cryptolib.api.FileNameCryptor#encryptFilename(com.google.common.io.BaseEncoding, String, byte[][]) encryptFilename(base32, cleartextFileName, uniqueIdOfDirectory.getBytes())}; + * String decryptedName = cryptor.fileNameCryptor().{@link org.cryptomator.cryptolib.api.FileNameCryptor#decryptFilename(com.google.common.io.BaseEncoding, String, byte[][]) decryptFilename(base32, encryptedName, uniqueIdOfDirectory.getBytes())}; * * // Encrypt file contents: * ByteBuffer plaintext = ...; diff --git a/src/main/java/org/cryptomator/cryptolib/v1/FileNameCryptorImpl.java b/src/main/java/org/cryptomator/cryptolib/v1/FileNameCryptorImpl.java index 089ec6e..374efe6 100644 --- a/src/main/java/org/cryptomator/cryptolib/v1/FileNameCryptorImpl.java +++ b/src/main/java/org/cryptomator/cryptolib/v1/FileNameCryptorImpl.java @@ -47,11 +47,6 @@ public String hashDirectoryId(String cleartextDirectoryId) { } } - @Override - public String encryptFilename(String cleartextName, byte[]... associatedData) { - return encryptFilename(BASE32, cleartextName, associatedData); - } - @Override public String encryptFilename(BaseEncoding encoding, String cleartextName, byte[]... associatedData) { try (DestroyableSecretKey ek = masterkey.getEncKey(); DestroyableSecretKey mk = masterkey.getMacKey()) { @@ -61,11 +56,6 @@ public String encryptFilename(BaseEncoding encoding, String cleartextName, byte[ } } - @Override - public String decryptFilename(String ciphertextName, byte[]... associatedData) throws AuthenticationFailedException { - return decryptFilename(BASE32, ciphertextName, associatedData); - } - @Override public String decryptFilename(BaseEncoding encoding, String ciphertextName, byte[]... associatedData) throws AuthenticationFailedException { try (DestroyableSecretKey ek = masterkey.getEncKey(); DestroyableSecretKey mk = masterkey.getMacKey()) { diff --git a/src/main/java/org/cryptomator/cryptolib/v2/FileNameCryptorImpl.java b/src/main/java/org/cryptomator/cryptolib/v2/FileNameCryptorImpl.java index 8c326e3..fd7133a 100644 --- a/src/main/java/org/cryptomator/cryptolib/v2/FileNameCryptorImpl.java +++ b/src/main/java/org/cryptomator/cryptolib/v2/FileNameCryptorImpl.java @@ -47,11 +47,6 @@ public String hashDirectoryId(String cleartextDirectoryId) { } } - @Override - public String encryptFilename(String cleartextName, byte[]... associatedData) { - return encryptFilename(BASE32, cleartextName, associatedData); - } - @Override public String encryptFilename(BaseEncoding encoding, String cleartextName, byte[]... associatedData) { try (DestroyableSecretKey ek = masterkey.getEncKey(); DestroyableSecretKey mk = masterkey.getMacKey()) { @@ -61,11 +56,6 @@ public String encryptFilename(BaseEncoding encoding, String cleartextName, byte[ } } - @Override - public String decryptFilename(String ciphertextName, byte[]... associatedData) throws AuthenticationFailedException { - return decryptFilename(BASE32, ciphertextName, associatedData); - } - @Override public String decryptFilename(BaseEncoding encoding, String ciphertextName, byte[]... associatedData) throws AuthenticationFailedException { try (DestroyableSecretKey ek = masterkey.getEncKey(); DestroyableSecretKey mk = masterkey.getMacKey()) { diff --git a/src/test/java/org/cryptomator/cryptolib/v1/FileNameCryptorImplTest.java b/src/test/java/org/cryptomator/cryptolib/v1/FileNameCryptorImplTest.java index 20fb932..ec77ab0 100644 --- a/src/test/java/org/cryptomator/cryptolib/v1/FileNameCryptorImplTest.java +++ b/src/test/java/org/cryptomator/cryptolib/v1/FileNameCryptorImplTest.java @@ -11,7 +11,6 @@ import com.google.common.io.BaseEncoding; import org.cryptomator.cryptolib.api.AuthenticationFailedException; import org.cryptomator.cryptolib.api.Masterkey; -import org.cryptomator.cryptolib.common.DestroyableSecretKey; import org.cryptomator.siv.UnauthenticCiphertextException; import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; @@ -28,6 +27,8 @@ public class FileNameCryptorImplTest { + private static final BaseEncoding BASE32 = BaseEncoding.base32(); + private final Masterkey masterkey = new Masterkey(new byte[64]); private final FileNameCryptorImpl filenameCryptor = new FileNameCryptorImpl(masterkey); @@ -39,9 +40,9 @@ private static Stream filenameGenerator() { @ParameterizedTest(name = "decrypt(encrypt({0}))") @MethodSource("filenameGenerator") public void testDeterministicEncryptionOfFilenames(String origName) throws AuthenticationFailedException { - String encrypted1 = filenameCryptor.encryptFilename(origName); - String encrypted2 = filenameCryptor.encryptFilename(origName); - String decrypted = filenameCryptor.decryptFilename(encrypted1); + String encrypted1 = filenameCryptor.encryptFilename(BASE32, origName); + String encrypted2 = filenameCryptor.encryptFilename(BASE32, origName); + String decrypted = filenameCryptor.decryptFilename(BASE32, encrypted1); Assertions.assertEquals(encrypted1, encrypted2); Assertions.assertEquals(origName, decrypted); @@ -65,9 +66,9 @@ public void testDeterministicEncryptionOfFilenamesWithCustomEncodingAndAssociate public void testDeterministicEncryptionOf128bitFilename() throws AuthenticationFailedException { // block size length file names String originalPath3 = "aaaabbbbccccdddd"; // 128 bit ascii - String encryptedPath3a = filenameCryptor.encryptFilename(originalPath3); - String encryptedPath3b = filenameCryptor.encryptFilename(originalPath3); - String decryptedPath3 = filenameCryptor.decryptFilename(encryptedPath3a); + String encryptedPath3a = filenameCryptor.encryptFilename(BASE32, originalPath3); + String encryptedPath3b = filenameCryptor.encryptFilename(BASE32, originalPath3); + String decryptedPath3 = filenameCryptor.decryptFilename(BASE32, encryptedPath3a); Assertions.assertEquals(encryptedPath3a, encryptedPath3b); Assertions.assertEquals(originalPath3, decryptedPath3); @@ -86,7 +87,7 @@ public void testDeterministicHashingOfDirectoryIds(String originalDirectoryId) { @DisplayName("decrypt non-ciphertext") public void testDecryptionOfMalformedFilename() { AuthenticationFailedException e = Assertions.assertThrows(AuthenticationFailedException.class, () -> { - filenameCryptor.decryptFilename("lol"); + filenameCryptor.decryptFilename(BASE32, "lol"); }); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(IllegalArgumentException.class)); } @@ -94,11 +95,11 @@ public void testDecryptionOfMalformedFilename() { @Test @DisplayName("decrypt tampered ciphertext") public void testDecryptionOfManipulatedFilename() { - final byte[] encrypted = filenameCryptor.encryptFilename("test").getBytes(UTF_8); + final byte[] encrypted = filenameCryptor.encryptFilename(BASE32, "test").getBytes(UTF_8); encrypted[0] ^= (byte) 0x01; // change 1 bit in first byte AuthenticationFailedException e = Assertions.assertThrows(AuthenticationFailedException.class, () -> { - filenameCryptor.decryptFilename(new String(encrypted, UTF_8)); + filenameCryptor.decryptFilename(BASE32, new String(encrypted, UTF_8)); }); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(UnauthenticCiphertextException.class)); } @@ -106,26 +107,26 @@ public void testDecryptionOfManipulatedFilename() { @Test @DisplayName("encrypt with different AD") public void testEncryptionOfSameFilenamesWithDifferentAssociatedData() { - final String encrypted1 = filenameCryptor.encryptFilename("test", "ad1".getBytes(UTF_8)); - final String encrypted2 = filenameCryptor.encryptFilename("test", "ad2".getBytes(UTF_8)); + final String encrypted1 = filenameCryptor.encryptFilename(BASE32, "test", "ad1".getBytes(UTF_8)); + final String encrypted2 = filenameCryptor.encryptFilename(BASE32, "test", "ad2".getBytes(UTF_8)); Assertions.assertNotEquals(encrypted1, encrypted2); } @Test @DisplayName("decrypt ciphertext with correct AD") public void testDeterministicEncryptionOfFilenamesWithAssociatedData() throws AuthenticationFailedException { - final String encrypted = filenameCryptor.encryptFilename("test", "ad".getBytes(UTF_8)); - final String decrypted = filenameCryptor.decryptFilename(encrypted, "ad".getBytes(UTF_8)); + final String encrypted = filenameCryptor.encryptFilename(BASE32, "test", "ad".getBytes(UTF_8)); + final String decrypted = filenameCryptor.decryptFilename(BASE32, encrypted, "ad".getBytes(UTF_8)); Assertions.assertEquals("test", decrypted); } @Test @DisplayName("decrypt ciphertext with incorrect AD") public void testDeterministicEncryptionOfFilenamesWithWrongAssociatedData() { - final String encrypted = filenameCryptor.encryptFilename("test", "right".getBytes(UTF_8)); + final String encrypted = filenameCryptor.encryptFilename(BASE32, "test", "right".getBytes(UTF_8)); Assertions.assertThrows(AuthenticationFailedException.class, () -> { - filenameCryptor.decryptFilename(encrypted, "wrong".getBytes(UTF_8)); + filenameCryptor.decryptFilename(BASE32, encrypted, "wrong".getBytes(UTF_8)); }); } diff --git a/src/test/java/org/cryptomator/cryptolib/v2/FileNameCryptorImplTest.java b/src/test/java/org/cryptomator/cryptolib/v2/FileNameCryptorImplTest.java index ebfa3d2..daa5da1 100644 --- a/src/test/java/org/cryptomator/cryptolib/v2/FileNameCryptorImplTest.java +++ b/src/test/java/org/cryptomator/cryptolib/v2/FileNameCryptorImplTest.java @@ -28,6 +28,8 @@ public class FileNameCryptorImplTest { + private static final BaseEncoding BASE32 = BaseEncoding.base32(); + private final Masterkey masterkey = new Masterkey(new byte[64]); private final FileNameCryptorImpl filenameCryptor = new FileNameCryptorImpl(masterkey); @@ -39,9 +41,9 @@ private static Stream filenameGenerator() { @ParameterizedTest(name = "decrypt(encrypt({0}))") @MethodSource("filenameGenerator") public void testDeterministicEncryptionOfFilenames(String origName) throws AuthenticationFailedException { - String encrypted1 = filenameCryptor.encryptFilename(origName); - String encrypted2 = filenameCryptor.encryptFilename(origName); - String decrypted = filenameCryptor.decryptFilename(encrypted1); + String encrypted1 = filenameCryptor.encryptFilename(BASE32, origName); + String encrypted2 = filenameCryptor.encryptFilename(BASE32, origName); + String decrypted = filenameCryptor.decryptFilename(BASE32, encrypted1); Assertions.assertEquals(encrypted1, encrypted2); Assertions.assertEquals(origName, decrypted); @@ -65,9 +67,9 @@ public void testDeterministicEncryptionOfFilenamesWithCustomEncodingAndAssociate public void testDeterministicEncryptionOf128bitFilename() throws AuthenticationFailedException { // block size length file names String originalPath3 = "aaaabbbbccccdddd"; // 128 bit ascii - String encryptedPath3a = filenameCryptor.encryptFilename(originalPath3); - String encryptedPath3b = filenameCryptor.encryptFilename(originalPath3); - String decryptedPath3 = filenameCryptor.decryptFilename(encryptedPath3a); + String encryptedPath3a = filenameCryptor.encryptFilename(BASE32, originalPath3); + String encryptedPath3b = filenameCryptor.encryptFilename(BASE32, originalPath3); + String decryptedPath3 = filenameCryptor.decryptFilename(BASE32, encryptedPath3a); Assertions.assertEquals(encryptedPath3a, encryptedPath3b); Assertions.assertEquals(originalPath3, decryptedPath3); @@ -86,7 +88,7 @@ public void testDeterministicHashingOfDirectoryIds(String originalDirectoryId) { @DisplayName("decrypt non-ciphertext") public void testDecryptionOfMalformedFilename() { AuthenticationFailedException e = Assertions.assertThrows(AuthenticationFailedException.class, () -> { - filenameCryptor.decryptFilename("lol"); + filenameCryptor.decryptFilename(BASE32, "lol"); }); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(IllegalArgumentException.class)); } @@ -94,11 +96,11 @@ public void testDecryptionOfMalformedFilename() { @Test @DisplayName("decrypt tampered ciphertext") public void testDecryptionOfManipulatedFilename() { - final byte[] encrypted = filenameCryptor.encryptFilename("test").getBytes(UTF_8); + final byte[] encrypted = filenameCryptor.encryptFilename(BASE32, "test").getBytes(UTF_8); encrypted[0] ^= (byte) 0x01; // change 1 bit in first byte AuthenticationFailedException e = Assertions.assertThrows(AuthenticationFailedException.class, () -> { - filenameCryptor.decryptFilename(new String(encrypted, UTF_8)); + filenameCryptor.decryptFilename(BASE32, new String(encrypted, UTF_8)); }); MatcherAssert.assertThat(e.getCause(), CoreMatchers.instanceOf(UnauthenticCiphertextException.class)); } @@ -106,26 +108,26 @@ public void testDecryptionOfManipulatedFilename() { @Test @DisplayName("encrypt with different AD") public void testEncryptionOfSameFilenamesWithDifferentAssociatedData() { - final String encrypted1 = filenameCryptor.encryptFilename("test", "ad1".getBytes(UTF_8)); - final String encrypted2 = filenameCryptor.encryptFilename("test", "ad2".getBytes(UTF_8)); + final String encrypted1 = filenameCryptor.encryptFilename(BASE32, "test", "ad1".getBytes(UTF_8)); + final String encrypted2 = filenameCryptor.encryptFilename(BASE32, "test", "ad2".getBytes(UTF_8)); Assertions.assertNotEquals(encrypted1, encrypted2); } @Test @DisplayName("decrypt ciphertext with correct AD") public void testDeterministicEncryptionOfFilenamesWithAssociatedData() throws AuthenticationFailedException { - final String encrypted = filenameCryptor.encryptFilename("test", "ad".getBytes(UTF_8)); - final String decrypted = filenameCryptor.decryptFilename(encrypted, "ad".getBytes(UTF_8)); + final String encrypted = filenameCryptor.encryptFilename(BASE32, "test", "ad".getBytes(UTF_8)); + final String decrypted = filenameCryptor.decryptFilename(BASE32, encrypted, "ad".getBytes(UTF_8)); Assertions.assertEquals("test", decrypted); } @Test @DisplayName("decrypt ciphertext with incorrect AD") public void testDeterministicEncryptionOfFilenamesWithWrongAssociatedData() { - final String encrypted = filenameCryptor.encryptFilename("test", "right".getBytes(UTF_8)); + final String encrypted = filenameCryptor.encryptFilename(BASE32, "test", "right".getBytes(UTF_8)); Assertions.assertThrows(AuthenticationFailedException.class, () -> { - filenameCryptor.decryptFilename(encrypted, "wrong".getBytes(UTF_8)); + filenameCryptor.decryptFilename(BASE32, encrypted, "wrong".getBytes(UTF_8)); }); }