【发布时间】:2011-07-20 15:20:05
【问题描述】:
我有一个在 c 中使用以下代码加密的文件:
unsigned char ckey[] = "0123456789ABCDEF";
unsigned char iv[8] = {0};
AES_set_encrypt_key(ckey, 128, &key);
AES_ctr128_encrypt(indata, outdata, 16, &key, aesstate.ivec, aesstate.ecount, &aesstate.num);
我必须使用 java 解密这个文件,所以我使用下面的代码来解密:
private static final byte[] encryptionKey = new byte[]{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
byte[] iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
IvParameterSpec ips = new IvParameterSpec(iv);
Cipher aesCipher = Cipher.getInstance("AES/CTR/NoPadding");
SecretKeySpec aeskeySpec = new SecretKeySpec(encryptionKey, "AES");
aesCipher.init(Cipher.DECRYPT_MODE, aeskeySpec, ips);
FileInputStream is = new FileInputStream(in);
CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), aesCipher);
copy(is, os);
os.close();
JAVA 代码没有给我任何错误,但输出不正确。
我做错了什么?
我的主要疑问是我是否使用了正确的填充(也尝试了 PKCS5Padding 没有成功)以及密钥和 iv 是否正确(不知道函数 AES_set_encrypt_key 的真正作用......)。
** 编辑 **
我想我对自己的问题有一个答案,但我仍然有一些疑问。
CTR 表示计数器模式。函数 AES_ctr128_encrypt 接收实际计数器 (ecount) 和使用的块数 (num) 作为参数。
文件以 16 字节的块进行加密,如下所示:
for(int i = 0; i < length; i+=16)
{
// .. buffer processing here
init_ctr(&aesstate, iv); //Counter call
AES_ctr128_encrypt(indata, outdata, 16, &key, aesstate.ivec, aesstate.ecount, &aesstate.num);
}
函数 init_ctr 这样做:
int init_ctr(struct ctr_state *state, const unsigned char iv[8])
{
state->num = 0;
memset(state->ecount, 0, 16);
memset(state->ivec + 8, 0, 8);
memcpy(state->ivec, iv, 8);
return 0;
}
这意味着在每次加密/解密之前,C 代码都会重置计数器和 ivec。
我正在尝试在 java 中将文件作为一个整体解密。这可能意味着 Java 正确使用了计数器,但 C 代码没有在每个块处重置计数器。
我的调查正确吗?
我完全无法控制调用 openssl 的 C 代码。有没有办法在 JAVA 中做同样的事情,即在每个 16 块处重置计数器? (API只请求密钥、算法、模式和IV)
我唯一的其他选择是通过 JNI 使用 openssl,但我试图避免它......
谢谢!
【问题讨论】:
-
请注意:您可以将初始化向量写成更短的
byte[] iv = new byte[16]。这在 C 和 Java 中不应该具有相同的长度吗? (或者你甚至在你的 C 代码中使用它?) -
谢谢保罗。使用的 IV 是 ivec,它是声明的 iv 的扩展(在 init_ctr 中完成)。最后,对于这个例子,它也将有 16 个字节的长度,全为零。
-
哎哟。这有效地使用了 CTR 函数来模拟 ECB 模式。请点击编写此 C 程序的人。
-
(实际上,不是在模拟 ECB,而是在 128 位字母表上模拟凯撒密码。请参阅我的答案。)