sure975 发表于 2023-3-16 10:51

RSA加解密工具类(支持分段加解密)

本帖最后由 sure975 于 2023-3-16 11:00 编辑

刚注册论坛,本人干java开发的,四年工作经验,给大家分享一下项目里面用到的RSA加解密工具类:
这个工具类的好处就是因为当需要加密的字符串长度较长的时候可以通过分段进行加密

import kafka.log.Log;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
* @description: RSA加解密工具类
* @fileName: RSAUtils.java
* @author: Sure
* @createAt: 2022/3/7 14:20
* @updateBy: Sure
* @remark:
*/
@Slf4j
public class RsaUtils {

    /**
   * 加解密算法关键字
   */
    public static final String KEY_ALGORITHM = "RSA";

    /**
   * 公钥关键字
   */
    private static final String PUBLIC_KEY = "RSAPublicKey";

    /**
   * 私钥关键字
   */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
   * 默认编码
   */
    public static final String CHARSET = "UTF-8";

    /**
   * 最大加密字节数,超出最大字节数需要分组加密
   */
    private static int MAX_ENCRYPT_BLOCK = 117;

    /**
   * 最大解密字节数,超出最大字节数需要分组解密
   */
    private static int MAX_DECRYPT_BLOCK = 256;

    /**
   * 解密
   *
   * @param str      加密的base64串
   * @param privateKey base64私钥串
   * @return 解密后字符
   */
    public static String decrypt(String str, String privateKey) throws Exception {
      //64位解码加密后的字符串
      byte[] inputByte = Base64.decodeBase64(str.getBytes(CHARSET));
      //base64编码的私钥
      byte[] keyBytes = Base64.decodeBase64(privateKey.getBytes(CHARSET));
      RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
      //RSA解密
      Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
      cipher.init(Cipher.DECRYPT_MODE, priKey);
      return new String(cipher.doFinal(inputByte), CHARSET);
    }

    /**
   * 加密
   *
   * @param data      需要加密的数据
   * @param publicKey base64公钥串
   * @return 加密后的base64字符串
   */
    public static String encrypt(String data, String publicKey) throws Exception {
      // 取得公钥
      Key key = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(publicKey.getBytes(CHARSET))));
      // 对数据加密
      Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
      cipher.init(Cipher.ENCRYPT_MODE, key);
      return new String(Base64.encodeBase64(cipher.doFinal(data.getBytes(CHARSET))), CHARSET);
    }

    /**
   * 获取base64私钥
   *
   * @param keyMap 秘钥
   * @return 私钥
   */
    public static String getPrivateKeyStr(Map<String, Object> keyMap) {
      Key key = (Key) keyMap.get(PRIVATE_KEY);
      return Base64.encodeBase64String(key.getEncoded());
    }

    /**
   * 取得base64公钥
   *
   * @param keyMap 秘钥
   * @return base64公钥
   */
    public static String getPublicKeyStr(Map<String, Object> keyMap) {
      Key key = (Key) keyMap.get(PUBLIC_KEY);
      return Base64.encodeBase64String(key.getEncoded());
    }

    /**
   * 初始化秘钥
   *
   * @return 秘钥
   * @throws NoSuchAlgorithmException
   */
    public static Map<String, Object> initKey() throws NoSuchAlgorithmException {
      KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
      keyPairGen.initialize(2048);
      KeyPair keyPair = keyPairGen.generateKeyPair();
      //公钥
      RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
      //私钥
      RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
      Map<String, Object> keyMap = new HashMap<>(5);

      keyMap.put(PUBLIC_KEY, publicKey);
      keyMap.put(PRIVATE_KEY, privateKey);
      return keyMap;
    }


    /**
   * 分段解密
   * @param inputData 加密的base64字符串
   * @param privateKey base64的私钥
   * @return 解密后内容
   * @throws Exception
   */
    public static String decryptByShort(String inputData, String privateKey) throws Exception {
      //64位解码加密后的字符串
      byte[] inputBytes = Base64.decodeBase64(inputData.getBytes(CHARSET));
      //base64编码的私钥
      byte[] keyBytes = Base64.decodeBase64(privateKey.getBytes(CHARSET));
      RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
      //RSA解密
      Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
      cipher.init(Cipher.DECRYPT_MODE, priKey);
      byte[] resultBytes = doFinalBySegment(inputBytes, cipher, MAX_DECRYPT_BLOCK);
      return new String(resultBytes, CHARSET);
    }

/**
   * 分段公钥加密
* @param inputData 需要加密的字符串
   * @param publicKey 公钥
* @return: 加密后的base64编码
*/
    public static String encryptByShort(String inputData, String publicKey) throws Exception {
      // 取得公钥
      Key key = KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(publicKey.getBytes(CHARSET))));
      // 对数据加密
      Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
      cipher.init(Cipher.ENCRYPT_MODE, key);
      byte[] resultBytes = doFinalBySegment(inputData.getBytes(CHARSET), cipher, MAX_ENCRYPT_BLOCK);
      return new String(Base64.encodeBase64(resultBytes), CHARSET);
    }

    /**
   * @Author: TheBigBlue
   * @Description: 分段加解密
   * @Date: 2019/9/24
   * @Return:
   **/
    private static byte[] doFinalBySegment(byte[] inputBytes, Cipher cipher, int maxLength) throws Exception {
      int inputLenth = inputBytes.length;
      log.info("数据超出最大字节数进行分段加解密:maxLength={}, inputLength={}", maxLength, inputLenth);
      // 标识
      int offSet = 0;
      byte[] cache;
      byte[] resultBytes = {};
      while (inputLenth - offSet > 0) {
            //超出最大字节数分组加密
            if (inputLenth - offSet > maxLength) {
                cache = cipher.doFinal(inputBytes, offSet, maxLength);
                offSet += maxLength;
            } else {
                //直接加密
                cache = cipher.doFinal(inputBytes, offSet, inputLenth - offSet);
                offSet = inputLenth;
            }
            resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
            System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
      }
      return resultBytes;
    }

}

sure975 发表于 2023-3-16 10:53

注解啥的也都很详细,有问题的可以留言

Hmily 发表于 2023-3-16 10:54

代码建议用代码框处理一下,会好看很多。

sure975 发表于 2023-3-16 10:57

Hmily 发表于 2023-3-16 10:54
代码建议用代码框处理一下,会好看很多。

我刚才编辑的时候还有的,我再研究研究

97okslj 发表于 2023-3-28 13:09

对于明文的密码帐号,怎么在代码里面加解密发布部署啊。
希望这样来实现明文传输密码信息而被泄露的风险
页: [1]
查看完整版本: RSA加解密工具类(支持分段加解密)