package org.bench4q.master.domain.service.auth;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Enumeration;

import javax.crypto.Cipher;

import org.springframework.stereotype.Component;

@Component
public class CryptoManager {
	private static final int MAX_ENCRYPT_BLOCK = 245;
	private static final int MAX_DECRYPT_BLOCK = 256;

	private PublicKey publicKey;
	private PrivateKey privateKey;

	private PublicKey getPublicKey() {
		return publicKey;
	}

	private void setPublicKey(PublicKey publicKey) {
		this.publicKey = publicKey;
	}

	private PrivateKey getPrivateKey() {
		return privateKey;
	}

	private void setPrivateKey(PrivateKey privateKey) {
		this.privateKey = privateKey;
	}

	public CryptoManager() {
		try {
			InputStream pfxInputStream = Thread.currentThread()
					.getContextClassLoader()
					.getResourceAsStream("org/bench4q/master/config/key.pfx");
			String pfxPassword = "123456";
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			keyStore.load(pfxInputStream, pfxPassword.toCharArray());
			pfxInputStream.close();
			Enumeration<String> aliases = keyStore.aliases();
			if (aliases.hasMoreElements()) {
				String alias = aliases.nextElement();
				PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) keyStore
						.getEntry(alias, new KeyStore.PasswordProtection(
								pfxPassword.toCharArray()));
				this.setPrivateKey(privateKeyEntry.getPrivateKey());
				this.setPublicKey(privateKeyEntry.getCertificate()
						.getPublicKey());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public byte[] encrypt(byte[] data) {
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, this.getPublicKey());
			int inputLen = data.length;
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			int offSet = 0;
			byte[] cache;
			int i = 0;
			while (inputLen - offSet > 0) {
				if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
					cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
				} else {
					cache = cipher.doFinal(data, offSet, inputLen - offSet);
				}
				out.write(cache, 0, cache.length);
				i++;
				offSet = i * MAX_ENCRYPT_BLOCK;
			}
			byte[] encryptedData = out.toByteArray();
			out.close();
			return encryptedData;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public byte[] decrypt(byte[] encryptedData) {
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.DECRYPT_MODE, this.getPrivateKey());
			int inputLen = encryptedData.length;
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			int offSet = 0;
			byte[] cache;
			int i = 0;
			while (inputLen - offSet > 0) {
				if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
					cache = cipher.doFinal(encryptedData, offSet,
							MAX_DECRYPT_BLOCK);
				} else {
					cache = cipher.doFinal(encryptedData, offSet, inputLen
							- offSet);
				}
				out.write(cache, 0, cache.length);
				i++;
				offSet = i * MAX_DECRYPT_BLOCK;
			}
			byte[] decryptedData = out.toByteArray();
			out.close();
			return decryptedData;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}
