使用shiro和aes加密遇到的一些问题

使用shiro和aes加密遇到的一些问题

背景说明

  1. 游戏服务器领域。
  2. client使用账号信息与平台交互,平台返回一个凭据(内部包含了敏感信息)。
  3. client拿到凭据后,向登入服发起登入请求。
  4. 登入服对凭证进行校验,解密出一些关键数据,然后触发登入处理逻辑。

使用shiro和aes加密遇到的一些问题_第1张图片

相关代码

    /**
     * 根据密钥生成一个用于aes的key。
     */
    public static SecretKey getSecretKey(int bits, String secret) {
        KeyGenerator keyGenerator = null;
        try {
            keyGenerator = KeyGenerator.getInstance("AES");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("aes[" + bits + "] not supported", e);
        }

        keyGenerator.init(bits, new SecureRandom(secret.getBytes()));
        return keyGenerator.generateKey();
    }

    /**
     * 对文本进行加密。
     *
     * @param text 将被加密的文本
     * @param secretKey 用于加密的key
     * @return 已被加密的文本
     */
    public static String encrypt(String text, SecretKey secretKey) {
        ByteSource byteSource = aesCipherService.encrypt(text.getBytes(), secretKey.getEncoded());
        return byteSource.toHex();
    }

    /**
     * 对被加密的文本进行解密。
     *
     * @param encryptedText 已被加密的文本
     * @param secretKey 用于解密的key
     * @return 解密后的内容
     */
    public static String decrypt(String encryptedText, SecretKey secretKey) {
        ByteSource byteSource = aesCipherService.decrypt(Hex.decode(encryptedText), secretKey.getEncoded());
        return new String(byteSource.getBytes());
    }

遇到的问题

在本地机器上运行了平台项目和登入服项目。
平台项目中返回的凭据,在登入服上进行解密会失败。

之前以为是shiro版本问题,平台用的是1.4.0,登入服用的是1.5.3,后来改成相同版本,发现不是这个问题。

为了排查问题,又启动了一个专门写java测试代码的项目,将加密和解密代码放到里面运行,结果出现了一个更诡异的事情。
在测试项目中得到的加密凭据,可以在登入服解密,但是在平台上解密会失败。

经过调试,发现平台生成的key字节数组(secretKey.getEncoded())和其它项目的不一样。
通过对比这几个项目的配置,发现jdk版本不一样:平台用的是jdk1.8.0_251,登入服和测试项目用的是jdk11.0.7。

通过在不同版本的jdk运行这段代码,得到了不同的结果。

    byte[] seed = "3X0m2+Kp@zj@ORr*xttVk7~ce&aT22.m^z#j,Zzj".getBytes();
    for (int i = 0; i < 10; ++i) {
        SecretKey secretKey = AesUtils.getSecretKey(128, "3X0m2+Kp@zj@ORr*xttVk7~ce&aT22.m^z#j,Zzj");
        System.out.println(Arrays.toString(secretKey.getEncoded()));
    }

    jdk1.8.0_251
    [32, 58, -78, 112, 122, 104, -86, -51, -77, 110, 122, -33, -123, 124, -13, -20]
    [32, 58, -78, 112, 122, 104, -86, -51, -77, 110, 122, -33, -123, 124, -13, -20]
    [32, 58, -78, 112, 122, 104, -86, -51, -77, 110, 122, -33, -123, 124, -13, -20]
    [32, 58, -78, 112, 122, 104, -86, -51, -77, 110, 122, -33, -123, 124, -13, -20]

    jdk11.0.7
    [93, -22, 110, 6, -100, 109, -9, -6, -65, 5, 30, 36, 55, -92, -27, -102]
    [102, 52, -27, -55, 127, 96, -110, -72, 58, 37, -106, -98, -23, 86, 27, 9]
    [-48, -18, -91, -34, -116, 15, -61, 57, -56, 104, 116, 118, -63, -106, 26, 75]
    [-21, 97, 49, 126, 123, 103, 104, 40, -51, 99, 98, 8, 84, 41, -14, 54]

可以看到,在jdk8中,只要种子一样,SecureRandom每次生成的字节数组都一样;在jdk11中,每次生成的字节数组不一样。

结论

aes的字节数组key,提前生成就可以了,可以不用SecureRandom方式在运行时生成。

jdk版本引起的SecureRandom问题违反了直觉。

你可能感兴趣的:(Java,遇到的问题)