Rijndael 128/256解密
Rijndael 128/256 decryption
我尝试了 SO 和网络上的许多答案,但仍然没有成功。
我用下面的tool来加密
text to encrypt: tom
key: exo123exo1exo123
input (textfield or selected file above) is: text/binary
Convert output to: [i leave this unselected]
Mode: CTR
Ciphers: Rijndael-128 and Rijndael-256
得到结果后我移动here:
并用base64编码。
然后我复制字符串并将其作为参数发送给我的函数:
public String authenticate(String base64EncodedData){
byte[] input = Base64.decodeBase64(base64EncodedData);
byte[] ivBytes = "1234567812345678".getBytes();
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(
Cipher.DECRYPT_MODE,
new SecretKeySpec("exo123exo1exo123".getBytes(), "AES"),
new IvParameterSpec(ivBytes)
);
byte[] plainText = new byte[cipher.getOutputSize(input.length)];
int plainTextLength = cipher.update(input, 0, input.length, plainText, 0);
plainTextLength += cipher.doFinal(plainText, plainTextLength);
return new String(plainText);
}
我得到的结果总是类似于这个(无论我使用 Rijndael-128 还是 256 加密字符串):
.�v�Y�
当我尝试 return input
值时 - 我得到了加密字符串。所以 base64 工作得很好。
我做错了什么?
我在这里慢慢生气。
谢谢。
您的假设和代码存在一些问题:
第一个工具的输出已经是 Base 64 编码。 RIJNDAEL-128:r0GR
和 RIJNDAEL-256:yAVy
。它不需要第二次编码。它会自动选择此选项,因为无法打印二进制数据。
Java 中没有原生的 Rijndael-256,您将不得不为此使用 BouncyCastle。 Rijndael-128 应该是 AES,这意味着两者的块大小都是 128 位。
IV 几乎肯定需要由零字节组成。例如:
byte[] ivBytes = new byte[16];
Arrays.fill(ivBytes, (byte)0); // might not be necessary
请注意,CTR 模式不使用 IV,而是使用随机数。
总是在检索字节时指定编码:"exo123exo1exo123".getBytes("UTF-8")
。最好在任何地方都使用 UTF-8。如果跨使用不同系统编码的系统发送数据,将导致难以发现问题。
再看一遍在线工具没有任何用处,因为不清楚它是如何工作的。我发现了什么:
无论大小如何,任何密钥都会产生密文,这表明您输入的 "key" 实际上是 散列的 并且存在一百万种方式那是可以做到的。我可以用上面的方法解密它,所以密钥实际上是按原样使用的,没有散列。这表明密钥被 0x00 字节填充,直到达到有效的密钥大小。当密钥太大时,它可能被截断。
16个字符的明文加密为16个字节的密文(编码为24),17个字符的明文加密为32个字节的密文(编码为44)。这意味着没有使用可识别的填充,实际上可能是零填充。
这是交易破坏者:
- 每次加密时,您都会得到不同的密文。在 CBC 模式下,这意味着在加密之前生成一个随机 IV。问题是这个 IV 没有显示。所以没有办法完全解密。因此,如果您加密超过 16 个字符,那么当您按照我在本答案第一部分中描述的方式解密时,您可以恢复除前 16 个字符以外的所有字符。
你不应该让你的系统依赖于闭源在线工具。编写自己的加密工具。一些一般性建议:
IV 应该在每次加密时随机生成。它不是秘密,但应该是独一无二的。只需在加密后将其添加到密文中,然后在解密前将其切掉即可。
尽可能使用 CCM 或 GCM 等身份验证模式。自己进行经过身份验证的加密比较困难,但另一种方法是使用先加密然后 mac 范式。
我尝试了 SO 和网络上的许多答案,但仍然没有成功。
我用下面的tool来加密
text to encrypt: tom
key: exo123exo1exo123
input (textfield or selected file above) is: text/binary
Convert output to: [i leave this unselected]
Mode: CTR
Ciphers: Rijndael-128 and Rijndael-256
得到结果后我移动here:
并用base64编码。
然后我复制字符串并将其作为参数发送给我的函数:
public String authenticate(String base64EncodedData){
byte[] input = Base64.decodeBase64(base64EncodedData);
byte[] ivBytes = "1234567812345678".getBytes();
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(
Cipher.DECRYPT_MODE,
new SecretKeySpec("exo123exo1exo123".getBytes(), "AES"),
new IvParameterSpec(ivBytes)
);
byte[] plainText = new byte[cipher.getOutputSize(input.length)];
int plainTextLength = cipher.update(input, 0, input.length, plainText, 0);
plainTextLength += cipher.doFinal(plainText, plainTextLength);
return new String(plainText);
}
我得到的结果总是类似于这个(无论我使用 Rijndael-128 还是 256 加密字符串):
.�v�Y�
当我尝试 return input
值时 - 我得到了加密字符串。所以 base64 工作得很好。
我做错了什么?
我在这里慢慢生气。
谢谢。
您的假设和代码存在一些问题:
第一个工具的输出已经是 Base 64 编码。 RIJNDAEL-128:
r0GR
和 RIJNDAEL-256:yAVy
。它不需要第二次编码。它会自动选择此选项,因为无法打印二进制数据。Java 中没有原生的 Rijndael-256,您将不得不为此使用 BouncyCastle。 Rijndael-128 应该是 AES,这意味着两者的块大小都是 128 位。
IV 几乎肯定需要由零字节组成。例如:
byte[] ivBytes = new byte[16]; Arrays.fill(ivBytes, (byte)0); // might not be necessary
请注意,CTR 模式不使用 IV,而是使用随机数。
总是在检索字节时指定编码:
"exo123exo1exo123".getBytes("UTF-8")
。最好在任何地方都使用 UTF-8。如果跨使用不同系统编码的系统发送数据,将导致难以发现问题。
再看一遍在线工具没有任何用处,因为不清楚它是如何工作的。我发现了什么:
无论大小如何,任何密钥都会产生密文,这表明您输入的 "key" 实际上是 散列的 并且存在一百万种方式那是可以做到的。我可以用上面的方法解密它,所以密钥实际上是按原样使用的,没有散列。这表明密钥被 0x00 字节填充,直到达到有效的密钥大小。当密钥太大时,它可能被截断。
16个字符的明文加密为16个字节的密文(编码为24),17个字符的明文加密为32个字节的密文(编码为44)。这意味着没有使用可识别的填充,实际上可能是零填充。
这是交易破坏者:
- 每次加密时,您都会得到不同的密文。在 CBC 模式下,这意味着在加密之前生成一个随机 IV。问题是这个 IV 没有显示。所以没有办法完全解密。因此,如果您加密超过 16 个字符,那么当您按照我在本答案第一部分中描述的方式解密时,您可以恢复除前 16 个字符以外的所有字符。
你不应该让你的系统依赖于闭源在线工具。编写自己的加密工具。一些一般性建议:
IV 应该在每次加密时随机生成。它不是秘密,但应该是独一无二的。只需在加密后将其添加到密文中,然后在解密前将其切掉即可。
尽可能使用 CCM 或 GCM 等身份验证模式。自己进行经过身份验证的加密比较困难,但另一种方法是使用先加密然后 mac 范式。