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();

}

}

JAVA中pin什么意思_银行业加密算法,PIN相关算法(java-国密)相关推荐

  1. java中解密的思想_北大青鸟翔天解密,Java核心思想两大点

    Java已经成为一个庞大而复杂的技术平台,对于开发人员而言,要想更好的掌握Java技术,深入理解底层的技术处理细节必不可少.对核心概念和思想的掌握可以帮助我们举一反三.触类旁通,有助于提升我们对整个J ...

  2. java中arraycopy的用法_[jdk源码阅读系列]Java中System.arraycopy()的用法

    本文转载,原文链接: 3分钟了解Java中System.arraycopy的用法 - 伊万夫斯基 - 博客园  https://www.cnblogs.com/benjieqiang/p/114288 ...

  3. java中二进制怎么说_面试常用:说清楚Java中synchronized和volatile的区别

    回顾一下两个关键字:synchronized和volatile 1.Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized.v ...

  4. java中Solution怎么用_【leetcode】solution in java——Easy4

    16:Invert Binary Tree 此题:以根为对称轴,反转二叉树. 思路:看到二叉树,我们第一时间要想到处理二叉树的常用方法--BFS.DFS,更常用的是DFS.此题我们先用BFS来思考:B ...

  5. java中异常+连接重置_是什么导致我的java.nett.ocketException:连接重置?

    是什么导致我的java.nett.ocketException:连接重置? 我们看到了频繁但断断续续的情况.java.net.SocketException: Connection reset我们日志 ...

  6. java中sql模糊查询_模糊查询的sql语句(java模糊查询sql语句)

    模糊查询的sql语句(java模糊查询sql语句) 2020-07-24 11:06:02 共10个回答 假设表名为product,商品名为name,简界为remark.则可如下写:select[na ...

  7. java中fork什么意思_最通俗的例子讲解Java中的fork-join

    public class SumArray { private static class SumTask extends RecursiveTask{ private final static int ...

  8. java中execution的作用_一文初步了解Java虚拟机

    大家都知道,Java中JVM的重要性,学习了JVM你对Java的运行机制.编译过程和如何对Java程序进行调优相信都会有一个很好的认知. 什么是JVM? JVM(Java Virtual Machin ...

  9. java中的复合数据类型是什么_【填空题】类是Java中的一种重要的复合数据类型,是组成Java程序的基本要素。一个类的实现包括两部分:____和_____....

    [填空题]类是Java中的一种重要的复合数据类型,是组成Java程序的基本要素.一个类的实现包括两部分:____和_____. 更多相关问题 [名词解释] 观叶树木 [单选] 开花时有浓郁香气的树种是 ...

最新文章

  1. Codeforces Round #643 (Div. 2)题解
  2. C语言基础知识【数据类型】
  3. 用python创建数据库监控平台(3)安装Python3.5
  4. 《基于Node.js实现简易聊天室系列之项目前期工作》
  5. FreeMarker学习2
  6. docker学习笔记(六)docker-compose
  7. AMD院士站台 异构计算与OpenCL编程师资培训首站清华开讲
  8. 区块链BAAS平台:公共或私人区块链编程以用于各种用途
  9. selectprovider 分页_MyBatis使用@SelectProvider拼接sql语句
  10. Spring Boot————单元测试
  11. 三星开源的 tcpflow 抓包工具
  12. SAP系统管理员的工作
  13. echarts 柱状图 横坐标文字纵向展示(超出显示...)
  14. python学习总结4 - 流程控制工具
  15. Atitit 学科与知识领域分类门类分类法 目录 1. 学位学科门类是授予学位的学科类别。国际上大体有两种划分方法: 1 2. 三大类法 文理科 医学 1 3. 五大门类 2 4. 13门类 2 5
  16. 两年数据对比柱形图_【系列课程】用Excel进行数据可视化组合图表的制作lt;二gt;...
  17. PFC离散元+3DEC离散元技术与应用学习
  18. C#技术交流④群正式开建,诚邀各路大佬莅临指导
  19. 小米路由器3G建站折腾笔记6 - 总结
  20. html文本框打tab,HTML标签textarea支持tab键

热门文章

  1. python 数组比较大小_python – 比较两个不同长度的numpy数组
  2. python创建文件对象的函数_Python学习笔记之—— File(文件) 对象常用函数
  3. unity2d自动生成敌人_【A*Pathfinding】超级简单的Unity2D寻路
  4. linux下的文档处理及tar命令
  5. 回顾JavsScript对象的克隆
  6. 从壹开始前后端分离 [ vue + .netcore 补充教程 ] 三十║ Nuxt实战:动态路由+同构...
  7. oc基础 不可变字符串的创建和使用
  8. Excel VBA入门的基础语句
  9. 利用CUTFTP Tranfer Engine开发.NET FTP客户端
  10. curl post json_curl 模拟 GETPOST 请求,以及 curl post 上传文件