RSAUtil非对称加密解密工具

RSAUtil非对称加密解密工具,RSA算法和公钥都是公开的,保管好私钥就能保证安全(破解极为困难)。

getKeyPair+getKeyString,支持生成密钥对和导出字符串以便保存,密钥长度最好512位以上(要整除8因为加密较长数据时需分块执行,且密文长度等于密钥长度),

getPrivateKey+getPublicKey,支持从字符串加载密钥,支持从证书加载密钥

sign+verify,支持签名和校验,签名可以防止数据被非法篡改(任何数据改动都会导致校验失败)

encrypt+decrypt,加密和解密,算法RSA/None/PKCS1Padding每次加密的密文都不同(填充随机数,提高了安全性),算法RSA/None/NoPadding在相同条件下产生相同密文,非对称加密相比对称加密要慢很多,所以通常不用RSA加密太多数据,而是加密对称加密的密码,然后对称加密敏感数据。

具体代码:

package com.becom.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @author changzhichen
 * @date 2020-04-02 19:36
 */
@Slf4j
public class RSAUtil {
    /**
     * 随机生成密钥对,返回公钥、私钥
     * 
     * @author changzhichen
     * @date 2020-12-16 09:11 
     * @return java.util.Map<java.lang.String,java.lang.Object> 
     **/
    public static Map<String, Object> genKeyPair() {
        try {
            final Map<String, Object> keyMap = new HashMap<>();
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化密钥对生成器,密钥大小为96-1024位
            keyPairGen.initialize(1024, new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            // 得到公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
            // 将公钥和私钥保存到Map
            //0表示公钥
            keyMap.put("publicKey", publicKeyString);
            //1表示私钥
            keyMap.put("privateKey", privateKeyString);
            log.info("-----publicKey = " + publicKeyString);
            log.info("-----privateKey = " + privateKeyString);
            return keyMap;
        } catch (NoSuchAlgorithmException e) {
            log.error("生成RSA密钥对异常", e);
        }
        return null;
    }

    /**
     * 加密
     *
     * @param message   需要加密的字符串
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encrypt(final String message, final String publicKey) {
        //base64编码的公钥
        try {
            final byte[] decoded = Base64.decodeBase64(publicKey);
            final RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            //RSA加密
            final Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);

            final byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
            //字符串长度
            final int len = bytes.length;
            int offset = 0;//偏移量
            int i = 0;//所分的段数
            final ByteArrayOutputStream bos = new ByteArrayOutputStream();

            while (len > offset) {
                byte[] cache;
                if (len - offset > 117) {
                    cache = cipher.doFinal(bytes, offset, 117);
                } else {
                    cache = cipher.doFinal(bytes, offset, len - offset);
                }
                bos.write(cache);
                i++;
                offset = 117 * i;
            }
            bos.close();

            final String encryptMessage = Base64.encodeBase64String(bos.toByteArray());
            return encryptMessage.replaceAll("[\r\n]", "");
        } catch (InvalidKeyException | InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException
                | IllegalBlockSizeException | BadPaddingException | IOException e) {
            log.error("使用公钥对数据加密异常", e);
        }
        return null;
    }

    /**
     * 解密
     *
     * @param message    需要解密的密文
     * @param privateKey 私钥
     * @return 解密后的字符串
     */
    public static String decrypt(String message, final String privateKey) {
        try {
            log.info("message1 = " + message);
            if (message.contains(" ")) {
                log.info("解码前的字符串包含空格");
                message = message.replaceAll(" ", "+");
            }
            log.info("message2 = " + message);
            //base64编码的私钥
            final byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            //64位解码加密后的字符串
            final byte[] inputByte = Base64.decodeBase64(message.getBytes(StandardCharsets.UTF_8));

            final int len = inputByte.length;//密文
            int offset = 0;//偏移量
            int i = 0;//段数
            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while (len - offset > 0) {
                byte[] cache;
                if (len - offset > 128) {
                    cache = cipher.doFinal(inputByte, offset, 128);
                } else {
                    cache = cipher.doFinal(inputByte, offset, len - offset);
                }
                bos.write(cache);
                i++;
                offset = 128 * i;
            }
            bos.close();

            return new String(bos.toByteArray(), StandardCharsets.UTF_8);
        } catch (InvalidKeyException | InvalidKeySpecException | NoSuchAlgorithmException
                | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | IOException e) {
            log.error("使用私钥对数据解密异常", e);
        }
        return null;
    }

    public static void main(String[] args) {
        Map<String, Object> map = genKeyPair();
        assert map != null;
        String publicKey = (String) map.get("publicKey");
        String privateKey = (String) map.get("privateKey");

        String content = "张三 李四";
                //  "http://localhost:8080/a.jpg";

        String encryptContent = encrypt(content, publicKey);
        System.out.println("加密后的字符串:\n" + encryptContent);

        assert encryptContent != null;
        String decryptContent = decrypt(encryptContent, privateKey);
        System.out.println("解密后的字符串:\n" + decryptContent);
    }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
对于前后端加密解密,Hutool 并没有提供直接的加密解密功能,但它提供了一些工具类可以方便地调用常用的加密解密算法。你可以使用这些工具类来实现前后端的加密解密操作。 在前端部分,可以使用 JavaScript 的加密库,如 CryptoJS,来进行加密操作。CryptoJS 提供了多种常见的加密算法,包括对称加密(如 AES、DES)和哈希算法(如 MD5、SHA),你可以根据具体需求选择合适的算法进行加密。 在后端部分,你可以使用 Hutool 的工具类进行加密解密操作。Hutool 提供了多个加密解密相关的工具类,包括 AESUtil、DESUtil、RSAUtil 等。你可以根据需要选择合适的工具类来完成相应的加密解密操作。 例如,如果你想在前端使用 AES 进行加密,在后端使用 Hutool 进行解密,可以按照以下步骤进行操作: 1. 在前端使用 CryptoJS 进行 AES 加密: ```javascript // 密钥和偏移量 var key = CryptoJS.enc.Utf8.parse("1234567890123456"); var iv = CryptoJS.enc.Utf8.parse("1234567890123456"); // 加密 var encrypted = CryptoJS.AES.encrypt("plaintext", key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 获取加密后的密文 var ciphertext = encrypted.toString(); ``` 2. 在后端使用 Hutool 进行 AES 解密: ```java // 密钥和偏移量 String key = "1234567890123456"; String iv = "1234567890123456"; // 解密 String decrypted = AESUtil.decrypt(ciphertext, key, iv); ``` 注意,前后端加密解密需要保持一致的密钥和算法参数,以确保正确的加解密结果。另外,加密解密涉及到数据安全,建议在实际应用中仔细设计和验证加密算法的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿在京

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值