
de.alpharogroup.file.zip.ZipDecryptInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of file-worker Show documentation
Show all versions of file-worker Show documentation
Project that holds utility class for file operations.
/**
* The MIT License
*
* Copyright (C) 2007 Asterios Raptis
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package de.alpharogroup.file.zip;
import java.io.IOException;
import java.io.InputStream;
// from 'http://blog.alutam.com/2009/10/31/reading-password-protected-zip-files-in-java/'
/**
* The Class ZipDecryptInputStream is from the blog from Martin's Weekend Coding from
* 'http://blog.alutam.com/2009/10/31/reading-password-protected-zip-files-in-java/'.
*/
public class ZipDecryptInputStream extends InputStream
{
/**
* The Enum State.
*/
private static enum State
{
/** The SIGNATURE. */
SIGNATURE,
/** The FLAGS. */
FLAGS,
/** The COMPRESSE d_ size. */
COMPRESSED_SIZE,
/** The F n_ length. */
FN_LENGTH,
/** The E f_ length. */
EF_LENGTH,
/** The HEADER. */
HEADER,
/** The DATA. */
DATA,
/** The TAIL. */
TAIL
}
/** The Constant CRC_TABLE. */
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;
}
}
/** The Constant DECRYPT_HEADER_SIZE. */
private static final int DECRYPT_HEADER_SIZE = 12;
/** The Constant LFH_SIGNATURE. */
private static final int[] LFH_SIGNATURE = { 0x50, 0x4b, 0x03, 0x04 };
/** The delegate. */
private final InputStream delegate;
/** The password. */
private final String password;
/** The keys. */
private final int keys[] = new int[3];
/** The state. */
private State state = State.SIGNATURE;
/** The skip bytes. */
private int skipBytes;
/** The compressed size. */
private int compressedSize;
/** The value. */
private int value;
/** The value pos. */
private int valuePos;
/** The value inc. */
private int valueInc;
/**
* Instantiates a new zip decrypt input stream.
*
* @param stream
* the stream
* @param password
* the password
*/
public ZipDecryptInputStream(final InputStream stream, final String password)
{
this.delegate = stream;
this.password = password;
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#close()
*/
@Override
public void close() throws IOException
{
delegate.close();
super.close();
}
/**
* Crc32.
*
* @param oldCrc
* the old crc
* @param charAt
* the char at
* @return the int
*/
private int crc32(final int oldCrc, final byte charAt)
{
return oldCrc >>> 8 ^ CRC_TABLE[(oldCrc ^ charAt) & 0xff];
}
/**
* Decrypt byte.
*
* @return the byte
*/
private byte decryptByte()
{
final int temp = keys[2] | 2;
return (byte)(temp * (temp ^ 1) >>> 8);
}
/**
* Inits the keys.
*
* @param password
* the password
*/
private void initKeys(final 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));
}
}
/*
* (non-Javadoc)
*
* @see java.io.InputStream#read()
*/
@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;
}
/**
* Update keys.
*
* @param charAt
* the char at
*/
private void updateKeys(final 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));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy