/**
 *
 * Licensed Property to China UnionPay Co., Ltd.
 * 
 * (C) Copyright of China UnionPay Co., Ltd. 2010
 *     All Rights Reserved.
 *
 * 
 * Modification History:
 * =============================================================================
 *   Author         Date          Description
 *   ------------ ---------- ---------------------------------------------------
 *   xshu       2014-05-28     报文加密解密等操作的工具类
 * =============================================================================
 */
package com.itstyle.modules.unionpay.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class SecureUtil {
	private static final Logger logger = LoggerFactory.getLogger(SecureUtil.class);
	/**
	 * 算法常量： MD5
	 */
	private static final String ALGORITHM_MD5 = "MD5";
	/**
	 * 算法常量： SHA1
	 */
	private static final String ALGORITHM_SHA1 = "SHA-1";

	/**
	 * 算法常量：SHA1withRSA
	 */
	private static final String BC_PROV_ALGORITHM_SHA1RSA = "SHA1withRSA";

	/**
	 * md5计算.
	 * 
	 * @param datas
	 *            待计算的数据
	 * @return 计算结果
	 */
	public static byte[] md5(byte[] datas) {
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance(ALGORITHM_MD5);
			md.reset();
			md.update(datas);
			return md.digest();
		} catch (Exception e) {
			logger.error("MD5计算失败", e);
			return null;
		}
	}

	/**
	 * sha1计算.
	 * 
	 * @param datas
	 *            待计算的数据
	 * @return 计算结果
	 */
	public static byte[] sha1(byte[] data) {
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance(ALGORITHM_SHA1);
			md.reset();
			md.update(data);
			return md.digest();
		} catch (Exception e) {
			logger.error("SHA1计算失败", e);
			return null;
		}
	}

	/**
	 * md5计算后进行16进制转换
	 * 
	 * @param datas
	 *            待计算的数据
	 * @param encoding
	 *            编码
	 * @return 计算结果
	 */
	public static byte[] md5X16(String datas, String encoding) {
		byte[] bytes = md5(datas, encoding);
		StringBuilder md5StrBuff = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
				md5StrBuff.append("0").append(
						Integer.toHexString(0xFF & bytes[i]));
			} else {
				md5StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
			}
		}
		try {
			return md5StrBuff.toString().getBytes(encoding);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	/**
	 * sha1计算后进行16进制转换
	 * 
	 * @param data
	 *            待计算的数据
	 * @param encoding
	 *            编码
	 * @return 计算结果
	 */
	public static byte[] sha1X16(String data, String encoding) {
		byte[] bytes = sha1(data, encoding);
		StringBuilder sha1StrBuff = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
				sha1StrBuff.append("0").append(
						Integer.toHexString(0xFF & bytes[i]));
			} else {
				sha1StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
			}
		}
		try {
			return sha1StrBuff.toString().getBytes(encoding);
		} catch (UnsupportedEncodingException e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}

	/**
	 * md5计算
	 * 
	 * @param datas
	 *            待计算的数据
	 * @param encoding
	 *            字符集编码
	 * @return
	 */
	public static byte[] md5(String datas, String encoding) {
		try {
			return md5(datas.getBytes(encoding));
		} catch (UnsupportedEncodingException e) {
			logger.error("MD5计算失败", e);
			return null;
		}
	}

	/**
	 * sha1计算
	 * 
	 * @param datas
	 *            待计算的数据
	 * @param encoding
	 *            字符集编码
	 * @return
	 */
	public static byte[] sha1(String datas, String encoding) {
		try {
			return sha1(datas.getBytes(encoding));
		} catch (UnsupportedEncodingException e) {
			logger.error("SHA1计算失败", e);
			return null;
		}
	}

	/**
	 * 软签名
	 * 
	 * @param privateKey
	 *            私钥
	 * @param data
	 *            待签名数据
	 * @param signMethod
	 *            签名方法
	 * @return 结果
	 * @throws Exception
	 */
	public static byte[] signBySoft(PrivateKey privateKey, byte[] data)
			throws Exception {
		byte[] result = null;
		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
		st.initSign(privateKey);
		st.update(data);
		result = st.sign();
		return result;
	}

	/**
	 * 软验证签名
	 * 
	 * @param publicKey
	 *            公钥
	 * @param signData
	 *            签名数据
	 * @param srcData
	 *            摘要
	 * @param validateMethod
	 *            签名方法.
	 * @return
	 * @throws Exception
	 */
	public static boolean validateSignBySoft(PublicKey publicKey,
			byte[] signData, byte[] srcData) throws Exception {
		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
		st.initVerify(publicKey);
		st.update(srcData);
		return st.verify(signData);
	}

	/**
	 * 解压缩.
	 * 
	 * @param inputByte
	 *            byte[]数组类型的数据
	 * @return 解压缩后的数据
	 * @throws IOException
	 */
	public static byte[] inflater(final byte[] inputByte) throws IOException {
		int compressedDataLength = 0;
		Inflater compresser = new Inflater(false);
		compresser.setInput(inputByte, 0, inputByte.length);
		ByteArrayOutputStream o = new ByteArrayOutputStream(inputByte.length);
		byte[] result = new byte[1024];
		try {
			while (!compresser.finished()) {
				compressedDataLength = compresser.inflate(result);
				if (compressedDataLength == 0) {
					break;
				}
				o.write(result, 0, compressedDataLength);
			}
		} catch (Exception ex) {
			System.err.println("Data format error!\n");
			ex.printStackTrace();
		} finally {
			o.close();
		}
		compresser.end();
		return o.toByteArray();
	}

	/**
	 * 压缩.
	 * 
	 * @param inputByte
	 *            需要解压缩的byte[]数组
	 * @return 压缩后的数据
	 * @throws IOException
	 */
	public static byte[] deflater(final byte[] inputByte) throws IOException {
		int compressedDataLength = 0;
		Deflater compresser = new Deflater();
		compresser.setInput(inputByte);
		compresser.finish();
		ByteArrayOutputStream o = new ByteArrayOutputStream(inputByte.length);
		byte[] result = new byte[1024];
		try {
			while (!compresser.finished()) {
				compressedDataLength = compresser.deflate(result);
				o.write(result, 0, compressedDataLength);
			}
		} finally {
			o.close();
		}
		compresser.end();
		return o.toByteArray();
	}

	/**
	 * 密码加密,进行base64加密
	 * 
	 * @param pin
	 *            密码
	 * @param card
	 *            卡号
	 * @param encoding
	 *            字符编码
	 * @param key
	 *            公钥
	 * @return 转PIN结果
	 */
	public static String EncryptPin(String pin, String card, String encoding,
			PublicKey key) {
		/** 生成PIN Block **/
		byte[] pinBlock = pin2PinBlockWithCardNO(pin, card);
		/** 使用公钥对密码加密 **/
		byte[] data = null;
		try {
			data = encryptedPin(key, pinBlock);
			return new String(SecureUtil.base64Encode(data), encoding);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return "";
		}
	}

	/**
	 * 对数据通过公钥进行加密，并进行base64计算
	 * 
	 * @param dataString
	 *            待处理数据
	 * @param encoding
	 *            字符编码
	 * @param key
	 *            公钥
	 * @return
	 */
	public static String EncryptData(String dataString, String encoding,
			PublicKey key) {
		/** 使用公钥对密码加密 **/
		byte[] data = null;
		try {
			data = encryptedPin(key, dataString.getBytes(encoding));
			return new String(SecureUtil.base64Encode(data), encoding);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return "";
		}
	}

	/**
	 * 通过私钥解密
	 * 
	 * @param dataString
	 *            base64过的数据
	 * @param encoding
	 *            编码
	 * @param key
	 *            私钥
	 * @return 解密后的数据
	 */
	public static String DecryptedData(String dataString, String encoding,
			PrivateKey key) {
		byte[] data = null;
		try {
			data = decryptedPin(key, dataString.getBytes(encoding));
			return new String(data, encoding);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return "";
		}
	}

	/**
	 * BASE64解码
	 * 
	 * @param inputByte
	 *            待解码数据
	 * @return 解码后的数据
	 * @throws IOException
	 */
	public static byte[] base64Decode(byte[] inputByte) throws IOException {
		return Base64.decodeBase64(inputByte);
	}

	/**
	 * BASE64编码
	 * 
	 * @param inputByte
	 *            待编码数据
	 * @return 解码后的数据
	 * @throws IOException
	 */
	public static byte[] base64Encode(byte[] inputByte) throws IOException {
		return Base64.encodeBase64(inputByte);
	}

	/**
	 * 将字符串转换为byte数组
	 * 
	 * @param str
	 *            待转换的字符串
	 * @return 转换结果
	 */
	public byte[] Str2Hex(String str) {
		char[] ch = str.toCharArray();
		byte[] b = new byte[ch.length / 2];
		for (int i = 0; i < ch.length; i++) {
			if (ch[i] == 0) {
				break;
			}
			if (ch[i] >= '0' && ch[i] <= '9') {
				ch[i] = (char) (ch[i] - '0');
			} else if (ch[i] >= 'A' && ch[i] <= 'F') {
				ch[i] = (char) (ch[i] - 'A' + 10);
			}
		}
		for (int i = 0; i < b.length; i++) {
			b[i] = (byte) (((ch[2 * i] << 4) & 0xf0) + (ch[2 * i + 1] & 0x0f));
		}
		return b;
	}

	/**
	 * 将byte数组转换为可见的字符串
	 * 
	 * @param b
	 *            待转换的byte数组
	 * @return 转换后的字符串
	 */
	public static String Hex2Str(byte[] b) {
		StringBuffer d = new StringBuffer(b.length * 2);
		for (int i = 0; i < b.length; i++) {
			char hi = Character.forDigit((b[i] >> 4) & 0x0F, 16);
			char lo = Character.forDigit(b[i] & 0x0F, 16);
			d.append(Character.toUpperCase(hi));
			d.append(Character.toUpperCase(lo));
		}
		return d.toString();
	}

	public static String ByteToHex(byte[] bytes) {
		StringBuffer sha1StrBuff = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
				sha1StrBuff.append("0").append(
						Integer.toHexString(0xFF & bytes[i]));
			} else {
				sha1StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
			}
		}
		return sha1StrBuff.toString();
	}

	/**
	 * 将byte数组转换为可见的字符串
	 * 
	 * @param b
	 *            待转换的byte数组
	 * @param len
	 *            转换长度
	 * @return
	 */
	public static String Hex2Str(byte[] b, int len) {
		String str = "";
		char[] ch = new char[len * 2];

		for (int i = 0; i < len; i++) {
			if ((((b[i] >> 4) & 0x0f) < 0x0a) && (((b[i] >> 4) & 0x0f) >= 0x0)) {
				ch[i * 2] = (char) (((b[i] >> 4) & 0x0f) + '0');
			} else {
				ch[i * 2] = (char) (((b[i] >> 4) & 0x0f) + 'A' - 10);
			}

			if ((((b[i]) & 0x0f) < 0x0a) && (((b[i]) & 0x0f) >= 0x0)) {
				ch[i * 2 + 1] = (char) (((b[i]) & 0x0f) + '0');
			} else {
				ch[i * 2 + 1] = (char) (((b[i]) & 0x0f) + 'A' - 10);
			}

		}
		str = new String(ch);
		return str;
	}

	/**
	 * 将byte数组转换为可见的大写字符串
	 * 
	 * @param b
	 *            待转换的byte数组
	 * @return 转换后的结果
	 */
	public String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			} else {
				hs = hs + stmp;
			}
			if (n < b.length - 1) {
				hs = hs + ":";
			}
		}
		return hs.toUpperCase();
	}

	/**
	 * 计算MAC
	 * 
	 * @param inputByte
	 *            待计算数据
	 * @param inputkey
	 *            密钥
	 * @return 计算出的MAC值
	 * @throws Exception
	 */
	public String genmac(byte[] inputByte, byte[] inputkey) throws Exception {
		try {
			Mac mac = Mac.getInstance("HmacMD5");
			SecretKey key = new SecretKeySpec(inputkey, "DES");
			mac.init(key);

			byte[] macCode = mac.doFinal(inputByte);
			String strMac = this.byte2hex(macCode);
			return strMac;
		} catch (Exception ex) {
			ex.printStackTrace();
			throw ex;
		}
	}

	/**
	 * MAC校验
	 * 
	 * @param inputByte
	 *            待计算的数据
	 * @param inputkey
	 *            密钥
	 * @param inputmac
	 *            比较MAC
	 * @return 校验结果
	 * @throws Exception
	 */
	public boolean checkmac(byte[] inputByte, byte[] inputkey, String inputmac)
			throws Exception {
		try {
			Mac mac = Mac.getInstance("HmacMD5");
			SecretKey key = new SecretKeySpec(inputkey, "DES");
			mac.init(key);

			byte[] macCode = mac.doFinal(inputByte);
			String strMacCode = this.byte2hex(macCode);

			if (strMacCode.equals(inputmac)) {
				return true;
			} else {
				return false;
			}
		} catch (Exception ex) {
			throw ex;
		}
	}

	/**
	 * 字符串填充
	 * 
	 * @param string
	 *            源串
	 * @param filler
	 *            填充值
	 * @param totalLength
	 *            填充总长度
	 * @param atEnd
	 *            头尾填充表急,true - 尾部填充;false - 头部填充
	 * @return
	 */
	public static String fillString(String string, char filler,
			int totalLength, boolean atEnd) {
		byte[] tempbyte = string.getBytes();
		int currentLength = tempbyte.length;
		int delta = totalLength - currentLength;

		for (int i = 0; i < delta; i++) {
			if (atEnd) {
				string += filler;
			} else {
				string = filler + string;
			}
		}
		return string;

	}

	/**
	 * 使用网关公钥对持卡人密码进行加密，并返回byte[]类型
	 * 
	 * @param publicKey
	 * @param plainPin
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptedPin(PublicKey publicKey, byte[] plainPin)
			throws Exception {
		try {
			// y
			// Cipher cipher = Cipher.getInstance("DES",
			// new org.bouncycastle.jce.provider.BouncyCastleProvider());

			// 本土的
//			Cipher cipher = CliperInstance.getInstance();
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			int blockSize = cipher.getBlockSize();
			int outputSize = cipher.getOutputSize(plainPin.length);
			int leavedSize = plainPin.length % blockSize;
			int blocksSize = leavedSize != 0 ? plainPin.length / blockSize + 1
					: plainPin.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (plainPin.length - i * blockSize > 0) {
				if (plainPin.length - i * blockSize > blockSize) {
					cipher.doFinal(plainPin, i * blockSize, blockSize, raw, i
							* outputSize);
				} else {
					cipher.doFinal(plainPin, i * blockSize, plainPin.length - i
							* blockSize, raw, i * outputSize);
				}
				i++;
			}
			return raw;
			
			/*Cipher cipher = CliperInstance.getInstance();
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(plainPin);
			return output;*/
			
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	/**
	 * 
	 * @param publicKey
	 * @param plainData
	 * @return
	 * @throws Exception
	 */
	public byte[] encryptedData(PublicKey publicKey, byte[] plainData)
			throws Exception {
		try {
//			Cipher cipher = CliperInstance.getInstance();
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			int blockSize = cipher.getBlockSize();
			int outputSize = cipher.getOutputSize(plainData.length);
			int leavedSize = plainData.length % blockSize;
			int blocksSize = leavedSize != 0 ? plainData.length / blockSize + 1
					: plainData.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (plainData.length - i * blockSize > 0) {
				if (plainData.length - i * blockSize > blockSize) {
					cipher.doFinal(plainData, i * blockSize, blockSize, raw, i
							* outputSize);
				} else {
					cipher.doFinal(plainData, i * blockSize, plainData.length
							- i * blockSize, raw, i * outputSize);
				}
				i++;
			}
			return raw;
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		}
	}

	/**
	 * 
	 * @param privateKey
	 * @param cryptPin
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptedPin(PrivateKey privateKey, byte[] cryptPin)
			throws Exception {

		try {
			/** 生成PIN Block **/
			byte[] pinBlock = SecureUtil.base64Decode(cryptPin);
			// 本土的
//			Cipher cipher = CliperInstance.getInstance();
			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			int blockSize = cipher.getBlockSize();
			int outputSize = cipher.getOutputSize(pinBlock.length);
			int leavedSize = pinBlock.length % blockSize;
			int blocksSize = leavedSize != 0 ? pinBlock.length / blockSize + 1
					: pinBlock.length / blockSize;
			byte[] pinData = new byte[outputSize * blocksSize];
			int i = 0;
			while (pinBlock.length - i * blockSize > 0) {
				if (pinBlock.length - i * blockSize > blockSize) {
					cipher.doFinal(pinBlock, i * blockSize, blockSize, pinData,
							i * outputSize);
				} else {
					cipher.doFinal(pinBlock, i * blockSize, pinBlock.length - i
							* blockSize, pinData, i * outputSize);
				}
				i++;
			}
			return pinData;
		} catch (Exception e) {
			logger.error("解密失败", e);
		}
		return null;
	}

	/**
	 * 
	 * @param aPin
	 * @return
	 */
	private static byte[] pin2PinBlock(String aPin) {
		int tTemp = 1;
		int tPinLen = aPin.length();

		byte[] tByte = new byte[8];
		try {
			/*******************************************************************
			 * if (tPinLen > 9) { tByte[0] = (byte) Integer.parseInt(new
			 * Integer(tPinLen) .toString(), 16); } else { tByte[0] = (byte)
			 * Integer.parseInt(new Integer(tPinLen) .toString(), 10); }
			 ******************************************************************/
//			tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen).toString(),
//					10);
			tByte[0] = (byte) Integer.parseInt(Integer.toString(tPinLen), 10);
			if (tPinLen % 2 == 0) {
				for (int i = 0; i < tPinLen;) {
					String a = aPin.substring(i, i + 2);
					tByte[tTemp] = (byte) Integer.parseInt(a, 16);
					if (i == (tPinLen - 2)) {
						if (tTemp < 7) {
							for (int x = (tTemp + 1); x < 8; x++) {
								tByte[x] = (byte) 0xff;
							}
						}
					}
					tTemp++;
					i = i + 2;
				}
			} else {
				for (int i = 0; i < tPinLen - 1;) {
					String a;
					a = aPin.substring(i, i + 2);
					tByte[tTemp] = (byte) Integer.parseInt(a, 16);
					if (i == (tPinLen - 3)) {
						String b = aPin.substring(tPinLen - 1) + "F";
						tByte[tTemp + 1] = (byte) Integer.parseInt(b, 16);
						if ((tTemp + 1) < 7) {
							for (int x = (tTemp + 2); x < 8; x++) {
								tByte[x] = (byte) 0xff;
							}
						}
					}
					tTemp++;
					i = i + 2;
				}
			}
		} catch (Exception e) {
		}

		return tByte;
	}

	/**
	 * 
	 * @param aPan
	 * @return
	 */
	private static byte[] formatPan(String aPan) {
		int tPanLen = aPan.length();
		byte[] tByte = new byte[8];
		;
		int temp = tPanLen - 13;
		try {
			tByte[0] = (byte) 0x00;
			tByte[1] = (byte) 0x00;
			for (int i = 2; i < 8; i++) {
				String a = aPan.substring(temp, temp + 2);
				tByte[i] = (byte) Integer.parseInt(a, 16);
				temp = temp + 2;
			}
		} catch (Exception e) {
		}
		return tByte;
	}

	/**
	 * 
	 * @param aPin
	 * @param aCardNO
	 * @return
	 */
	public static byte[] pin2PinBlockWithCardNO(String aPin, String aCardNO) {
		byte[] tPinByte = pin2PinBlock(aPin);
		if (aCardNO.length() == 11) {
			aCardNO = "00" + aCardNO;
		} else if (aCardNO.length() == 12) {
			aCardNO = "0" + aCardNO;
		}
		byte[] tPanByte = formatPan(aCardNO);
		byte[] tByte = new byte[8];
		for (int i = 0; i < 8; i++) {
			tByte[i] = (byte) (tPinByte[i] ^ tPanByte[i]);
		}
		return tByte;
	}

	/**
	 * 
	 * @param aBytesText
	 * @param aBlockSize
	 * @return
	 */
	private static byte[] addPKCS1Padding(byte[] aBytesText, int aBlockSize) {
		if (aBytesText.length > (aBlockSize - 3)) {
			return null;
		}
		SecureRandom tRandom = new SecureRandom();
		byte[] tAfterPaddingBytes = new byte[aBlockSize];
		tRandom.nextBytes(tAfterPaddingBytes);
		tAfterPaddingBytes[0] = 0x00;
		tAfterPaddingBytes[1] = 0x02;
		int i = 2;
		for (; i < aBlockSize - 1 - aBytesText.length; i++) {
			if (tAfterPaddingBytes[i] == 0x00) {
				tAfterPaddingBytes[i] = (byte) tRandom.nextInt();
			}
		}
		tAfterPaddingBytes[i] = 0x00;
		System.arraycopy(aBytesText, 0, tAfterPaddingBytes, (i + 1),
				aBytesText.length);

		return tAfterPaddingBytes;
	}

	/**
	 * 
	 * @param tPIN
	 * @param iPan
	 * @param publicKey
	 * @return
	 */
	public String assymEncrypt(String tPIN, String iPan, RSAPublicKey publicKey) {

		System.out.println("SampleHashMap::assymEncrypt([" + tPIN + "])");
		System.out.println("SampleHashMap::assymEncrypt(PIN =[" + tPIN + "])");

		try {
			int tKeyLength = 1024;
			int tBlockSize = tKeyLength / 8;

			byte[] tTemp = null;

			tTemp = SecureUtil.pin2PinBlockWithCardNO(tPIN, iPan);
			tTemp = addPKCS1Padding(tTemp, tBlockSize);

			BigInteger tPlainText = new BigInteger(tTemp);
			BigInteger tCipherText = tPlainText.modPow(publicKey
					.getPublicExponent(), publicKey.getModulus());

			byte[] tCipherBytes = tCipherText.toByteArray();
			int tCipherLength = tCipherBytes.length;
			if (tCipherLength > tBlockSize) {
				byte[] tTempBytes = new byte[tBlockSize];
				System.arraycopy(tCipherBytes, tCipherLength - tBlockSize,
						tTempBytes, 0, tBlockSize);
				tCipherBytes = tTempBytes;
			} else if (tCipherLength < tBlockSize) {
				byte[] tTempBytes = new byte[tBlockSize];
				for (int i = 0; i < tBlockSize - tCipherLength; i++) {
					tTempBytes[i] = 0x00;
				}
				System.arraycopy(tCipherBytes, 0, tTempBytes, tBlockSize
						- tCipherLength, tCipherLength);
				tCipherBytes = tTempBytes;
			}
			String tEncryptPIN = new String(SecureUtil
					.base64Encode(tCipherBytes));

			System.out.println("SampleHashMap::assymEncrypt(EncryptCardNo =["
					+ tEncryptPIN + "])");

			return tEncryptPIN;
		} catch (Exception e) {
			e.printStackTrace(System.out);
			return tPIN;
		} catch (Error e) {
			e.printStackTrace(System.out);
			return tPIN;
		}
	}

	/**
	 * 以16进制对照的方式打印byte数组
	 * 
	 * @param inBytes
	 * @return
	 */
	public static String trace(byte[] inBytes) {
		int i, j = 0;
		byte[] temp = new byte[76];
		bytesSet(temp, ' ');
		StringBuffer strc = new StringBuffer("");
		strc
				.append("----------------------------------------------------------------------------"
						+ "\n");
		for (i = 0; i < inBytes.length; i++) {
			if (j == 0) {
				System.arraycopy(String.format("%03d: ", i).getBytes(), 0,
						temp, 0, 5);
				System.arraycopy(String.format(":%03d", i + 15).getBytes(), 0,
						temp, 72, 4);
			}
			System.arraycopy(String.format("%02X ", inBytes[i]).getBytes(), 0,
					temp, j * 3 + 5 + (j > 7 ? 1 : 0), 3);
			if (inBytes[i] == 0x00) {
				temp[j + 55 + ((j > 7 ? 1 : 0))] = '.';
			} else {
				temp[j + 55 + ((j > 7 ? 1 : 0))] = inBytes[i];
			}
			j++;
			if (j == 16) {
				strc.append(new String(temp)).append("\n");
				bytesSet(temp, ' ');
				j = 0;
			}
		}
		if (j != 0) {
			strc.append(new String(temp)).append("\n");
			bytesSet(temp, ' ');
		}
		strc
				.append("----------------------------------------------------------------------------"
						+ "\n");
		return strc.toString();
	}

	/**
	 * 
	 * @param inBytes
	 * @param fill
	 */
	private static void bytesSet(byte[] inBytes, char fill) {
		if (inBytes.length == 0) {
			return;
		}
		for (int i = 0; i < inBytes.length; i++) {
			inBytes[i] = (byte) fill;
		}
	}
	
    public static PublicKey getPublicKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
			return keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			throw new RuntimeException("getPublicKey error", e);
		}
	}
    
}
