import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.log4j.Logger;
import cia.broker.common.function.BrokerCommFunc;
/**
* Description: 密码转PIN
*
* (C) Copyright of China UnionPay Co., Ltd. 2010.
* @author leoyan
*/
public class SoftSecProc {
/**
* 日志
*/
private static final Logger logger = Logger.getLogger(SoftSecProc.class);
/**
* 卡号密码转PIN -- 密码解密
*
* @param encStr
* @param key
* @return
* @throws CIAException
*/
public String decryptedPin(String encStr, PrivateKey key) throws Exception {
String clrPin = null;
Base64Coder base64 = new Base64Coder();
try {
byte[] cryptPin = base64.decode(encStr.getBytes());
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, key);
int blockSize = cipher.getBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;
while (cryptPin.length - j * blockSize > 0) {
bout.write(cipher.doFinal(cryptPin, j * blockSize, blockSize));
j++;
}
// 加密后的密码
byte[] data = bout.toByteArray();
// 转换成16进制
clrPin = BrokerCommFunc.Hex2Str(data);
} catch (Exception ex) {
logger.error(ex);
throw new Exception(ex);
}
return clrPin;
}
/**
* 卡号密码转PIN -- 加密
*
* @param plainDataByte
* @return
* @throws CIAException
*/
public String encryptedDataByGwCert(byte[] plainDataByte, PublicKey publicKey) throws Exception {
String encData = null;
Base64Coder base64 = new Base64Coder();
// 参数检查
if (plainDataByte == null) {
return null;
}
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
// 加密块大小为127
// byte,加密后为128个byte;因此共有2个加密块,第一个127
// byte第二个为1个byte
int outputSize = cipher.getOutputSize(plainDataByte.length);// 获得加密块加密后块大小
int leavedSize = plainDataByte.length % blockSize;
int blocksSize = leavedSize != 0
? plainDataByte.length / blockSize + 1
: plainDataByte.length / blockSize;
// 加密后的数据定义
byte[] data = new byte[outputSize * blocksSize];
int i = 0;
while (plainDataByte.length - i * blockSize > 0) {
if (plainDataByte.length - i * blockSize > blockSize)
cipher.doFinal(plainDataByte, i * blockSize, blockSize, data, i * outputSize);
else
cipher.doFinal(plainDataByte, i * blockSize, plainDataByte.length - i
* blockSize, data, i * outputSize);
i++;
}
// 对加密后的数据进行编码
byte[] raw = base64.encode(data);
encData = new String(raw);
} catch (Exception ex) {
logger.error(ex);
throw new Exception(ex);
}
return encData;
}
/**
* 卡号密码转PIN -- 根据卡号加密
*
* @param clrPin
* @param sPan
* @return
* @throws CIAException
*/
public String encryptedPin(String clrPin, String pan, PublicKey publicKey) throws Exception {
String encPin = null;
Base64Coder base64 = new Base64Coder();
// 参数判断
if (clrPin == null || clrPin.trim().equals("") || pan == null || pan.trim().equals("")) {
return null;
}
try {
/* 生成PIN Block */
byte[] pinBlock = pin2PinBlockWithCardNO(clrPin, pan);
// 加密开始
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
// 加密块大小为127
// byte,加密后为128个byte;因此共有2个加密块,第一个127
// byte第二个为1个byte
int outputSize = cipher.getOutputSize(pinBlock.length);// 获得加密块加密后块大小
int leavedSize = pinBlock.length % blockSize;
int blocksSize = leavedSize != 0 ? pinBlock.length / blockSize + 1 : pinBlock.length
/ blockSize;
// 加密后的数据
byte[] data = 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, data, i * outputSize);
} else {
cipher.doFinal(pinBlock, i * blockSize, pinBlock.length - i * blockSize, data,
i * outputSize);
}
// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了OutputSize所以只好用dofinal方法。
i++;
}
// 对密码进行编码
byte[] raw = base64.encode(data);
encPin = new String(raw);
} catch (Exception ex) {
logger.error(ex);
throw new Exception(ex);
}
return encPin;
}
/**
* 产生MAC
*
* @param inputByte
* @param inputkey
* @param algorithm
* "DES" "AES"
* @return
* @throws CIAException
*/
public byte[] genmac(byte[] inputByte, byte[] inputkey, String algorithm) throws Exception {
try {
Mac mac = Mac.getInstance("HmacMD5");
SecretKey key = new SecretKeySpec(inputkey, algorithm);
mac.init(key);
byte[] macCode = mac.doFinal(inputByte);
return macCode;
} catch (Exception ex) {
logger.error(ex);
throw new Exception(ex);
}
}
/**
* 二进制转换成十六进制
*
* @param b
* @return
*/
public String byte2hex(byte[] b) {
String hs = "";
String stmp;
for (byte aB : b) {
stmp = (Integer.toHexString(aB & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
}
return hs.toLowerCase();
}
public 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;
}
/**
* 使用DES算法产生MAC
*
* @param inputByte
* @param inputkey
* @return
* @throws IOException
*/
public String genMac(byte[] macData, byte[] macKey) {
try {
// get a instance of Mac, using HmacMD5 algorithm
Mac mac = Mac.getInstance("DES",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
// init the IV of the algorithm, 8 bytes. may read from file
byte[] ivInitKey = {0X00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
IvParameterSpec spec = new IvParameterSpec(ivInitKey);
// the secrete key bytes of the Mac validation, May read from file too
byte[] keyBytes = new byte[8];
// "82A6672F3B05AC25" MAC = 39:92:72:EB
// MAC KEY
BrokerCommFunc.Str2Hex(macKey, keyBytes, 16);
// generate the secrete Key Object using secrete bytes and DESede algorithm
SecretKey key = new SecretKeySpec(keyBytes, "DES");
// init Mac
mac.init(key, spec);
byte[] macCode = mac.doFinal(macData);
System.out.println("MAC = [" + byte2hex(macCode) + "]");
return byte2hex(macCode);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public static void main(String[] args) throws Exception {
String inputStr = "0220 196222600113522102649 000000 000000000011 1201123145 004023 5311 00 0800207900 0800040000 00000000 020790048140001";
byte[] bMacTmp = inputStr.getBytes();
/* 去掉mac域 */
byte[] bReqMac = new byte[bMacTmp.length - 8];
for (int i = 0; i < bMacTmp.length - 8; i++) {
bReqMac[i] = bMacTmp[i];
}
SoftSecProc macProc = new SoftSecProc();
byte[] MAC = new byte[8];
String mac = macProc.DecMACKey(inputStr.getBytes(), "4944AB7E278E7F89".getBytes());
System.out.println("mac=[" + mac + "]");
mac = macProc.DecMACKey(bReqMac, "4944AB7E278E7F89".getBytes());
System.out.println("mac=[" + mac + "]");
BrokerCommFunc.Str2Hex(mac.getBytes(), MAC, mac.getBytes().length);
System.out.println(new String(MAC));
byte[] MACKey = new byte[16];
BrokerCommFunc.Hex2Str(MAC, MACKey, 8);
System.out.println("MAC=" + new String(MACKey));
String aaaa = macProc.genMac(inputStr.getBytes(), "4944AB7E278E7F89".getBytes());
MACKey = new byte[16];
BrokerCommFunc.Hex2Str(aaaa.getBytes(), MACKey, 8);
System.out.println("MAC=" + new String(MACKey));
System.out.println("DESede解密");
String rlt = macProc.decDESede("33333333333333333333333333333333",
macProc.hex2byte("0A06BB727EE3B97E".getBytes()));
System.out.println("正确结果:[D338F73E98250775];计算结果:[" + rlt + "]");
System.out.println("DESede加密");
rlt = macProc.encDESede("33333333333333333333333333333333",
macProc.hex2byte(rlt.getBytes()));
System.out.println("正确结果:[0A06BB727EE3B97E];计算结果:[" + rlt + "]");
}
/**
* 计算MAC,使用DES加密算法
*
* @param inputByte
* @param inputkey
* @return
*/
public String DecMACKey(byte[] inputByte, byte[] inputkey) {
try {
// Base64Coder base64 = new Base64Coder();
byte[] BMK = new byte[8];
BrokerCommFunc.Str2Hex(inputkey, BMK, 16);
SecretKey key = new SecretKeySpec(BMK, "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cc = cipher.doFinal(inputByte);
byte[] MACKey = new byte[16];
BrokerCommFunc.Hex2Str(cc, MACKey, 8);
String DecMAK = new String(MACKey);
return DecMAK;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* 校验MAC
*
* @param inputByte
* @param inputkey
* @param inputmac
* @param algorithm
* "DES" "AES"
* @return
* @throws Exception
*/
public boolean checkmac(byte[] inputByte, byte[] inputkey, String inputmac, String algorithm)
throws Exception {
try {
java.security.Security
.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Mac mac = Mac.getInstance(algorithm);
byte[] keyBytes = new byte[8];
// MAC KEY
BrokerCommFunc.Str2Hex(inputkey, keyBytes, inputkey.length);
SecretKey key = new SecretKeySpec(keyBytes, algorithm);
mac.init(key);
byte[] macCode = mac.doFinal(inputByte);
String strMacCode = byte2hex(macCode);
System.out.println("MAC = [" + strMacCode + "]; inputmac=[" + inputmac + "]");
if (strMacCode.equals(inputmac)) {
return true;
} else {
return false;
}
} catch (Exception ex) {
logger.error(ex);
return false;
}
}
/**
* 消费密码转PIN Block(加入卡号)
*
* @param aPin
* 消费密码
* @param aCardNO
* 卡号
* @return PIN Block
*/
public 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;
}
/**
* 消费密码转PIN Block
*
* @param aPin
* 消费密码
* @param aCardNO
* 卡号
* @return PIN Block
*/
private 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);
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 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;
}
/**
* 对传入的Byte数组进行PKCS#1填充
*
* @param aBytesText
* 欲进行PKCS#1填充的Byte数组
* @param aBlockSize
* 区块大小
* @return 经过PKCS#1填充后的Byte数组,大小等于传入的区块大小。<br>
* 若传入的Byte数组长度超过(填充区块大小-3)时无法进行填充作业,将回传null。
*/
private static byte[] addPKCS1Padding(byte[] aBytesText, int aBlockSize) {
if (aBytesText.length > (aBlockSize - 3)) {
// 传入的Byte数组长度超过(填充区块大小-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;
}
/**
* DESede解密(DESede/ECB/NoPadding)
*
* @param desKey
* 十六进制编码的KEY
* @param data
* 被加密的数据
* @return 返回十六进制的解密结果
*/
public String decDESede(String desKey, byte[] data) {
Cipher c1 = null;
try {
c1 = Cipher.getInstance("DESede/ECB/NoPadding",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
} catch (NoSuchAlgorithmException e) {
logger.error("DESede/ECB/NoPadding NoSuchAlgorithmException", e);
return "";
} catch (NoSuchPaddingException e) {
logger.error("DESede/ECB/NoPadding NoSuchPaddingException", e);
return "";
}
SecretKeySpec sk = new SecretKeySpec(hex2byte(desKey.getBytes()), "DESede");
try {
c1.init(Cipher.DECRYPT_MODE, sk);
} catch (InvalidKeyException e) {
logger.error("DESede/ECB/NoPadding InvalidKeyException", e);
return "";
}
byte encode[] = null;
try {
encode = c1.doFinal(data);
} catch (IllegalBlockSizeException e) {
logger.error("IllegalBlockSizeException", e);
return "";
} catch (BadPaddingException e) {
logger.error("BadPaddingException", e);
return "";
}
String rlt = byte2hex(encode).toUpperCase();
logger.info("desKey=[" + desKey + "];input data=[" + byte2hex(data) + "]; 解密=[" + rlt + "]");
return rlt;
}
/**
* DESede加密(DESede/ECB/NoPadding)
*
* @param desKey
* 十六进制编码的KEY
* @param data
* 被加密的数据
* @return 返回十六进制的解密结果
*/
public String encDESede(String desKey, byte[] data) {
Cipher c1 = null;
try {
c1 = Cipher.getInstance("DESede/ECB/NoPadding",
new org.bouncycastle.jce.provider.BouncyCastleProvider());
} catch (NoSuchAlgorithmException e) {
logger.error("DESede/ECB/NoPadding NoSuchAlgorithmException", e);
return "";
} catch (NoSuchPaddingException e) {
logger.error("DESede/ECB/NoPadding NoSuchPaddingException", e);
return "";
}
SecretKeySpec sk = new SecretKeySpec(hex2byte(desKey.getBytes()), "DESede");
try {
c1.init(Cipher.ENCRYPT_MODE, sk);
} catch (InvalidKeyException e) {
logger.error("DESede/ECB/NoPadding InvalidKeyException", e);
return "";
}
byte encode[] = null;
try {
encode = c1.doFinal(data);
} catch (IllegalBlockSizeException e) {
logger.error("IllegalBlockSizeException", e);
return "";
} catch (BadPaddingException e) {
logger.error("BadPaddingException", e);
return "";
}
String rlt = byte2hex(encode).toUpperCase();
logger.info("desKey=[" + desKey + "];input data=[" + byte2hex(data) + "]; 解密=[" + rlt + "]");
return rlt;
}
// public String encryptedDataByGwCert(byte[] plainDataByte, PublicKey publicKey)
}