程序员的资源宝库

网站首页 > gitee 正文

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

sanyeah 2024-04-12 17:39:19 gitee 3 ℃ 0 评论

背景

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

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

 

方案一

仅采用非对称加密

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

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

 

 

 

 

方案二

非对称加密+对称加密

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

 

 

加密工具类可以使用: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);
    }
}

 

目前本人实现了一套简单的安全对外开放api的sdk,可以直接拿来使用,支持上述方案一和方案二。

https://github.com/hdwang123/openapi

 

参考文章:

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

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

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

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表