1
/ZIP 2.0加密我想o實施/ ZIP 2.0加密algoritm處理加密的zip文件作爲ZipCrypto的實現在java中
http://www.pkware.com/documents/casestudies/APPNOTE.TXT
討論我相信我已經跟着的zipcrypto規格,但似乎無法得到它的工作。我很確定這個問題與我對crc算法的解釋有關。
文檔狀態
CRC-32: (4 bytes)
The CRC-32 algorithm was generously contributed by
David Schwaderer and can be found in his excellent
book "C Programmers Guide to NetBIOS" published by
Howard W. Sams & Co. Inc. The 'magic number' for
the CRC is 0xdebb20e3. The proper CRC pre and post
conditioning is used, meaning that the CRC register
is pre-conditioned with all ones (a starting value
of 0xffffffff) and the value is post-conditioned by
taking the one's complement of the CRC residual.
下面是我使用的CRC32
public class PKZIPCRC32 {
private static final int CRC32_POLYNOMIAL = 0xdebb20e3;
private int crc = 0xffffffff;
private int CRCTable[];
public PKZIPCRC32() {
buildCRCTable();
}
private void buildCRCTable() {
int i, j;
CRCTable = new int[256];
for (i = 0; i <= 255; i++) {
crc = i;
for (j = 8; j > 0; j--)
if ((crc & 1) == 1)
crc = (crc >>> 1)^CRC32_POLYNOMIAL;
else
crc >>>= 1;
CRCTable[i] = crc;
}
}
private int crc32(byte buffer[], int start, int count, int lastcrc) {
int temp1, temp2;
int i = start;
crc = lastcrc;
while (count-- != 0) {
temp1 = crc >>> 8;
temp2 = CRCTable[(crc^buffer[i++]) & 0xFF];
crc = temp1^temp2;
}
return crc;
}
public int crc32(int crc, byte buffer) {
return crc32(new byte[] { buffer }, 0, 1, crc);
}
}
下面是我完整的代碼片段。任何人都可以看到我做錯了什麼。
package org.apache.commons.compress.archivers.zip;
import java.io.IOException;
import java.io.InputStream;
public class ZipCryptoInputStream extends InputStream {
public class PKZIPCRC32 {
private static final int CRC32_POLYNOMIAL = 0xdebb20e3;
private int crc = 0xffffffff;
private int CRCTable[];
public PKZIPCRC32() {
buildCRCTable();
}
private void buildCRCTable() {
int i, j;
CRCTable = new int[256];
for (i = 0; i <= 255; i++) {
crc = i;
for (j = 8; j > 0; j--)
if ((crc & 1) == 1)
crc = (crc >>> 1)^CRC32_POLYNOMIAL;
else
crc >>>= 1;
CRCTable[i] = crc;
}
}
private int crc32(byte buffer[], int start, int count, int lastcrc) {
int temp1, temp2;
int i = start;
crc = lastcrc;
while (count-- != 0) {
temp1 = crc >>> 8;
temp2 = CRCTable[(crc^buffer[i++]) & 0xFF];
crc = temp1^temp2;
}
return crc;
}
public int crc32(int crc, byte buffer) {
return crc32(new byte[] { buffer }, 0, 1, crc);
}
}
private static final long ENCRYPTION_KEY_1 = 0x12345678;
private static final long ENCRYPTION_KEY_2 = 0x23456789;
private static final long ENCRYPTION_KEY_3 = 0x34567890;
private InputStream baseInputStream = null;
private final PKZIPCRC32 checksumEngine = new PKZIPCRC32();
private long[] keys = null;
public ZipCryptoInputStream(ZipArchiveEntry zipEntry, InputStream inputStream, String passwd) throws Exception {
baseInputStream = inputStream;
// Decryption
// ----------
// PKZIP encrypts the compressed data stream. Encrypted files must
// be decrypted before they can be extracted.
//
// Each encrypted file has an extra 12 bytes stored at the start of
// the data area defining the encryption header for that file. The
// encryption header is originally set to random values, and then
// itself encrypted, using three, 32-bit keys. The key values are
// initialized using the supplied encryption password. After each byte
// is encrypted, the keys are then updated using pseudo-random number
// generation techniques in combination with the same CRC-32 algorithm
// used in PKZIP and described elsewhere in this document.
//
// The following is the basic steps required to decrypt a file:
//
// 1) Initialize the three 32-bit keys with the password.
// 2) Read and decrypt the 12-byte encryption header, further
// initializing the encryption keys.
// 3) Read and decrypt the compressed data stream using the
// encryption keys.
// Step 1 - Initializing the encryption keys
// -----------------------------------------
//
// Key(0) <- 305419896
// Key(1) <- 591751049
// Key(2) <- 878082192
//
// loop for i <- 0 to length(password)-1
// update_keys(password(i))
// end loop
//
// Where update_keys() is defined as:
//
// update_keys(char):
// Key(0) <- crc32(key(0),char)
// Key(1) <- Key(1) + (Key(0) & 000000ffH)
// Key(1) <- Key(1) * 134775813 + 1
// Key(2) <- crc32(key(2),key(1) >> 24)
// end update_keys
//
// Where crc32(old_crc,char) is a routine that given a CRC value and a
// character, returns an updated CRC value after applying the CRC-32
// algorithm described elsewhere in this document.
keys = new long[] { ENCRYPTION_KEY_1, ENCRYPTION_KEY_2, ENCRYPTION_KEY_3 };
for (int i = 0; i < passwd.length(); ++i) {
update_keys((byte) passwd.charAt(i));
}
// Step 2 - Decrypting the encryption header
// -----------------------------------------
//
// The purpose of this step is to further initialize the encryption
// keys, based on random data, to render a plaintext attack on the
// data ineffective.
//
// Read the 12-byte encryption header into Buffer, in locations
// Buffer(0) thru Buffer(11).
//
// loop for i <- 0 to 11
// C <- buffer(i)^decrypt_byte()
// update_keys(C)
// buffer(i) <- C
// end loop
//
// Where decrypt_byte() is defined as:
//
// unsigned char decrypt_byte()
// local unsigned short temp
// temp <- Key(2) | 2
// decrypt_byte <- (temp * (temp^1)) >> 8
// end decrypt_byte
//
// After the header is decrypted, the last 1 or 2 bytes in Buffer
// should be the high-order word/byte of the CRC for the file being
// decrypted, stored in Intel low-byte/high-byte order. Versions of
// PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is
// used on versions after 2.0. This can be used to test if the password
// supplied is correct or not.
byte[] encryptionHeader = new byte[12];
baseInputStream.read(encryptionHeader);
for (int i = 0; i < encryptionHeader.length; i++) {
encryptionHeader[i] ^= decrypt_byte();
update_keys(encryptionHeader[i]);
}
}
protected byte decrypt_byte() {
byte temp = (byte) (keys[2] | 2);
return (byte) ((temp * (temp^1)) >> 8);
}
@Override
public int read() throws IOException {
//
// Step 3 - Decrypting the compressed data stream
// ----------------------------------------------
//
// The compressed data stream can be decrypted as follows:
//
// loop until done
// read a character into C
// Temp <- C^decrypt_byte()
// update_keys(temp)
// output Temp
// end loop
int read = baseInputStream.read();
read ^= decrypt_byte();
update_keys((byte) read);
return read;
}
private final void update_keys(byte ch) {
keys[0] = checksumEngine.crc32((int) keys[0], ch);
keys[1] = keys[1] + (byte) keys[0];
keys[1] = keys[1] * 134775813 + 1;
keys[2] = checksumEngine.crc32((int) keys[2], (byte) (keys[1] >> 24));
}
}
java.util.zip.CRC32不會在這種情況下工作嗎? – 2009-10-30 18:29:39
不能這樣做,因爲它是不同的,你需要在處理之前用crc值填充 看下面指向的代碼zz編碼器,你可以看到我在說什麼。由於java zip crc 32只需要sinl; ge輸入,所以基於文檔也不確定兩個輸入是如何連接在一起的。另外,我被假設爲多項式的整個魔力數字都讓我失望。 http://csfviewer.googlecode.com/svn/src/utils/Crc32.java – gomesla 2009-10-30 19:52:35