java - Java 中相同的密码会产生不同的 AES key

标签 java encryption aes

我正在尝试使用 Java 跨两个设备实现 AES 加密的基本示例。然而,每次我们运行应用程序时,在两台设备上使用相同的密码(128 位)来生成 AES key 会导致两台设备上的 key 不同。因此我们无法解密在设备之间发送的文本。

我使用的方法如下,它们是我在其他地方找到的代码的稍微修改版本:

public String encryptMessage(String message, String password) throws Exception {

    // Creating key and cipher
    SecretKeySpec aesKey = new SecretKeySpec(password.getBytes("UTF-8"), "AES");


    byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    //AES cipher
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

    // encrypt the text
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivspec);

    byte[] encrypted;

    encrypted = cipher.doFinal(message.getBytes());

    return new String(encrypted, "UTF-8");
}

public String decryptMessage(String encryptedMessage, String password) throws Exception {

    // Creating key and cipher
    byte[] passwordBytes = password.getBytes("UTF-8");

    SecretKeySpec aesKey = new SecretKeySpec(passwordBytes, "AES");

    byte[] iv = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    //AES cipher
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

    // decrypting the text
    cipher.init(Cipher.DECRYPT_MODE, aesKey, ivspec);
    String decrypted = new String(cipher.doFinal(encryptedMessage.getBytes(Charset.forName("UTF-8"))));

    //returning decrypted text
    return decrypted;
}

每次我运行此代码并打印出 aesKey 时,它都是不同的。

我对 AES 和对称加密的理解是,给定相同的密码,它应该生成相同的 key ,否则它如何能够解密文物? 我是否对 AES 搞错了,或者有人可以建议可能发生的情况吗?

最佳答案

您的理解是正确的,并且代码中的 key 是相同的。

您无法“打印”aesKey,因为 SecretKeySpec 没有 toString() 方法。因此会调用内置的Object.toString(),它只是打印内存中对象的地址

javax.crypto.spec.SecretKeySpec@14c7f    // <--- useless info //

您的代码存在一些问题:

  • 不要将加密字节转换为 UTF-8 字符串。可能存在在 UTF-8 中无效的组合以及 00 字节。使用 Base64 或 Hex 编码打印加密数据。

  • 您不应使用 ASCII 字节作为 key ,这会大大降低 key 的安全性。 从密码中派生 key ,至少使用 SHA-256,但最好使用 PBKDF2 或 scrypt。

  • 使用高熵随机 IV 并将其与密文一起存储。

这是一个更新版本,证明它正在工作:

public static String encryptMessageGH(String message, String password) throws Exception {
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    byte[] key = sha.digest(password.getBytes("UTF-8"));
    SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
    byte[] iv = new byte[16];
    new SecureRandom().nextBytes(iv);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, new IvParameterSpec(iv));
    byte[] ciphertext = cipher.doFinal(message.getBytes());
    byte[] encrypted = new byte[iv.length + ciphertext.length];
    System.arraycopy(iv, 0, encrypted, 0, iv.length);
    System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
    return Base64.getEncoder().encodeToString(encrypted);
}

public static String decryptMessageGH(String encryptedMessage, String password) throws Exception {
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    byte[] key = sha.digest(password.getBytes("UTF-8"));
    SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
    byte[] encrypted = Base64.getDecoder().decode(encryptedMessage);
    byte[] iv = new byte[16];
    System.arraycopy(encrypted, 0, iv, 0, iv.length);
    byte[] ciphertext = new byte[encrypted.length - iv.length];
    System.arraycopy(encrypted, iv.length, ciphertext, 0, ciphertext.length);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(iv));
    return new String(cipher.doFinal(ciphertext), "UTF-8");
}

public static void main(String[] args) throws Exception {
    String orig = "Test message";
    String enc = encryptMessageGH(orig, "abcdef123");
    System.out.println("Encrypted: " + enc);
    String dec = decryptMessageGH(enc, "abcdef123");
    System.out.println("Decrypted: " + dec);
}

输出:

Encrypted: lcqcd9UZpjLSY9SsQ/N7kV/cpdzL3c7HQcCSiIs6p/k=
Decrypted: Test message

关于java - Java 中相同的密码会产生不同的 AES key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52515653/

相关文章:

java - 服务器关闭后 Quartz 作业重新触发

java - 如何从java中的字符串中提取子字符串

javascript - 不同的 AES 实现不一致

java - “陷害”tomcat6 丢失 session

Java 8 Predicate - 为什么不能连接通配符泛型谓词?

iis - 如何在 IIS 中查找加密和哈希算法信息?

c++ - OpenSSL AES 仅适用于某些机器,即使使用静态链接也是如此

没有填充的 Java AES

ios - AES256 加密在 node.js 和 objective-c 之间得到不同的结果

凯撒密码 (C) : Read from textfile