Implement simple RSA key generation and encryption/decryption (Java), rsajava
Recently I have been studying PKI and have come into contact with some encryption algorithms. I focused on RSA and wrote a simple Demo to implement the RSA algorithm, including public and private key generation and encryption and decryption. Although relatively simple, it also covers the core ideas and processes of RSA encryption and decryption. Here we will share it with you.
RSA Overview:
RSA is currently the most influential public key encryption algorithm. It can resist the vast majority of known password attacks so far and has been recommended as the Public Key Data Encryption Standard by ISO. The mathematical basis of RSA is the decomposition of big integer factors, which are described as follows:
Given two prime numbers p and q, it is easy to calculate the product pq = n.
Given the integer n, it is very difficult to obtain the prime factor p and q of n, which makes n = pq
RSA password system:
Set n = pq, where p and q are large prime numbers. Set P = E = Zn, and define K = {(n, p, q, a, B): AB 1_1 (mod PHI (n)} Where PHI (n) = (p-1) (q-1 ). For K = {(n, p, q, a, B)}, define encryption E (x) = xb mod n; decrypt D (y) = ya mod n; (x, the values n and B constitute the public key, and p, q, and a constitute the private key.
- How to generate an RSA key
The Code is as follows:
First, write three encapsulation classes, PrivateKey. java PublicKey. java RsaKeyPair. java (the implementation in JDK is highly abstract. Here we will simply encapsulate it)
1 package com. khalid. pki; 2 3 import java. math. bigInteger; 4 5 public class PublicKey {6 7 private final BigInteger n; 8 9 private final BigInteger B; 10 11 public PublicKey (BigInteger n, BigInteger B) {12 this. n = n; 13 this. B = B; 14} 15 16 public BigInteger getN () {17 return n; 18} 19 20 public BigInteger getB () {21 return B; 22} 23}View Code 1 package com. khalid. pki; 2 3 import java. math. bigInteger; 4 5 public class PrivateKey {6 7 private final BigInteger n; 8 9 private final BigInteger a; 10 11 public PrivateKey (BigInteger n, BigInteger a) {12 this. n = n; 13 this. a = a; 14} 15 16 public BigInteger getN () {17 return n; 18} 19 20 public BigInteger getA () {21 return a; 22} 23}View Code 1 package com. khalid. pki; 2 3 public class RsaKeyPair {4 5 private final PrivateKey privateKey; 6 7 private final PublicKey publicKey; 8 9 public RsaKeyPair (PublicKey publicKey, PrivateKey privateKey) {10 this. privateKey = privateKey; 11 this. publicKey = publicKey; 12} 13 14 public PrivateKey getPrivateKey () {15 return privateKey; 16} 17 18 public PublicKey getPublicKey () {19 return publicKey; 20} 21}View Code
The method for generating a large prime number is not implemented by itself. The probablePrime (int bitlength, SecureRandom random) method in the BigInteger class is used.
SecureRandom random = new SecureRandom (); random. setSeed (new Date (). getTime (); BigInteger bigPrimep, bigPrimeq; while (! (BigPrimep = BigInteger. probablePrime (bitlength, random). isProbablePrime (1) {continue;} // generate a large prime number p while (! (BigPrimeq = BigInteger. probablePrime (bitlength, random). isProbablePrime (1) {continue;} // generate a large prime q
Calculates the values of k, n, and B.
1 BigInteger n = bigPrimep. multiply (bigPrimeq); // generates n2 // generates k3 BigInteger k = bigPrimep. subtract (BigInteger. ONE ). multiply (bigPrimeq. subtract (BigInteger. ONE); 4 // generates B smaller than k, or uses 655375 BigInteger B = BigInteger. probablePrime (bitlength-1, random );
Core calculates the value of a. The Extended Euclidean algorithm is as follows:
Note that the second method cal can still pass the third parameter, the modulo value, but we omit this parameter here, because the modulo in RSA is 1
1 private static BigInteger x; // store the temporary location variable x and y for recursion. 2 3 private static BigInteger y; 4 5 6 // Euclidean extension algorithm 7 public static BigInteger ex_gcd (BigInteger a, BigInteger B) {8 if (B. intValue () = 0) {9 x = new BigInteger ("1"); 10 y = new BigInteger ("0"); 11 return; 12} 13 BigInteger ans = ex_gcd (B,. mod (B); 14 BigInteger temp = x; 15 x = y; 16 y = temp. subtract (. divide (B ). multiply (y); 17 return ans; 18 19} 20 21 // reverse modulus 22 publi C static BigInteger cal (BigInteger a, BigInteger k) {23 BigInteger gcd = ex_gcd (a, k); 24 if (BigInteger. ONE. mod (gcd). intValue ()! = 0) {25 return new BigInteger ("-1"); 26} 27 // BigInteger is used here because we only want to calculate the inverse element of multiplication. one. In practice, if you need more flexibility, you can pass another parameter. The value of the modulo is replaced by 28 x = x. multiply (BigInteger. ONE. divide (gcd); 29 k = k. abs (); 30 BigInteger ans = x. mod (k); 31 if (ans. compareTo (BigInteger. ZERO) <0) ans = ans. add (k); 32 return ans; 33 34}
We only need
1 BigInteger a = cal (B, k );
You can calculate the value of a at the Log level.
Combine the preceding code into RSAGeneratorKey. java
1 package com. khalid. pki; 2 3 import java. math. bigInteger; 4 import java. security. secureRandom; 5 import java. util. date; 6 7 public class RSAGeneratorKey {8 9 private static BigInteger x; // store the temporary location variable x, y for recursion 10 11 private static BigInteger y; 12 13 14 // Euclidean expansion algorithm 15 public static BigInteger ex_gcd (BigInteger a, BigInteger B) {16 if (B. intValue () = 0) {17 x = new BigInteger ("1"); 18 y = new BigInteger ("0"); 19 re Turn a; 20} 21 BigInteger ans = ex_gcd (B,. mod (B); 22 BigInteger temp = x; 23 x = y; 24 y = temp. subtract (. divide (B ). multiply (y); 25 return ans; 26 27} 28 29 // reverse modulus 30 public static BigInteger cal (BigInteger a, BigInteger k) {31 BigInteger gcd = ex_gcd (, k); 32 if (BigInteger. ONE. mod (gcd ). intValue ()! = 0) {33 return new BigInteger ("-1"); 34} 35 // BigInteger is used here because we only need to calculate the inverse element of multiplication. in practice, if you need more flexibility, you can pass another parameter. The value of the modulo is 36 x = x. multiply (BigInteger. ONE. divide (gcd); 37 k = k. abs (); 38 BigInteger ans = x. mod (k); 39 if (ans. compareTo (BigInteger. ZERO) <0) ans = ans. add (k); 40 return ans; 41 42} 43 44 public static RsaKeyPair generatorKey (int bitlength) {45 SecureRandom random = new SecureRandom (); 46 random. setSeed (new Date (). getTi Me (); 47 BigInteger bigPrimep, bigPrimeq; 48 while (! (BigPrimep = BigInteger. probablePrime (bitlength, random). isProbablePrime (1) {49 continue; 50} // generate a large prime number p51 52 while (! (BigPrimeq = BigInteger. probablePrime (bitlength, random )). isProbablePrime (1) {53 continue; 54} // generate a large prime number q55 56 BigInteger n = bigPrimep. multiply (bigPrimeq); // generate n57 // generate k58 BigInteger k = bigPrimep. subtract (BigInteger. ONE ). multiply (bigPrimeq. subtract (BigInteger. ONE); 59 // generates B smaller than k, or uses 6553760 BigInteger B = BigInteger. probablePrime (bitlength-1, random); 61 // generate B 62 BigInteger a = cal (B, k) based on the Extended Euclidean algorithm ); 63 // 64 PrivateKey privateKey = new PrivateKey (n, a); 65 PublicKey publicKey = new PublicKey (n, B ); 66 67 // generate a key pair return key pair 68 return new RsaKeyPair (publicKey, privateKey); 69} 70}View Code
Compile a simple JUnit test code without displaying the results in byte stream encoding. It is relatively lazy ....
1 package com. khalid. pki; 2 3 import org. junit. test; 4 5 public class RSATest {6 7 @ Test 8 public void testGeneratorKey () {9 RsaKeyPair keyPair = RSAGeneratorKey. generatorKey (256); 10 System. out. println ("n value:" + keyPair. getPublicKey (). getN (); 11 System. out. println ("Public Key B:" + keyPair. getPublicKey (). getB (); 12 System. out. println ("Private Key a:" + keyPair. getPrivateKey (). getA (); 13} 14 15 16}View Code
This completes key pair generation.
Encryption and decryption
The root of encryption and decryption is to use the formula E (x) = xb mod n D (y) = ya mod n, therefore, we must first convert the data into the underlying binary string, convert it to BigInteger for calculation, and convert the result into a Base64 code.
The Code is as follows:
1 package com. khalid. pki; 2 3 import java. io. unsupportedEncodingException; 4 import java. math. bigInteger; 5 import java. util. arrays; 6 7 import org. apache. commons. codec. binary. base64; 8 9 public class RSAUtil {10 11 public static String encrypt (String source, PublicKey key, String charset) {12 byte [] sourceByte = null; 13 try {14 sourceByte = source. getBytes (charset); 15} catch (UnsupportedEncodingException e) {16 // TODO Auto-generated catch block17 e. printStackTrace (); 18} 19 BigInteger temp = new BigInteger (1, sourceByte); 20 BigInteger encrypted = temp. modPow (key. getB (), key. getN (); 21 return Base64.encodeBase64String (encrypted. toByteArray (); 22} 23 24 public static String decrypt (String cryptdata, PrivateKey key, String charset) throws UnsupportedEncodingException {25 byte [] byteTmp = Base64.decodeBase64 (cryptdata ); 26 BigInteger cryptedBig = new BigInteger (byteTmp); 27 byte [] cryptedData = cryptedBig. modPow (key. getA (), key. getN ()). toByteArray (); 28 cryptedData = Arrays. copyOfRange (cryptedData, 1, cryptedData. length); // remove the byte 29 return new String (cryptedData, charset); 30 31} 32}View Code
It is difficult to remember that BigInteger has a signed bit. Remember to remove the symbol bit when reorganizing the String. Otherwise, there will be more spaces in the first place in Chinese.
Compile a test code.
1 package com. khalid. pki; 2 3 import java. io. unsupportedEncodingException; 4 import org. junit. test; 5 6 public class RSATest {7 8 9 @ Test10 public void testRSA () throws UnsupportedEncodingException {11 // generate KeyPair12 RsaKeyPair keyPair = RSAGeneratorKey. generatorKey (1024); 13 // metadata 14 String source = new String ("Haha ~~~ Hey, hey ~~ --- Hehahahahahahaoah! "); 15 16 System. out. println ("before encryption:" + source); 17 // use the public key to encrypt 18 String cryptdata = RSAUtil. encrypt (source, keyPair. getPublicKey (), "UTF-8"); 19 System. out. println ("encrypted:" + cryptdata); 20 // use the private key to decrypt 21 try {22 String result = RSAUtil. decrypt (cryptdata, keyPair. getPrivateKey (), "UTF-8"); 23 System. out. println ("decrypted:" + result); 24 System. out. println (result. equals (source); 25} catch (UnsupportedEncodingException e) {26 // TODO Auto-generated catch block27 e. printStackTrace (); 28} 29 30} 31}View Code
Test results. Bingo.