Java Can';t解密使用openssl AES加密的文件\u ctr128\u加密
我有一个使用以下c代码加密的文件:Java Can';t解密使用openssl AES加密的文件\u ctr128\u加密,java,openssl,aes,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解密此文件,
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代码没有给我任何错误,但输出不正确
我做错了什么
我的主要疑问是我是否使用了正确的填充(也尝试了PKCS5P添加,但没有成功),以及密钥和iv是否正确(不知道函数AES\u set\u encrypt\u 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);
}
这意味着在每次加密/解密之前,C代码都会重置计数器和ivec
我试图用java对整个文件进行解密。这可能意味着Java正在正确地使用计数器,但C代码不是这样,因为它正在每个块重置计数器
我的调查正确吗
我完全无法控制调用openssl的C代码。在JAVA中是否有同样的方法,即在16的每个块上重置计数器?(API仅请求密钥、算法、模式和IV)
我唯一的其他选择是通过JNI使用openssl,但我试图避免它
谢谢大家! 您的加密密钥不同
C代码对
0
到F
使用ASCII字符代码,而Javacode使用实际字节0
到16
您的加密密钥不同
C代码使用ASCII字符代码表示
0
到F
,而Javacode使用实际字节0
到16
,我没有尝试过,但您应该能够有效地模拟C端的操作-分别解密每个16字节(=128位)块,并在两次调用之间重置密码
请注意,仅对一个块使用CTR模式,且初始化向量和计数器为零,这违背了CTR模式的目标-它比更糟糕 如果我看得对,您可以尝试用C函数(或等效的Java版本)加密一些零块——它们每次都应该显示为相同的块。用任何密文对该块进行异或,以恢复明文
这相当于128位字母表(例如16字节块)上的凯撒密码,块密码在这里不为简单的128位异或密码增加安全性。猜测一个纯文本块(或者更一般地说,在正确的位置猜测128位,不需要在同一块中全部猜测)可以获得有效密钥,这可以获得所有剩余的纯文本块。我没有尝试过,但您应该能够有效地模拟C端的操作-解密每个16字节(=128位)分别分组,并在两次调用之间重置密码
请注意,仅对一个块使用CTR模式,且初始化向量和计数器为零,这违背了CTR模式的目标-它比更糟糕 如果我看得对,你可以尝试用你的C函数(或等效的Java版本)加密一些零块——每次都应该是相同的块。用任何密文对这个块进行异或,以获得明文
这相当于128位字母表(例如16字节块)上的凯撒密码,块密码在这里不会给简单的128位异或密码增加安全性。猜测一块纯文本(或者更一般地说,在正确的位置猜测128位,不必全部在同一块中)允许获取有效密钥,从而获取所有剩余的明文块。该C代码存在许多严重问题:
- 如前所述,它正在重新初始化每个块上的计数器。这使得加密完全不安全。在加密第一个块之前,只需调用
一次即可解决此问题init\u ctr()
- 它将IV静态设置为零。应随机生成新的IV,例如
if(!RAND_bytes(IV,8)){/*handle error*/}
- 代码似乎直接使用密码字符串作为密钥。相反,应该使用密钥派生函数(如PBKDF2)从密码生成密钥(在OpenSSL中通过
PKCS5_PBKDF2_HMAC_SHA1()实现)
- 如前所述,它正在重新初始化每个块上的计数器。这使得加密完全不安全。在加密第一个块之前,只需调用
一次即可解决此问题init\u ctr()
- 它将IV静态设置为零。应随机生成新的IV,例如
if(!RAND_bytes(IV,8)){/*handle error*/}
- 代码似乎直接使用密码字符串作为密钥。相反,应该使用密钥派生函数(如PBKDF2)从密码生成密钥(在OpenSSL中通过
PKCS5_PBKDF2_HMAC_SHA1()实现)
'0'
是0x30
。谢谢,我会尝试一下,看看它是如何进行更改的,键应该是{48、49、50、51、52、53、54、55、56、57、65、66、67、68、69、70}在JAVA中,但文件仍然没有正确解密:(任何其他
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;
}