public class PIN {
/**
* 加密PIN明文
*
* @param pin
* @param pan
* @param key
* @return
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws NoSuchPaddingException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeySpecException
* @throws IllegalArgumentException
* @throws SecurityException
* @throws IOException
*/
public static String encrypt(String pin, String pan, String pik)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException, IllegalArgumentException, SecurityException, IOException {
return encrypt(pin, pan, pik, PINFormat.ANSIX98);
}
public static String encrypt(String pin, String pan, String pik, PINFormat format)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException, IllegalArgumentException, SecurityException, IOException {
String pinBlock = Format.formatPin(pin, pan, format);
byte[] cipherPin = SM4.encryptECB(Convert.hexToByte(pik), Convert.hexToByte(pinBlock));
return Convert.byteToHexStr(cipherPin);
}
/**
* 解密pin密文
*
* @param pinBlock
* @param pan
* @param key
* @return
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws NoSuchPaddingException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeySpecException
* @throws IllegalArgumentException
* @throws SecurityException
* @throws IOException
*/
public static String decrypt(String pinBlock, String pan, String pik)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException, IllegalArgumentException, SecurityException, IOException {
return decrypt(pinBlock, pan, pik, PINFormat.ANSIX98);
}
public static String decrypt(String pinBlock, String pan, String pik, PINFormat format)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException, IllegalArgumentException, SecurityException, IOException {
byte[] cipherPin = SM4.decryptECB(Convert.hexToByte(pik), Convert.hexToByte(pinBlock));
String pin = Format.formatPinBack(Convert.byteToHexStr(cipherPin), pan, format);
return pin;
}
/**
* 字符pin加密
*
* @param pin
* @param pik
* @return
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws NoSuchPaddingException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeySpecException
* @throws IllegalArgumentException
* @throws SecurityException
* @throws IOException
*/
public static String encryptCharPin(String pin, String pik)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException, IllegalArgumentException, SecurityException, IOException {
String pinBlock = Format.formatPin(pin, pin, PINFormat.CHARPIN);
byte[] cipherPin = SM4.encryptECB(Convert.hexToByte(pinBlock), Convert.hexToByte(pik));
return Convert.byteToHexStr(cipherPin);
}
/**
* 字符pin解密
*
* @param pinBlock
* @param pik
* @return
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws NoSuchPaddingException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeySpecException
* @throws IllegalArgumentException
* @throws SecurityException
* @throws IOException
*/
public static String decryptCharPin(String pinBlock, String pik)
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
ShortBufferException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException, IllegalArgumentException, SecurityException, IOException {
byte[] cipherPin = SM4.decryptECB(Convert.hexToByte(pinBlock), Convert.hexToByte(pik));
String pin = Format.formatPinBack(Convert.byteToHexStr(cipherPin), "", PINFormat.CHARPIN);
return pin;
}
//计算pinoffset的10进制对照表
public static final String D_TABLE = "0123456789012345";
/**
* IBM3624计算自然PIN
*
* @param pan
* @param pinLength
* @param pvk
* @return
* @throws SecurityException
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws NoSuchPaddingException
* @throws ShortBufferException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeySpecException
* @throws IOException
*/
public static String calculateNaturalPin(String pan, int pinLength, String pvk)
throws SecurityException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,
NoSuchPaddingException, ShortBufferException, IllegalBlockSizeException, BadPaddingException,
InvalidAlgorithmParameterException, InvalidKeySpecException, IOException {
String formatPan = String.format("%-16s", pan).replace(' ', 'F');
byte[] cipherPan = SM4.encryptECB(Convert.hexToByte(formatPan), Convert.hexToByte(pvk));
String cpStr = Convert.byteToHexStr(cipherPan);
StringBuilder builder = new StringBuilder("");
for (int i = 0; i < pinLength; i++) {
builder.append(D_TABLE.charAt(Integer.parseInt(cpStr.substring(i, i + 1), 16)));
}
return builder.toString();
}
/**
* ibm3624计算pinoffset
*
* @param pan
* @param pin
* @param pinLength
* @param pvk
* @return
* @throws Exception
*/
public static String calculatePINOffset(String pan, String pin, int pinLength, String pvk) throws Exception {
if (pin.length() != pinLength) {
throw new SecurityException("bad pinLength");
}
String natrualPin = calculateNaturalPin(pan, pinLength, pvk);
StringBuilder builder = new StringBuilder("");
int cpin;
int npin;
for (int i = 0; i < pinLength; i++) {
cpin = Integer.parseInt(pin.substring(i, i + 1));
npin = Integer.parseInt(natrualPin.substring(i, i + 1));
builder.append(Integer.toString(cpin >= npin ? cpin - npin : 10 + cpin - npin));
}
return builder.toString();
}
/**
* ibm3624校验pin
*
* @param pan
* @param pin
* @param pinLength
* @param offset
* @param pvk
* @return
* @throws Exception
*/
public static boolean validatePINOffset(String pan, String pin, int pinLength, String offset, String pvk)
throws Exception {
if (pin.length() != pinLength) {
throw new SecurityException("bad pinLength");
}
String natrualPin = calculateNaturalPin(pan, pinLength, pvk);
StringBuilder builder = new StringBuilder("");
int opin;
int npin;
for (int i = 0; i < pinLength; i++) {
opin = Integer.parseInt(offset.substring(i, i + 1));
npin = Integer.parseInt(natrualPin.substring(i, i + 1));
builder.append(Integer.toString(opin + npin >= 10 ? opin + npin - 10 : opin + npin));
}
return builder.toString().equals(pin);
}
public static void main(String[] args) throws Exception {
System.out.println(String.format("%-14s", "11").replace(" ", "F"));
String pinc = encrypt("123456", "123456789012345678",
"0123456789ABCDEF0123456789ABCDEF");
System.out.println(pinc);
// ;
// System.out.println(decrypt(pinc, "123456789012345678",
// "0123456789ABCDEF0123456789ABCDEF"));
System.out.println(calculatePINOffset("1234567899876543", "3096", 4, "0123456789ABCDEFFEDCBA9876543210"));
System.out
.println(validatePINOffset("1234567899876543", "3096", 4, "0900", "0123456789ABCDEFFEDCBA9876543210"));
System.out.println(encryptCharPin("oracle9i", "0123456789ABCDEFFEDCBA9876543210"));
System.out.println(decryptCharPin("1E716BD9406500C9B8D9F178DCD52F26058AAFCE50FDFC69", "0123456789ABCDEFFEDCBA9876543210"));
}
}
对应pin格式化帮助类
/**
* https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/com.ibm.zos.v2r3.csfb400/pinbf.htm
* 参考以上链接-IBM Knowledge Center
* PIN 格式化
*
* P = 一个4位十进制数字,是PIN值的一位数。 C = 一个4位十六进制控制值。有效值为X'0',X'1'和X'2'。 L =
* 一个4位十六进制值,指定PIN数字的数量。值范围为4到12,包括4和12。 F = 值为X'F'的 4位字段定界符。 f =
* 一个4位分隔符填充符,它是P或F,具体取决于PIN的长度。 D = 一个4位十进制填充值。PIN块中的所有填充数字具有相同的值。 X =
* 一个4位十六进制填充值。PIN块中的所有填充数字具有相同的值。 x = 一个4位十六进制填充符,它是P或X,具体取决于PIN的长度。 R =
* 一个4位十六进制随机数字。R位的序列可以各自取不同的值。 r = 4位随机填充,P或R,取决于PIN的长度。 Z = 一个4位十六进制零(X'0')。 z
* = 一个4位零填充,可以是P或Z,具体取决于PIN的长度。 S = 一个4位十六进制数字,构成序列号的一位数。 A =
* 一个4位十进制数字,构成用户指定常量的一位数。
*
* @author Administrator
*
*/
public class Format {
/**
* ANSI X9.8/ISO0/VISA1/VISA4/ECI1
*
* P1 = CLPPPPffffffffFF P2 = ZZZZAAAAAAAAAAAA PIN Block = P1 XOR P2 where C =
* X'0' L = X'4' to X'C'
*
* https://max.book118.com/html/2017/0907/132467659.shtm
* 中国银联银行卡交换系统技术规范(国际卷)第4部分
* https://max.book118.com/html/2015/0713/20968185.shtm
*
* PIN域:共64bit,每4bit为1位十六进制数字,共16位十六进制数字 第1位(1~4bit):固定值0x0(0000)
* 第2位(5~8bit):PIN长度,取值范围0x4(0100) ~ 0xC(1100)
* 第3~16位(9~64bit):PIN,不足14位右补0xF(1111),因为PIN最多12位,所以最后2位一定是0xFF(1111,1111)
*
* PAN域:共64bit,每4bit为1位十六进制数字,共16位十六进制数字
* 第1~4位(1~16bit):固定值0x0000(0000,0000,0000,0000)
* 第5~16位(17~64bit):PAN,去掉最右边1位校验数字后,从右边数12位,不足12位左补0x0(0000)
*
* @param pin
* 密码
* @param pan
* 账号
* @return Format 0 PIN block 十六进制字符串
* @throws SecurityException
*/
private static String formatPin0(String pin, String pan) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN域,64bit,16位十六进制数字
// 固定值0x0 + PIN长度 + PIN(不足14位右补F)
String PINField = "0" + Integer.toHexString(pin.length()) + String.format("%-14s", pin).replace(' ', 'F');
// PAN域,64bit,16位十六进制数字
// 固定值0x0000 + PAN,去掉校验数字,从右边数12位,不足12位左补0x0
String PANWithoutCheckDigit = pan.substring(0, pan.length() - 1);
String PANField = "0000" + (PANWithoutCheckDigit.length() > 12
? PANWithoutCheckDigit.substring(PANWithoutCheckDigit.length() - 12, PANWithoutCheckDigit.length())
: String.format("%12s", PANWithoutCheckDigit).replace(' ', '0'));
// 十六进制转byte数组
byte[] PINFieldByteArray = Convert.hexToByte(PINField);
// 十六进制转byte数组
byte[] PANFieldByteArray = Convert.hexToByte(PANField);
// 异或
byte[] PINBlockByteArray = new byte[8];
for (int i = 0; i < 8; i++) {
PINBlockByteArray[i] = (byte) (PINFieldByteArray[i] ^ PANFieldByteArray[i]);
}
// 返回十六进制
return Convert.byteToHexStr(PINBlockByteArray).toUpperCase();
}
private static String formatPin0Back(String pinBlock, String pan) throws SecurityException {
// 十六进制转byte数组
byte[] pinBlockByteArray = Convert.hexToByte(pinBlock);
// 十六进制转byte数组
String PANWithoutCheckDigit = pan.substring(0, pan.length() - 1);
String PANField = "0000" + (PANWithoutCheckDigit.length() > 12
? PANWithoutCheckDigit.substring(PANWithoutCheckDigit.length() - 12, PANWithoutCheckDigit.length())
: String.format("%12s", PANWithoutCheckDigit).replace(' ', '0'));
byte[] panByteArray = Convert.hexToByte(PANField);
// 异或
byte[] pinByteArray = new byte[8];
for (int i = 0; i < 8; i++) {
pinByteArray[i] = (byte) (pinBlockByteArray[i] ^ panByteArray[i]);
}
String pinBlockStr = Convert.byteToHexStr(pinByteArray);
int lengh = Integer.parseInt(pinBlockStr.substring(1, 2), 16);
return pinBlockStr.substring(2, 2 + lengh);
}
/**
* ISO1/ECI4
*
* PIN Block = CLPPPPrrrrrrrrRR where C = X'1' L = X'4' to X'C'
*
* @param PIN
* @return
* @throws SecurityException
*/
private static String formatPin1(String pin) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位右补交易域
String PINBlock = "1" + Integer.toHexString(pin.length()) + pin;
// 交易域使用随机数,取值范围是0x0~0xF
Random r = new Random();
for (int i = 0; i < 14 - pin.length(); i++) {
PINBlock += Integer.toHexString(r.nextInt(16));
}
return PINBlock.toUpperCase();
}
private static String formatPin1Back(String pinBlock) {
int length = Integer.parseInt("" + pinBlock.charAt(1), 16);
return pinBlock.substring(2, 2 + length);
}
/**
* ISO2
*
* PIN Block = CLPPPPffffffffFF where C = X'2' L = X'4' to X'C'
*
* @param PIN
* @return
* @throws SecurityException
*/
private static String formatPin2(String pin) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位0xF
String PINBlock = "2" + Integer.toHexString(pin.length()) + String.format("%-14s", pin).replace(' ', 'F');
return PINBlock.toUpperCase();
}
private static String formatPin2Back(String pinBlock) {
int length = Integer.parseInt("" + pinBlock.charAt(1), 16);
return pinBlock.substring(2, 2 + length);
}
/**
* ISO3
*
* P1 = CLPPPPrrrrrrrrRR P2 = ZZZZAAAAAAAAAAAA PIN Block = P1 XOR P2 where C =
* X'3' L = X'4' to X'C'
*
* @param pin
* @param pan
* @return
* @throws SecurityException
*/
private static String formatPin3(String pin, String pan) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位右补交易域
String PINField = "3" + Integer.toHexString(pin.length()) + pin;
// 交易域使用随机数,取值范围是0x0~0xF
Random r = new Random();
for (int i = 0; i < 14 - pin.length(); i++) {
PINField += Integer.toHexString(r.nextInt(16));
}
// PAN域,64bit,16位十六进制数字
// 固定值0x0000 + PAN,去掉校验数字,从右边数12位,不足12位左补0x0
String PANWithoutCheckDigit = pan.substring(0, pan.length() - 1);
String PANField = "0000" + (PANWithoutCheckDigit.length() > 12
? PANWithoutCheckDigit.substring(PANWithoutCheckDigit.length() - 12, PANWithoutCheckDigit.length())
: String.format("%12s", PANWithoutCheckDigit).replace(' ', '0'));
// 十六进制转byte数组
byte[] PINFieldByteArray = Convert.hexToByte(PINField);
// 十六进制转byte数组
byte[] PANFieldByteArray = Convert.hexToByte(PANField);
// 异或
byte[] PINBlockByteArray = new byte[8];
for (int i = 0; i < 8; i++) {
PINBlockByteArray[i] = (byte) (PINFieldByteArray[i] ^ PANFieldByteArray[i]);
}
// 返回十六进制
return Convert.byteToHexStr(PINBlockByteArray).toUpperCase();
}
private static String formatPin3Back(String pinBlock, String pan) throws SecurityException {
// PAN域,64bit,16位十六进制数字
// 固定值0x0000 + PAN,去掉校验数字,从右边数12位,不足12位左补0x0
String PANWithoutCheckDigit = pan.substring(0, pan.length() - 1);
String PANField = "0000" + (PANWithoutCheckDigit.length() > 12
? PANWithoutCheckDigit.substring(PANWithoutCheckDigit.length() - 12, PANWithoutCheckDigit.length())
: String.format("%12s", PANWithoutCheckDigit).replace(' ', '0'));
// 十六进制转byte数组
byte[] PINFieldByteArray = Convert.hexToByte(pinBlock);
// 十六进制转byte数组
byte[] PANFieldByteArray = Convert.hexToByte(PANField);
// 异或
byte[] PINBlockByteArray = new byte[8];
for (int i = 0; i < 8; i++) {
PINBlockByteArray[i] = (byte) (PINFieldByteArray[i] ^ PANFieldByteArray[i]);
}
String pb = Convert.byteToHexStr(PINBlockByteArray);
int length = Integer.parseInt("" + pb.charAt(1), 16);
return pb.substring(2, 2 + length);
}
/**
* VISA2
*
* PIN Block = LPPPPzzDDDDDDDDD where L = X'4' to X'6'
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin4(String pin) throws SecurityException {
if (pin.length() > 6 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = "" + Integer.toHexString(pin.length()) + String.format("%-6s", pin).replace(' ', '0')
+ "999999999";
return PINBlock.toUpperCase();
}
private static String formatPin4Back(String pinBlock) {
int length = Integer.parseInt("" + pinBlock.charAt(0), 16);
return pinBlock.substring(1, 1 + length);
}
/**
* visa3
*
* PIN Block = PPPPPPFXXXXXXXXX
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin5(String pin) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = pin + "F";
while (PINBlock.length() < 16) {
PINBlock += "9";
}
return PINBlock.toUpperCase();
}
private static String formatPin5Back(String pinBlock) {
int length = pinBlock.indexOf("F");
return pinBlock.substring(0, length);
}
/**
* IBM4700
*
* PIN Block = LPPPPffffffffFSS where L = X'4' to X'C'
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin6(String pin) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = "" + Integer.toHexString(pin.length()) + String.format("%-12s", pin).replace(' ', '9')
+ "F00";
for (int i = PINBlock.length(); i < 16; i++) {
PINBlock += "9";
}
return PINBlock.toUpperCase();
}
private static String formatPin6Back(String pinBlock) {
int length = Integer.parseInt("" + pinBlock.charAt(0), 16);
return pinBlock.substring(1, 1 + length);
}
/**
* IBM3624
*
* PIN Block = PPPPxxxxxxxxXXXX
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin7(String pin) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = String.format("%-16s", pin).replace(' ', 'F');
return PINBlock.toUpperCase();
}
private static String formatPin7Back(String pinBlock) {
int length = pinBlock.indexOf("F");
return pinBlock.substring(0, length);
}
/**
* IBM3621
*
* PIN Block = SSSSPPPPxxxxxxxx
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin8(String pin) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = "0000" + String.format("%-14s", pin).replace(' ', 'A');
return PINBlock.toUpperCase();
}
private static String formatPin8Back(String pinBlock) {
int length = pinBlock.indexOf("A");
return pinBlock.substring(4, length);
}
/**
* ECI2
*
* PIN Block = PPPPRRRRRRRRRRRR
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin9(String pin) throws SecurityException {
if (pin.length() != 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = pin;
Random r = new Random();
for (int i = 0; i < 16 - pin.length(); i++) {
PINBlock += Integer.toHexString(r.nextInt(16));
}
return PINBlock.toUpperCase();
}
private static String formatPin9Back(String pinBlock) {
return pinBlock.substring(0, 4);
}
/**
* ECI3
*
* PIN Block = LPPPPzzRRRRRRRRR where L = X'4' to X'6'
*
* @param pin
* @return
* @throws SecurityException
*/
private static String formatPin10(String pin) throws SecurityException {
if (pin.length() > 6 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN block,64bit,16位十六进制数字
// 固定值0x1 + PIN长度 + PIN,不足14位十进制9
String PINBlock = "" + Integer.toHexString(pin.length()) + String.format("%-6s", pin).replace(' ', '0');
Random r = new Random();
for (int i = 0; i < 9; i++) {
PINBlock += Integer.toHexString(r.nextInt(16));
}
return PINBlock.toUpperCase();
}
private static String formatPin10Back(String pinBlock) {
int length = Integer.parseInt(pinBlock.substring(0, 1), 16);
return pinBlock.substring(1, 1 + length);
}
/**
* 格式化字符PIN
* @param charPin
* @return
* @throws SecurityException
*/
private static String formatCharPin(String charPin) throws SecurityException {
if(charPin.length() > 20 || charPin.length() < 6) {
throw new SecurityException("bad pin");
}
String pinBlock = "";
//长度以10进制8byte字符标识
if(charPin.length() < 16) {
pinBlock += ("0" + Integer.toHexString(charPin.length()));
}else {
pinBlock += Integer.toHexString(charPin.length());
}
//总长24位,不足填充F
pinBlock += String.format("%-22s", charPin).replace(' ', 'F');
byte[] pbByte = ASCII.stringToByteArr(pinBlock);
return Convert.byteToHexStr(pbByte);
}
private static String formatCharPinBack(String charPinBlock) throws SecurityException {
byte[] pbByte = Convert.hexToByte(charPinBlock);
String pinBlock = new String(ASCII.byteArrToCharArr(pbByte));
return pinBlock.substring(2, 2 + Integer.parseInt(pinBlock.substring(0, 2), 16));
}
private static String formatPinGM(String pin, String pan) throws SecurityException {
if (pin.length() > 12 || pin.length() < 4) {
throw new SecurityException("bad pin");
}
// PIN域,64bit,16位十六进制数字
// 固定值0x0 + PIN长度 + PIN(不足14位右补F)
String PINField = "0" + Integer.toHexString(pin.length()) + String.format("%-30s", pin).replace(' ', 'F');
// PAN域,64bit,16位十六进制数字
// 固定值0x0000 + PAN,去掉校验数字,从右边数12位,不足12位左补0x0
String PANWithoutCheckDigit = pan.substring(0, pan.length() - 1);
String PANField = "00000000000000000000" + (PANWithoutCheckDigit.length() > 12
? PANWithoutCheckDigit.substring(PANWithoutCheckDigit.length() - 12, PANWithoutCheckDigit.length())
: String.format("%12s", PANWithoutCheckDigit).replace(' ', '0'));
// 十六进制转byte数组
byte[] PINFieldByteArray = Convert.hexToByte(PINField);
// 十六进制转byte数组
byte[] PANFieldByteArray = Convert.hexToByte(PANField);
// 异或
byte[] PINBlockByteArray = new byte[16];
for (int i = 0; i < 16; i++) {
PINBlockByteArray[i] = (byte) (PINFieldByteArray[i] ^ PANFieldByteArray[i]);
}
// 返回十六进制
return Convert.byteToHexStr(PINBlockByteArray).toUpperCase();
}
private static String formatPinGMBack(String pinBlock, String pan) throws SecurityException {
// 十六进制转byte数组
byte[] pinBlockByteArray = Convert.hexToByte(pinBlock);
// 十六进制转byte数组
String PANWithoutCheckDigit = pan.substring(0, pan.length() - 1);
String PANField = "00000000000000000000" + (PANWithoutCheckDigit.length() > 12
? PANWithoutCheckDigit.substring(PANWithoutCheckDigit.length() - 12, PANWithoutCheckDigit.length())
: String.format("%12s", PANWithoutCheckDigit).replace(' ', '0'));
byte[] panByteArray = Convert.hexToByte(PANField);
// 异或
byte[] pinByteArray = new byte[16];
for (int i = 0; i < 16; i++) {
pinByteArray[i] = (byte) (pinBlockByteArray[i] ^ panByteArray[i]);
}
String pinBlockStr = Convert.byteToHexStr(pinByteArray);
int lengh = Integer.parseInt(pinBlockStr.substring(1, 2), 16);
return pinBlockStr.substring(2, 2 + lengh);
}
/**
* 格式化PIN
*
* @param pin
* @param pan
* @param format
* @return
* @throws SecurityException
*/
public static String formatPin(String pin, String pan, PINFormat format) throws SecurityException {
String pinBlock = "";
switch (format) {
case ANSIX98:
case ISO0:
case VISA1:
case VISA4:
case ECI1:
pinBlock = formatPin0(pin, pan);
break;
case ISO1:
case ECI4:
pinBlock = formatPin1(pin);
break;
case ISO2:
pinBlock = formatPin2(pin);
break;
case ISO3:
pinBlock = formatPin3(pin, pan);
break;
case VISA2:
pinBlock = formatPin4(pin);
break;
case VISA3:
pinBlock = formatPin5(pin);
break;
case IBM4700:
pinBlock = formatPin6(pin);
break;
case IBM3624:
pinBlock = formatPin7(pin);
break;
case IBM3621:
pinBlock = formatPin8(pin);
break;
case ECI2:
pinBlock = formatPin9(pin);
break;
case ECI3:
pinBlock = formatPin10(pin);
break;
case CHARPIN:
pinBlock = formatCharPin(pin);
break;
case GMANSI98:
pinBlock = formatPinGM(pin, pan);
break;
default:
break;
}
return pinBlock;
}
/**
* 反解PIN
*
* @param pin
* @param pan
* @param format
* @return
* @throws SecurityException
*/
public static String formatPinBack(String pinBlock, String pan, PINFormat format) throws SecurityException {
String pin = "";
switch (format) {
case ANSIX98:
case ISO0:
case VISA1:
case VISA4:
case ECI1:
pin = formatPin0Back(pinBlock, pan);
break;
case ISO1:
case ECI4:
pin = formatPin1Back(pinBlock);
break;
case ISO2:
pin = formatPin2Back(pinBlock);
break;
case ISO3:
pin = formatPin3Back(pinBlock, pan);
break;
case VISA2:
pin = formatPin4Back(pinBlock);
break;
case VISA3:
pin = formatPin5Back(pinBlock);
break;
case IBM4700:
pin = formatPin6Back(pinBlock);
break;
case IBM3624:
pin = formatPin7Back(pinBlock);
break;
case IBM3621:
pin = formatPin8Back(pinBlock);
break;
case ECI2:
pin = formatPin9Back(pinBlock);
break;
case ECI3:
pin = formatPin10Back(pinBlock);
break;
case CHARPIN:
pin = formatCharPinBack(pinBlock);
break;
case GMANSI98:
pin = formatPinGMBack(pinBlock, pan);
break;
default:
break;
}
return pin;
}
public static void main(String[] args) throws SecurityException {
String pin = "851019";
String pan = "6225881297078266";
System.out.println(formatPin0(pin, pan));
//PINFormat[] ps = PINFormat.values();
//for (PINFormat pinFormat : ps) {
//if(PINFormat.ECI2 == pinFormat || PINFormat.CHARPIN == pinFormat) {
//continue;
//}
//String pinBlock = formatPin(pin, pan, pinFormat);
//System.out.println(pinBlock);
//System.out.println(formatPinBack(pinBlock, pan, pinFormat));
//System.out.println();
//}
//String pinBlock = formatPin("oracle9i", pan, PINFormat.CHARPIN);
//System.out.println(pinBlock);
//System.out.println(formatPinBack(pinBlock, pan, PINFormat.CHARPIN));
//System.out.println();
}
}