All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.chrl.nutils.ncrypt.CryptEngine Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of Aion-Finish 
 * 
 * Aion-Finish is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Aion-Finish is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * Aion-Finish. If not, see .
 */
package at.chrl.nutils.ncrypt;

import at.chrl.nutils.Rnd;

/**
 * Crypto engine for ecnrypting/decrypting packets, error handling and verifying
 * checksum
 *
 * @author EvilSpirit
 */
public class CryptEngine {
	/**
	 * A key
	 */
	private byte[] key = { (byte) 0x6b, (byte) 0x60, (byte) 0xcb, (byte) 0x5b, (byte) 0x82, (byte) 0xce, (byte) 0x90, (byte) 0xb1, (byte) 0xcc, (byte) 0x2b, (byte) 0x6c, (byte) 0x55, (byte) 0x6c, (byte) 0x6c, (byte) 0x6c, (byte) 0x6c };
	/**
	 * Tells you whether the key is updated or not
	 */
	private boolean updatedKey = false;
	/**
	 * A secret blowfish cipher
	 */
	private BlowfishCipher cipher;

	/**
	 * Default constructor. Initialize the Blowfish Cipher with an initial
	 * static key to encrypt the first packet sent to the client
	 */
	public CryptEngine() {
		cipher = new BlowfishCipher(key);
	}

	/**
	 * Update the key for packet encryption/decryption with the Blowfish Cipher
	 * 
	 * @param newKey
	 *            new Blowfish Key
	 */
	public void updateKey(byte[] newKey) {
		this.key = newKey;
	}

	/**
	 * Decrypt given data
	 * 
	 * @param data
	 *            byte array to be decrypted
	 * @param offset
	 *            byte array offset
	 * @param length
	 *            byte array length
	 * @return true, if decrypted packet has valid checksum, false overwise
	 */
	public boolean decrypt(byte[] data, int offset, int length) {
		cipher.decipher(data, offset, length);

		return verifyChecksum(data, offset, length);
	}

	/**
	 * Encrypt given data
	 * 
	 * @param data
	 *            byte array to be encrypted
	 * @param offset
	 *            byte array offset
	 * @param length
	 *            byte array length
	 * @return length of encrypted byte array
	 */
	public int encrypt(byte[] data, int offset, int length) {
		length += 4;

		// the key is not updated, so the first packet should be encrypted with
		// initial key
		if (!updatedKey) {
			length += 4;
			length += 8 - length % 8;
			encXORPass(data, offset, length, Rnd.nextInt());
			cipher.cipher(data, offset, length);
			cipher.updateKey(key);
			updatedKey = true;
		} else {
			length += 8 - length % 8;
			appendChecksum(data, offset, length);
			cipher.cipher(data, offset, length);
		}

		return length;
	}

	/**
	 * Verify checksum in a packet
	 * 
	 * @param data
	 *            byte array - encrypted packet
	 * @param offset
	 *            byte array offset
	 * @param length
	 *            byte array size
	 * @return true, if checksum is ok, false overwise
	 */
	private boolean verifyChecksum(byte[] data, int offset, int length) {
		if ((length & 3) != 0 || (length <= 4)) {
			return false;
		}

		long chksum = 0;
		int count = length - 4;
		long check;
		int i;

		for (i = offset; i < count; i += 4) {
			check = data[i] & 0xff;
			check |= data[i + 1] << 8 & 0xff00;
			check |= data[i + 2] << 0x10 & 0xff0000;
			check |= data[i + 3] << 0x18 & 0xff000000;
			chksum ^= check;
		}

		check = data[i] & 0xff;
		check |= data[i + 1] << 8 & 0xff00;
		check |= data[i + 2] << 0x10 & 0xff0000;
		check |= data[i + 3] << 0x18 & 0xff000000;
		check = data[i] & 0xff;
		check |= data[i + 1] << 8 & 0xff00;
		check |= data[i + 2] << 0x10 & 0xff0000;
		check |= data[i + 3] << 0x18 & 0xff000000;

		return 0 == chksum;
	}

	/**
	 * add checksum to the end of the packet
	 * 
	 * @param raw
	 *            byte array - encrypted packet
	 * @param offset
	 *            byte array offset
	 * @param length
	 *            byte array size
	 */
	private void appendChecksum(byte[] raw, int offset, int length) {
		long chksum = 0;
		int count = length - 4;
		long ecx;
		int i;

		for (i = offset; i < count; i += 4) {
			ecx = raw[i] & 0xff;
			ecx |= raw[i + 1] << 8 & 0xff00;
			ecx |= raw[i + 2] << 0x10 & 0xff0000;
			ecx |= raw[i + 3] << 0x18 & 0xff000000;
			chksum ^= ecx;
		}

		ecx = raw[i] & 0xff;
		ecx |= raw[i + 1] << 8 & 0xff00;
		ecx |= raw[i + 2] << 0x10 & 0xff0000;
		ecx |= raw[i + 3] << 0x18 & 0xff000000;
		raw[i] = (byte) (chksum & 0xff);
		raw[i + 1] = (byte) (chksum >> 0x08 & 0xff);
		raw[i + 2] = (byte) (chksum >> 0x10 & 0xff);
		raw[i + 3] = (byte) (chksum >> 0x18 & 0xff);
	}

	/**
	 * First packet encryption with XOR key (integer - 4 bytes)
	 * 
	 * @param data
	 *            byte array to be encrypted
	 * @param offset
	 *            byte array offset
	 * @param length
	 *            byte array length
	 * @param key
	 *            integer value as key
	 */
	private void encXORPass(byte[] data, int offset, int length, int key) {
		int stop = length - 8;
		int pos = 4 + offset;
		int edx;
		int ecx = key;

		while (pos < stop) {
			edx = (data[pos] & 0xFF);
			edx |= (data[pos + 1] & 0xFF) << 8;
			edx |= (data[pos + 2] & 0xFF) << 16;
			edx |= (data[pos + 3] & 0xFF) << 24;
			ecx += edx;
			edx ^= ecx;
			data[pos++] = (byte) (edx & 0xFF);
			data[pos++] = (byte) (edx >> 8 & 0xFF);
			data[pos++] = (byte) (edx >> 16 & 0xFF);
			data[pos++] = (byte) (edx >> 24 & 0xFF);
		}

		data[pos++] = (byte) (ecx & 0xFF);
		data[pos++] = (byte) (ecx >> 8 & 0xFF);
		data[pos++] = (byte) (ecx >> 16 & 0xFF);
		data[pos] = (byte) (ecx >> 24 & 0xFF);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy