【问题标题】:Java AES encryption issueJava AES 加密问题
【发布时间】:2019-12-11 02:35:00
【问题描述】:

每次使用 AES 更改加密值时,让任何人调查以下代码并让我知道问题

代码:

private static final String secretKeys = "58BA833E57A51CBF9BF8BAB696BF9"

public static String encrypt() throws Exception {
        byte[] salt = new byte[16];
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        PBEKeySpec pbeKeySpec = new PBEKeySpec(secretKeys.getChars(),salt,1000, 256);
        Key secretKey = factory.generateSecret(pbeKeySpec);
        byte[] key = new byte[32];
        byte[] iv = new byte[16];
        SecretKeySpec secret = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] result = cipher.doFinal("welcome".getBytes("UTF-8"));
        String s = Base64.getEncoder().encodeToString(result);
        return s
        }

输出 我第一次得到下面加密的字符串

CZRIP35M4CnJtuDQ6YpmaQ==

第二次得到下面加密的字符串

/fylTjohAZDsnCaHhiZo3A==

我有三个问题:

  1. 为什么加密的字符串不是常量?

  2. 如何设置块大小? (AES.BlockSize = 128;)

  3. 如何设置填充模式? (AES.Padding = PaddingMode.PKCS7;)

【问题讨论】:

  • 每次执行时 salt 的值是否会发生变化?
  • @Freiheit 抱歉,我不知道如何检查盐值?
  • 当我打印盐值时,它显示为 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  • 您是否意识到您总是使用一个全为 0 的字节数组作为您的密钥,而前 4 行代码没有做任何事情?而且你也从不使用 iv 吗?
  • 你为什么关心输出?重要的是它可以用相同的密钥解密。

标签: java encryption aes salt crypt


【解决方案1】:
  1. 对于第一个问题,@Freiheit 已经回答了this。 长话短说,基于作为盐的 iv(初始化向量),并且对于每个加密都会有所不同。 话虽如此,加密相同的纯文本将导致不同的加密文本,但解密(如果需要)将导致返回相同的纯文本。 IV 有助于使加密可预测。 在数据库中为 2 个不同的用户存储相同的密码将具有不同的值,但将是相同的密码。

  2. 配置当前密码后,您已经拥有 128 个块大小。您可以阅读更多关于不同密码转换的信息here。您还可以找到更多关于不同算法的块大小的信息here

  3. 您只需将Cipher.getInstance() 更改为AES/CBC/PKCS7Padding

【讨论】:

  • 1.嗯,有点,但 IV 和盐是不可互换的。 2. 是的。 3.没有。
【解决方案2】:

1) 加密文本总是不同的,因为 Cipher 初始化提供了它自己的 IV,因为您没有提供一个。您需要提供您“计算”的 IV 以获得一致的输出。请记住,无论这段代码最终打算做什么,您都不想多次使用 IV。

2) 密钥大小可以是 128、192 或 256,但块大小始终为 128。

3) Java 只提供 PKCS5,但 AES 的实现没有区别。见what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding

正如已经指出的那样,提供的代码存在几个问题,例如第一行实际上没有做任何事情,并且 key 和 iv 都未初始化。我还建议您使用 SecureRandom 来初始化您的密钥和 iv。如果您打算只使用单个 AES 密钥,则可以计算一次并将其放入代码或配置文件中,而不是每次都运行 PBKDF2。

【讨论】:

【解决方案3】:

仅添加@micker提供的答案,您需要调用另一个版本的Cipher.init();将 IV 考虑在内的一种:

...
byte[] iv = new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(iv); // <= Wrap your IV bytes here.
SecretKeySpec secret = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, ivSpec); // <= Add IV here.
...

话虽如此,实现还存在许多其他问题(键全为零,IV 全为零,前 4 行对您没有任何作用(正如@JBNizet 指出的那样))。我希望你只是用它来研究 Java 的加密机制是如何工作的。

【讨论】:

    猜你喜欢
    • 2012-01-18
    • 2011-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    • 2012-07-20
    • 2021-04-22
    • 2011-04-11
    相关资源
    最近更新 更多