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对摘要做签名。
通常我们会想到,RSA与HMAC、MD5、SHA有什么区别,其实区别还是很明显的
如果以上都懂了,那么也就懂得了,微信支付文档中的这张图
商户请求微信时,用商户私钥产生签名,微信用商户公钥验证签名;响应信息中,用平台私钥产生签名,商户用平台公钥验证签名;
微信请求商户时,用微信私钥产生签名,商户用微信公钥验证签名;响应信息中,用商户私钥产生签名,平台用商户公钥验证签名;
上述私钥、公钥就是RSA的私钥、公钥。商户公钥、平台公钥分别存在商户证书、平台证书中。
注意这里的证书与https中的证书不是一回事,但相似,证书就是公钥的载体,证书上有证书签发机构的签名,可以防止中间人攻击,可以证明公钥的合法性。
APIV3 key就是AES算法的密钥,微信与商户共享;