0
点赞
收藏
分享

微信扫一扫

Java 实现 RSA 加密

微笑沉默 2021-09-21 阅读 49
JavaJava web

本文介绍 RSA 加密的原理、示例、安全性分析及 Java 语言实现。


目录

  • RSA 简介
    • 原理
    • 示例
    • 安全性
    • 常见用途
  • 代码实现

RSA 简介

RSA 是一种非对称加密算法,于1977年由 MIT 的 Ron Rivest,Adi Shamir 和 Leonard Adleman 三人一起提出。

原理及示例
  1. 选择 2 个质数 pq
  2. 计算 n = p * q
  3. 根据欧拉函数 φ(n) = (p - 1) * (q - 1) 计算出 φ(n)
  4. 确定公钥(整数)e,要求:1 < e < φ(n)eφ(n) 互质
  5. 确定私钥(整数)d,要求:(e * d) / φ(n) 的余数为 1
  6. 加密:原文 m,计算 me 次幂除以 n,求余数 cc 就是加密后所得的密文
  7. 解密:密文 c,计算 cd 次幂除以 n,求余数得到原文 m
示例

来自 wikipedia

  1. p = 61q = 53
  2. n = 61 * 53 = 3233
  3. φ(n) = (61 - 1) * (53 - 1) = 60 * 52 = 3120
  4. e = 17
  5. d = 2753
  6. 公钥 (3233,17),私钥 (3233,2753)
  7. 原文 18,公钥加密密文 2100,私钥解密得到原文 18
  8. 原文 81,私钥加密密文 2083,公钥解密得到原文 81
安全性
  1. 加解需要 n 和公钥 e 生成密文 c
  2. 解密需要 n 、密钥 d 和密文 c
  3. 公开场合窃听者只能获取 n e c,但是获取不到密钥 d,需要通过 e 计算出 d
  4. 如果想通过 e 计算出 d 则必须知道 φ(n)
  5. 想知道 φ(n) 必须求出 pq
  6. 因为 n = p * qn 已知,所以必须进行【质因数分解】,数学证明大数质因数分解十分困难,这也是 RSA 算法安全性的根本保证。

美国国家标准与技术局和 ANSI X9 已经设定了最小密钥长度的要求,RSA 是 2048 位,这样在 2030 年以前是安全的。

常见用途
  • 公钥加密、私钥解密:加密数据及信息
  • 私钥加密、公钥解密:数字签名

代码实现

package tutorial.java.util;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.util.Base64;

public class RsaUtils {

/**
* 算法名称
*/

private static final String ALGORITHM_RSA = "RSA";

/**
* 签名算法
*/

public static final String SIGNATURE_ALGORITHM = "SHA512withRSA";

/**
* 生成密钥对
*
* @param keySize 密钥长度
* @return 密钥对
*/

public static KeyPair keyPair(int keySize) throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_RSA);
keyPairGenerator.initialize(keySize);
return keyPairGenerator.generateKeyPair();
}

/**
* RSA 私钥加密
*
* @param privateKey 私钥
* @param content 待加密内容
* @return 加密后密文字节数组
*/

public static byte[] encryptByPrivateKey(PrivateKey privateKey, byte[] content) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(content);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No Such Algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No Such Padding");
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad Padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal Block Size");
}
}

/**
* RSA 公钥加密
*
* @param publicKey 公钥
* @param content 待加密内容
* @return 加密后密文字节数组
*/

public static byte[] encryptByPublicKey(PublicKey publicKey, byte[] content) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(content);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No Such Algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No Such Padding");
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad Padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal Block Size");
}
}

/**
* RSA 私钥解密
*
* @param privateKey 私钥
* @param content 密文
* @return 解密后原文字节数组
*/

public static byte[] decryptByPrivateKey(PrivateKey privateKey, byte[] content) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(content);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No Such Algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No Such Padding");
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad Padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal Block Size");
}
}

/**
* RSA 公钥解密
*
* @param publicKey 公钥
* @param content 密文
* @return 解密后原文字节数组
*/

public static byte[] decryptByPublicKey(PublicKey publicKey, byte[] content) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(content);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No Such Algorithm");
} catch (NoSuchPaddingException e) {
throw new UnsupportedOperationException("No Such Padding");
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
} catch (BadPaddingException e) {
throw new UnsupportedOperationException("Bad Padding");
} catch (IllegalBlockSizeException e) {
throw new UnsupportedOperationException("Illegal Block Size");
}
}

/**
* 用私钥生成数字签名
*
* @param content 签名内容
* @param privateKey 私钥
* @return 数字签名
*/

public static String sign(byte[] content, PrivateKey privateKey) {
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateKey);
signature.update(content);
return Base64.getEncoder().encodeToString(signature.sign());
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No Such Algorithm");
} catch (SignatureException e) {
throw new UnsupportedOperationException("Signature Exception");
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
}
}

/**
* 用公钥验证数字签名
*
* @param content 签名内容
* @param publicKey 公钥
* @param sign 签名
* @return 验证结果
*/

public static boolean verify(byte[] content, PublicKey publicKey, String sign) {
try {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicKey);
signature.update(content);
return signature.verify(Base64.getDecoder().decode(sign));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("No Such Algorithm");
} catch (SignatureException e) {
throw new UnsupportedOperationException("Signature Exception");
} catch (InvalidKeyException e) {
throw new UnsupportedOperationException("Invalid Key");
}
}
}

单元测试:

package tutorial.java.util;

import org.junit.Assert;
import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;

public class RsaUtilsTest {

@Test
public void test() throws NoSuchAlgorithmException {
String content = "RSA encrypt/decrypt demo";
KeyPair keyPair = RsaUtils.keyPair(2048);
// 测试私钥加密公钥解密
byte[] encryptByPrivateKeyResult = RsaUtils.encryptByPrivateKey(keyPair.getPrivate(),
content.getBytes(StandardCharsets.UTF_8));
byte[] decryptByPublicKeyResult = RsaUtils.decryptByPublicKey(keyPair.getPublic(),
encryptByPrivateKeyResult);
Assert.assertEquals(content, new String(decryptByPublicKeyResult, StandardCharsets.UTF_8));
// 测试公钥加密私钥解密
byte[] encryptByPublicKeyResult = RsaUtils.encryptByPublicKey(keyPair.getPublic(),
content.getBytes(StandardCharsets.UTF_8));
byte[] decryptByPrivateKeyResult = RsaUtils.decryptByPrivateKey(keyPair.getPrivate(),
encryptByPublicKeyResult);
Assert.assertEquals(content, new String(decryptByPrivateKeyResult, StandardCharsets.UTF_8));
// 测试签名
String sign = RsaUtils.sign(content.getBytes(StandardCharsets.UTF_8), keyPair.getPrivate());
Assert.assertTrue(RsaUtils.verify(content.getBytes(StandardCharsets.UTF_8), keyPair.getPublic(), sign));
}
}
举报

相关推荐

0 条评论