1. 程式人生 > >PinBlock 演算法 使用ANSI x9.8計算

PinBlock 演算法 使用ANSI x9.8計算

PIN格式
ANSI X9.8 Format(帶主帳號資訊)
PIN BLOCK 格式等於 PIN 按位異或主帳號:
PIN 格式:
BYTE 1 PIN的長度
BYTE 2 – BYTE 3/4/5/6/7   4--12個PIN(每個PIN佔4個BIT)
BYTE 4/5/6/7/8 – BYTE 8   FILLER “F” (每個“F“佔4個BIT)
 
主帳號格式:
BYTE 1 — BYTE 2  0X0000
BYTE 3 — BYTE 8 12個主帳號
 12位主帳號的取法:取主帳號的右12位(不包括最右邊的校驗位),不足12位左補“0X00”。

例如:明文 PIN 123456,
設:磁卡上的主帳號為:123456789012345678
擷取下的主帳號為:678901234567 則
用於PIN加密的主帳號為:0x00 0x00 0x67 0x89 0x01 0x23 0x45 0x67
則 PIN BLOCK 為 0x06 0x12 0x34 0x56 0xFF 0xFF 0xFF 0xFF
異或 0x00 0x00 0x67 0x89 0x01 0x23 0x45 0x67
結果為 0x06 0x12 0x53 0xDF 0xFE 0xDC 0xBA 0x98

設:磁卡上的主帳號為:1234567890123456
擷取下的主帳號為:456789012345
則用於PIN加密的主帳號為:0x00 0x00 0x45 0x67 0x89 0x01 0x23 0x45
則 PIN BLOCK 為 0x06 0x12 0x34 0x56 0xFF 0xFF 0xFF 0xFF
  異或 0x00 0x00 0x45 0x67 0x89 0x01 0x23 0x45
  結果為 0x06 0x12 0x71 0x31 0x76 0xFE 0xDC 0xBA
? PIN 加密解密
省中心(外圍系統)在傳送訊息給全國中心(省中心)之前,
應用本中心的PIK對PIN加密後發往全國中心(省中心)。


  /**
   * getPinBlock
   * 標準ANSI X9.8 Format(帶主帳號資訊)的PIN BLOCK計算
   * PIN BLOCK 格式等於 PIN  按位異或  主帳號;
   * @param pin String
   * @param accno String
   * @return byte[]
   */
  private byte[] process(String pin, String accno) {
    byte arrAccno[] = getHAccno(accno);
    byte arrPin[] = getHPin(pin);
    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;
  }

  /**
   * getHPin
   * 對密碼進行轉換
   * PIN格式
   * BYTE 1 PIN的長度
   * BYTE 2 – BYTE 3/4/5/6/7   4--12個PIN(每個PIN佔4個BIT)
   * BYTE 4/5/6/7/8 – BYTE 8   FILLER “F” (每個“F“佔4個BIT)
   * @param pin String
   * @return byte[]
   */
  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;
  }

  /**
   * getHAccno
   * 對帳號進行轉換
   * BYTE 1 — BYTE 2  0X0000
   * BYTE 3 — BYTE 8 12個主帳號
   * 取主帳號的右12位(不包括最右邊的校驗位),不足12位左補“0X00”。
   * @param accno String
   * @return byte[]
   */
  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;
  }