RSA加密算法
Posted QQ_851228082
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RSA加密算法相关的知识,希望对你有一定的参考价值。
RSA加密算法
RSA是非对称加密算法,非对称加密算法指的是加密和解密使用不同的密钥,除了加解密的作用,还有“签名”的作用。通常来说非对称加密比对称加密要耗时间。
- 加解密
用公钥加密,用私钥解密;这样可以确保数据不被破解,因为公钥加密后,只有私钥才能解密,所以可以保证数据不被破解。; - 签名
用私钥生成签名,用公钥验证签名;这样可以确定发送者的是不是目标身份。
生成密钥对
无论是加解密还是签名都需要使用密钥对。
public static KeyPair genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024,new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
return keyPair;
}
加解密例子
本例子的代码很大程度参考了RSA加密与解密(Java实现)
加解密
用公钥加密
public static String encrypt( String str, Key publicKey ) throws Exception{
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
用私钥解密
public static String decrypt(String str, Key privateKey) throws Exception{
//64位解码加密后的字符串
byte[] inputByte = Base64.getDecoder().decode(str.getBytes("UTF-8"));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
public static void main(String[] args) throws Exception {
//加密字符串
String message = "df723820";
KeyPair keyPair = genKeyPair();
PrivateKey privateKey = keyPair.getPrivate(); // 得到私钥
PublicKey publicKey = keyPair.getPublic(); // 得到公钥
String messageEn = encrypt(message,publicKey);
log.info("加密前:{}",message);
log.info("加密后:{}",messageEn);
String messageDe = decrypt(messageEn,privateKey);
log.info("还原后的字符串为:{}" , messageDe);
}
签名例子
本例子主要参考Java 实现RSA签名和加密
私钥生成签名
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes(StandardCharsets.UTF_8));
byte[] signature = privateSignature.sign();
return Base64.getEncoder().encodeToString(signature);
}
公钥验证签名
public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception {
Signature publicSignature = Signature.getInstance("SHA256withRSA");
publicSignature.initVerify(publicKey);
publicSignature.update(plainText.getBytes(StandardCharsets.UTF_8));
byte[] signatureBytes = Base64.getDecoder().decode(signature);
return publicSignature.verify(signatureBytes);
}
完整代码
public static void main(String[] args) throws Exception {
String sign = sign(message, keyPair.getPrivate());
boolean verify = verify(message,sign, keyPair.getPublic());
log.info("校验通过:{}",verify);
}
可以看到,签名的步骤与加解密步骤很像。但这里用的算法是SHA256withRSA
,它包含SHA256和RSA。因为直接对数据做签名运算量太大,所以一般先根据数据生成信息摘要,然后对信息摘要做签名以减小运算量;SHA代表Secure Hash Algorithm,SHA256是个散列函数,它对数据做信息摘要,然后RSA对摘要做签名。
HMAC、MD5
通常我们会想到,RSA与HMAC、MD5、SHA有什么区别,其实区别还是很明显的
- HMAC
- HMAC是基于密钥和散列函数对数据进行信息摘要,通常通信双方共享密钥;可以选择指定的散列函数,比如MD5、SHA256,分别称为HMAC-MD5、HmacSHA256、;HMAC可以验证数据完整性校验、身份认证功能。
- MD5、SHA
- MD5、SHA仅是散列函数,实现了信息摘要作用,可以用于验证数据完整性,但无法证明身份。
常见问题
- 一般都是,公钥加密,私钥解密;那私钥加密,公钥解密,可以吗?
- 可以的,根据RSA的推导公式,公钥私钥是可以互相加密解密;上边的代码,互换一下key试一下就可以了,是可以的。
- 将私钥公开,公钥保密,可以吗?
- 不可以。这很容易被破解,因为私钥长、公钥短(在线生成器查看),hacker眼中“私钥”其实是“公钥”,公钥值短,很容易被穷举出来;这点可参考RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?
联系实际
如果以上都懂了,那么也就懂得了,微信支付文档中的这张图
商户请求微信时,用商户私钥产生签名,微信用商户公钥验证签名;响应信息中,用平台私钥产生签名,商户用平台公钥验证签名;
微信请求商户时,用微信私钥产生签名,商户用微信公钥验证签名;响应信息中,用商户私钥产生签名,平台用商户公钥验证签名;
上述私钥、公钥就是RSA的私钥、公钥。商户公钥、平台公钥分别存在商户证书、平台证书中。
注意这里的证书与https中的证书不是一回事,但相似,证书就是公钥的载体,证书上有证书签发机构的签名,可以防止中间人攻击,可以证明公钥的合法性。
APIV3 key就是AES算法的密钥,微信与商户共享;
以上是关于RSA加密算法的主要内容,如果未能解决你的问题,请参考以下文章