转:标准银联POS加解密、及MAC算法

原文链接

银联标准3DES加、解密(是双倍长),32位明文进,32位密文出,用于卡密码、金额等敏感信息加、解密:

对于加解密前的异或等操作就不做说明了

private static final int iSelePM1[] = { // 置换选择1的矩阵
	57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43,
			35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7,
			62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28,
			20, 12, 4 };
	
	private static final int iSelePM2[] = { // 置换选择2的矩阵
	14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7,
			27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44,
			49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 };
	
	private static final int iROLtime[] = { // 循环左移位数表
	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
	
	private static final int iInitPM[] = { // 初始置换IP
	58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46,
			38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33,
			25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29,
			21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 };
	
	private static final int iInvInitPM[] = { // 初始逆置换
	40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46,
			14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12,
			52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50,
			18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 };
	
	private static final int iEPM[] = { // 选择运算E
	32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15,
			16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26,
			27, 28, 29, 28, 29, 30, 31, 32, 1 };
	
	private static final int iPPM[] = { // 置换运算P
	16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14,
			32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 };
	
	private static final int iSPM[][] = { // 8个S盒
			{ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7,
					4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8,
					13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4,
					9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 },
			{ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4,
					7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11,
					10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3,
					15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 },
			{ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0,
					9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8,
					15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9,
					8, 7, 4, 15, 14, 3, 11, 5, 2, 12 },
			{ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11,
					5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12,
					11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1,
					13, 8, 9, 4, 5, 11, 12, 7, 2, 14 },
			{ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2,
					12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10,
					13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14,
					2, 13, 6, 15, 0, 9, 10, 4, 5, 3 },
			{ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4,
					2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2,
					8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15,
					10, 11, 14, 1, 7, 6, 0, 8, 13 },
			{ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11,
					7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13,
					12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4,
					10, 7, 9, 5, 0, 15, 14, 2, 3, 12 },
			{ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13,
					8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9,
					12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10,
					8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } };

	private static int[] iCipherKey = new int[64];
	private static int[] iCKTemp = new int[56];
	private static int[] iPlaintext = new int[64];
	private static int[] iCiphertext = new int[64];
	private static int[] iPKTemp = new int[64];
	private static int[] iL = new int[32];
	private static int[] iR = new int[32];

	// 数组置换
	// iSource与iDest的大小不一定相等
	private static void permu(int[] iSource, int[] iDest, int[] iPM) {
		for (int i = 0; i < iPM.length; i++)
			iDest[i] = iSource[iPM[i] - 1];
	}

	// 将字节数组进行 位-〉整数 压缩
	// 例如:{0x35,0xf3}->{0,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1}, bArray->iArray
	private static void arrayBitToI(byte[] bArray, int[] iArray) {
		for (int i = 0; i < iArray.length; i++) {
			iArray[i] = (int) (bArray[i / 8] >> (7 - i % 8) & 0x01);
		}
	}

	// 将整形数组进行 整数-〉位 压缩
	// arrayBitToI的逆变换,iArray->bArray
	private static void arrayIToBit(byte[] bArray, int[] iArray) {
		for (int i = 0; i < bArray.length; i++) {
			bArray[i] = (byte) iArray[8 * i];
			for (int j = 1; j < 8; j++) {
				bArray[i] = (byte) (bArray[i] << 1);
				bArray[i] += (byte) iArray[8 * i + j];
			}
		}
	}

	// 数组的逐项模2加
	// array1[i]=array1[i]^array2[i]
	private static void arrayM2Add(int[] array1, int[] array2) {
		for (int i = 0; i < array2.length; i++) {
			array1[i] ^= array2[i];
		}
	}

	// 一个数组等分成两个数组-数组切割
	private static void arrayCut(int[] iSource, int[] iDest1, int[] iDest2) {
		int k = iSource.length;
		for (int i = 0; i < k / 2; i++) {
			iDest1[i] = iSource[i];
			iDest2[i] = iSource[i + k / 2];
		}
	}

	// 两个等大的数组拼接成一个
	// arrayCut的逆变换
	private static void arrayComb(int[] iDest, int[] iSource1, int[] iSource2) {
		int k = iSource1.length;
		for (int i = 0; i < k; i++) {
			iDest[i] = iSource1[i];
			iDest[i + k] = iSource2[i];
		}
	}

	// 子密钥产生算法中的循环左移
	private static void ROL(int[] array) {
		int temp = array[0];
		for (int i = 0; i < 27; i++) {
			array[i] = array[i + 1];
		}
		array[27] = temp;

		temp = array[28];
		for (int i = 0; i < 27; i++) {
			array[28 + i] = array[28 + i + 1];
		}
		array[55] = temp;
	}

	// 16个子密钥完全倒置
	private static int[][] invSubKeys(int[][] iSubKeys) {
		int[][] iInvSubKeys = new int[16][48];
		for (int i = 0; i < 16; i++)
			for (int j = 0; j < 48; j++)
				iInvSubKeys[i][j] = iSubKeys[15 - i][j];
		return iInvSubKeys;
	}

	// S盒代替
	// 输入输出皆为部分数组,因此带偏移量
	private static void Sbox(int[] iInput, int iOffI, int[] iOutput, int iOffO,
			int[] iSPM) {
		int iRow = iInput[iOffI] * 2 + iInput[iOffI + 5]; // S盒中的行号
		int iCol = iInput[iOffI + 1] * 8 + iInput[iOffI + 2] * 4
				+ iInput[iOffI + 3] * 2 + iInput[iOffI + 4];
		// S盒中的列号
		int x = iSPM[16 * iRow + iCol];
		iOutput[iOffO] = x >> 3 & 0x01;
		iOutput[iOffO + 1] = x >> 2 & 0x01;
		iOutput[iOffO + 2] = x >> 1 & 0x01;
		iOutput[iOffO + 3] = x & 0x01;
	}

	// 加密函数f
	private static int[] encFunc(int[] iInput, int[] iSubKey) {
		int iTemp1[] = new int[48];
		int iTemp2[] = new int[32];
		int iOutput[] = new int[32];
		permu(iInput, iTemp1, iEPM);
		arrayM2Add(iTemp1, iSubKey);
		for (int i = 0; i < 8; i++)
			Sbox(iTemp1, i * 6, iTemp2, i * 4, iSPM[i]);
		permu(iTemp2, iOutput, iPPM);
		return iOutput;
	}

	// 子密钥生成
	private static int[][] makeSubKeys(byte[] bCipherKey) {
		int[][] iSubKeys = new int[16][48];
		arrayBitToI(bCipherKey, iCipherKey);
		//int[] tmp = iCipherKey;
		permu(iCipherKey, iCKTemp, iSelePM1);
		for (int i = 0; i < 16; i++) {
			for (int j = 0; j < iROLtime[i]; j++)
				ROL(iCKTemp);
			permu(iCKTemp, iSubKeys[i], iSelePM2);
		}
		return iSubKeys;
	}

	// 加密
	private static byte[] encrypt(byte[] bPlaintext, int[][] iSubKeys) {
		byte bCiphertext[] = new byte[8];
		arrayBitToI(bPlaintext, iPlaintext);
		permu(iPlaintext, iPKTemp, iInitPM);
		arrayCut(iPKTemp, iL, iR);
		for (int i = 0; i < 16; i++) {
			if (i % 2 == 0) {
				arrayM2Add(iL, encFunc(iR, iSubKeys[i]));
			} else {
				arrayM2Add(iR, encFunc(iL, iSubKeys[i]));
			}
		}
		arrayComb(iPKTemp, iR, iL);
		permu(iPKTemp, iCiphertext, iInvInitPM);
		arrayIToBit(bCiphertext, iCiphertext);
		return bCiphertext;
	}

	// 解密
	private static byte[] decrypt(byte[] bCiphertext, int[][] iSubKeys) {
		int[][] iInvSubKeys = invSubKeys(iSubKeys);
		return encrypt(bCiphertext, iInvSubKeys);
	}

	// Bit XOR
	private static byte[] BitXor(byte[] Data1, byte[] Data2, int Len) {
		int i;
		byte Dest[] = new byte[Len];

		for (i = 0; i < Len; i++)
			Dest[i] = (byte) (Data1[i] ^ Data2[i]);

		return Dest;
	}

	private static String byte2hex(byte[] b) { //一个字节的数,
		// 转成16进制字符串
		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;
		}
		return hs.toUpperCase(); //转成大写
	}

	private static byte[] hex2byte(byte[] b) {
		if ((b.length % 2) != 0)
			throw new IllegalArgumentException("长度不是偶数");
		byte[] b2 = new byte[b.length / 2];
		for (int n = 0; n < b.length; n += 2) {
			String item = new String(b, n, 2);
			b2[n / 2] = (byte) Integer.parseInt(item, 16);
		}
		return b2;
	}
	/**
	 * 3DES加密
	 * @see [类、类#方法、类#成员]   
	 * @since [1.0]
	 * @param strKey
	 * @param strEncData
	 * @return
	 */
	public static String encryptDES(String strKey, String strEncData)
	{
		String strKey1;
		String strKey2;
		String strTemp1;
		String strTemp2;

		if ((strKey.length()) != 32) {
			throw new IllegalArgumentException("密钥长度不正确,必须为32");
		}
		if ((strEncData.length()) != 32) {
			throw new IllegalArgumentException("数据明文长度不正确,必须为32");
		}

		strKey1 = strKey.substring(0, 16);
		strKey2 = strKey.substring(16, 32);
		strTemp1 = strEncData.substring(0, 16);
		strTemp2 = strEncData.substring(16, 32);

		byte[] cipherKey1 = hex2byte(strKey1.getBytes()); //3DES的密钥K1
		byte[] cipherKey2 = hex2byte(strKey2.getBytes()); //3DES的密钥K2

		byte[] bCiphertext1 = hex2byte(strTemp1.getBytes()); //数据1
		byte[] bCiphertext2 = hex2byte(strTemp2.getBytes()); //数据1

		int[][] subKeys1 = new int[16][48]; //用于存放K1产生的子密钥
		int[][] subKeys2 = new int[16][48]; //用于存放K2产生的子密钥
		subKeys1 = makeSubKeys(cipherKey1);
		subKeys2 = makeSubKeys(cipherKey2);

		byte[] bTemp11 = encrypt(bCiphertext1, subKeys1);
		byte[] bTemp21 = decrypt(bTemp11, subKeys2);
		byte[] bPlaintext11 = encrypt(bTemp21, subKeys1);

		byte[] bTemp12 = encrypt(bCiphertext2, subKeys1);
		byte[] bTemp22 = decrypt(bTemp12, subKeys2);
		byte[] bPlaintext12 = encrypt(bTemp22, subKeys1);

		return byte2hex(bPlaintext11) + byte2hex(bPlaintext12);
	}
	/**
	 * 3DES解密
	 * @see [类、类#方法、类#成员]   
	 * @since [1.0]
	 * @param strKey
	 * @param strEncData
	 * @return
	 */
	public static String decryptDES(String strKey, String strEncData)
	{
		String strKey1;
		String strKey2;
		String strTemp1;
		String strTemp2;

		if ((strKey.length()) != 32) {
			throw new IllegalArgumentException("密钥长度不正确,必须为32");
		}
		if ((strEncData.length()) != 32) {
			throw new IllegalArgumentException("数据密文长度不正确,必须为32");
		}

		strKey1 = strKey.substring(0, 16);
		strKey2 = strKey.substring(16, 32);
		strTemp1 = strEncData.substring(0, 16);
		strTemp2 = strEncData.substring(16, 32);

		byte[] cipherKey1 = hex2byte(strKey1.getBytes()); //3DES的密钥K1
		byte[] cipherKey2 = hex2byte(strKey2.getBytes()); //3DES的密钥K2

		byte[] bCiphertext1 = hex2byte(strTemp1.getBytes()); //数据1
		byte[] bCiphertext2 = hex2byte(strTemp2.getBytes()); //数据1

		int[][] subKeys1 = new int[16][48]; //用于存放K1产生的子密钥
		int[][] subKeys2 = new int[16][48]; //用于存放K2产生的子密钥
		subKeys1 = makeSubKeys(cipherKey1);
		subKeys2 = makeSubKeys(cipherKey2);

		byte[] bTemp11 = decrypt(bCiphertext1, subKeys1);
		byte[] bTemp21 = encrypt(bTemp11, subKeys2);
		byte[] bPlaintext11 = decrypt(bTemp21, subKeys1);

		byte[] bTemp12 = decrypt(bCiphertext2, subKeys1);
		byte[] bTemp22 = encrypt(bTemp12, subKeys2);
		byte[] bPlaintext12 = decrypt(bTemp22, subKeys1);

		return byte2hex(bPlaintext11) + byte2hex(bPlaintext12);
	}

以下是MAC算法(银联是ANSI-9.9-MAC,ANSI-X9.9-MAC算法,对敏感信息校验相当于数字签名,下面也包括了PBOC-DES-MAC算法) 

/** ***************************压缩替换S-Box************************ */

	private static final int[][] s1 = {
			{ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
			{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
			{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
			{ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } };
	private static final int[][] s2 = {
			{ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
			{ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
			{ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
			{ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } };
	private static final int[][] s3 = {
			{ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
			{ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
			{ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
			{ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } };
	private static final int[][] s4 = {
			{ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
			{ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },// erorr
			{ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
			{ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } };
	private static final int[][] s5 = {
			{ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
			{ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
			{ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
			{ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } };
	private static final int[][] s6 = {
			{ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
			{ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
			{ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
			{ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } };
	private static final int[][] s7 = {
			{ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
			{ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
			{ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
			{ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } };
	private static final int[][] s8 = {
			{ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
			{ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
			{ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
			{ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } };
	private static final int[] ip = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52,
			44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48,
			40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35,
			27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31,
			23, 15, 7 };
	private static final int[] _ip = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7,
			47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45,
			13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11,
			51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49,
			17, 57, 25 };
	// 每次密钥循环左移位数
	private static final int[] LS = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
			2, 1 };
	private static int[][] subKey = new int[16][48];
	private static int HEX = 0;
	private static int ASC = 1;

	/**
	 * 将十六进制A--F转换成对应数
	 * 
	 * @param ch
	 * @return
	 * @throws Exception
	 */
	public static int getIntByChar(char ch) throws Exception {
		char t = Character.toUpperCase(ch);
		int i = 0;
		switch (t) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			i = Integer.parseInt(Character.toString(t));
			break;
		case 'A':
			i = 10;
			break;
		case 'B':
			i = 11;
			break;
		case 'C':
			i = 12;
			break;
		case 'D':
			i = 13;
			break;
		case 'E':
			i = 14;
			break;
		case 'F':
			i = 15;
			break;
		default:
			throw new Exception("getIntByChar was wrong");
		}
		return i;
	}

	/**
	 * 将字符串转换成二进制数组
	 * 
	 * @param source :
	 *            16字节
	 * @return
	 */
	public static int[] string2Binary(String source) {
		int len = source.length();
		int[] dest = new int[len * 4];
		char[] arr = source.toCharArray();
		for (int i = 0; i < len; i++) {
			int t = 0;
			try {
				t = getIntByChar(arr[i]);
				// System.out.println(arr[i]);
			} catch (Exception e) {
				e.printStackTrace();
			}
			String[] str = Integer.toBinaryString(t).split("");
			int k = i * 4 + 3;
			for (int j = str.length - 1; j > 0; j--) {
				dest[k] = Integer.parseInt(str[j]);
				k--;
			}
		}
		return dest;
	}

	/**
	 * 返回x的y次方
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public static int getXY(int x, int y) {
		int temp = x;
		if (y == 0)
			x = 1;
		for (int i = 2; i <= y; i++) {
			x *= temp;
		}
		return x;
	}

	/**
	 * s位长度的二进制字符串
	 * 
	 * @param s
	 * @return
	 */
	public static String binary2Hex(String s) {
		int len = s.length();
		int result = 0;
		int k = 0;
		if (len > 4)
			return null;
		for (int i = len; i > 0; i--) {
			result += Integer.parseInt(s.substring(i - 1, i)) * getXY(2, k);
			k++;
		}
		switch (result) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
			return "" + result;
		case 10:
			return "A";
		case 11:
			return "B";
		case 12:
			return "C";
		case 13:
			return "D";
		case 14:
			return "E";
		case 15:
			return "F";
		default:
			return null;
		}
	}

	/**
	 * 将int转换成Hex
	 * 
	 * @param i
	 * @return
	 * @throws Exception
	 */
	public static String int2Hex(int i) {
		switch (i) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
			return "" + i;
		case 10:
			return "A";
		case 11:
			return "B";
		case 12:
			return "C";
		case 13:
			return "D";
		case 14:
			return "E";
		case 15:
			return "F";
		default:
			return null;
		}
	}

	/**
	 * 将二进制字符串转换成十六进制字符
	 * 
	 * @param s
	 * @return
	 */
	public static String binary2ASC(String s) {
		String str = "";
		int ii = 0;
		int len = s.length();
		// 不够4bit左补0
		if (len % 4 != 0) {
			while (ii < 4 - len % 4) {
				s = "0" + s;
			}
		}
		for (int i = 0; i < len / 4; i++) {
			str += binary2Hex(s.substring(i * 4, i * 4 + 4));
		}
		return str;
	}

	/**
	 * IP初始置换
	 * 
	 * @param source
	 * @return
	 */
	public static int[] changeIP(int[] source) {
		int[] dest = new int[64];
		for (int i = 0; i < 64; i++) {
			dest[i] = source[ip[i] - 1];
		}
		return dest;
	}

	/**
	 * IP-1逆置
	 * 
	 * @param source
	 * @return
	 */
	public static int[] changeInverseIP(int[] source) {
		int[] dest = new int[64];
		for (int i = 0; i < 64; i++) {
			dest[i] = source[_ip[i] - 1];
		}
		return dest;
	}

	/**
	 * 2bit扩展8bit
	 * 
	 * @param source
	 * @return
	 */
	public static int[] expend(int[] source) {
		int[] ret = new int[48];
		int[] temp = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12,
				13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22,
				23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 };
		for (int i = 0; i < 48; i++) {
			ret[i] = source[temp[i] - 1];
		}
		return ret;
	}

	/**
	 * 8bit压缩2bit
	 * 
	 * @param source(48bit)
	 * @return R(32bit) B=E(R)⊕K,将48 位的B 分成8 个分组,B=B1B2B3B4B5B6B7B8
	 */
	public static int[] press(int[] source) {
		int[] ret = new int[32];
		int[][] temp = new int[8][6];
		int[][][] s = { s1, s2, s3, s4, s5, s6, s7, s8 };
		StringBuffer str = new StringBuffer();
		for (int i = 0; i < 8; i++) {
			for (int j = 0; j < 6; j++) {
				temp[i][j] = source[i * 6 + j];
			}
		}
		for (int i = 0; i < 8; i++) {
			// (16)
			int x = temp[i][0] * 2 + temp[i][5];
			// (2345)
			int y = temp[i][1] * 8 + temp[i][2] * 4 + temp[i][3] * 2
					+ temp[i][4];
			int val = s[i][x][y];
			String ch = int2Hex(val);
			// System.out.println("x=" + x + ",y=" + y + "-->" + ch);
			// String ch = Integer.toBinaryString(val);
			str.append(ch);
		}
		// System.out.println(str.toString());
		ret = string2Binary(str.toString());
		// printArr(ret);
		// 置换P
		ret = dataP(ret);
		return ret;
	}

	/**
	 * 置换P(32bit)
	 * 
	 * @param source
	 * @return
	 */
	public static int[] dataP(int[] source) {
		int[] dest = new int[32];
		int[] temp = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31,
				10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 };
		int len = source.length;
		for (int i = 0; i < len; i++) {
			dest[i] = source[temp[i] - 1];
		}
		return dest;
	}

	/**
	 * 
	 * @param R(2bit)
	 * 
	 * @param K(48bit的轮子密
	 * 
	 * @return 32bit
	 * 
	 */
	public static int[] f(int[] R, int[] K) {
		int[] dest = new int[32];
		int[] temp = new int[48];
		// 先将输入32bit扩展8bit
		int[] expendR = expend(R);// 48bit
		// 与轮子密钥进行异或运
		temp = diffOr(expendR, K);
		// 压缩2bit
		dest = press(temp);
		// System.out.println("need press data----->");
		// printArr(temp);
		return dest;
	}

	/**
	 * 
	 * 两个等长的数组做异或
	 * 
	 * @param source1
	 * 
	 * @param source2
	 * 
	 * @return
	 * 
	 */
	public static int[] diffOr(int[] source1, int[] source2) {
		int len = source1.length;
		int[] dest = new int[len];
		for (int i = 0; i < len; i++) {
			dest[i] = source1[i] ^ source2[i];
		}
		return dest;
	}

	/**
	 * 
	 * DES加密--->对称密钥
	 * 
	 * D = Ln(32bit)+Rn(32bit)
	 * 
	 * 经过16轮置
	 * 
	 * @param D(16byte)明文
	 * 
	 * @param K(16byte)轮子密钥
	 * 
	 * @return (16byte)密文
	 * 
	 */
	public static String encryption(String D, String K) {
		String str = "";
		int[] temp = new int[64];
		int[] data = string2Binary(D);
		// printArr(data);
		// 第一步初始置
		data = changeIP(data);
		// printArr(data);
		int[][] left = new int[17][32];
		int[][] right = new int[17][32];
		for (int j = 0; j < 32; j++) {
			left[0][j] = data[j];
			right[0][j] = data[j + 32];
		}
		// printArr(left[0]);
		// printArr(right[0]);
		setKey(K);// sub key ok
		for (int i = 1; i < 17; i++) {
			// 获取(48bit)的轮子密
			int[] key = subKey[i - 1];
			// L1 = R0
			left[i] = right[i - 1];
			// R1 = L0 ^ f(R0,K1)
			int[] fTemp = f(right[i - 1], key);// 32bit
			right[i] = diffOr(left[i - 1], fTemp);
		}
		// 组合的时候,左右调换**************************************************
		for (int i = 0; i < 32; i++) {
			temp[i] = right[16][i];
			temp[32 + i] = left[16][i];
		}
		temp = changeInverseIP(temp);
		str = binary2ASC(intArr2Str(temp));
		return str;
	}

	/**
	 * 
	 * DES解密--->对称密钥
	 * 
	 * 解密算法与加密算法基本相同,不同之处仅在于轮子密钥的使用顺序逆序,即解密的第1
	 * 
	 * 轮子密钥为加密的6 轮子密钥,解密的 轮子密钥为加密的5 轮子密钥,…,
	 * 
	 * 解密的第16 轮子密钥为加密的 轮子密钥
	 * 
	 * @param source密文
	 * 
	 * @param key密钥
	 * 
	 * @return
	 * 
	 */
	public static String discryption(String source, String key) {
		String str = "";
		int[] data = string2Binary(source);// 64bit
		// 第一步初始置
		data = changeIP(data);
		int[] left = new int[32];
		int[] right = new int[32];
		int[] tmp = new int[32];
		for (int j = 0; j < 32; j++) {
			left[j] = data[j];
			right[j] = data[j + 32];
		}
		setKey(key);// sub key ok
		for (int i = 16; i > 0; i--) {
			// 获取(48bit)的轮子密
			/** *******不同之处********* */
			int[] sKey = subKey[i - 1];
			tmp = left;
			// R1 = L0
			left = right;
			// L1 = R0 ^ f(L0,K1)
			int[] fTemp = f(right, sKey);// 32bit
			right = diffOr(tmp, fTemp);
		}
		// 组合的时候,左右调换**************************************************
		for (int i = 0; i < 32; i++) {
			data[i] = right[i];
			data[32 + i] = left[i];
		}
		data = changeInverseIP(data);
		for (int i = 0; i < data.length; i++) {
			str += data[i];
		}
		str = binary2ASC(str);
		return str;
	}

	/**
	 * 
	 * 单长密钥DES(16byte)
	 * 
	 * @param source
	 * 
	 * @param key
	 * 
	 * @param type
	 *            0:encrypt 1:discrypt
	 * 
	 * @return
	 * 
	 */
	public static String DES_1(String source, String key, int type) {
		if (source.length() != 16 || key.length() != 16)
			return null;
		if (type == 0) {
			return encryption(source, key);
		}
		if (type == 1) {
			return discryption(source, key);
		}
		return null;
	}
	/** **********************************48bit的轮子密钥的生成********************************************************* */
	/**
	 * 
	 * 4bit的密钥转换成56bit
	 * 
	 * @param source
	 * 
	 * @return
	 * 
	 */

	public static int[] keyPC_1(int[] source) {
		int[] dest = new int[56];
		int[] temp = { 57, 49, 41, 33, 25, 17, 9,
		1, 58, 50, 42, 34, 26, 18,
		10, 2, 59, 51, 43, 35, 27,
		19, 11, 3, 60, 52, 44, 36,
		63, 55, 47, 39, 31, 23, 15,
		7, 62, 54, 46, 38, 30, 22,
		14, 6, 61, 53, 45, 37, 29,
		21, 13, 5, 28, 20, 12, 4 };
		for (int i = 0; i < 56; i++) {
			dest[i] = source[temp[i] - 1];
		}
		return dest;
	}
	/**
	 * 
	 * 将密钥循环左移i
	 * 
	 * @param source
	 *            二进制密钥数
	 * 
	 * @param i
	 *            循环左移位数
	 * 
	 * @return
	 * 
	 */
	public static int[] keyLeftMove(int[] source, int i) {
		int temp = 0;
		int len = source.length;
		int ls = LS[i];
		// System.out.println("len" + len + ",LS[" + i + "]=" + ls);
		for (int k = 0; k < ls; k++) {
			temp = source[0];
			for (int j = 0; j < len - 1; j++) {
				source[j] = source[j + 1];
			}
			source[len - 1] = temp;
		}
		return source;
	}

	/**
	 * 
	 * 6bit的密钥转换成48bit
	 * 
	 * @param source
	 * 
	 * @return
	 * 
	 */
	public static int[] keyPC_2(int[] source) {
		int[] dest = new int[48];
		int[] temp = { 14, 17, 11, 24, 1, 5,
		3, 28, 15, 6, 21, 10,
		23, 19, 12, 4, 26, 8,
		16, 7, 27, 20, 13, 2,
		41, 52, 31, 37, 47, 55,
		30, 40, 51, 45, 33, 48,
		44, 49, 39, 56, 34, 53,
		46, 42, 50, 36, 29, 32 };
		for (int i = 0; i < 48; i++) {
			dest[i] = source[temp[i] - 1];
		}
		return dest;
	}

	/**
	 * 
	 * 获取轮子密钥(48bit)
	 * 
	 * @param source
	 * 
	 * @return
	 * 
	 */
	public static void setKey(String source) {
		if (subKey.length > 0)
			subKey = new int[16][48];
		// 装换4bit
		int[] temp = string2Binary(source);
		// 6bit均分成两部分
		int[] left = new int[28];
		int[] right = new int[28];
		// 经过PC-14bit转换6bit
		int[] temp1 = new int[56];
		temp1 = keyPC_1(temp);
		// printArr(temp1);
		// 将经过转换的temp1均分成两部分
		for (int i = 0; i < 28; i++) {
			left[i] = temp1[i];
			right[i] = temp1[i + 28];
		}
		// 经过16次循环左移,然后PC-2置换
		for (int i = 0; i < 16; i++) {
			left = keyLeftMove(left, LS[i]);
			right = keyLeftMove(right, LS[i]);
			for (int j = 0; j < 28; j++) {
				temp1[j] = left[j];
				temp1[j + 28] = right[j];
			}
			// printArr(temp1);
			subKey[i] = keyPC_2(temp1);
		}
	}
	public static void printArr(int[] source) {
		int len = source.length;
		for (int i = 0; i < len; i++) {
			System.out.print(source[i]);
		}
		System.out.println();
	}
	/**
	 * 
	 * 将ASC字符串转16进制字符
	 * 
	 * @param asc
	 * 
	 * @return
	 * 
	 */
	public static String ASC_2_HEX(String asc) {
		StringBuffer hex = new StringBuffer();
		try {
			byte[] bs = asc.toUpperCase().getBytes("UTF-8");
			for (byte b : bs) {
				hex.append(Integer.toHexString(new Byte(b).intValue()));
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return hex.toString();
	}
	/**
	 * 
	 * 16进制的字符串转换成ASC的字符串
	 * 
	 * 16进制的字符串压缩成BCD(30313233343536373839414243444546)-->(0123456789ABCDEF)
	 * 
	 * @param hex
	 * 
	 * @return
	 * 
	 */
	public static String HEX_2_ASC(String hex) {
		String asc = null;
		int len = hex.length();
		byte[] bs = new byte[len / 2];
		for (int i = 0; i < len / 2; i++) {
			bs[i] = Byte.parseByte(hex.substring(i * 2, i * 2 + 2), 16);
		}
		try {
			asc = new String(bs, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return asc;
	}

	/**
	 * 计算MAC(hex)
	 * ANSI-X9.9-MAC(16的整数不补)
	 * PBOC-DES-MAC(16的整数补8000000000000000)
	 * 使用单倍长密钥DES算法
	 * @param key密钥(16byte)
	 * @param vector初始向量0000000000000000
	 * @param data数据
	 * @return mac
	 */
	public static String PBOC_DES_MAC(String key, String vector, String data, int type) {
		if (key.length()!=16){
			return null;
		}
		if (type == ASC) {
			data = ASC_2_HEX(data);
		}
		int len = data.length();
		int arrLen = len / 16 + 1;
		String[] D = new String[arrLen];
		if (vector == null)
			vector = "0000000000000000";
		if (len % 16 == 0) {
			data += "8000000000000000";
		} else {
			data += "80";
			for (int i = 0; i < 15 - len % 16; i++) {
				data += "00";
			}
		}
		for (int i = 0; i < arrLen; i++) {
			D[i] = data.substring(i * 16, i * 16 + 16);
			System.out.println("D[" + i + "]=" + D[i]);
		}
		// D0 Xor Vector
		String I = xOr(D[0], vector);
		String O = null;
		for (int i = 1; i < arrLen; i++) {
			System.out.println(i + "**************");
			System.out.println("I=" + I);
			O = DES_1(I, key, 0);
			System.out.println("O=" + O);
			I = xOr(D[i], O);
			System.out.println("I=" + I);
		}
		I = DES_1(I, key, 0);
		return I;
	}
	
	/**
	 * 
	 * 将s1和s2做异或,然后返回
	 * 
	 * @param s1
	 * 
	 * @param s2
	 * 
	 * @return
	 * 
	 */
	public static String xOr(String s1, String s2) {
		int[] iArr = diffOr(string2Binary(s1), string2Binary(s2));
		return binary2ASC(intArr2Str(iArr));
	}

	/**
	 * 
	 * 将int类型数组拼接成字符串
	 * 
	 * @param arr
	 * 
	 * @return
	 * 
	 */
	public static String intArr2Str(int[] arr) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < arr.length; i++) {
			sb.append(arr[i]);
		}
		return sb.toString();
	}

	/**
	 * 
	 * 将data分散
	 * 
	 * @param data
	 * 
	 * @param key
	 * 
	 * @param type
	 * 
	 * @return
	 * 
	 */
	public static String divData(String data, String key, int type) {
		String left = null;
		String right = null;
		if (type == HEX) {
			left = key.substring(0, 16);
			right = key.substring(16, 32);
		}
		if (type == ASC) {
			left = ASC_2_HEX(key.substring(0, 8));
			right = ASC_2_HEX(key.substring(8, 16));
		}
		// 加密
		data = DES_1(data, left, 0);
		// 解密
		data = DES_1(data, right, 1);
		// 加密
		data = DES_1(data, left, 0);
		return data;
	}

	/**
	 * 取反(10001)--->(01110)
	 * 
	 * @param source
	 * @return
	 */
	public static String reverse(String source) {
		int[] data = string2Binary(source);
		int j = 0;
		for (int i : data) {
			data[j++] = 1 - i;
		}
		return binary2ASC(intArr2Str(data));
	}

	/**
	 * 主密钥需要经过两次分散获得IC卡中的子密钥
	 * 空圈的通讯类过程密钥使用这种密钥分散机制
	 * 
	 * @param issuerFlag发卡方标识符
	 * @param appNo应用序列号即卡号
	 * @param mpk主密钥
	 * @return
	 */
	public static String getDPK(String issuerFlag, String appNo, String mpk) {
		// 第一次分散
		StringBuffer issuerMPK = new StringBuffer();
		// 获取Issuer MPK左半边
		issuerMPK.append(divData(issuerFlag, mpk, 0));
		// 获取Issuer MPK右半边
		issuerMPK.append(divData(reverse(issuerFlag), mpk, 0));
		// 第二次分散
		StringBuffer dpk = new StringBuffer();
		// 获取DPK左半边
		dpk.append(divData(appNo, issuerMPK.toString(), 0));
		// 获取DPK右半边
		dpk.append(divData(reverse(appNo), issuerMPK.toString(), 0));
		return dpk.toString();
	}
	
	/**
	 * 主密钥需要经过一次分散获得的子密钥
	 * 空圈的交易类过程密钥使用这种密钥分散机制
	 * 
	 * @param issuerFlag发卡方标识符
	 * @param appNo应用序列号即卡号
	 * @param mpk主密钥
	 * @return
	 */
	public static String getDPK4Once(String data, String mpk) {
		// 第一次分散
		StringBuffer dpk = new StringBuffer();
		// 获取DPK左半边
		dpk.append(divData(data, mpk, 0));
		// 获取DPK右半边
		dpk.append(divData(reverse(data), mpk.toString(), 0));
		return dpk.toString();
	}

zhangzxl这个人写的,真是帮了大忙。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值