|
4 | 4 | import java.security.SecureRandom;
|
5 | 5 |
|
6 | 6 | /**
|
7 |
| - * @author Nguyen Duy Tiep on 23-Oct-17. |
| 7 | + * RSA is an asymmetric cryptographic algorithm used for secure data encryption and decryption. |
| 8 | + * It relies on a pair of keys: a public key (used for encryption) and a private key |
| 9 | + * (used for decryption). The algorithm is based on the difficulty of factoring large prime numbers. |
| 10 | + * |
| 11 | + * This implementation includes key generation, encryption, and decryption methods that can handle both |
| 12 | + * text-based messages and BigInteger inputs. For more details on RSA: |
| 13 | + * <a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">RSA Cryptosystem - Wikipedia</a>. |
| 14 | + * |
| 15 | + * Example Usage: |
| 16 | + * <pre> |
| 17 | + * RSA rsa = new RSA(1024); |
| 18 | + * String encryptedMessage = rsa.encrypt("Hello RSA!"); |
| 19 | + * String decryptedMessage = rsa.decrypt(encryptedMessage); |
| 20 | + * System.out.println(decryptedMessage); // Output: Hello RSA! |
| 21 | + * </pre> |
| 22 | + * |
| 23 | + * Note: The key size directly affects the security and performance of the RSA algorithm. |
| 24 | + * Larger keys are more secure but slower to compute. |
| 25 | + * |
| 26 | + * @author Nguyen Duy Tiep |
| 27 | + * @version 23-Oct-17 |
8 | 28 | */
|
9 | 29 | public class RSA {
|
10 | 30 |
|
11 | 31 | private BigInteger modulus;
|
12 | 32 | private BigInteger privateKey;
|
13 | 33 | private BigInteger publicKey;
|
14 | 34 |
|
| 35 | + /** |
| 36 | + * Constructor that generates RSA keys with the specified number of bits. |
| 37 | + * |
| 38 | + * @param bits The bit length of the keys to be generated. Common sizes include 512, 1024, 2048, etc. |
| 39 | + */ |
15 | 40 | public RSA(int bits) {
|
16 | 41 | generateKeys(bits);
|
17 | 42 | }
|
18 | 43 |
|
19 | 44 | /**
|
20 |
| - * @return encrypted message |
| 45 | + * Encrypts a text message using the RSA public key. |
| 46 | + * |
| 47 | + * @param message The plaintext message to be encrypted. |
| 48 | + * @throws IllegalArgumentException If the message is empty. |
| 49 | + * @return The encrypted message represented as a String. |
21 | 50 | */
|
22 | 51 | public synchronized String encrypt(String message) {
|
| 52 | + if (message.isEmpty()) { |
| 53 | + throw new IllegalArgumentException("Message is empty"); |
| 54 | + } |
23 | 55 | return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString();
|
24 | 56 | }
|
25 | 57 |
|
26 | 58 | /**
|
27 |
| - * @return encrypted message as big integer |
| 59 | + * Encrypts a BigInteger message using the RSA public key. |
| 60 | + * |
| 61 | + * @param message The plaintext message as a BigInteger. |
| 62 | + * @return The encrypted message as a BigInteger. |
28 | 63 | */
|
29 | 64 | public synchronized BigInteger encrypt(BigInteger message) {
|
30 | 65 | return message.modPow(publicKey, modulus);
|
31 | 66 | }
|
32 | 67 |
|
33 | 68 | /**
|
34 |
| - * @return plain message |
| 69 | + * Decrypts an encrypted message (as String) using the RSA private key. |
| 70 | + * |
| 71 | + * @param encryptedMessage The encrypted message to be decrypted, represented as a String. |
| 72 | + * @throws IllegalArgumentException If the message is empty. |
| 73 | + * @return The decrypted plaintext message as a String. |
35 | 74 | */
|
36 | 75 | public synchronized String decrypt(String encryptedMessage) {
|
| 76 | + if (encryptedMessage.isEmpty()) { |
| 77 | + throw new IllegalArgumentException("Message is empty"); |
| 78 | + } |
37 | 79 | return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray());
|
38 | 80 | }
|
39 | 81 |
|
40 | 82 | /**
|
41 |
| - * @return plain message as big integer |
| 83 | + * Decrypts an encrypted BigInteger message using the RSA private key. |
| 84 | + * |
| 85 | + * @param encryptedMessage The encrypted message as a BigInteger. |
| 86 | + * @return The decrypted plaintext message as a BigInteger. |
42 | 87 | */
|
43 | 88 | public synchronized BigInteger decrypt(BigInteger encryptedMessage) {
|
44 | 89 | return encryptedMessage.modPow(privateKey, modulus);
|
45 | 90 | }
|
46 | 91 |
|
47 | 92 | /**
|
48 |
| - * Generate a new public and private key set. |
| 93 | + * Generates a new RSA key pair (public and private keys) with the specified bit length. |
| 94 | + * Steps: |
| 95 | + * 1. Generate two large prime numbers p and q. |
| 96 | + * 2. Compute the modulus n = p * q. |
| 97 | + * 3. Compute Euler's totient function: φ(n) = (p-1) * (q-1). |
| 98 | + * 4. Choose a public key e (starting from 3) that is coprime with φ(n). |
| 99 | + * 5. Compute the private key d as the modular inverse of e mod φ(n). |
| 100 | + * The public key is (e, n) and the private key is (d, n). |
| 101 | + * |
| 102 | + * @param bits The bit length of the keys to be generated. |
49 | 103 | */
|
50 | 104 | public final synchronized void generateKeys(int bits) {
|
51 |
| - SecureRandom r = new SecureRandom(); |
52 |
| - BigInteger p = new BigInteger(bits / 2, 100, r); |
53 |
| - BigInteger q = new BigInteger(bits / 2, 100, r); |
| 105 | + SecureRandom random = new SecureRandom(); |
| 106 | + BigInteger p = new BigInteger(bits / 2, 100, random); |
| 107 | + BigInteger q = new BigInteger(bits / 2, 100, random); |
54 | 108 | modulus = p.multiply(q);
|
55 | 109 |
|
56 |
| - BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); |
| 110 | + BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); |
57 | 111 |
|
58 | 112 | publicKey = BigInteger.valueOf(3L);
|
59 |
| - |
60 |
| - while (m.gcd(publicKey).intValue() > 1) { |
| 113 | + while (phi.gcd(publicKey).intValue() > 1) { |
61 | 114 | publicKey = publicKey.add(BigInteger.TWO);
|
62 | 115 | }
|
63 | 116 |
|
64 |
| - privateKey = publicKey.modInverse(m); |
| 117 | + privateKey = publicKey.modInverse(phi); |
65 | 118 | }
|
66 | 119 | }
|
0 commit comments