java程式碼實現加密壓縮檔案解壓
阿新 • • 發佈:2019-01-29
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(); } }
有時候編碼有問題 要根據具體情況處理
- ZipInputStream zis = new ZipInputStream(zdis,Charset.forName("GBK"));