非对称加密
非对称加密:
- 通信双方分别创建公钥和私钥,
- 并且保证公钥所加密的信息,只有配对的私钥可以解密,
- 接下来,双方公开交换公钥,通信时,使用对方的公钥进行加密,
- 如此,就能确保对方能够通过自己的私钥解密
加密算法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