填充错误 - 在Java和解密使用C中的AES加密时, [英] Padding error - when using AES Encryption in Java and Decryption in C

查看:320
本文介绍了填充错误 - 在Java和解密使用C中的AES加密时,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,而在解密Rijndael算法的'C'code中的XL文件(该文件得到通过JCE加密在Java中),而这个问题只是发生了哪些具有式的的Excel文件类型。剩下的所有文件类型的加密/解密正常发生的事情。

(如果我解密在Java中输出来了精细的同一个文件。)

虽然我甩了一个文件,我可以看到java的解密和'C'文件解密之间的差异。

OD -c -b文件名(文件用C解密)

  0034620 005 006 \\ 0 \\ 0 \\ 0 \\ 0 022 \\ 022 0 \\ 0 320 004 \\ 0 \\ 0 4 276005 006 000 000 000 000 022 000 022 000 320 004 000 000 276 0640034640 \\ 0 \\ 0 \\ 0 \\ 0 \\ F \\ F \\ F \\ F \\ F \\ F \\ F \\ F \\ F \\ F \\ F \\ F000 000 000 000 014 014 014 014 014 014 014 014 014 014 014 014 0034660

OD -c -b文件名(文件中的Java解密)

  0034620 005 006 \\ 0 \\ 0 \\ 0 \\ 0 022 \\ 022 0 \\ 0 320 004 \\ 0 \\ 0 4 276005 006 000 000 000 000 022 000 022 000 320 004 000 000 276 0640034640 \\ 0 \\ 0 \\ 0 \\ 0 000 000 000 000 0034644

(上面是转储文件之间的差异)

下面的Java $ C C I用来加密文件。

 公共类AES {    / **
     *打开的字节数组转换为字符串
     *
     * @参数BUF
     *字节数组转换为十六进制字符串
     * @返回生成的十六进制字符串
     * /    公共静态无效的主要(字串[] args)抛出异常{        档案文件=新的文件(testxls.xls);        字节[] = lContents新的字节[(INT)file.length()];
        尝试{
            的FileInputStream的FileInputStream =新的FileInputStream(文件);
            fileInputStream.read(lContents);
        }赶上(FileNotFoundException异常五){
            e.printStackTrace();
        }赶上(IOException异常E1){
            e1.printStackTrace();
        }
        尝试{
            的KeyGenerator kgen = KeyGenerator.getInstance(AES);
            kgen.init(256); // 192和256位可能无法使用
            //生成密钥规格。
            SecretKey的SKEY = kgen.generateKey();
            //字节[] =原skey.getEn codeD();
            字节[]生=aabbccddeeffgghhaabbccddeeffgghh.getBytes();
            SecretKeySpec skeySpec =新SecretKeySpec(生,AES);
            密密码= Cipher.getInstance(AES);
            cipher.init(Cipher.ENCRYPT_MODE,skeySpec);
            字节[] =加密cipher.doFinal(lContents);
            cipher.init(Cipher.DECRYPT_MODE,skeySpec);
            字节[] =原cipher.doFinal(lContents);
            FileOutputStream中F1 =新的FileOutputStream(testxls_java.xls);
            f1.write(原件);        }赶上(例外五){
            // TODO自动生成catch块
            e.printStackTrace();
        }    }
}

我用的'C'解密以下文件。

 的#include<&stdio.h中GT;
#包括rijndael.h
#定义KEYBITS 256#包括LT&;&stdio.h中GT;
#包括rijndael.h#定义KEYBITS 256    INT主(INT ARGC,字符** argv的)
    {
     无符号长RK [RKLENGTH(KEYBITS)];
     无符号的字符键[KEYLENGTH(KEYBITS)];
     INT I;
     INT nrounds;
     炭虚设[100] =aabbccddeeffgghhaabbccddeeffgghh;
     字符*密码;
     FILE *输入,输出*;
     密码=假;
     对于(i = 0; I<的sizeof(关键);我++)
          键[i] = *密码!= 0? *密码++:0;
     输入=的fopen(doc_for_logu.xlsb,RB);
     如果(输入== NULL)
     {
         的fputs(文件读取错误,标准错误);
          返回1;
     }
    输出=的fopen(ori_c_res.xlsb,W);
    nrounds = rijndaelSetupDecrypt(RK,钥匙,256);
     而(1)
     {
      unsigned char型明文[16];
      无符号字符密文[16];
      诠释J;
      如果(的fread(密文,sizeof的(密文),1,输入)!= 1)
            打破;
      rijndaelDecrypt(RK,nrounds,密文,明文);
      的fwrite(明文,sizeof的(明文),1,输出);
     }
     fclose函数(输入);
     fclose函数(输出);
    }


解决方案

为了去除Java已加入PKCS填充,C面需要读取最终decypted块中的最后一个字节的值,然后修剪了许多字节从解密流的末尾

这意味着,你不能做你的 FWRITE ,直到在您尝试阅读的下次的块(因为你需要知道是否当前块是最后一个或没有):

  unsigned char型明文[16];
无符号字符密文[16];
INT last_block;last_block =(的fread(密文,sizeof的(密文),1,输入)= 1!);
而(!last_block)
{
    为size_t plaintext_size = sizeof的明文;    rijndaelDecrypt(RK,nrounds,密文,明文);
    last_block =(的fread(密文,sizeof的(密文),1,输入)= 1!);    如果(last_block)
    {
        / *移除填充* /
        plaintext_size - =明文[(sizeof的明文) - 1];
    }    如果(plaintext_size)
    {
        的fwrite(明文,plaintext_size,1,输出);
    }
}

I have a problem while decrypting the xl file in rijndael 'c' code (The file got encrypted in Java through JCE) and this problem is happening only for the excel files types which having formula's. Remaining all file type encryption/decryption is happening properly.

(If i decrypt the same file in java the output is coming fine.)

While i dumped a file i can see the difference between java decryption and 'C' file decryption.

od -c -b filename(file decrypted in C)

0034620  005 006  \0  \0  \0  \0 022  \0 022  \0 320 004  \0  \0 276   4

005 006 000 000 000 000 022 000 022 000 320 004 000 000 276 064

0034640   \0  \0  \0  \0  \f  \f  \f  \f  \f  \f  \f  \f  \f  \f  \f  \f

000 000 000 000 014 014 014 014 014 014 014 014 014 014 014 014 0034660 

od -c -b filename(file decrypted in Java)

0034620  005 006  \0  \0  \0  \0 022  \0 022  \0 320 004  \0  \0 276   4

005 006 000 000 000 000 022 000 022 000 320 004 000 000 276 064

0034640   \0  \0  \0  \0 000 000 000 000 0034644

(the above is the difference between the dumped files)

The following java code i used to encrypt the file.

public class AES {

    /**
     * Turns array of bytes into string
     * 
     * @param buf
     *            Array of bytes to convert to hex string
     * @return Generated hex string
     */

    public static void main(String[] args) throws Exception {

        File file = new File("testxls.xls");

        byte[] lContents = new byte[(int) file.length()];
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            fileInputStream.read(lContents);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(256); // 192 and 256 bits may not be available
            // Generate the secret key specs.
            SecretKey skey = kgen.generateKey();
            // byte[] raw = skey.getEncoded();
            byte[] raw = "aabbccddeeffgghhaabbccddeeffgghh".getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] encrypted = cipher.doFinal(lContents);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] original = cipher.doFinal(lContents);
            FileOutputStream f1 = new FileOutputStream("testxls_java.xls");
            f1.write(original);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

I used the following file for decryption in 'C'.

#include <stdio.h>
#include "rijndael.h"


#define KEYBITS 256

#include <stdio.h>
#include "rijndael.h"

#define KEYBITS 256 

    int main(int argc, char **argv)  
    {  
     unsigned long rk[RKLENGTH(KEYBITS)];  
     unsigned char key[KEYLENGTH(KEYBITS)];  
     int i;  
     int nrounds;  
     char dummy[100] = "aabbccddeeffgghhaabbccddeeffgghh";  
     char *password;  
     FILE *input,*output;  
     password = dummy;  
     for (i = 0; i < sizeof(key); i++)  
          key[i] = *password != 0 ? *password++ : 0;  
     input = fopen("doc_for_logu.xlsb", "rb");  
     if (input == NULL)  
     {  
         fputs("File read error", stderr);  
          return 1;  
     }  
    output = fopen("ori_c_res.xlsb","w");  
    nrounds = rijndaelSetupDecrypt(rk, key, 256);  
     while (1)  
     {
      unsigned char plaintext[16];  
      unsigned char ciphertext[16];  
      int j;  
      if (fread(ciphertext, sizeof(ciphertext), 1, input) != 1)  
            break;  
      rijndaelDecrypt(rk, nrounds, ciphertext, plaintext);  
      fwrite(plaintext, sizeof(plaintext), 1, output);    
     }  
     fclose(input);  
     fclose(output);  
    }

解决方案

In order to remove the PKCS padding that Java is adding, the C side needs to read the value of the last byte in the final decypted block, then trim that many bytes from the end of the decrypted stream.

This means that you can't do your fwrite until after you try to read the next block (because you need to know whether the current block is the last one or not):

unsigned char plaintext[16];  
unsigned char ciphertext[16];
int last_block;

last_block = (fread(ciphertext, sizeof(ciphertext), 1, input) != 1);  
while (!last_block)
{
    size_t plaintext_size = sizeof plaintext;

    rijndaelDecrypt(rk, nrounds, ciphertext, plaintext);
    last_block = (fread(ciphertext, sizeof(ciphertext), 1, input) != 1);

    if (last_block)
    {
        /* Remove padding */
        plaintext_size -= plaintext[(sizeof plaintext) - 1];
    }

    if (plaintext_size)
    {
        fwrite(plaintext, plaintext_size, 1, output);
    }
}

这篇关于填充错误 - 在Java和解密使用C中的AES加密时,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆