非对称加密
非对称加密:
- 通信双方分别创建公钥和私钥,
- 并且保证公钥所加密的信息,只有配对的私钥可以解密,
- 接下来,双方公开交换公钥,通信时,使用对方的公钥进行加密,
- 如此,就能确保对方能够通过自己的私钥解密
加密算法RSA
按RSA的固定步骤:
-
选择素数:
- 随机选择两个大素数,通常表示为p和q。
-
计算乘积:
- 计算两个素数的乘积n,即n = p * q。
-
计算欧拉函数:
- 计算n的欧拉函数φ(n),其中φ(n) = (p-1) * (q-1)。
-
选择公钥:
- 选择一个整数e,满足1 < e < φ(n),并且e与φ(n)互质。通常,公钥是一个包含两个部分的数对(e, n)。
-
计算私钥:
- 计算私钥d,使得e * d ≡ 1 (mod φ(n))。通常,私钥是一个包含两个部分的数对(d, n)。
-
加密数据:
- 使用接收者的公钥(e, n),对要传输的数据进行加密。加密操作通常是将明文m的e次方,然后取模n,得到密文c:c = m^e mod n。
-
解密数据:
- 接收者使用自己的私钥(d, n)对密文进行解密。解密操作通常是将密文c的d次方,然后取模n,得到明文m:m = c^d mod n。
/*** RSA非对称加密算法客户端*/
@Slf4j
public class RSAClient {/*** 生成两个质数*/public List<Integer> getTwoPrime() {List<Integer> primes = new ArrayList<>();int len=0;while (len<2) {Random random = new Random();int num = random.nextInt(500);if (isPrime(num)) {primes.add(num);len++;}}log.info("(1)生成两个质数:{}", primes);return primes;}private boolean isPrime(int num) {for (int i = 2; i < Math.sqrt(num); i++) {if (num % i == 0) {return false;}}return true;}/*** 计算n,m*/public Map<String, Integer> getNAndM(List<Integer> primes) {if (primes.size() != 2) {throw new IllegalArgumentException("只接受两个质数");}Integer prime1 = primes.get(0);Integer prime2 = primes.get(1);Map<String, Integer> map = new HashMap<>();//核心算法map.put("n", prime1 * prime2);map.put("m", (prime1 - 1) * (prime2 - 1));log.info("n,m:{}", map);return map;}/*** 随机选出m的一个质数,该质数为正且小于m*/public Integer getPrime(Integer m) {while (true) {Random random = new Random();int e = random.nextInt(m);while (e == 0) {e = random.nextInt(m);}if (getGCD(e, m) == 1) {return e;}}}/*** 欧几里得算法:a,b最大公因数等于b,a%b的最大公因数,当两数的最大公因数是1时,两数互质,初始时,a<b*/private int getGCD(int a, int b) {if (b == 0) {return a;}return getGCD(b, a % b);}/*** 通过扩展欧几里得算法获得d,d满足:(d * e) % m =1*/public int getD(int e, int m) {int d = 1;while (true) {if ((d * e) % m == 1) {break;}d++;}return d;}/*** 加密*/public byte[] encrypt(String content,Integer n,Integer e) {//2.利用公钥加密//2.1原文转成数字串List<Integer> integers = new ArrayList<>();for (byte b : content.getBytes()) {integers.add(((int) b ^e) % n);}Byte[] bytes = integers.stream().map(integer -> (byte) integer.intValue()).toArray(Byte[]::new);byte[] result = new byte[bytes.length];for (int i = 0; i < bytes.length; i++) {result[i]= bytes[i];}return result;}/*** 解密* */public String decrypt(byte[] bytes,Integer n,Integer m,Integer e){//获取私钥int d = getD(e, m);log.info("私钥:({},{})",d,n);byte[] result = new byte[bytes.length];for (int i = 0; i < bytes.length; i++) {int num = bytes[i];result[i]= (byte) ((num^e)%n);}return new String(result);}public static void main(String[] args) {RSAClient rsaClient = new RSAClient();//计算公钥Map<String, Integer> nAndM = rsaClient.getNAndM(rsaClient.getTwoPrime());Integer n = nAndM.get("n");Integer m = nAndM.get("m");Integer e = rsaClient.getPrime(m);log.info("公钥:({},{})", e, n);//加密byte[] bytes = rsaClient.encrypt("hello world",n,e);log.info("密文:{}", new String(bytes));//解密String decrypt = rsaClient.decrypt(bytes, n, m, e);log.info("解密:{}",decrypt);}}
效果:
2024-05-07 13:52:17 INFO [main] c.e.p.RSAClient.(): [信息] (1)生成两个质数:[4, 127]
2024-05-07 13:52:17 INFO [main] c.e.p.RSAClient.(): [信息] n,m:{m=378, n=508}
2024-05-07 13:52:17 INFO [main] c.e.p.RSAClient.(): [信息] 公钥:(85,508)
2024-05-07 13:52:17 INFO [main] c.e.p.RSAClient.(): [信息] 密文:=099:u":'91
2024-05-07 13:52:17 INFO [main] c.e.p.RSAClient.(): [信息] 私钥:(169,508)
2024-05-07 13:52:17 INFO [main] c.e.p.RSAClient.(): [信息] 解密:hello world