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试一下就可以了,是可以的。
  • 将私钥公开,公钥保密,可以吗?

联系实际

如果以上都懂了,那么也就懂得了,微信支付文档中的这张图
在这里插入图片描述

商户请求微信时,用商户私钥产生签名,微信用商户公钥验证签名;响应信息中,用平台私钥产生签名,商户用平台公钥验证签名;
微信请求商户时,用微信私钥产生签名,商户用微信公钥验证签名;响应信息中,用商户私钥产生签名,平台用商户公钥验证签名;
上述私钥、公钥就是RSA的私钥、公钥。商户公钥、平台公钥分别存在商户证书、平台证书中。
注意这里的证书与https中的证书不是一回事,但相似,证书就是公钥的载体,证书上有证书签发机构的签名,可以防止中间人攻击,可以证明公钥的合法性。

APIV3 key就是AES算法的密钥,微信与商户共享;

以上是关于RSA加密算法的主要内容,如果未能解决你的问题,请参考以下文章

PHP RSA和RSA2加密算法代码

求RSA加密解密算法,c++源代码

非对称加密及RSA加密算法

RSA 加密算法在C++中的实现 面向初学者(附代码)

jmeter接口测试-使用rsa加密解密算法

5_RSA加密算法