content: /*
  * Copyright 2010 Srikanth Reddy Lingala  
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); 
  * you may not use this file except in compliance with the License. 
  * You may obtain a copy of the License at 
  * 
  * https://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, 
  * software distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  * See the License for the specific language governing permissions and 
  * limitations under the License. 
  */
  
  package net.lingala.zip4j.crypto;
  
  import net.lingala.zip4j.crypto.engine.ZipCryptoEngine;
  import net.lingala.zip4j.exception.ZipException;
  import net.lingala.zip4j.exception.ZipExceptionConstants;
  import net.lingala.zip4j.model.FileHeader;
  import net.lingala.zip4j.util.InternalZipConstants;
  
  public class StandardDecrypter implements IDecrypter {
  	
  	private FileHeader fileHeader;
  	private byte[] crc = new byte[4];
  	private ZipCryptoEngine zipCryptoEngine;
  	
  	public StandardDecrypter(FileHeader fileHeader, byte[] headerBytes) throws ZipException{
  		if (fileHeader == null) {
  			throw new ZipException("one of more of the input parameters were null in StandardDecryptor");
  		}
  		
  		this.fileHeader = fileHeader;
  		this.zipCryptoEngine = new ZipCryptoEngine();
  		init(headerBytes);
  	}
  	
  	public int decryptData(byte[] buff) throws ZipException {
  		return decryptData(buff, 0, buff.length);
  	}
  	
  	public int decryptData(byte[] buff, int start, int len) throws ZipException {
  		if (start < 0 || len < 0) {
  			throw new ZipException("one of the input parameters were null in standard decrpyt data");
  		}
  		
  		try {
  			for (int i = start; i <  start + len; i++) {
  				int val = buff[i] & 0xff;
  				val = (val ^ zipCryptoEngine.decryptByte()) & 0xff;
  				zipCryptoEngine.updateKeys((byte) val);
  				buff[i] = (byte)val;
  			}
  			return len;
  		} catch (Exception e) {
  			throw new ZipException(e);
  		}
  	}
  	
  	public void init(byte[] headerBytes) throws ZipException {
  		byte[] crcBuff = fileHeader.getCrcBuff();
  		crc[3] = (byte) (crcBuff[3] & 0xFF);  
          crc[2] = (byte) ((crcBuff[3] >> 8) & 0xFF);  
          crc[1] = (byte) ((crcBuff[3] >> 16) & 0xFF);  
          crc[0] = (byte) ((crcBuff[3] >> 24) & 0xFF);
          
          if(crc[2] > 0 || crc[1] > 0 || crc[0] > 0)
          	throw new IllegalStateException("Invalid CRC in File Header");
          
          if (fileHeader.getPassword() == null || fileHeader.getPassword().length <= 0) {
          	throw new ZipException("Wrong password!", ZipExceptionConstants.WRONG_PASSWORD);
          }
          
          zipCryptoEngine.initKeys(fileHeader.getPassword());
          
          try {
  			int result = headerBytes[0];
  			for (int i = 0; i < InternalZipConstants.STD_DEC_HDR_SIZE; i++) {
  //				Commented this as this check cannot always be trusted
  //				New functionality: If there is an error in extracting a password protected file, 
  //				"Wrong Password?" text is appended to the exception message
  //				if(i+1 == InternalZipConstants.STD_DEC_HDR_SIZE && ((byte)(result ^ zipCryptoEngine.decryptByte()) != crc[3]) && !isSplit)
  //					throw new ZipException("Wrong password!", ZipExceptionConstants.WRONG_PASSWORD);
  				
  				zipCryptoEngine.updateKeys((byte) (result ^ zipCryptoEngine.decryptByte()));
  				if (i+1 != InternalZipConstants.STD_DEC_HDR_SIZE)
  					result = headerBytes[i+1];
  			}
  		} catch (Exception e) {
  			throw new ZipException(e);
  		}
  	}
  	
  }
  