填充错误——在Java中使用AES加密和在C中解密。

时间:2021-11-10 18:22:59

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.

我在用rijndael 'c'代码解密xl文件时遇到了一个问题(该文件通过JCE在Java中加密),这个问题只发生在具有公式的excel文件类型上。保持所有文件类型加密/解密正在正常进行。

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

(如果我在java中解密相同的文件,输出就会很好。)

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

当我转储一个文件时,我可以看到java解密和“C”文件解密之间的区别。

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

od -c -b文件名(在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)

od -c -b文件名(在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.

下面是我用来加密文件的java代码。

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'.

我使用下面的文件在“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);  
    }

2 个解决方案

#1


1  

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.

为了删除Java所添加的PKCS填充,C端需要读取最后一个被标记的块中的最后一个字节的值,然后从解密流的末尾减少许多字节。

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):

这意味着,在您尝试读取下一个块之前,您不能进行fwrite(因为您需要知道当前块是否是最后一个块):

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);
    }
}

#2


0  

I modified the file read operation in 'c' file. Now it is coming fine.

我修改了“c”文件中的文件读取操作。现在一切都很好。

Thanks for your support. :-)

谢谢你的支持。:-)

#1


1  

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.

为了删除Java所添加的PKCS填充,C端需要读取最后一个被标记的块中的最后一个字节的值,然后从解密流的末尾减少许多字节。

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):

这意味着,在您尝试读取下一个块之前,您不能进行fwrite(因为您需要知道当前块是否是最后一个块):

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);
    }
}

#2


0  

I modified the file read operation in 'c' file. Now it is coming fine.

我修改了“c”文件中的文件读取操作。现在一切都很好。

Thanks for your support. :-)

谢谢你的支持。:-)