Java -- RSA配合AES加密(未完待续)

介绍

  非对称加密存在加密数据限制问题(即使用非对称密钥加密数据时,一次加密的数据长度是(密钥长度/8-11)本程序中,密钥长度是1024( keyPairGen.initialize(1024);程序中这里指定了),那么加密内容应该不得超过1024/8-11=117,解密要求密文最大长度为1024/8=128字节,如果需要加密的数据长度大于117,则会报错:Data must not be longer than 117 bytes,并且对于非对称加密来说,加密内容越大,则加解密越慢,所以不是很推荐。
  大家推荐的,就是加解密用AES对称加密,然后用RSA的公钥加密AES的私钥,最后用RSA的私钥解密出来AES的私钥,再AES对称解密。

原理

在这里插入图片描述

代码

AES工具类
package com.caxs.warn.common.utils;

import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * @Author: TheBigBlue
 * @Description:
 * @Date: 2019/9/25
 */
public class AESUtils {

    private static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算法

    /**
     * AES 加密操作
     *
     * @param content  待加密内容
     * @param password 加密密码
     * @return 返回Base64转码后的加密数据
     */
    public static String encrypt(String content, String password) {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器

            byte[] result = cipher.doFinal(byteContent);// 加密

            return Base64Utils.encodeToString(result);//通过Base64转码返回
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param password
     * @return
     */
    public static String decrypt(String content, String password) {

        try {
            //实例化
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            //使用密钥初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));

            //执行操作
            byte[] result = cipher.doFinal(Base64Utils.decodeFromString(content));

            return new String(result, "utf-8");
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

    /**
     * 生成加密秘钥
     *
     * @return
     */
    private static SecretKeySpec getSecretKey(String password) {
        //返回生成指定算法密钥生成器的 KeyGenerator 对象
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
            //AES 要求密钥长度为 128
            kg.init(128, new SecureRandom(password.getBytes()));
            //生成一个密钥
            SecretKey secretKey = kg.generateKey();
            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}

RSA工具类
package com.caxs.warn.common.utils;

import com.caxs.warn.common.exception.BusinessException;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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;

/**
 * @Author: TheBigBlue
 * @Description:
 * @Date: 2019/9/23
 */
public class RSAUtils {

    private RSAUtils() {
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class);

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

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

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

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

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

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

    /**
     * @Author: TheBigBlue
     * @Description: 加密
     * @Date: 2019/9/23
     * @Param data: 需要加密的数据
     * @Param publicKey: Base64公钥串
     * @Return:
     **/
    public static String encrypt(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/23
     * @Param str: 加密的base64串
     * @Param privateKey: Base64私钥串
     * @Return: 明文
     **/
    public static String decrypt(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);
    }

    /**
     * @Author: TheBigBlue
     * @Description: 分段加解密
     * @Date: 2019/9/24
     * @Return:
     **/
    public static byte[] doFinalBySegment(byte[] inputBytes, Cipher cipher, int maxLength) throws Exception {
        int inputLenth = inputBytes.length;
        LOGGER.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;
    }

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

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

    /**
     * 初始化密钥。
     */
    public static Map<String, Object> initKey() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        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;
    }

    /**
     * @Author: TheBigBlue
     * @Description: 生成公私钥,并保存至指定目录下
     * @Date: 2019/9/23
     * @Param filepath: 保存路径
     * @Return:
     **/
    public static void getKeyAndSave(String savePath) {
        try {
            Map<String, Object> keyMap = initKey();
            LOGGER.info("密钥保存路径为:{}", savePath);
            FileUtil.writeFile(getPrivateKeyStr(keyMap), savePath + "/private.store");
            FileUtil.writeFile(getPublicKeyStr(keyMap), savePath + "/public.store");
        } catch (Exception e) {
            LOGGER.error("生成密钥失败", e);
            throw new BusinessException("生成密钥失败", e);
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值