java - 无法解密使用 openssl AES_ctr128_encrypt 加密的文件

标签 java openssl aes

我在 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 但没有成功)以及 key 和 iv 是否正确(不知道 AES_set_encrypt_key 函数的真正作用...)。

** 编辑 **

我想我自己的问题有了答案,但我仍然有一些疑问。

CTR 表示计数器模式。 AES_ctr128_encrypt 函数接收实际计数器 (ecount) 和使用的 block 数 (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 代码并没有正确使用它,因为它在每个 block 中都重置了计数器。

我的调查是否正确?

我完全无法控制调用 openssl 的 C 代码。有没有办法在 JAVA 中做同样的事情,即在每个 16 block 重置计数器? (API只请求key、algorithm、mode和IV)

我唯一的其他选择是通过 JNI 使用 openssl,但我试图避免它...

谢谢!

最佳答案

我没有尝试过,但您应该能够有效地模拟在 C 端所做的事情 - 分别解密每个 16 字节(=128 位) block ,并在两次调用之间重置密码。


请注意,仅对一个 block 使用 CTR 模式,初始化 vector 和计数器为零,违背了 CTR 模式的目标 - 它比 ECB 更糟糕.

如果我没看错,您可以尝试使用您的 C 函数(或等效的 Java 版本)加密一些零 block - 这些应该每次都作为同一个 block 出现。将此 block 与任何密文进行 XOR 以获得明文。

这相当于 128 位字母表(例如 16 字节 block )上的凯撒密码, block 密码不会为简单的 128 位异或密码增加安全性。猜测一个明文 block (或更一般地,在正确位置猜测 128 位,不一定都在同一个 block 中)可以得到有效 key ,从而可以得到所有剩余的明文 block 。

关于java - 无法解密使用 openssl AES_ctr128_encrypt 加密的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6764313/

相关文章:

java - 使用 Glide 在 ImageView 中加载图像

java - 优化和重新设计现有应用程序

java - 简单的纯java CSV读取和解析

ruby - 为什么我得到的不是我预期的哈希值?

javax.crypto.BadPaddingException

Golang AES-CBC 256 使用 CryptoJS 解密

java - 在可下载的 jar 应用程序中插入图标

ruby-on-rails - 无法解密存储的加密数据

ssl - 替换 SSL 证书后启动 WAMP 图标时出现 WAMP 错误为橙色

ios - 如何使用 Objective-c 实现 AES PKCS5Padding