RSA非对称加密原理
1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。
RSA非对称加密原理
RSA非堆成加密算法利用了大数求模运算实现。这里只讲加解密原理,不讲具体的推到证明。若有需要请转到阮一峰的网络日志
.
密钥的生成步骤
- 随机选择两个不相等的质数p和q。(一般情况下这两个质数都是非常大的。实际应用中,这两个质数越大,就越难破解。)
- 计算p和q的乘积n。($φ(n) = (p-1)(q-1)$)
- 计算n的欧拉函数φ(n)。
- 随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。
- 计算e对于φ(n)的模反元素d。($ed ≡ 1 (mod φ(n))$ 等价于 $ed - 1 = kφ(n)$)
- 将n和e封装成公钥,n和d封装成私钥。
RSA算法的可靠性
上述步骤出现的六个数字中,公钥用到了两个(n和e),其余四个数字都是不公开的。其中最关键的是d,因为n和d组成了私钥,一旦d泄漏,就等于私钥泄漏。
加密与解密
- 加密要用公钥 (n,e),公式为:$me ≡ c (mod n)$
- 解密要用私钥(n,d),公式为:$cd ≡ m (mod n)$
Java生成RSA密钥对
- 生成KeySize为2048bit的RSA密钥对
String KEY_ALGORITHM = "RSA"; //获得对象 KeyPairGenerator 参数 RSA 2048个字节 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(2048); //通过对象 KeyPairGenerator 获取对象KeyPair KeyPair pair = keyPairGen.generateKeyPair(); //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey PrivateKey privateKey2048 = pair.getPrivate(); PublicKey publicKey2048 = pair.getPublic();
- 写入到文件(Hutool工具)
PemUtil.writePemObject("RSA PRIVATE KEY", privateKey2048.getEncoded(), FileUtil.getOutputStream("private_key.pem")); PemUtil.writePemObject("RSA PUBLIC KEY", publicKey2048.getEncoded(), FileUtil.getOutputStream("public_key.pem"));
发行证书
CA证书(根证书)的特点就是自签发:
- 颁发者信息与使用者信息一致
- 基本约束带有CA标识
- 使用证书含有公钥对应的私钥对自己进行证书签发
/**
* 根据如下参数获取对应base64编码格式的证书文件字符串
* issuerName 与 reqName 对象是同一个则认为生成的是CA证书
* @param issuerName 颁发者信息
* @param reqName 请求证主题信息
* <br> issuerName == reqName ---> CA
* @param serial 证书序列号
* <br>eg: BigInteger serial = BigInteger.valueOf(System.currentTimeMillis() / 1000);
* @param notBefore 有效期开始时间 2018-08-01 00:00:00
* @param notAfter 有效期截至时间 2028-08-01 00:00:00
* @param userPublicKey 请求者主题公钥信息
* @param rootPrivateKey 颁发者私钥信息
* @return String
* @throws OperatorCreationException
* @throws CertificateException
* @throws IOException
*/
public static String certBuilder(X500Name issuerName, X500Name reqName, BigInteger serial, Date notBefore, Date notAfter, PublicKey userPublicKey, PrivateKey rootPrivateKey) throws OperatorCreationException, CertificateException, IOException {
JcaX509v3CertificateBuilder x509v3CertificateBuilder = new JcaX509v3CertificateBuilder(
issuerName, serial, notBefore, notAfter, reqName, userPublicKey);
// 签发者 与 使用者 信息一致则是CA证书生成,增加CA 基本约束属性
if(issuerName == reqName){
BasicConstraints constraint = new BasicConstraints(1);
x509v3CertificateBuilder.addExtension(Extension.basicConstraints, false, constraint);
}
//签名的工具
ContentSigner signer = new JcaContentSignerBuilder("SHA256WITHRSA").setProvider("BC").build(rootPrivateKey);
//触发签名产生用户证书
X509CertificateHolder x509CertificateHolder = x509v3CertificateBuilder.build(signer);
JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
certificateConverter.setProvider("BC");
Certificate userCertificate = certificateConverter.getCertificate(x509CertificateHolder);
String certStr = genCert(userCertificate);
return certStr;
}
/**
* 签发CA证书
*/
public void genCaCertTest() throws Exception{
//根证书Issue基本信息
X500Name issuerName = getX500Name("Dev", "VK", "BeiJing", "BeiJing", "CN", "R&D");
// 证书序列号
BigInteger serial = BigInteger.valueOf(System.currentTimeMillis() / 1000);
//证书有 起始日期 与 结束日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date notBefore = sdf.parse("2018-08-01 00:00:00");
Date notAfter = sdf.parse("2028-08-01 00:00:00");
//构建 用户证书 对应的公钥
PublicKey userPublicKey = getPublicKey(16,publicRootMudulus,publicRootexpoent);
//构建CAroot证书 对应的私钥
PrivateKey rootPrivateKey = getPrivateKey(16,publicRootMudulus,publicRootexpoent);
//构建证书的build
String cert = certBuilder(issuerName, issuerName, serial, notBefore, notAfter, userPublicKey, rootPrivateKey);
System.out.println("\n"+cert);
}
签发用户证书的特点:
- 这里要用用户证书的公钥以及请求信息,使用CA证书的私钥做签名达到证书结果。
- 签发证书的颁发者信息 要与生成ca证书时的签发信息一致,不然会出错。证书链验证不过。
/**
* 生成用户证书
*/
public void genUserCertTest() throws Exception{
//根证书Issue基本信息
X500Name issuerName = getX500Name("Dev", "Vk", "BeiJing", "BeiJing", "CN", "R&D");
// 用户证书 基本使用者
X500Name reqName = getX500Name("vkuser", "vkuser", "BeiJing", "BeiJing", "CN", "R&D");
// 证书序列号
BigInteger serial = BigInteger.valueOf(System.currentTimeMillis() / 1000);
//证书 起始日期 与 结束日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date notBefore = sdf.parse("2018-08-02 00:00:00");
Date notAfter = sdf.parse("2028-07-01 00:00:00");
//构建 用户证书 对应的公钥
PublicKey userPublicKey = getPublicKey(16,publicUserMudulus,publicUserexpoent);
//构建CAroot证书 对应的私钥
PrivateKey rootPrivateKey = getPrivateKey(16,publicRootMudulus,privateRootexpoent);
//构建证书的build
String cert = certBuilder(issuerName, reqName, serial, notBefore, notAfter, userPublicKey, rootPrivateKey);
System.out.println("\n"+cert);
}
RSA非对称加密原理
https://blog.cikaros.top/doc/a3f58b37.html