1. 程式人生 > >java程式碼實現加密壓縮檔案解壓

java程式碼實現加密壓縮檔案解壓

package com.dashu.basicinfo.zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipDecryptInputStream extends InputStream {
   private static final int[] CRC_TABLE = new int[256];
   // compute the table
   // (could also have it pre-computed - see http://snippets.dzone.com/tag/crc32)
   static {
       for (int i = 0; i < 256; i++) {
           int r = i;
           for (int j = 0; j < 8; j++) {
               if ((r & 1) == 1) {
                   r = (r >>> 1) ^ 0xedb88320;
               } else {
                   r >>>= 1;
               }
           }
           CRC_TABLE[i] = r;
       }
   }

   private static final int DECRYPT_HEADER_SIZE = 12;
   private static final int[] LFH_SIGNATURE = {0x50, 0x4b, 0x03, 0x04};

   private final InputStream delegate;
   private final String password;
   private final int keys[] = new int[3];

   private State state = State.SIGNATURE;
   private int skipBytes;
   private int compressedSize;
   private int value;
   private int valuePos;
   private int valueInc;

   public ZipDecryptInputStream(InputStream stream, String password) {
       this.delegate = stream;
       this.password = password;
   }

   @Override
   public int read() throws IOException {
       int result = delegate.read();
       if (skipBytes == 0) {
           switch (state) {
               case SIGNATURE:
                   if (result != LFH_SIGNATURE[valuePos]) {
                       state = State.TAIL;
                   } else {
                       valuePos++;
                       if (valuePos >= LFH_SIGNATURE.length) {
                           skipBytes = 2;
                           state = State.FLAGS;
                       }
                   }
                   break;
               case FLAGS:
                   if ((result & 1) == 0) {
                       throw new IllegalStateException("ZIP not password protected.");
                   }
                   if ((result & 64) == 64) {
                       throw new IllegalStateException("Strong encryption used.");
                   }
                   if ((result & 8) == 8) {
                       throw new IllegalStateException("Unsupported ZIP format.");
                   }
                   result -= 1;
                   compressedSize = 0;
                   valuePos = 0;
                   valueInc = DECRYPT_HEADER_SIZE;
                   state = State.COMPRESSED_SIZE;
                   skipBytes = 11;
                   break;
               case COMPRESSED_SIZE:
                   compressedSize += result << (8 * valuePos);
                   result -= valueInc;
                   if (result < 0) {
                       valueInc = 1;
                       result += 256;
                   } else {
                       valueInc = 0;
                   }
                   valuePos++;
                   if (valuePos > 3) {
                       valuePos = 0;
                       value = 0;
                       state = State.FN_LENGTH;
                       skipBytes = 4;
                   }
                   break;
               case FN_LENGTH:
               case EF_LENGTH:
                   value += result << 8 * valuePos;
                   if (valuePos == 1) {
                       valuePos = 0;
                       if (state == State.FN_LENGTH) {
                           state = State.EF_LENGTH;
                       } else {
                           state = State.HEADER;
                           skipBytes = value;
                       }
                   } else {
                       valuePos = 1;
                   }
                   break;
               case HEADER:
                   initKeys(password);
                   for (int i = 0; i < DECRYPT_HEADER_SIZE; i++) {
                       updateKeys((byte) (result ^ decryptByte()));
                       result = delegate.read();
                   }
                   compressedSize -= DECRYPT_HEADER_SIZE;
                   state = State.DATA;
                   // intentionally no break
               case DATA:
                   result = (result ^ decryptByte()) & 0xff;
                   updateKeys((byte) result);
                   compressedSize--;
                   if (compressedSize == 0) {
                       valuePos = 0;
                       state = State.SIGNATURE;
                   }
                   break;
               case TAIL:
                   // do nothing
           }
       } else {
           skipBytes--;
       }
       return result;
   }

   @Override
   public void close() throws IOException {
       delegate.close();
       super.close();
   }

   private void initKeys(String password) {
       keys[0] = 305419896;
       keys[1] = 591751049;
       keys[2] = 878082192;
       for (int i = 0; i < password.length(); i++) {
           updateKeys((byte) (password.charAt(i) & 0xff));
       }
   }

   private void updateKeys(byte charAt) {
       keys[0] = crc32(keys[0], charAt);
       keys[1] += keys[0] & 0xff;
       keys[1] = keys[1] * 134775813 + 1;
       keys[2] = crc32(keys[2], (byte) (keys[1] >> 24));
   }

   private byte decryptByte() {
       int temp = keys[2] | 2;
       return (byte) ((temp * (temp ^ 1)) >>> 8);
   }

   private int crc32(int oldCrc, byte charAt) {
       return ((oldCrc >>> 8) ^ CRC_TABLE[(oldCrc ^ charAt) & 0xff]);
   }

   private static enum State {
       SIGNATURE, FLAGS, COMPRESSED_SIZE, FN_LENGTH, EF_LENGTH, HEADER, DATA, TAIL
   }
   
   
	public static void main(String[] args) throws Exception {
		  // password-protected zip file I need to read
      FileInputStream fis = new FileInputStream("d:/123/one.zip");
      // wrap it in the decrypt stream
      ZipDecryptInputStream zdis = new ZipDecryptInputStream(fis, "1234567");
      // wrap the decrypt stream by the ZIP input stream
      ZipInputStream zis = new ZipInputStream(zdis);

      // read all the zip entries and save them as files
      ZipEntry ze;
      while ((ze = zis.getNextEntry()) != null) {
      	File f = new File("d:/123/"+ze.getName());
          FileOutputStream fos = new FileOutputStream(f);
          int b;
          try {
				while ((b = zis.read()) != -1) {
				    fos.write(b);
				}
			} catch (Exception e) {
				fos.close();
				f.delete();
				 zis.closeEntry();
				 break;
			}
          fos.close();
          zis.closeEntry();
      }
      zis.close();
	}
}

有時候編碼有問題 要根據具體情況處理

  1. ZipInputStream zis = new ZipInputStream(zdis,Charset.forName("GBK"));