Java加密算法—非对称加密

😊 @ 作者: 一恍过去
🎊 @ 社区: Java技术栈交流
🎉 @ 主题: Java加密算法—非对称加密
⏱️ @ 创作时间: 2022年03月15日

在这里插入图片描述

前言

非对称加密是一种加密算法,它使用一对相关的密钥(公钥和私钥)来进行加密和解密操作。这种加密方法也被称为公钥加密,因为公钥可以公开分享给其他人,而私钥必须保密。

非对称加密算法的工作原理如下:

  • 生成密钥对: 首先,使用非对称加密算法(如RSA或ECC)生成一对密钥,包括公钥和私钥。
  • 公钥加密: 公钥用于加密数据。发送方使用接收方的公钥对数据进行加密,并将加密后的数据发送给接收方。
  • 私钥解密: 接收方使用自己的私钥对收到的加密数据进行解密,以恢复原始的明文数据。

非对称加密的关键特点是公钥和私钥的不对称性。公钥用于加密数据,私钥用于解密数据。由于私钥是保密的,只有私钥的持有者能够解密数据,这样可以确保数据的机密性。公钥则可以公开分享给其他人,用于加密数据,以便发送给私钥的持有者。

非对称加密的应用场景包括:

  • 加密通信: 可以使用接收方的公钥对数据进行加密,确保只有接收方的私钥持有者能够解密数据,从而实现安全的通信。
  • 数字签名: 发送方可以使用自己的私钥对数据进行签名,接收方可以使用发送方的公钥验证签名的有效性,确保数据的完整性和认证性。
  • 密钥交换: 可以使用非对称加密算法安全地交换对称密钥,从而在后续的通信中使用更高效的对称加密算法进行加密。

1、概述

与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)私有密钥(privatekey),公开密钥和私有密钥是一对,如果用公开密钥加密需要私有密钥解密,反之用私有密钥加密需要公开密钥解密,因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

特点:

  • 加密和解密使用不同的密钥。
  • 如果使用私钥加密, 只能使用公钥解密。
  • 如果使用公钥加密, 只能使用私钥解密。
  • 安全级别高,处理数据的速度较慢。

注意:
理论上私钥是可以推导出公钥的,公钥无法推导出私钥。

私钥中获取公钥测试地址:http://tool.chacuo.net/cryptgetpubkey

在这里插入图片描述

2、对称加密、解密实现

将非对称加密的两种方式进行封装处理,达到一套代码实现两种加密方式,代码可以直进行使用。

public class AsymmetricTest {
    private final static String RSA = "RSA";

    public static void main(String[] args) {
        // 加密密文
        String input = "key=85CD019515D14B91AD942787532314FF&startTime=1629431243245&endTime=1660967243244";
        // 生成密钥对文件,在实际开发中,根据实际需求生成文件位置
        String pubPath = "C:\\Users\\Desktop\\publicKey.pub";
        String priPath = "C:\\Users\\Desktop\\privateKey.pri";
        // 生成公钥和私钥文件,并且打印公钥的字符串和私钥字符串
        generateKeyPair(pubPath, priPath);

        System.out.println("\n==============================================\n");

        // 从文件中加载密钥
        PublicKey publicKey = loadPublicKeyFromFile(pubPath);
        PrivateKey privateKey = loadPrivateKeyFromFile(priPath);
        // 公钥加密,私钥解密
        String encrypted = encryptByAsymmetric(input, publicKey);
        System.out.println("非对称RSA-公钥加密:" + encrypted);
        System.out.println("非对称RSA-私钥解密:" + decryptByAsymmetric(encrypted, privateKey));

        System.out.println("\n==============================================\n");


        // 私钥加密,公钥解密
        String encrypted2 = encryptByAsymmetric(input, privateKey);
        System.out.println("非对称RSA-私钥加密:" + encrypted2);
        System.out.println("非对称RSA-公钥解密:" + decryptByAsymmetric(encrypted2, publicKey));

    }

    /**
     * 从文件中加载公钥
     *
     * @param filePath : 文件路径
     * @return : 公钥
     * @throws Exception
     */
    public static PublicKey loadPublicKeyFromFile(String filePath) {
        try {
            // 将文件内容转为字符串
            String keyString = FileUtils.readFileToString(new File(filePath), String.valueOf(StandardCharsets.UTF_8));

            return loadPublicKeyFromString(keyString);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取公钥文件字符串失败!");
        }
    }

    /**
     * 从文件中加载私钥
     *
     * @param filePath : 文件路径
     * @return : 私钥
     * @throws Exception
     */
    public static PrivateKey loadPrivateKeyFromFile(String filePath) {
        try {
            // 将文件内容转为字符串
            String keyString = FileUtils.readFileToString(new File(filePath), String.valueOf(StandardCharsets.UTF_8));
            return loadPrivateKeyFromString(keyString);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取私钥文件字符串失败!");
        }
    }

    /**
     * 从字符串中加载公钥
     *
     * @param keyString : 公钥
     * @return : 公钥
     * @throws Exception
     */
    public static PublicKey loadPublicKeyFromString(String keyString) {
        try {
            // 进行Base64解码
            byte[] decode = Base64.decode(keyString);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            // 构建密钥规范
            X509EncodedKeySpec key = new X509EncodedKeySpec(decode);
            // 获取公钥
            return keyFactory.generatePublic(key);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取公钥失败!");
        }
    }

    /**
     * 从字符串中加载私钥
     *
     * @param keyString : 私钥
     * @return : 私钥
     * @throws Exception
     */
    public static PrivateKey loadPrivateKeyFromString(String keyString) {
        try {
            // 进行Base64解码
            byte[] decode = Base64.decode(keyString);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            // 构建密钥规范
            PKCS8EncodedKeySpec key = new PKCS8EncodedKeySpec(decode);
            // 生成私钥
            return keyFactory.generatePrivate(key);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取私钥失败!");
        }
    }


    /**
     * 打印密钥对并且保存到文件
     *
     * @return
     */
    public static void generateKeyPair(String pubPath, String priPath) {
        try {
            //  创建密钥对生成器对象
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
            // 生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            String privateKeyString = Base64.encode(privateKey.getEncoded());
            String publicKeyString = Base64.encode(publicKey.getEncoded());

            System.out.println("私钥:" + privateKeyString);
            System.out.println("公钥:" + publicKeyString);

            // 保存文件
            if (pubPath != null) {
                FileUtils.writeStringToFile(new File(pubPath), publicKeyString, String.valueOf(StandardCharsets.UTF_8));
            }
            if (priPath != null) {
                FileUtils.writeStringToFile(new File(priPath), privateKeyString, String.valueOf(StandardCharsets.UTF_8));
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("生成密钥对失败!");
        }
    }

    /**
     * 非对称加密数据
     *
     * @param input : 原文
     * @param key   : 密钥
     * @return : 密文
     * @throws Exception
     */
    public static String encryptByAsymmetric(String input, Key key) {
        try {
            // 获取Cipher对象
            Cipher cipher = Cipher.getInstance(RSA);
            // 初始化模式(加密)和密钥
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] resultBytes = getMaxResultEncrypt(input, cipher);
            return Base64.encode(resultBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("加密失败!");
        }
    }

    /**
     * 非对称解密数据
     *
     * @param encrypted : 密文
     * @param key       : 密钥
     * @return : 原文
     * @throws Exception
     */
    public static String decryptByAsymmetric(String encrypted, Key key) {
        try {
            // 获取Cipher对象
            Cipher cipher = Cipher.getInstance(RSA);
            // 初始化模式(解密)和密钥
            cipher.init(Cipher.DECRYPT_MODE, key);
            return new String(getMaxResultDecrypt(encrypted, cipher));
        } catch (
                Exception e) {
            e.printStackTrace();
            throw new RuntimeException("解密失败!");
        }
    }

    /**
     * 分段处理加密数据
     *
     * @param input  : 加密文本
     * @param cipher : Cipher对象
     * @return
     */
    private static byte[] getMaxResultEncrypt(String input, Cipher cipher) throws Exception {
        byte[] inputArray = input.getBytes();
        int inputLength = inputArray.length;
        // 最大加密字节数,超出最大字节数需要分组加密
        int MAX_ENCRYPT_BLOCK = 117;
        // 标识
        int offSet = 0;
        byte[] resultBytes = {};
        byte[] cache = {};
        while (inputLength - offSet > 0) {
            if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
                offSet += MAX_ENCRYPT_BLOCK;
            } else {
                cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
                offSet = inputLength;
            }
            resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
            System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
        }
        return resultBytes;
    }

    /**
     * 分段处理解密数据
     *
     * @param decryptText : 加密文本
     * @param cipher      : Cipher对象
     * @throws Exception
     */
    private static byte[] getMaxResultDecrypt(String decryptText, Cipher cipher) throws Exception {
        byte[] inputArray = Base64.decode(decryptText.getBytes(StandardCharsets.UTF_8));
        int inputLength = inputArray.length;

        // 最大解密字节数,超出最大字节数需要分组加密
        int MAX_ENCRYPT_BLOCK = 128;
        // 标识
        int offSet = 0;
        byte[] resultBytes = {};
        byte[] cache = {};
        while (inputLength - offSet > 0) {
            if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
                offSet += MAX_ENCRYPT_BLOCK;
            } else {
                cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
                offSet = inputLength;
            }
            resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
            System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
        }
        return resultBytes;
    }
}

效果:
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一恍过去

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

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

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

打赏作者

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

抵扣说明:

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

余额充值