2024-03-21
原文作者:小小工匠 原文地址: https://artisan.blog.csdn.net/article/details/136491951

202403212042359911.png


Pre

加密与安全_探索非对称加密算法_RSA算法


概述

在数字化时代,网络通信的安全性是必须关注的重要问题之一。非对称加密算法作为现代密码学的重要组成部分,为保护通信的隐私提供了一种可靠的解决方案。


什么是非对称加密算法?

非对称加密算法,又称为公钥加密算法,是一种密码学中的重要概念。它与传统的对称加密算法不同,需要一对密钥:公钥和私钥。这对密钥之间存在着特殊的数学关系,但无法通过公钥推导出私钥,从而保证了通信的安全性。

如何工作?

当发送方A希望将数据发送给接收方B时,A可以使用B的公钥对数据进行加密,得到密文。只有拥有对应私钥的B才能解密这个密文。同样地,B也可以使用A的公钥加密数据,只有A持有私钥才能解密。这种加密和解密使用不同的密钥的特点,使得非对称加密算法成为了保护通信隐私的重要工具。

示例:RSA算法

RSA算法是非对称加密算法中最常见的一种,它利用了大数分解的数学难题,保证了通信的安全性。在RSA算法中,公钥是公开的,私钥是保密的。发送方使用接收方的公钥对数据进行加密,而接收方使用自己的私钥进行解密,从而实现了安全的通信。

特点和优势

  • 加密和解密使用不同的密钥,提高了通信的安全性。
  • 如果使用私钥加密,只能使用公钥解密;反之亦然。
  • 非对称加密算法安全性高,但处理数据速度较慢。

ECC:另一种非对称加密算法

除了RSA算法,还有一种备受关注的非对称加密算法,即椭圆曲线密码学(ECC)。ECC利用了椭圆曲线上的数学难题,相比RSA算法,它能够以更短的密钥长度实现相当于甚至更高的安全级别,同时在资源受限的环境下拥有更好的性能表现。


Code

生成公钥和私钥

    package com.artisan;
    
    import com.sun.org.apache.xml.internal.security.utils.Base64;
    
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    
    /**
     * @author 小工匠
     * @version 1.0 
     */
    public class RsaKeyPair {
    
        public static void main(String[] args) throws Exception {
    
            // 指定加密算法为RSA
            String algorithm = "RSA";
            // 创建密钥对生成器对象
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
            // 生成RSA密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 获取生成的私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 获取生成的公钥
            PublicKey publicKey = keyPair.getPublic();
            // 获取私钥的编码字节数组
            byte[] privateKeyEncoded = privateKey.getEncoded();
            // 获取公钥的编码字节数组
            byte[] publicKeyEncoded = publicKey.getEncoded();
            // 对公私钥的编码字节数组进行Base64编码
            String privateKeyString = Base64.encode(privateKeyEncoded);
            String publicKeyString = Base64.encode(publicKeyEncoded);
    
            // 打印私钥的Base64编码字符串
            System.out.println(privateKeyString);
    
            System.out.println("----------------------------------");
    
            // 打印公钥的Base64编码字符串
            System.out.println(publicKeyString);
        }
    }

使用RSA算法生成一个密钥对,并将私钥和公钥进行Base64编码后打印出来了。

202403212042367662.png


私钥加密

    package com.artisan;
    
    import com.sun.org.apache.xml.internal.security.utils.Base64;
    
    import javax.crypto.Cipher;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    
    /**
     * @author 小工匠
     * @version 1.0
     * @mark: 显示代码,改变世界
     */
    public class PrivateKeyEnc {
        public static void main(String[] args) throws Exception {
            String input = "小工匠的IT生活";
            // 指定加密算法为RSA
            String algorithm = "RSA";
            // 创建密钥对生成器对象
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
            // 生成RSA密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 获取生成的私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 获取生成的公钥
            PublicKey publicKey = keyPair.getPublic();
            // 获取私钥的编码字节数组
            byte[] privateKeyEncoded = privateKey.getEncoded();
            // 获取公钥的编码字节数组
            byte[] publicKeyEncoded = publicKey.getEncoded();
            // 对公私钥的编码字节数组进行Base64编码
            String privateKeyString = Base64.encode(privateKeyEncoded);
            String publicKeyString = Base64.encode(publicKeyEncoded);
    
            // 打印生成的密钥对
            System.out.println("私钥(Base64编码): " + privateKeyString);
            System.out.println("公钥(Base64编码): " + publicKeyString);
    
            // 创建加密对象,参数表示加密算法
            Cipher cipher = Cipher.getInstance(algorithm);
            // 初始化加密对象
            // 第一个参数:加密模式
            // 第二个参数:使用私钥进行加密
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            // 使用私钥加密输入的字符串
            byte[] encryptedBytes = cipher.doFinal(input.getBytes());
            // 对加密后的字节数组进行Base64编码,并打印
            System.out.println("加密后的字符串(Base64编码): " + Base64.encode(encryptedBytes));
        }
    }

私钥加密私钥解密 ( 行不通 )

在上面的代码上追加

    // 私钥进行解密 (错误的演示)
    cipher.init(Cipher.DECRYPT_MODE,privateKey);
     // 对密文进行解密,不需要使用base64,因为原文不会乱码
     byte[] bytes1 = cipher.doFinal(encryptedBytes);
     System.out.println(new String(bytes1));

202403212042373053.png


私钥加密公钥解密

将上述代码的 私钥解密,换成使用公钥解密

    // 公钥进行解密
    cipher.init(Cipher.DECRYPT_MODE,publicKey);
    // 对密文进行解密,不需要使用base64,因为原文不会乱码
    byte[] bytes1 = cipher.doFinal(encryptedBytes);
    System.out.println("解密后的字符串: " + new String(bytes1));

202403212042377794.png


公钥加密和公钥解密 (行不通)

202403212042382075.png

202403212042386016.png


保存公钥和私钥

生成RSA非对称加密算法的密钥对,并将生成的公钥和私钥保存在本地文件中。

    package com.artisan;
    
    import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.nio.charset.Charset;
    import java.security.*;
    
    public class KeyPairOperate {
    
        public static void main(String[] args) throws Exception {
            // 加密算法
            String algorithm = "RSA";
    
            // 生成密钥对并保存在本地文件中
            generateKeyToFile(algorithm, "a.pub", "a.pri");
        }
    
        /**
         * 生成密钥对并保存在本地文件中
         *
         * @param algorithm : 算法
         * @param pubPath   : 公钥保存路径
         * @param priPath   : 私钥保存路径
         * @throws Exception
         */
        private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
            // 获取密钥对生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
            // 获取密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 获取公钥
            PublicKey publicKey = keyPair.getPublic();
            // 获取私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 获取byte数组
            byte[] publicKeyEncoded = publicKey.getEncoded();
            byte[] privateKeyEncoded = privateKey.getEncoded();
            // 进行Base64编码
            String publicKeyString = Base64.encode(publicKeyEncoded);
            String privateKeyString = Base64.encode(privateKeyEncoded);
            // 保存文件
            FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
            FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
    
        }
    }

202403212042390577.png


读取私钥

    // 读取私钥
    PrivateKey privateKey = readPrivateKeyFromFile(algorithm, "a.pri");
    
     byte[] encoded = privateKey.getEncoded();
     String privateContent = Base64.encode(encoded);
     System.out.println("私钥内容:" + privateContent);
     /**
         * @param algorithm
         * @param filePath
         * @return
         * @throws Exception
         */
        private static PrivateKey readPrivateKeyFromFile(String algorithm, String filePath) throws Exception {
            // 从文件中读取私钥字符串
            String privateKeyString = FileUtils.readFileToString(new File(filePath), StandardCharsets.UTF_8);
            // 进行Base64解码
            byte[] privateKeyEncoded = Base64.decode(privateKeyString);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            // 构建密钥规范 进行Base64解码
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
            return keyFactory.generatePrivate(spec);
        }

202403212042393718.png
看下生成的文件中的内容:

202403212042398659.png


读取公钥

    // 读取公钥
    PublicKey publicKey = readPublicKeyFromFile(algorithm, "a.pub");
    
    byte[] publicKeyEncoded = publicKey.getEncoded();
    String publicContent = Base64.encode(publicKeyEncoded);
    System.out.println("公钥内容:" + publicContent);
     /**
         * @param algorithm
         * @param filePath
         * @return
         * @throws Exception
         */
        private static PublicKey readPublicKeyFromFile(String algorithm, String filePath) throws Exception {
            // 将文件内容转为字符串
            String publicKeyString = FileUtils.readFileToString(new File(filePath), StandardCharsets.UTF_8);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            // 构建密钥规范 进行Base64解码
            X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
            // 生成公钥
            return keyFactory.generatePublic(spec);
        }

2024032120424051510.png

2024032120424094111.png


使用读取的公钥加密,私钥解密

    // 使用公钥私钥实现加解密
    String text = "小工匠的IT生活";
    System.out.println("原文:" + text);
    
    
    String enc = encryptRSA(algorithm, publicKey, text);
    System.out.println("公钥加密后的数据:" + enc);
    
    String plainText = decryptRSA(algorithm, privateKey, enc);
    System.out.println("私钥解密后的数据:" + plainText);
     /**
         * 解密数据
         *
         * @param algorithm : 算法
         * @param encrypted : 密文
         * @param key       : 密钥
         * @return : 原文
         * @throws Exception
         */
        public static String decryptRSA(String algorithm, Key key, String encrypted) throws Exception {
            // 创建加密对象
            // 参数表示加密算法
            Cipher cipher = Cipher.getInstance(algorithm);
            // 私钥进行解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            // 由于密文进行了Base64编码, 在这里需要进行解码
            byte[] decode = Base64.decode(encrypted);
            // 对密文进行解密,不需要使用base64,因为原文不会乱码
            byte[] bytes1 = cipher.doFinal(decode);
            return new String(bytes1);
    
        }
    
        /**
         * 使用密钥加密数据
         *
         * @param algorithm : 算法
         * @param input     : 原文
         * @param key       : 密钥
         * @return : 密文
         * @throws Exception
         */
        public static String encryptRSA(String algorithm, Key key, String input) throws Exception {
            // 创建加密对象
            // 参数表示加密算法
            Cipher cipher = Cipher.getInstance(algorithm);
            // 初始化加密
            // 第一个参数:加密的模式
            // 第二个参数:使用私钥进行加密
            cipher.init(Cipher.ENCRYPT_MODE, key);
            // 私钥加密
            byte[] bytes = cipher.doFinal(input.getBytes());
            // 对密文进行Base64编码
            return Base64.encode(bytes);
        }

2024032120424135112.png

Source

    package com.artisan;
    
    import com.sun.org.apache.xml.internal.security.utils.Base64;
    import org.apache.commons.io.FileUtils;
    
    import javax.crypto.Cipher;
    import java.io.File;
    import java.nio.charset.Charset;
    import java.nio.charset.StandardCharsets;
    import java.security.*;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    /**
     * @author 小工匠
     * @version 1.0
     * @mark: show me the code , change the world
     */
    public class KeyPairOperate {
    
        public static void main(String[] args) throws Exception {
            // 加密算法
            String algorithm = "RSA";
    
            // 生成密钥对并保存在本地文件中
            generateKeyToFile(algorithm, "a.pub", "a.pri");
    
            // 读取私钥
            PrivateKey privateKey = readPrivateKeyFromFile(algorithm, "a.pri");
    
            byte[] encoded = privateKey.getEncoded();
            String privateContent = Base64.encode(encoded);
            System.out.println("私钥内容:" + privateContent);
    
    
            // 读取公钥
            PublicKey publicKey = readPublicKeyFromFile(algorithm, "a.pub");
    
            byte[] publicKeyEncoded = publicKey.getEncoded();
            String publicContent = Base64.encode(publicKeyEncoded);
            System.out.println("公钥内容:" + publicContent);
    
    
            // 使用公钥私钥实现加解密
            String text = "小工匠的IT生活";
            System.out.println("原文:" + text);
    
    
            String enc = encryptRSA(algorithm, publicKey, text);
            System.out.println("公钥加密后的数据:" + enc);
    
            String plainText = decryptRSA(algorithm, privateKey, enc);
            System.out.println("私钥解密后的数据:" + plainText);
    
        }
    
    
        /**
         * 解密数据
         *
         * @param algorithm : 算法
         * @param encrypted : 密文
         * @param key       : 密钥
         * @return : 原文
         * @throws Exception
         */
        public static String decryptRSA(String algorithm, Key key, String encrypted) throws Exception {
            // 创建加密对象
            // 参数表示加密算法
            Cipher cipher = Cipher.getInstance(algorithm);
            // 私钥进行解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            // 由于密文进行了Base64编码, 在这里需要进行解码
            byte[] decode = Base64.decode(encrypted);
            // 对密文进行解密,不需要使用base64,因为原文不会乱码
            byte[] bytes1 = cipher.doFinal(decode);
            return new String(bytes1);
    
        }
    
        /**
         * 使用密钥加密数据
         *
         * @param algorithm : 算法
         * @param input     : 原文
         * @param key       : 密钥
         * @return : 密文
         * @throws Exception
         */
        public static String encryptRSA(String algorithm, Key key, String input) throws Exception {
            // 创建加密对象
            // 参数表示加密算法
            Cipher cipher = Cipher.getInstance(algorithm);
            // 初始化加密
            // 第一个参数:加密的模式
            // 第二个参数:使用私钥进行加密
            cipher.init(Cipher.ENCRYPT_MODE, key);
            // 私钥加密
            byte[] bytes = cipher.doFinal(input.getBytes());
            // 对密文进行Base64编码
            return Base64.encode(bytes);
        }
    
    
        /**
         * @param algorithm
         * @param filePath
         * @return
         * @throws Exception
         */
        private static PublicKey readPublicKeyFromFile(String algorithm, String filePath) throws Exception {
            // 将文件内容转为字符串
            String publicKeyString = FileUtils.readFileToString(new File(filePath), StandardCharsets.UTF_8);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            // 构建密钥规范 进行Base64解码
            X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
            // 生成公钥
            return keyFactory.generatePublic(spec);
        }
    
    
        /**
         * @param algorithm
         * @param filePath
         * @return
         * @throws Exception
         */
        private static PrivateKey readPrivateKeyFromFile(String algorithm, String filePath) throws Exception {
            // 从文件中读取私钥字符串
            String privateKeyString = FileUtils.readFileToString(new File(filePath), StandardCharsets.UTF_8);
            // 进行Base64解码
            byte[] privateKeyEncoded = Base64.decode(privateKeyString);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            // 构建密钥规范 进行Base64解码
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
            return keyFactory.generatePrivate(spec);
        }
    
    
        /**
         * 生成密钥对并保存在本地文件中
         *
         * @param algorithm : 算法
         * @param pubPath   : 公钥保存路径
         * @param priPath   : 私钥保存路径
         * @throws Exception
         */
        private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
            // 获取密钥对生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
            // 获取密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 获取公钥
            PublicKey publicKey = keyPair.getPublic();
            // 获取私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 获取byte数组
            byte[] publicKeyEncoded = publicKey.getEncoded();
            byte[] privateKeyEncoded = privateKey.getEncoded();
            // 进行Base64编码
            String publicKeyString = Base64.encode(publicKeyEncoded);
            String privateKeyString = Base64.encode(privateKeyEncoded);
            // 保存文件
            FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
            FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
    
        }
    }

2024032120424181413.png

阅读全文