百木园-与人分享,
就是让自己快乐。

基于hutool实现非对称加密(RSA和国密SM2)的加解密和加签验签

背景

对外服务的接口为了安全起见,往往需要进行相应的安全处理:数据加密传输和身份认证。数据加密传输有对称加密和非对称加密两种,为了更加安全起见采用非对称加密比较好些,身份认证则采用数字签名可以实现。

非对称加密缺点:加解密速度慢、RSA有最大长度要求。

 

方案一

仅采用非对称加密

RSA对内容长度的要求可以通过分组加解密解决

参考:https://blog.csdn.net/draven1122/article/details/55212252

 

方案二

非对称加密+对称加密

内容采用对称加密(AES)加密,非对称加密仅加密AES密钥

调用方

  1.签名生成:接口参数->摘要算法(SHA)->参数摘要->签名(自己RSA私钥)->签名

  2.内容(接口参数 + 签名 ) -->对称加密(AES)--> 内容密文

  3.AES密钥-->非对称加密(对方RSA公钥)--> AES密钥密文

  4. 内容密文(请求体)+AES密钥密文(请求头)-> 传输给接收方

接收方

 1. 获取AES密钥密文-> 非对称解密(自己RSA私钥)->AES密钥

 2. 内容密文-> AES密钥-> 内容明文

 3. 验证签名:内容里的参数->摘要算法(SHA)->参数摘要->验签(对方RSA公钥)->签名

 4. 验签通过,继续执行接口

 5. 返回值(加解密可选)

 

加密工具类可以使用:https://hutool.cn/docs/#/crypto/%E6%A6%82%E8%BF%B0 

基于hutool中密码工具类实现的rsa和国密的非对称加解密算法和加签验签算法代码如下

maven依赖

 <!-- huTool工具箱 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.22</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15to18</artifactId>
            <version>1.69</version>
        </dependency>

rsa非对称加密

package com.hdwang.test.hutool;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

/**
 * @author wanghuidong
 * @date 2022/5/25 21:00
 */
public class RsaTest {

    public static void main(String[] args) {
        String text = \"人最宝贵的是生命.生命对每个人只有一次.人的一生应当这样度过:当他回首往事的时候,不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻.这样,在临死的时候,他能够说:“我已把自己的整个的生命和全部的精力献给了世界上最壮丽的事业---------为人类的解放而斗争.”\";
        System.out.println(\"原文:\" + text);

        //生成公私钥对
        KeyPair pair = SecureUtil.generateKeyPair(\"RSA\");
        PrivateKey privateKey = pair.getPrivate();
        PublicKey publicKey = pair.getPublic();
        //获得私钥
        String privateKeyStr = bytesToBase64(privateKey.getEncoded());
        System.out.println(\"私钥:\" + privateKeyStr);
        //获得公钥
        String publicKeyStr = bytesToBase64(publicKey.getEncoded());
        System.out.println(\"公钥:\" + publicKeyStr);

        RSA rsa = new RSA(privateKeyStr, publicKeyStr);
        System.out.println(rsa);

        //公钥加密,私钥解密
        byte[] encrypt = rsa.encrypt(StrUtil.bytes(text, CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey);
        System.out.println(\"公钥加密:\" + bytesToBase64(encrypt));

        byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);
        System.out.println(\"私钥解密:\" + new String(decrypt,StandardCharsets.UTF_8));

//        //私钥加密,公钥解密
//        byte[] encrypt2 = rsa.encrypt(StrUtil.bytes(text, CharsetUtil.CHARSET_UTF_8), KeyType.PrivateKey);
//        System.out.println(\"私钥加密:\" + bytesToBase64(encrypt2));
//        byte[] decrypt2 = rsa.decrypt(encrypt2, KeyType.PublicKey);
//        System.out.println(\"公钥解密:\" + bytesToBase64(decrypt2));

        Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKeyStr, publicKeyStr);
        //签名
        byte[] data = text.getBytes(StandardCharsets.UTF_8);
        byte[] signed = sign.sign(data);
        String signedStr = bytesToBase64(signed);
        System.out.println(\"签名:\" + signedStr);

        //验证签名
        boolean verify = sign.verify(data, base64ToBytes(signedStr));
        System.out.println(\"验签:\" + verify);

    }

    /**
     * 字节数组转Base64编码
     *
     * @param bytes 字节数组
     * @return Base64编码
     */
    private static String bytesToBase64(byte[] bytes) {
        byte[] encodedBytes = Base64.getEncoder().encode(bytes);
        return new String(encodedBytes, StandardCharsets.UTF_8);
    }

    /**
     * Base64编码转字节数组
     *
     * @param base64Str Base64编码
     * @return 字节数组
     */
    private static byte[] base64ToBytes(String base64Str) {
        byte[] bytes = base64Str.getBytes(StandardCharsets.UTF_8);
        return Base64.getDecoder().decode(bytes);
    }
}

国密非对称加密(SM2)

package com.hdwang.test.hutool;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.util.Base64;

/**
 * 国密非对称加解密和加签验签算法
 *
 * @author wanghuidong
 * @date 2022/5/25 20:50
 */
public class SmTest {
    public static void main(String[] args) {
        String text = \"人最宝贵的是生命.生命对每个人只有一次.人的一生应当这样度过:当他回首往事的时候,不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻.这样,在临死的时候,他能够说:“我已把自己的整个的生命和全部的精力献给了世界上最壮丽的事业---------为人类的解放而斗争.”\";
        System.out.println(\"原文:\" + text);

        KeyPair pair = SecureUtil.generateKeyPair(\"SM2\");
        byte[] privateKey = pair.getPrivate().getEncoded();
        byte[] publicKey = pair.getPublic().getEncoded();
        System.out.println(\"公钥:\\n\" + bytesToBase64(publicKey));
        System.out.println(\"私钥:\\n\" + bytesToBase64(privateKey));

        SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
        // 公钥加密,私钥解密
        String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
        System.out.println(\"加密后:\" + encryptStr);

        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
        System.out.println(\"解密后:\" + decryptStr);
        //加签
        String sign = sm2.signHex(HexUtil.encodeHexStr(text));
        System.out.println(\"签名:\" + sign);
        //验签
        boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(text), sign);
        System.out.println(\"验签:\" + verify);

    }


    /**
     * 字节数组转Base64编码
     *
     * @param bytes 字节数组
     * @return Base64编码
     */
    private static String bytesToBase64(byte[] bytes) {
        byte[] encodedBytes = Base64.getEncoder().encode(bytes);
        return new String(encodedBytes, StandardCharsets.UTF_8);
    }

    /**
     * Base64编码转字节数组
     *
     * @param base64Str Base64编码
     * @return 字节数组
     */
    private static byte[] base64ToBytes(String base64Str) {
        byte[] bytes = base64Str.getBytes(StandardCharsets.UTF_8);
        return Base64.getDecoder().decode(bytes);
    }
}

 

 

参考文章:

https://www.cnblogs.com/pcheng/p/9629621.html

https://blog.csdn.net/woniu211111/article/details/108114402

https://blog.csdn.net/draven1122/article/details/55212252


来源:https://www.cnblogs.com/hdwang/p/16310314.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » 基于hutool实现非对称加密(RSA和国密SM2)的加解密和加签验签

相关推荐

  • 暂无文章