本文介绍了在java中实现ZipCrypto / Zip 2.0加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在尝试执行zipcrypto / zip 2.0加密算法来处理加密的zip文件,如
I'm trying o implement the zipcrypto / zip 2.0 encryption algoritm to deal with encrypted zip files as discussed in
我相信我遵循了这些规范,但似乎无法让它工作。我相当确定这个问题与我对crc算法的解释有关。
I believe I've followed the specs but just can't seem to get it working. I'm fairly sure the issue has to do with my interpretation of the crc algorithm.
文档说明
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的代码片段
Here is the snippet that I'm using for the 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);
}
}
以下是我的完整代码。任何人都可以看到我做错了什么。
Below is my complete code. Can anyone see what I'm doing wrong.
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));
}
}
推荐答案
你为什么要写自己的?你可以在线找到几个版本。我使用这个,
Why do you have to write your own? You can find several versions on line. I use this one,
这篇关于在java中实现ZipCrypto / Zip 2.0加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!