欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AES加密过程分析

程序员文章站 2024-03-14 14:34:04
...

最近做前后端AES加解密遇到了一个麻烦的问题,因为之前只是按照网上的Demo照着Copy了一份,当时测试可用:

  public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
        return cipher.doFinal(stringToBytes(content));
    }
/**
Cipher 类为加密和解密提供密码功能
Cipher 的 getInstance ()参数有两种格式:“算法/模式/填充”或“算法”,后一种情况下,
使用模式和填充方案特定于提供者的默认值
cipher.init(a,b),两个参数:a表示当前的加密模式,b代表用于加密的最终**
public static final int ENCRYPT_MODE  用于将 Cipher 初始化为加密模式的常量。
public static final int DECRYPT_MODE  用于将 Cipher 初始化为解密模式的常量。
public static final int WRAP_MODE     用于将 Cipher 初始化为**包装模式的常量。
public static final int UNWRAP_MODE   用于将 Cipher 初始化为**解包模式的常量。
public static final int PUBLIC_KEY    用于表示要解包的**为“公钥”的常量。
public static final int PRIVATE_KEY   用于表示要解包的**为“私钥”的常量。
public static final int SECRET_KEY    用于表示要解包的**为“秘***”的常量。

*/

这里我们把约定的加密Key:encryptKey直接转为byte[]数组的形式来用于加密:encryptKey.getBytes()。我们知道AES加密是分段加密的,不清楚的可以参考:AES详解,每一段的长度是约定好的,128或256,同时,**Key长度也是定好的,128或192或256。因为AES是对称加密,也就是加密完的东西要能完整的解密出来,所以这些约定的规则很重要。刚刚的代码,我们把约定的key直接用于加密了,所以约定的key长度也必须符合128/192/256位。当我们希望key更随意,不是必须为32位的倍数时,我们需要在执行加密前对**做一次加工:

KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(stringToBytes(encryptKey));
kgen.init(256, secureRandom);

Cipher cipher = Cipher.getInstance("AES");
byte[] tt=  kgen.generateKey().getEncoded();
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(tt, ENCRYPT_AES_TYPE));
return cipher.doFinal(stringToBytes(content));

这里我们没有直接对**encryptKey.getBytes(),而是利用KeyGenerator 和SecureRandom 两个类对**先做处理,将其转化为32的倍数位。SecureRandom.getInstance("SHA1PRNG")指定使用随机数的算法, secureRandom.setSeed(stringToBytes(encryptKey))指定随机数生成的种子,它的实现是伪随机数生成器 (PRNG) 形式,这意味着它们将使用确定的算法根据实际的随机种子生成伪随机序列。kgen.init(256, secureRandom)指定生成的**位数是256位,随机源是刚刚的随机数对象。这样当我们使用 kgen.generateKey().getEncoded();生成**时,**就是256位的根据约定的encryptKey产生的新的**了。

前端我们使用的是JS库CryptoJs,如何对应实现和java匹配的加密呢?先安装CryptoJs.js包,再用法如下:

encrypt(word) {
    const key = CryptoJS.enc.Hex.parse("这里是真实的**,16位字符串形式");//方式一
//  const key = CryptoJS.enc.Utf8.parse("这里是约定的**,普通字符串形式");//方式二
    const srcs = CryptoJS.enc.Utf8.parse(word);
    const encrypted = CryptoJS.AES.encrypt(srcs, key, {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.ciphertext.toString();
  }

我遇到的问题是直接把双方约定的**按方式二的形式使用。但是我们知道,我们上面真正解密前是对约定的**做了处理的,所以这里不能直接用,否则必然不匹配。

怎么办呢?,很简单,只需要把处理后的结果拷贝过来当作最终**就好了!

上述java代码中: 
byte[] tt=  kgen.generateKey().getEncoded();
//得到字符数组,再将数组转化为16进制字符串如:6D6F6FB1290134B63038E7B384E89A7F79CBCFB3F7B235580742C70F5B3AF269

用这个**当作最终**,就可以前后端加解密成功了。

这里贴出一个CrypJs的快速开发指南:https://blog.csdn.net/u013821237/article/details/83176037

非常的有用!

相关标签: AES