• 对称加密算法———AES算法


    目录

    一、什么是对称加密算法

    二、常用的对称加密算法

    三、AES算法

    1、ECB工作模式

    2、CBC工作模式

    3、小结

    四、非对称加密算法

    五、对称加密算法与非对称加密算法的区别


    一、什么是对称加密算法

    对称加密算法就是用一个秘钥进行加密和解密。

    从程序的角度看:

    加密:一个函数,接收密码和明文,然后输出密文

    解密:一个函数,接收密文和密码,然后输出明文

    二、常用的对称加密算法

    在软件开发的过程中,常用的对称加密算法有:

     本篇博客以AES算法为例,实现对称加密。

    三、AES算法

      在AES算法中常用的是ECBCBC两种工作模式,我们分别来介绍:

    1、ECB工作模式

    在ECB工作模式下,我们的秘钥是固定的,这里为了方便大家理解,加密与解密的过程使用方法来进行封装。在主函数里直接调用加密与解密的方法。

    1. //原文
    2. String message = "hello";
    3. System.out.println("Message:" + message);
    4. //128位秘钥 = 16 bytes key:
    5. byte[] key = "987654321zxcvbnm".getBytes();
    6. //加密
    7. byte[] data = message.getBytes();
    8. byte[] encrypted = encrypt(key, data);
    9. System.out.println("Encrypted(加密) :" + Base64.getEncoder().encodeToString(encrypted));
    10. //解密
    11. byte[] decrypted = decrypt(key, encrypted);
    12. System.out.println("解密:" + new String(decrypted));

    加密:

    1.创建密码对象,需要传入算法名称/工作模式/填充模式,这里使用ECB工作模式

    2.根据我们写入的16字节的秘钥,使用SecretKey来恢复秘钥(秘钥必须是指定长度的)

    3.初始化秘钥,设置加密模式

    1. //加密
    2. public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException {
    3. //创建密码对象,需要传入算法名称/工作模式/填充模式
    4. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    5. //根据key的字节内容,“恢复”秘钥
    6. SecretKey keySpec = new SecretKeySpec(key,"AES");
    7. //初始化秘钥:设置加密模式
    8. cipher.init(Cipher.ENCRYPT_MODE, keySpec);
    9. //根据原始内容(字节),进行加密
    10. return cipher.doFinal(input);
    11. }

    解密:

    解密与加密唯一不同的是:在初始化过程中设置的是解密模式

    1. public static byte[] decrypt (byte[] key ,byte[] input) throws GeneralSecurityException{
    2. //创建密码对象,需要传入算法名称/工作模式/填充模式
    3. Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    4. //根据key的字节内容,“恢复”秘钥
    5. SecretKey keySpec = new SecretKeySpec(key,"AES");
    6. //初始化秘钥:设置解密模式
    7. cipher.init(Cipher.DECRYPT_MODE, keySpec);
    8. //根据原始内容(字节),进行加密
    9. return cipher.doFinal(input);
    10. }

    2、CBC工作模式

    CBC的算法步骤大致相同,与EBC最大的不同之处,就是CBC多了一个动态IV,一个随机数作为参数,相同的明文,每次产生的密文都不同。

    加密:

    与EBC相比多了一个需要使用SecureRandom 实例化一个对象,来生成一个16字节的随机数,把它存放在一个字节数组,将随机数封装成ParameterSpec对象。

    在初始化秘钥的时候,把这个参数iv一起传进去。

    最后在调用一个数组合并的方法将iv与传入的数据都返回出去

    1. //加密
    2. public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException {
    3. //创建密码对象,需要传入算法名称/CBC工作模式/填充模式
    4. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    5. //根据key的字节内容,“恢复”秘钥
    6. SecretKey keySpec = new SecretKeySpec(key,"AES");
    7. //CBC模式需要生成一个16bytes的initialization vector:
    8. SecureRandom sr = SecureRandom.getInstanceStrong();
    9. byte[] iv = sr.generateSeed(16); //生成16个字节的随机数
    10. IvParameterSpec ivps = new IvParameterSpec(iv); //随机数封装成IvParameterSpec对象
    11. //初始化秘钥:设置加密模式、秘钥、iv
    12. cipher.init(Cipher.ENCRYPT_MODE, keySpec,ivps);
    13. //进行加密
    14. byte[] data = cipher.doFinal(input);
    15. //IV不需要保密,把IV和密文一起返回
    16. return join(iv, data);
    17. }

    数组合并:

    1. //合并数组
    2. public static byte[] join(byte[] bs1,byte[] bs2) {
    3. byte[] r = new byte[bs1.length + bs2.length];
    4. System.arraycopy(bs1, 0, r, 0, bs1.length);
    5. System.arraycopy(bs2, 0, r, bs1.length,bs2.length);
    6. return r;
    7. }

    解密:

    我们需要将输入的内容分割成IV和密文,创建两个字节数组分别来保存。

    将分割出的iv封装成ParameterSpec对象ipvs,在秘钥初始化时,选择解密模式,连同秘钥一起传进去。

    最后调用doFinal()方法进行解密。

    1. public static byte[] decrypt (byte[] key ,byte[] input) throws GeneralSecurityException{
    2. //把input分割成IV和密文
    3. byte[] iv = new byte[16];
    4. byte[] data = new byte[input.length - 16];
    5. System.arraycopy(input, 0, iv, 0, 16); //IV
    6. System.arraycopy(input, 16, data, 0, data.length); //密文
    7. //解密:
    8. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    9. //根据key的字节内容,“恢复”秘钥
    10. SecretKey keySpec = new SecretKeySpec(key,"AES");
    11. IvParameterSpec ivps = new IvParameterSpec(iv);
    12. //初始化秘钥:设置解密模式、秘钥、IV参数
    13. cipher.init(Cipher.DECRYPT_MODE, keySpec,ivps);
    14. //解密
    15. return cipher.doFinal(data);
    16. }

    3、小结

            两种工作模式,ECB模式采用固定秘钥,安全性略低,CBC模式使用动态随机数iv,来保证安全性更高,其实不论是ECB模式还是CBC模式,在进行解密与加密的过程中,步骤大致相似,只有在初始化秘钥是,选择的模式不同:加密使用的是==>Cipher.ENCRYPT_MODE,解密使用的是==>Cipher.DECRYPT_MODE,但自始至终使用的都是同一个秘钥,这就是对称加密算法。

    四、非对称加密算法

    非对称加密算法也叫RSA算法。       

    与对称加密算法不同的是,进行加密与解密使用的是不同的秘钥,只有一个公钥-私钥,秘钥对才可以正常的加解密。

    例如:如果我向小王准备发送一个加密文件,我需要先得到小王的公钥进行加密,而在进行解密的过程中,只有小王的与之匹配的私钥才可以进行解密,除此之外,任何人都解不开。

    非对称加密的优点:  对称加密需要协商密钥,而非对称加密可以安全地公开各自的公钥,在N个人之间通信的时候:使用非对称加密只需要N个密钥对,每个人只管理自己的密钥对。而使用对称加密需要则需要N(N-1)/2个密钥,因此每个人需要管理N 1个密钥,密钥管理难度大,而且非常容易泄漏。
    非对称加密的缺点:运算速度非常慢,比对称加密要慢很多。

    具体实现步骤如下:

    为了方便我们使用,我们把加密与解密的过程封装在方法中。

    第一步:我们需要一个用户类,有用户的姓名,公钥、私钥、及构造方法,传入当前对象的名字,以及实例化一个KeyPairGenerator 对象调用generateKeyPair()方法生成一对儿秘钥。

    1. // 用户类
    2. class Human {
    3. // 姓名
    4. String name;
    5. // 私钥:
    6. PrivateKey sk;
    7. // 公钥:
    8. PublicKey pk;
    9. // 构造方法
    10. public Human(String name) throws GeneralSecurityException {
    11. // 初始化姓名
    12. this.name = name;
    13. // 生成公钥/私钥对:
    14. KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
    15. kpGen.initialize(1024);
    16. KeyPair kp = kpGen.generateKeyPair();
    17. this.sk = kp.getPrivate();
    18. this.pk = kp.getPublic();
    19. }
    20. }

    第二步:把生成的秘钥对编码成字节

    1. // 把私钥导出为字节
    2. public byte[] getPrivateKey() {
    3. return this.sk.getEncoded();
    4. }
    5. // 把公钥导出为字节
    6. public byte[] getPublicKey() {
    7. return this.pk.getEncoded();
    8. }

    第三步:使用公钥进行加密

    1.使用Cipher 实例化对象声明使用的是RSA算法

    2.使用公钥进行初始化

    3.调用doFianl()方法进行加密,返回一个字节数组。

    1. // 用公钥加密:
    2. public byte[] encrypt(byte[] message) throws GeneralSecurityException {
    3. Cipher cipher = Cipher.getInstance("RSA");
    4. cipher.init(Cipher.ENCRYPT_MODE, this.pk); // 使用公钥进行初始化(使用公钥加密)
    5. return cipher.doFinal(message);
    6. }

    第四步:使用私钥进行解密

    与加密不同的是,在传入参数时,传入的字节数组是加密后的密文字节数组,初始化时,使用的是私钥。

    1. // 用私钥解密:
    2. public byte[] decrypt(byte[] input) throws GeneralSecurityException {
    3. Cipher cipher = Cipher.getInstance("RSA");
    4. cipher.init(Cipher.DECRYPT_MODE, this.sk); // 使用私钥进行初始化 (使用私钥解密)
    5. return cipher.doFinal(input);
    6. }

    在主函数调用想要的方法来完成:

    值得注意的是,在完成对象创建时,就已经在构造方法中创建好了一对秘钥对(公钥---私钥)

    1. public static void main(String[] args) throws Exception {
    2. // 明文:
    3. byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
    4. // 创建公钥/私钥对:
    5. Human alice = new Human("Alice");
    6. // 用Alice的公钥加密:
    7. // 获取Alice的公钥
    8. byte[] pk = alice.getPublicKey();
    9. // 使用公钥加密
    10. byte[] encrypted = alice.encrypt(plain);
    11. System.out.println(String.format("encrypted(加密): %x", new BigInteger(1, encrypted)));
    12. // 用Alice的私钥解密:
    13. // 获取Alice的私钥
    14. byte[] sk = alice.getPrivateKey();
    15. // 使用私钥解密
    16. byte[] decrypted = alice.decrypt(encrypted);
    17. System.out.println("解密:" + new String(decrypted, "UTF-8"));
    18. }

    五、对称加密算法与非对称加密算法的区别

    1、对称加密算法不论是在加密还是解密的过程中,使用的都是同一个秘钥,这也体现了它的对称性,而非对称加密算法使用的是一对儿秘钥(公钥---私钥),加密过程使用的是公钥,解密过程中只有使用同一个公钥--私钥对才可以解开,体现了不对称性。

    2.在安全性方面来看,非对称加密算法的安全性更高

    3.从运行速度来看:非对称加密的运行速度比对称加密慢得多

    对称加密算法非对称加密算法
    秘钥同一个秘钥一对儿秘钥
    安全性较低更高
    运行速度很慢

  • 相关阅读:
    webpack 开发环境一次
    css 写带三角形的对话框,空心的三角形边框
    2023-09-24 LeetCode每日一题(LRU 缓存)
    4. Java并发编程-管程
    vue基于promise可以用于浏览器和node.js的网络请求库【axios封装-收藏版】
    打开算法之门
    Windows系统Python语言环境下通过SDK进行动作捕捉数据传输
    SpringAOP入门
    「算法小记」-1:Ackermann函数/阿克曼函数的一点思考解法【递归/非递归/堆栈方法】(C++ )
    Linux系统防火墙iptables
  • 原文地址:https://blog.csdn.net/qq_59616295/article/details/125899109