package com.one;

import com.classpath.hash.MessageDigest;
import com.classpath.hash.Sha160;
import java.io.*;
import com.vmx.*;

/**
 * Шифратор.
 * Для шифрования используется метод гаммирования с псевдослучайным ключом.
 */
public class RTEF
{
	protected ExtRandom rnd;
	
	/**
	 * Хеширование строки.
	 * Хеш вычисляется по алгоритму SHA-1, строка рассматривается
	 * как последовательность символов в Юникоде.
	 */
	public static int[] hashString(String s)
	{
		MessageDigest md = new Sha160();
		int len = s.length();
		char c;
		
		for(int i = 0; i < len; i++)
		{
			c = s.charAt(i);
			
			md.update((byte)(c >> 8));
			md.update((byte)c);
		}

		byte[] digest = md.digest();
		int[] res = new int[5];

		res[0] = (((int)digest[0]  & 0xFF) << 24) | (((int)digest[1]  & 0xFF) << 16) | (((int)digest[2]  & 0xFF) << 8) | ((int)digest[3]  & 0xFF);
		res[1] = (((int)digest[4]  & 0xFF) << 24) | (((int)digest[5]  & 0xFF) << 16) | (((int)digest[6]  & 0xFF) << 8) | ((int)digest[7]  & 0xFF);
		res[2] = (((int)digest[8]  & 0xFF) << 24) | (((int)digest[9]  & 0xFF) << 16) | (((int)digest[10] & 0xFF) << 8) | ((int)digest[11] & 0xFF);
		res[3] = (((int)digest[12] & 0xFF) << 24) | (((int)digest[13] & 0xFF) << 16) | (((int)digest[14] & 0xFF) << 8) | ((int)digest[15] & 0xFF);
		res[4] = (((int)digest[16] & 0xFF) << 24) | (((int)digest[17] & 0xFF) << 16) | (((int)digest[18] & 0xFF) << 8) | ((int)digest[19] & 0xFF);

		return res;
	}
	
	/**
	 * Создание шифратора с паролем в виде строки
	 */
	public RTEF(String password)
	{
		int[] hash = hashString(password);
		
		rnd = new ExtRandom(hash[0] ^ hash[1] ^ hash[2]);
		
		int offset = (hash[3] ^ hash[4]) & 0xFFFF;
		
		for(int i = 0; i < offset; i++)
		{
			rnd.nextInt();
		}
		
		rnd.mark();
	}
	
	/**
	 * Создание шифратора с паролем в виде параметров ГСЧ
	 */
	public RTEF(long key, int offset)
	{
		rnd = new ExtRandom(key);
		
		for(int i = 0; i < offset; i++)
		{
			rnd.nextInt();
		}
		
		rnd.mark();
	}
	
	/**
	 * Шифрование потока.
	 * Для каждой операции шифрования используется одинаковая гамма.
	 */
	public void crypt(InputStream is, OutputStream os, ProgressCallback callback) throws IOException
	{
		rnd.reset();
		
		int k = rnd.nextInt();
		int shift = 0;
		
		byte[] buf = new byte[AuxClass.COPYBUFSIZE];
		int buflen, i;
		
		while(is.available() > 0)
		{
			buflen = is.read(buf);
			
			for(i = 0; i < buflen; i++)
			{
				buf[i] ^= (byte)(k >>> shift);
				
				shift += 8;
				
				if(shift >= 32)
				{
					k = rnd.nextInt();
					shift = 0;
				}
			}
			
			os.write(buf, 0, buflen);
			
			if(callback != null)
			{
				callback.progress(buflen);
			}
		}
	}
}
