Java 文件加密丢失字节

发布于 2024-11-03 05:58:18 字数 1739 浏览 1 评论 0原文

我正在尝试编写一个简单的程序来使用 AES 算法加密和解密文件。稍后的目的是在更复杂的程序中使用将简单程序拆分为加密和解密方法。 他是程序的加密部分:

 KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey key = kg.generateKey();
 Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis;    FileOutputStream fos;    CipherOutputStream cos;
fis = new FileInputStream("FileTo.encrypt");
fos = new FileOutputStream("Encrypted.file");

//write encrypted to file
cos = new CipherOutputStream(fos, c);
byte[] b = new byte[16];
int i = fis.read(b);
while (i != -1) {
    cos.write(b, 0, i);
    i = fis.read(b);
}
cos.close();

 //write key to file
 byte[] keyEncoded = key.getEncoded();    
 FileOutputStream kos = new FileOutputStream("crypt.key");
 kos.write(keyEncoded);
 kos.close();

这是解密部分:

 //Load Key
 FileInputStream fis2= new FileInputStream("a.key");
 File f=new File("a.key");
 long l=f.length();
 byte[] b1=new byte[(int)l];
 fis2.read(b1, 0, (int)l);



 SecretKeySpec ks2=new SecretKeySpec(b1,"AES");

  Cipher c1 = Cipher.getInstance("AES");
  c1.init(Cipher.DECRYPT_MODE, ks2);
 FileInputStream fis1=new FileInputStream("Encrypted.file");
 CipherInputStream in= new CipherInputStream(fis1,c1);
 FileOutputStream fos0 =new FileOutputStream("decrypted.file");
 byte[] b3=new byte[1];
 int ia=in.read(b3);
 while (ia >=0)
 {
    c1.update(b3); //<-------remove this
    fos0.write(b3, 0, ia);
    ia=in.read(b3);
 }
in.close();
fos0.flush();
fos0.close();

现在的问题是解密部分没有解密最后的位,有些位丢失了。在我看来,它只解密每 16 个字节,但变量 in(cipherinputstream) 在应该返回最后一个字节时返回 -1。 我如何获得最后几位?

提前致谢已

编辑:添加评论以指出必须删除的内容。下面是一些使用 AES 正确(即无需在 Java 中加载整个文件)加密和解密 Java 文件的代码。可以添加其他参数(填充等),但这是基本代码。

I'm trying to write a simple program to encrypt and decrypt files using the AES algortihm. The intention later is to use split the simple program into encryption and decrytion methods in a more complex program.
He is the encryption part of the program:

 KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey key = kg.generateKey();
 Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis;    FileOutputStream fos;    CipherOutputStream cos;
fis = new FileInputStream("FileTo.encrypt");
fos = new FileOutputStream("Encrypted.file");

//write encrypted to file
cos = new CipherOutputStream(fos, c);
byte[] b = new byte[16];
int i = fis.read(b);
while (i != -1) {
    cos.write(b, 0, i);
    i = fis.read(b);
}
cos.close();

 //write key to file
 byte[] keyEncoded = key.getEncoded();    
 FileOutputStream kos = new FileOutputStream("crypt.key");
 kos.write(keyEncoded);
 kos.close();

Here's the decryption part:

 //Load Key
 FileInputStream fis2= new FileInputStream("a.key");
 File f=new File("a.key");
 long l=f.length();
 byte[] b1=new byte[(int)l];
 fis2.read(b1, 0, (int)l);



 SecretKeySpec ks2=new SecretKeySpec(b1,"AES");

  Cipher c1 = Cipher.getInstance("AES");
  c1.init(Cipher.DECRYPT_MODE, ks2);
 FileInputStream fis1=new FileInputStream("Encrypted.file");
 CipherInputStream in= new CipherInputStream(fis1,c1);
 FileOutputStream fos0 =new FileOutputStream("decrypted.file");
 byte[] b3=new byte[1];
 int ia=in.read(b3);
 while (ia >=0)
 {
    c1.update(b3); //<-------remove this
    fos0.write(b3, 0, ia);
    ia=in.read(b3);
 }
in.close();
fos0.flush();
fos0.close();

Now the problem is the decryption part is not decrypting the last bits, some bits are missing. It seems to me that it only decrypts every 16 bytes, but the variable in(cipherinputstream) returns -1 when it should be returning the last bytes.
How do I get the last bits?

Thanks in advance

Edited: Added comment to point out what has to be removed. Here's some code to properly (i.e., without loading the entire file in java) encrypt and decrypt a file in Java using AES. It's possible to add additional parameters (padding, etc.) but here's the basic code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱已欠费 2024-11-10 05:58:18

您只需删除代码中的这一行即可正常工作:

c1.update(b3);

由于您使用的是 CipherInputStream,因此无需手动更新 Cipher。它会为你处理这个问题,并且通过调用它,你会干扰解密。

另外,为了提高效率,您应该增加 byte[] bbyte[] b3 数组的大小。通常 8192 是适合缓冲的大小。

You just need to remove this line in your code and it'll work fine:

c1.update(b3);

Since you're using a CipherInputStream you don't need to update the Cipher manually. It handles that for you, and by calling it you're interfering with the decryption.

On a side note, for efficiency you should increase the size of your byte[] b and byte[] b3 arrays. Typically 8192 is a good size for buffering.

柳絮泡泡 2024-11-10 05:58:18

这是我挖掘的一些 DES 示例代码,可能会有所帮助......尤其是对 doFinal 的调用。

package forums;

import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/**
   This program tests the DES cipher. Usage:
   java DESTest -genkey keyfile
   java DESTest -encrypt plaintext encrypted keyfile
   java DESTest -decrypt encrypted decrypted keyfile
*/
public class DESTest
{
   private static void usage() {
      System.err.print(
          "This program tests the javax.crypto DES cipher package.\n"
        + "usage: java DESTest -genkey keyfile\n"
        + "java DESTest -encrypt plaintext encrypted keyfile\n"
        + "java DESTest -decrypt encrypted decrypted keyfile\n"
      );
   }

   public static void main(String[] args) {
      if ( args.length < 2 || args.length > 4
        || !args[0].matches("-genkey|-encrypt|-decrypt")
      ) {
          usage();
          return;
      }
      try {
         if ("-genkey".equals(args[0])) {
            KeyGenerator keygen = KeyGenerator.getInstance("DES");
            SecureRandom random = new SecureRandom();
            keygen.init(random);
            SecretKey key = keygen.generateKey();
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1]));
            out.writeObject(key);
            out.close();
         } else {
            int mode;
            if ("-encrypt".equals(args[0])) {
               mode = Cipher.ENCRYPT_MODE;
            } else { //-decrypt
               mode = Cipher.DECRYPT_MODE;
            }

            ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
            Key key = (Key) keyIn.readObject();
            keyIn.close();

            InputStream in = new FileInputStream(args[1]);
            OutputStream out = new FileOutputStream(args[2]);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(mode, key);

            crypt(in, out, cipher);
            in.close();
            out.close();
         }
      } catch (IOException exception) {
         exception.printStackTrace();
      } catch (GeneralSecurityException exception) {
         exception.printStackTrace();
      } catch (ClassNotFoundException exception) {
         exception.printStackTrace();
      }
   }

   /**
      Uses a cipher to transform the bytes in an input stream
      and sends the transformed bytes to an output stream.
      @param in the input stream
      @param out the output stream
      @param cipher the cipher that transforms the bytes
   */
   public static void crypt(InputStream in, OutputStream out, Cipher cipher) 
      throws IOException, GeneralSecurityException
   {
      int blockSize = cipher.getBlockSize();
      int outputSize = cipher.getOutputSize(blockSize);
      byte[] inBytes = new byte[blockSize];
      byte[] outBytes = new byte[outputSize];

      int inLength = 0;;
      boolean more = true;
      while (more) {
         inLength = in.read(inBytes);
         if (inLength == blockSize) {
            int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
            out.write(outBytes, 0, outLength);
            System.out.println(outLength);
         } else {
            more = false;
         }
      }
      if (inLength > 0) {
         outBytes = cipher.doFinal(inBytes, 0, inLength);
      } else {
         outBytes = cipher.doFinal();
      }
      System.out.println(outBytes.length);
      out.write(outBytes);
   }

}

Here's some DES example code I dug up, which might be helpful... especially the calls to doFinal.

package forums;

import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/**
   This program tests the DES cipher. Usage:
   java DESTest -genkey keyfile
   java DESTest -encrypt plaintext encrypted keyfile
   java DESTest -decrypt encrypted decrypted keyfile
*/
public class DESTest
{
   private static void usage() {
      System.err.print(
          "This program tests the javax.crypto DES cipher package.\n"
        + "usage: java DESTest -genkey keyfile\n"
        + "java DESTest -encrypt plaintext encrypted keyfile\n"
        + "java DESTest -decrypt encrypted decrypted keyfile\n"
      );
   }

   public static void main(String[] args) {
      if ( args.length < 2 || args.length > 4
        || !args[0].matches("-genkey|-encrypt|-decrypt")
      ) {
          usage();
          return;
      }
      try {
         if ("-genkey".equals(args[0])) {
            KeyGenerator keygen = KeyGenerator.getInstance("DES");
            SecureRandom random = new SecureRandom();
            keygen.init(random);
            SecretKey key = keygen.generateKey();
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1]));
            out.writeObject(key);
            out.close();
         } else {
            int mode;
            if ("-encrypt".equals(args[0])) {
               mode = Cipher.ENCRYPT_MODE;
            } else { //-decrypt
               mode = Cipher.DECRYPT_MODE;
            }

            ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
            Key key = (Key) keyIn.readObject();
            keyIn.close();

            InputStream in = new FileInputStream(args[1]);
            OutputStream out = new FileOutputStream(args[2]);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(mode, key);

            crypt(in, out, cipher);
            in.close();
            out.close();
         }
      } catch (IOException exception) {
         exception.printStackTrace();
      } catch (GeneralSecurityException exception) {
         exception.printStackTrace();
      } catch (ClassNotFoundException exception) {
         exception.printStackTrace();
      }
   }

   /**
      Uses a cipher to transform the bytes in an input stream
      and sends the transformed bytes to an output stream.
      @param in the input stream
      @param out the output stream
      @param cipher the cipher that transforms the bytes
   */
   public static void crypt(InputStream in, OutputStream out, Cipher cipher) 
      throws IOException, GeneralSecurityException
   {
      int blockSize = cipher.getBlockSize();
      int outputSize = cipher.getOutputSize(blockSize);
      byte[] inBytes = new byte[blockSize];
      byte[] outBytes = new byte[outputSize];

      int inLength = 0;;
      boolean more = true;
      while (more) {
         inLength = in.read(inBytes);
         if (inLength == blockSize) {
            int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
            out.write(outBytes, 0, outLength);
            System.out.println(outLength);
         } else {
            more = false;
         }
      }
      if (inLength > 0) {
         outBytes = cipher.doFinal(inBytes, 0, inLength);
      } else {
         outBytes = cipher.doFinal();
      }
      System.out.println(outBytes.length);
      out.write(outBytes);
   }

}
挥剑断情 2024-11-10 05:58:18
import javax.crypto.Cipher;  
import javax.crypto.spec.SecretKeySpec;  

public class AESTest {  
     public static String asHex (byte buf[]) {
          StringBuffer strbuf = new StringBuffer(buf.length * 2);
          int i;

          for (i = 0; i < buf.length; i++) {
           if (((int) buf[i] & 0xff) < 0x10)
            strbuf.append("0");

           strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
          }

          return strbuf.toString();
     }

     public static void main(String[] args) throws Exception {  
        String keyString = "ssssssssssssssss";  
        // 546578746F2070617261207465737465 (Hex)  
        byte[] key = keyString.getBytes();  
        System.out.println(asHex(key).toUpperCase());  

        String clearText = "sdhhgfffhamayaqqqaaaa";  
        // ZXNzYXNlbmhhZWhmcmFjYQ== (Base64)  
        // 6573736173656E686165686672616361 (Hex)  
        byte[] clear = clearText.getBytes();  
        System.out.println(asHex(clear).toUpperCase());  

        SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");  
        // PKCS5Padding or NoPadding  
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");  
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);  

        byte[] encrypted = cipher.doFinal(clear);  
        System.out.println(asHex(encrypted).toUpperCase());  
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] original =
                    cipher.doFinal(encrypted);

        System.out.println(original);
        String originalString = new String(original);
        System.out.println("Original string: " +
                    originalString + " " + asHex(original));
    }  
}  
import javax.crypto.Cipher;  
import javax.crypto.spec.SecretKeySpec;  

public class AESTest {  
     public static String asHex (byte buf[]) {
          StringBuffer strbuf = new StringBuffer(buf.length * 2);
          int i;

          for (i = 0; i < buf.length; i++) {
           if (((int) buf[i] & 0xff) < 0x10)
            strbuf.append("0");

           strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
          }

          return strbuf.toString();
     }

     public static void main(String[] args) throws Exception {  
        String keyString = "ssssssssssssssss";  
        // 546578746F2070617261207465737465 (Hex)  
        byte[] key = keyString.getBytes();  
        System.out.println(asHex(key).toUpperCase());  

        String clearText = "sdhhgfffhamayaqqqaaaa";  
        // ZXNzYXNlbmhhZWhmcmFjYQ== (Base64)  
        // 6573736173656E686165686672616361 (Hex)  
        byte[] clear = clearText.getBytes();  
        System.out.println(asHex(clear).toUpperCase());  

        SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");  
        // PKCS5Padding or NoPadding  
        Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");  
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);  

        byte[] encrypted = cipher.doFinal(clear);  
        System.out.println(asHex(encrypted).toUpperCase());  
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] original =
                    cipher.doFinal(encrypted);

        System.out.println(original);
        String originalString = new String(original);
        System.out.println("Original string: " +
                    originalString + " " + asHex(original));
    }  
}  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文