/* 
 * $Header: $
 * $Revision: $
 * $Date: $
 */
package org.apache.commons.httpclient;

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

/**
 * <p>Wrapper class that provides DES encryption.  This class enables a
 * simple mechanism to switch between the JCE DES encryption module and
 * an alternative (possibly more lightweight) implementation.</p>
 * 
 * @version $Revision: $ $Date: $
 *
 * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
 */
public class DES {

	Cipher ecipher;

	/** Creates a new DES encrypter with the given key.
	 * @param key the DES key to use.
	 */
	public DES(byte[] key) throws HttpException {
		Security.addProvider(new com.sun.crypto.provider.SunJCE());
		try {
			ecipher = Cipher.getInstance("DES/ECB/NoPadding");
			key = setupKey(key);
			ecipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "DES"));
		} catch (NoSuchAlgorithmException e) {
			throw new HttpException("DES encryption is not available.");
		} catch (InvalidKeyException e) {
			throw new HttpException("Invalid Key for DES encryption.");
		} catch (NoSuchPaddingException e) {
			throw new HttpException("NoPadding option for DES is not available.");
		} 
	}

	/** Adds parity bits to the key if required.
	 */
	private byte[] setupKey(byte[] key56) {
		byte[] key = new byte[8];
		key[0] = (byte)((key56[0] >> 1) & 0xff);
		key[1] = (byte)((((key56[0] & 0x01) << 6) | (((key56[1] & 0xff)>>2) & 0xff)) & 0xff);
		key[2] = (byte)((((key56[1] & 0x03) << 5) | (((key56[2] & 0xff)>>3) & 0xff)) & 0xff);
		key[3] = (byte)((((key56[2] & 0x07) << 4) | (((key56[3] & 0xff)>>4) & 0xff)) & 0xff);
		key[4] = (byte)((((key56[3] & 0x0f) << 3) | (((key56[4] & 0xff)>>5) & 0xff)) & 0xff);
		key[5] = (byte)((((key56[4] & 0x1f) << 2) | (((key56[5] & 0xff)>>6) & 0xff)) & 0xff);
		key[6] = (byte)((((key56[5] & 0x3f) << 1) | (((key56[6] & 0xff)>>7) & 0xff)) & 0xff);
		key[7] = (byte)(key56[6] & 0x7f);
		
		for (int i = 0; i < key.length; i++) {
			key[i] = (byte)(key[i] << 1);
		}
		return key;
	}

	public byte[] encrypt(byte[] bytes) throws HttpException {
		try {
			byte[] enc = ecipher.doFinal(bytes);
			return enc;
		} catch (IllegalBlockSizeException e) {
			throw new HttpException("Invalid block size for DES encryption.");
		} catch (BadPaddingException e) {
			throw new HttpException(
					"Data not padded correctly for DES encryption.");
		}
	}
}

