gpt4 book ai didi

java - AES-128 加密不适用于 Java < 1.7

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:52:23 26 4
gpt4 key购买 nike

我已经为一项学校作业埋头苦干了 3 天,今天终于完成了它,没有错误并且工作正常!除了,我在 Java 1.7 上测试它,而学校服务器(教授将编译它的地方)运行 1.6。因此,我在 1.6 上测试了我的代码,想要涵盖我的所有基础,并且在解密时得到了一个 BadPaddingException

[编辑] 警告:此代码不遵循常见的安全实践,不应在生产代码中使用。

最初,我有这个,它在 1.7 上运行良好(抱歉,很多代码......所有相关......):

public static String aes128(String key, String data, final int direction) {
SecureRandom rand = new SecureRandom(key.getBytes());
byte[] randBytes = new byte[16];
rand.nextBytes(randBytes);
SecretKey encKey = new SecretKeySpec(randBytes, "AES");

Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES");
cipher.init((direction == ENCRYPT ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE), encKey);
} catch (InvalidKeyException e) {
return null;
} catch (NoSuchPaddingException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
}

try {
if (direction == ENCRYPT) {
byte[] encVal = cipher.doFinal(data.getBytes());
String encryptedValue = Base64.encode(encVal);
return encryptedValue;
} else {
byte[] dataBytes = Base64.decode(data);
byte[] encVal = cipher.doFinal(dataBytes);
return new String(encVal);
}
} catch (NullPointerException e) {
return null;
} catch (BadPaddingException e) {
return null;
} catch (IllegalBlockSizeException e) {
return null;
}
}

但是,我的 BadPaddingException catch block 在解密时执行:

javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at CipherUtils.aes128(CipherUtils.java:112)
at CipherUtils.decryptFile(CipherUtils.java:44)
at decryptFile.main(decryptFile.java:21)

这是我试图修复它的方法(基本上,我自己添加了所有填充/取消填充,并使用了 NoPadding):

public static String aes128(String key, String data, final int direction) {
// PADCHAR = (char)0x10 as String
while (key.length() % 16 > 0)
key = key + PADCHAR; // Added this loop

SecureRandom rand = new SecureRandom(key.getBytes());
byte[] randBytes = new byte[16];
rand.nextBytes(randBytes);
SecretKey encKey = new SecretKeySpec(randBytes, "AES");
AlgorithmParameterSpec paramSpec = new IvParameterSpec(key.getBytes()); // Created this

Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding"); // Added CBC/NoPadding
cipher.init((direction == ENCRYPT ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE), encKey, paramSpec); // Added paramSpec
} catch (InvalidKeyException e) {
return null;
} catch (NoSuchPaddingException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
} catch (InvalidAlgorithmParameterException e) {
return null; // Added this catch{}
}

try {
if (direction == ENCRYPT) {
while (data.length() % 16 > 0)
data = data + PADCHAR; // Added this loop

byte[] encVal = cipher.doFinal(data.getBytes());
String encryptedValue = Base64.encode(encVal);
return encryptedValue;
} else {
byte[] dataBytes = Base64.decode(data);
byte[] encVal = cipher.doFinal(dataBytes);
return new String(encVal);
}
} catch (NullPointerException e) {
return null;
} catch (BadPaddingException e) {
return null;
} catch (IllegalBlockSizeException e) {
return null;
}
}

当使用这个时,我只是进进出出乱码:

Out: u¢;èÉ÷JRLòB±J°N°[9cRÐ{ªv=]I¯¿©:
´RLA©êí;R([¶Ü9¸ßv&%®µ^#û|Bá (80)
Unpadded: u¢;èÉ÷JRLòB±J°N°[9cRÐ{ªv=]I¯¿©:
´RLA©êí;R([¶Ü9¸ßv&%®µ^#û|Bá (79)

还值得注意的是,1.6 和 1.7 产生不同的加密字符串。

例如,在 1.7 上,使用 key hi 加密 xy(包括 SHA-1 哈希)会产生:

XLUVZBIJv1n/FV2MzaBK3FLPQRCQF2FY+ghyajdqCGsggAN4aac8bfwscrLaQT7BMHJgfnjJLn+/rwGv0UEW+dbRIMQkNAwkGeSjda3aEpk=

在 1.6 上,同样的事情产生:

nqeahRnA0IuRn7HXUD1JnkhWB5uq/Ng+srUBYE3ycGHDC1QB6Xo7cPU6aEJxH7NKqe3kRN3rT/Ctl/OrhqVkyDDThbkY8LLP39ocC3oP/JE=

没想到作业这么长,所以我的时间已经用完了,确实需要今晚完成。但是,如果到那时还没有答案,我会就此事给我的老师留个便条。这似乎是在 1.7 中修复的一些问题...尽管希望可以通过在我的代码中正确添加/修复来解决。

非常感谢大家的宝贵时间!

最佳答案

首先:

对于几乎所有系统,两次加密相同的明文应该总是(即以非常高的概率)产生不同的密文。

传统的例子是,它允许 CPA 攻击者仅通过两个查询来区分 E(“黎明攻击”)和 E(“黄昏攻击”)。 (有少数系统需要确定性加密,但正确的方法是“合成 IV”或 CMC 和 EME 等密码模式。)

最终,问题是 SecureRandom() 不适用于 key 派生。

  • 如果输入的“ key ”是密码短语,您应该使用类似 PBKDF2(或 scrypt()bcrypt())的东西。
    • 此外,您应该使用明确的字符集,例如String.getBytes("UTF-8").
  • 如果输入的“key”是一个键,最常见的字符串表示形式是 hexdump。 Java 不包含 unhexing 函数,但有几个 here .
    • 如果输入是一个“主 key ”并且您想派生一个子 key ,那么您应该用其他数据对其进行哈希处理。如果子项始终相同,则意义不大。

额外的挑剔:

  • 您的代码容易受到 padding oracle 攻击;你真的应该在对数据做任何事情之前验证 MAC(或者更好,使用经过身份验证的加密模式)。
  • 在您的第二个 list 中,您明确重复使用了 IV。坏的!假设 CBC 模式,使用的 IV 应该是不可预测的; SecureRandom 在这里很有用。

关于java - AES-128 加密不适用于 Java < 1.7,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12791339/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com