From 99a035399915a5588bf7c7688c554b9d5c80a44e Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Sat, 19 Oct 2024 18:52:04 +0530 Subject: [PATCH 1/4] refactor: Enhance docs, add more tests in `XORCipher` --- .../com/thealgorithms/ciphers/XORCipher.java | 58 +++++++++++++- .../thealgorithms/ciphers/XORCipherTest.java | 77 +++++++++++++++---- 2 files changed, 120 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/thealgorithms/ciphers/XORCipher.java b/src/main/java/com/thealgorithms/ciphers/XORCipher.java index c4410d8c77ba..a612ccfbcdef 100644 --- a/src/main/java/com/thealgorithms/ciphers/XORCipher.java +++ b/src/main/java/com/thealgorithms/ciphers/XORCipher.java @@ -5,18 +5,46 @@ import java.util.HexFormat; /** - * A simple implementation of XOR cipher that, given a key, allows to encrypt and decrypt a plaintext. + * A simple implementation of the XOR cipher that allows both encryption and decryption + * using a given key. This cipher works by applying the XOR bitwise operation between + * the bytes of the input text and the corresponding bytes of the key (repeating the key + * if necessary). * - * @author lcsjunior + * Usage: + * - Encryption: Converts plaintext into a hexadecimal-encoded ciphertext. + * - Decryption: Converts the hexadecimal ciphertext back into plaintext. + * + * Characteristics: + * - Symmetric: The same key is used for both encryption and decryption. + * - Simple but vulnerable: XOR encryption is insecure for real-world cryptography, + * especially when the same key is reused. + * + * Example: + * Plaintext: "Hello!" + * Key: "key" + * Encrypted: "27090c03120b" + * Decrypted: "Hello!" * + * Reference: XOR Cipher - Wikipedia + * + * @author lcsjunior */ public final class XORCipher { + // Default character encoding for string conversion private static final Charset CS_DEFAULT = StandardCharsets.UTF_8; private XORCipher() { } + /** + * Applies the XOR operation between the input bytes and the key bytes. + * If the key is shorter than the input, it wraps around (cyclically). + * + * @param inputBytes The input byte array (plaintext or ciphertext). + * @param keyBytes The key byte array used for XOR operation. + * @return A new byte array containing the XOR result. + */ public static byte[] xor(final byte[] inputBytes, final byte[] keyBytes) { byte[] outputBytes = new byte[inputBytes.length]; for (int i = 0; i < inputBytes.length; ++i) { @@ -25,14 +53,40 @@ public static byte[] xor(final byte[] inputBytes, final byte[] keyBytes) { return outputBytes; } + /** + * Encrypts the given plaintext using the XOR cipher with the specified key. + * The result is a hexadecimal-encoded string representing the ciphertext. + * + * @param plainText The input plaintext to encrypt. + * @param key The encryption key. + * @throws IllegalArgumentException if the key is empty. + * @return A hexadecimal string representing the encrypted text. + */ public static String encrypt(final String plainText, final String key) { + if (key.isEmpty()) { + throw new IllegalArgumentException("Key must not be empty"); + } + byte[] plainTextBytes = plainText.getBytes(CS_DEFAULT); byte[] keyBytes = key.getBytes(CS_DEFAULT); byte[] xorResult = xor(plainTextBytes, keyBytes); return HexFormat.of().formatHex(xorResult); } + /** + * Decrypts the given ciphertext (in hexadecimal format) using the XOR cipher + * with the specified key. The result is the original plaintext. + * + * @param cipherText The hexadecimal string representing the encrypted text. + * @param key The decryption key (must be the same as the encryption key). + * @throws IllegalArgumentException if the key is empty. + * @return The decrypted plaintext. + */ public static String decrypt(final String cipherText, final String key) { + if (key.isEmpty()) { + throw new IllegalArgumentException("Key must not be empty"); + } + byte[] cipherBytes = HexFormat.of().parseHex(cipherText); byte[] keyBytes = key.getBytes(CS_DEFAULT); byte[] xorResult = xor(cipherBytes, keyBytes); diff --git a/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java b/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java index 15e27d5d6778..fdfe640cc19b 100644 --- a/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java +++ b/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java @@ -1,34 +1,85 @@ package com.thealgorithms.ciphers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; class XORCipherTest { @Test - void xorEncryptTest() { - // given + void xorEncryptDecryptTest() { String plaintext = "My t&xt th@t will be ençrypted..."; String key = "My ç&cret key!"; - // when String cipherText = XORCipher.encrypt(plaintext, key); + String decryptedText = XORCipher.decrypt(cipherText, key); - // then - assertEquals("000000b7815e1752111c601f450e48211500a1c206061ca6d35212150d4429570eed", cipherText); + assertEquals("My t&xt th@t will be ençrypted...", decryptedText); } @Test - void xorDecryptTest() { - // given - String cipherText = "000000b7815e1752111c601f450e48211500a1c206061ca6d35212150d4429570eed"; - String key = "My ç&cret key!"; + void testEmptyPlaintext() { + String plaintext = ""; + String key = "anykey"; + + String cipherText = XORCipher.encrypt(plaintext, key); + String decryptedText = XORCipher.decrypt(cipherText, key); + + assertEquals("", cipherText); + assertEquals("", decryptedText); + } + + @Test + void testEmptyKey() { + String plaintext = "Hello World!"; + String key = ""; + + assertThrows(IllegalArgumentException.class, () -> XORCipher.encrypt(plaintext, key)); + assertThrows(IllegalArgumentException.class, () -> XORCipher.decrypt(plaintext, key)); + } + + @Test + void testShortKey() { + String plaintext = "Short message"; + String key = "k"; + + String cipherText = XORCipher.encrypt(plaintext, key); + String decryptedText = XORCipher.decrypt(cipherText, key); + + assertEquals(plaintext, decryptedText); + } - // when - String plainText = XORCipher.decrypt(cipherText, key); + @Test + void testNonASCIICharacters() { + String plaintext = "こんにちは世界"; // "Hello World" in Japanese (Konichiwa Sekai) + String key = "key"; + + String cipherText = XORCipher.encrypt(plaintext, key); + String decryptedText = XORCipher.decrypt(cipherText, key); + + assertEquals(plaintext, decryptedText); + } + + @Test + void testSameKeyAndPlaintext() { + String plaintext = "samekey"; + String key = "samekey"; + + String cipherText = XORCipher.encrypt(plaintext, key); + String decryptedText = XORCipher.decrypt(cipherText, key); + + assertEquals(plaintext, decryptedText); + } + + @Test + void testLongPlaintextShortKey() { + String plaintext = "This is a long plaintext message."; + String key = "key"; + + String cipherText = XORCipher.encrypt(plaintext, key); + String decryptedText = XORCipher.decrypt(cipherText, key); - // then - assertEquals("My t&xt th@t will be ençrypted...", plainText); + assertEquals(plaintext, decryptedText); } } From 2314d01af376d9c517cf6f9a3174811f44cba8f2 Mon Sep 17 00:00:00 2001 From: Hardvan Date: Sat, 26 Oct 2024 09:59:26 +0000 Subject: [PATCH 2/4] Update directory --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 10922d761952..0074f212551b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -320,6 +320,7 @@ * [BresenhamLine](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/BresenhamLine.java) * [ConvexHull](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/ConvexHull.java) * [GrahamScan](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/GrahamScan.java) + * [MidpointEllipse](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/MidpointEllipse.java) * [Point](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/Point.java) * graph * [StronglyConnectedComponentOptimized](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java) @@ -967,6 +968,7 @@ * [BresenhamLineTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java) * [ConvexHullTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/ConvexHullTest.java) * [GrahamScanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/GrahamScanTest.java) + * [MidpointEllipseTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java) * graph * [StronglyConnectedComponentOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java) * greedyalgorithms From 782140cc6020e45907e0041ac1c8f87949e8b8b3 Mon Sep 17 00:00:00 2001 From: siriak Date: Sat, 26 Oct 2024 11:55:47 +0000 Subject: [PATCH 3/4] Update directory --- DIRECTORY.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 0074f212551b..2aaa29460f8b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -320,6 +320,7 @@ * [BresenhamLine](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/BresenhamLine.java) * [ConvexHull](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/ConvexHull.java) * [GrahamScan](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/GrahamScan.java) + * [MidpointCircle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/MidpointCircle.java) * [MidpointEllipse](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/MidpointEllipse.java) * [Point](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/Point.java) * graph @@ -361,6 +362,7 @@ * [Average](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Average.java) * [BinaryPow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/BinaryPow.java) * [BinomialCoefficient](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java) + * [CatalanNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CatalanNumbers.java) * [Ceil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Ceil.java) * [ChineseRemainderTheorem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java) * [CircularConvolutionFFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java) @@ -968,6 +970,7 @@ * [BresenhamLineTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java) * [ConvexHullTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/ConvexHullTest.java) * [GrahamScanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/GrahamScanTest.java) + * [MidpointCircleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java) * [MidpointEllipseTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java) * graph * [StronglyConnectedComponentOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java) @@ -1005,6 +1008,7 @@ * [AverageTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AverageTest.java) * [BinaryPowTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/BinaryPowTest.java) * [BinomialCoefficientTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/BinomialCoefficientTest.java) + * [CatalanNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CatalanNumbersTest.java) * [CeilTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CeilTest.java) * [ChineseRemainderTheoremTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java) * [CollatzConjectureTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CollatzConjectureTest.java) From ebce5b4fd36a65a5460af393d9c043ae4a046972 Mon Sep 17 00:00:00 2001 From: siriak Date: Sat, 26 Oct 2024 14:55:23 +0000 Subject: [PATCH 4/4] Update directory --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 9ebbd484376b..2b47ae08ba4a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -597,6 +597,7 @@ * slidingwindow * [LongestSubstringWithoutRepeatingCharacters](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java) * [MaxSumKSizeSubarray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarray.java) + * [MinSumKSizeSubarray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarray.java) * sorts * [AdaptiveMergeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java) * [BeadSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BeadSort.java) @@ -1217,6 +1218,7 @@ * slidingwindow * [LongestSubstringWithoutRepeatingCharactersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharactersTest.java) * [MaxSumKSizeSubarrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarrayTest.java) + * [MinSumKSizeSubarrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarrayTest.java) * sorts * [AdaptiveMergeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java) * [BeadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BeadSortTest.java)