From b891ca043bb453d872d8eef7bd799bdb5ebe5ca1 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Sat, 19 Oct 2024 18:38:23 +0530 Subject: [PATCH 1/3] refactor: Enhance docs, add more tests in `RSA` --- .../java/com/thealgorithms/ciphers/RSA.java | 79 ++++++++++++++++--- .../com/thealgorithms/ciphers/RSATest.java | 59 +++++++++++--- 2 files changed, 116 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/thealgorithms/ciphers/RSA.java b/src/main/java/com/thealgorithms/ciphers/RSA.java index f50e501e68c8..28af1a62032a 100644 --- a/src/main/java/com/thealgorithms/ciphers/RSA.java +++ b/src/main/java/com/thealgorithms/ciphers/RSA.java @@ -4,7 +4,27 @@ import java.security.SecureRandom; /** - * @author Nguyen Duy Tiep on 23-Oct-17. + * RSA is an asymmetric cryptographic algorithm used for secure data encryption and decryption. + * It relies on a pair of keys: a public key (used for encryption) and a private key + * (used for decryption). The algorithm is based on the difficulty of factoring large prime numbers. + * + * This implementation includes key generation, encryption, and decryption methods that can handle both + * text-based messages and BigInteger inputs. For more details on RSA: + * RSA Cryptosystem - Wikipedia. + * + * Example Usage: + *
+ * RSA rsa = new RSA(1024);
+ * String encryptedMessage = rsa.encrypt("Hello RSA!");
+ * String decryptedMessage = rsa.decrypt(encryptedMessage);
+ * System.out.println(decryptedMessage);  // Output: Hello RSA!
+ * 
+ * + * Note: The key size directly affects the security and performance of the RSA algorithm. + * Larger keys are more secure but slower to compute. + * + * @author Nguyen Duy Tiep + * @version 23-Oct-17 */ public class RSA { @@ -12,55 +32,88 @@ public class RSA { private BigInteger privateKey; private BigInteger publicKey; + /** + * Constructor that generates RSA keys with the specified number of bits. + * + * @param bits The bit length of the keys to be generated. Common sizes include 512, 1024, 2048, etc. + */ public RSA(int bits) { generateKeys(bits); } /** - * @return encrypted message + * Encrypts a text message using the RSA public key. + * + * @param message The plaintext message to be encrypted. + * @throws IllegalArgumentException If the message is empty. + * @return The encrypted message represented as a String. */ public synchronized String encrypt(String message) { + if (message.isEmpty()) { + throw new IllegalArgumentException("Message is empty"); + } return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString(); } /** - * @return encrypted message as big integer + * Encrypts a BigInteger message using the RSA public key. + * + * @param message The plaintext message as a BigInteger. + * @return The encrypted message as a BigInteger. */ public synchronized BigInteger encrypt(BigInteger message) { return message.modPow(publicKey, modulus); } /** - * @return plain message + * Decrypts an encrypted message (as String) using the RSA private key. + * + * @param encryptedMessage The encrypted message to be decrypted, represented as a String. + * @throws IllegalArgumentException If the message is empty. + * @return The decrypted plaintext message as a String. */ public synchronized String decrypt(String encryptedMessage) { + if (encryptedMessage.isEmpty()) { + throw new IllegalArgumentException("Message is empty"); + } return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray()); } /** - * @return plain message as big integer + * Decrypts an encrypted BigInteger message using the RSA private key. + * + * @param encryptedMessage The encrypted message as a BigInteger. + * @return The decrypted plaintext message as a BigInteger. */ public synchronized BigInteger decrypt(BigInteger encryptedMessage) { return encryptedMessage.modPow(privateKey, modulus); } /** - * Generate a new public and private key set. + * Generates a new RSA key pair (public and private keys) with the specified bit length. + * Steps: + * 1. Generate two large prime numbers p and q. + * 2. Compute the modulus n = p * q. + * 3. Compute Euler's totient function: φ(n) = (p-1) * (q-1). + * 4. Choose a public key e (starting from 3) that is coprime with φ(n). + * 5. Compute the private key d as the modular inverse of e mod φ(n). + * The public key is (e, n) and the private key is (d, n). + * + * @param bits The bit length of the keys to be generated. */ public final synchronized void generateKeys(int bits) { - SecureRandom r = new SecureRandom(); - BigInteger p = new BigInteger(bits / 2, 100, r); - BigInteger q = new BigInteger(bits / 2, 100, r); + SecureRandom random = new SecureRandom(); + BigInteger p = new BigInteger(bits / 2, 100, random); + BigInteger q = new BigInteger(bits / 2, 100, random); modulus = p.multiply(q); - BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); + BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); publicKey = BigInteger.valueOf(3L); - - while (m.gcd(publicKey).intValue() > 1) { + while (phi.gcd(publicKey).intValue() > 1) { publicKey = publicKey.add(BigInteger.TWO); } - privateKey = publicKey.modInverse(m); + privateKey = publicKey.modInverse(phi); } } diff --git a/src/test/java/com/thealgorithms/ciphers/RSATest.java b/src/test/java/com/thealgorithms/ciphers/RSATest.java index c82f68d11f4c..577f56426be8 100644 --- a/src/test/java/com/thealgorithms/ciphers/RSATest.java +++ b/src/test/java/com/thealgorithms/ciphers/RSATest.java @@ -1,23 +1,64 @@ package com.thealgorithms.ciphers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.math.BigInteger; import org.junit.jupiter.api.Test; class RSATest { - RSA rsa = new RSA(1024); + private final RSA rsa = new RSA(1024); @Test - void testRSA() { - // given - String textToEncrypt = "Such secure"; + void testEncryptDecryptString() { + String originalMessage = "Such secure"; + String encryptedMessage = rsa.encrypt(originalMessage); + String decryptedMessage = rsa.decrypt(encryptedMessage); + assertEquals(originalMessage, decryptedMessage); + } + + @Test + void testEncryptDecryptBigInteger() { + BigInteger originalMessage = new BigInteger("12345678901234567890"); + BigInteger encryptedMessage = rsa.encrypt(originalMessage); + BigInteger decryptedMessage = rsa.decrypt(encryptedMessage); + assertEquals(originalMessage, decryptedMessage); + } - // when - String cipherText = rsa.encrypt(textToEncrypt); - String decryptedText = rsa.decrypt(cipherText); + @Test + void testEmptyMessage() { + String originalMessage = ""; + assertThrows(IllegalArgumentException.class, () -> rsa.encrypt(originalMessage)); + assertThrows(IllegalArgumentException.class, () -> rsa.decrypt(originalMessage)); + } + + @Test + void testDifferentKeySizes() { + // Testing with 512-bit RSA keys + RSA smallRSA = new RSA(512); + String originalMessage = "Test with smaller key"; - // then - assertEquals("Such secure", decryptedText); + String encryptedMessage = smallRSA.encrypt(originalMessage); + String decryptedMessage = smallRSA.decrypt(encryptedMessage); + + assertEquals(originalMessage, decryptedMessage); + + // Testing with 2048-bit RSA keys + RSA largeRSA = new RSA(2048); + String largeOriginalMessage = "Test with larger key"; + + String largeEncryptedMessage = largeRSA.encrypt(largeOriginalMessage); + String largeDecryptedMessage = largeRSA.decrypt(largeEncryptedMessage); + + assertEquals(largeOriginalMessage, largeDecryptedMessage); + } + + @Test + void testSpecialCharacters() { + String originalMessage = "Hello, RSA! @2024#"; + String encryptedMessage = rsa.encrypt(originalMessage); + String decryptedMessage = rsa.decrypt(encryptedMessage); + assertEquals(originalMessage, decryptedMessage); } } From 8aee39c62bcf267c2e6bdbec5876bb37c7273e93 Mon Sep 17 00:00:00 2001 From: Hardvan Date: Sat, 26 Oct 2024 09:56:34 +0000 Subject: [PATCH 2/3] 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 09deb81f69129e2ffa9b4720b2fd28cf5dc923ab Mon Sep 17 00:00:00 2001 From: siriak Date: Sat, 26 Oct 2024 11:56:15 +0000 Subject: [PATCH 3/3] 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)