(1) ANSI X9.8 Format(不帶主帳號信息)html
PIN(我的識別碼 Personal Identity Number)總共有8個byte長度,分爲兩個部分;(相似數據包的格式)java
1:Byte1 記錄PIN的長度算法
2:Byte2-Byte8 6-12位(字符)PIN(每一個字符佔4個BIT,不足8位右補F)工具
例如:明文PIN爲 123456,測試
則PIN BLOCK爲 0x06 0x12 0x34 0x56 0xFF 0xFF 0xFF 0xFFthis
0x06記錄了PIN的長度爲6,後邊不足16位均以F補齊,而後轉換爲BCD碼(BCD碼爲8位二進制數爲一個單元,也就是一個Byte的大小也是一個十六進制數HEX的佔用長度)。加密
(2)ANSI X9.8 Format(帶主賬號信息)
PIN BLOCK 格式:等於 PIN 按位異或主賬號
PIN 格式:(與1中的格式相似)
Byte 1 PIN的長度
Byte 2 – Byte 3/4/5/6/7 4--12個PIN(每一個PIN佔4個BIT)
Byte4/5/6/7/8 – Byte 8 FILLER 「F」 (每一個「F「佔4個BIT)
PAN(主賬號 Primary Account Number)一樣包含8個byte,格式以下:
Byte 1 — Byte 2 0x00 0x00
Byte 3 — Byte 8 12個主賬號字符(最後一位爲校驗位)
12位字符主賬號的取法:取主賬號的右12位(不包括最右邊的校驗位),不足12位左補「0X00」。url
例子:spa
明文 PIN:123456,
主賬號 PAN:123456789012345678
截取下的主賬號爲:678901234567 (最後一位校驗位8的前12位字符爲截取的主賬號)code
則用於PIN加密的主賬號爲:0x00 0x00 0x67 0x89 0x01 0x23 0x45 0x67
則 PIN BLOCK (PIN按位異或主賬號PAN)
便是爲: 0x06 0x12 0x34 0x56 0xFF 0xFF 0xFF 0xFF
異或上: 0x00 0x00 0x67 0x89 0x01 0x23 0x45 0x67
結果爲: 0x06 0x12 0x53 0xDF 0xFE 0xDC 0xBA 0x98
算法源碼:(包含一個工具類Util和一個轉換類ANSIFormat.java)
Util.java
package CodeApe;
public class Util {
public Util() {
}
public static void printHexString(String hint, byte[] b) {
System.out.print(hint);
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
System.out.print(hex.toUpperCase() + " ");
}
System.out.println("");
}
public static String Bytes2HexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
public static byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
.byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
.byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}
public static byte[] HexString2Bytes(String src) {
byte[] ret = new byte[8];
byte[] tmp = src.getBytes();
for (int i = 0; i < 8; i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
}
ANSIFormat.java
package CodeApe;
import java.io.ObjectInputStream.GetField;
import javax.annotation.processing.Processor;
import CodeApe.Util;
public class ANSIFormat {
private String pin;
private String accno;
public ANSIFormat(String pin , String accno){
this.pin = pin;
this.accno = accno;
}
public byte[] process(String pin, String accno) {
byte arrPin[] = getHPin(pin);
byte arrAccno[] = getHAccno(accno);
byte arrRet[] = new byte[8];
//PIN BLOCK 格式等於 PIN 按位異或 主賬號;
for (int i = 0; i < 8; i++) {
arrRet[i] = (byte) (arrPin[i] ^ arrAccno[i]);
}
Util.printHexString("PinBlock:", arrRet);
return arrRet;
}
private byte[] getHPin(String pin) {
byte arrPin[] = pin.getBytes();
byte encode[] = new byte[8];
encode[0] = (byte) 0x06;
encode[1] = (byte) Util.uniteBytes(arrPin[0], arrPin[1]);
encode[2] = (byte) Util.uniteBytes(arrPin[2], arrPin[3]);
encode[3] = (byte) Util.uniteBytes(arrPin[4], arrPin[5]);
encode[4] = (byte) 0xFF;
encode[5] = (byte) 0xFF;
encode[6] = (byte) 0xFF;
encode[7] = (byte) 0xFF;
Util.printHexString("encoded pin:", encode);
return encode;
}
private byte[] getHAccno(String accno) {
//取出主賬號;
int len = accno.length();
byte arrTemp[] = accno.substring(len < 13 ? 0 : len - 13, len - 1).getBytes();
byte arrAccno[] = new byte[12];
for (int i = 0; i < 12; i++) {
arrAccno[i] = (i <= arrTemp.length ? arrTemp[i] : (byte) 0x00);
}
byte encode[] = new byte[8];
encode[0] = (byte) 0x00;
encode[1] = (byte) 0x00;
encode[2] = (byte) Util.uniteBytes(arrAccno[0], arrAccno[1]);
encode[3] = (byte) Util.uniteBytes(arrAccno[2], arrAccno[3]);
encode[4] = (byte) Util.uniteBytes(arrAccno[4], arrAccno[5]);
encode[5] = (byte) Util.uniteBytes(arrAccno[6], arrAccno[7]);
encode[6] = (byte) Util.uniteBytes(arrAccno[8], arrAccno[9]);
encode[7] = (byte) Util.uniteBytes(arrAccno[10], arrAccno[11]);
Util.printHexString("encoded accno:", encode);
return encode;
}
}
test.java(測試類)
package CodeApe;
public class test {
private static ANSIFormat pass;
public static void main(String[] args) {
// TODO Auto-generated method stub
String pin = "123456";
String accno = "123456789012345678";
System.out.println("encoded pin:"+pin);
System.out.println("encoded accno:"+accno);
pass = new ANSIFormat(pin, accno);
byte[] b = pass.process(pin, accno);
}
}
效果圖: - -!