[.NET][C#]Parse ISO8583筆記(七)PIN的驗證值(PVV)

在Parse ISO8583(五)及(六)中,筆記了Natural PIN及PIN Offset運作,前兩種驗證在處理過程中,免不了用正確金鑰計算出正確的密碼值PIN,這因此有了一種過程風險。
為了避免風險,在PIN的驗證上也有PVV(PIN Verification Value),概念很像取雜湊驗證(Hash),但精確度不同。

 

Wiki上三種PIN的驗證方式,今天筆記第三種: Visa PVV

  • IBM 3624: 通常只使用在產生Natural PIN,非常不適合使用在PIN驗證。
  • IBM 3624 + PIN-Offset
  • Visa PVV: 不是專屬Visa卡使用喔,其他Mastercard、JCB也適用。
PVV Generation Algorithm

1.卡號PAN:11位 + PVKI:1位 + PIN前4位 用PVK金鑰下去做2TDEA運算,

2.依序取出前4位小於10的運算結果,若位數不足,再將超過10的16進位字元除10的餘數補在後方。

  • 卡號PAN 11位: 不含最後1位檢查碼,從右邊開始取11位
  • PVKI 1位: 0-6 ,用來表示使用哪一組PVK
  • PIN  4位: 密碼值的前4位。

 

算出PVV後,實際PT(PIN Tranaction)時怎麼驗證PIN?

PIN驗證流程主要分成卡片製卡及持卡人進行需要PIN的交易時兩個階段

A.卡片製卡時:

  1. 會先用卡號PAN:11位 + PVKI:1位 + Natural PIN或動態PIN前4位算PVV。
  2. 依據ISO7813規格,在磁軌二(Track2)的Discretionary data欄位中分別寫入PVKI(1位)、PVV(4位)。


B.當持卡人進行需要PIN的交易時:

  1. 前端POS設備或刷卡機會讀取磁軌二(Track2)放在ISO8583 DE35欄位。
  2. 持卡人輸入的PIN在前端經過初步加密運算成PIN Block,交易傳遞時放在ISO8583 DE52(PIN Block)欄位。
  3. 後台收到ISO8583後先從DE52 PIN Block還原出持卡人輸入的PIN
  4. 後台再拿ISO8583中的卡號PAN:11位 + PVKI:1位 + PIN前4位 用PVK金鑰下去做2TDEA運算,算出PVV
  5. 驗算步驟(4)算出的PVV是否與ISO8583 DE35 磁軌二中的PVV相符

小結:

  • 即使卡片被側錄(skimming),密碼還是必須正確才能提款(withdraw)或進行其他需要PIN的交易。
  • 另外除了卡片製卡,在驗證過程中,流程中只算PVV,不會用有"正確的金鑰"計算出"正確的密碼值"的過程風險。

 

理論筆記完了,來實務計算: 

1.準備2TDEA呼叫方法: 

輸入兩把PVK(基碼)及卡號(PAN)明文 

這一段和先前那篇[.NET][C#]Parse ISO8583筆記(五)Natural PIN內容完全相同!!

參數1是PVKA+PVKB;參數2則是16 Byte的明文資料。

/// <summary>
/// 輸入16位KEY byte[]及明文byte[]進行加密
/// </summary>
/// <param name="key"></param>
/// <param name="plaintext"></param>
/// <returns></returns>
public static byte[] Encryption(byte[] Deskey, byte[] plainText)
{
    SymmetricAlgorithm TdesAlg = new TripleDESCryptoServiceProvider();
    //設定基碼
    TdesAlg.Key = Deskey;
    //加密工作模式:CBC
    TdesAlg.Mode = CipherMode.CBC;
    //補充字元方式:0
    TdesAlg.Padding = PaddingMode.Zeros;
    //初始向量IV = 0
    TdesAlg.IV = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    ICryptoTransform ict = TdesAlg.CreateEncryptor(TdesAlg.Key, TdesAlg.IV);
    MemoryStream mStream = new MemoryStream();
    CryptoStream cStream = new CryptoStream(mStream, ict, CryptoStreamMode.Write);
    cStream.Write(plainText, 0, plainText.Length);
    cStream.FlushFinalBlock();
    cStream.Close();
    return mStream.ToArray();
}

2.寫一段組成明文並執行測試的方法

明文項目 明文組成
PAN 1234567899876543
PVKI 1
PIN 1234
[TestMethod]
public void TesPVVGen()
{
    //Visa Methid PVV(PVKI:1 PIN:1234)

    //PVKA + PVKB
    string Deskey = "0123456789ABCDEFFEDCBA9876543210";
    //含PIN的明文資料 (卡號:11位 + PVKI:1位 + PIN前4位)
    string plainText = "5678998765411234";

    //取得加密演算結果
    byte[] b = Encryption(Deskey.HexToByte(), plainText.HexToByte());

    List<int> hexInt = new List<int>();
    //依序取出小於10的數字並保留大於10的數字(ABCDEF)在小於10的數字區塊右方
    for (int i = 0; i < b.BToHex().Length; i++)
    {
        int p = Convert.ToInt32(b.BToHex().Substring(i, 1), 16);
        if (p < 10)
        {
            Console.WriteLine("PVV(number) Value: {0} ", p);
        }
        else
        {
            hexInt.Add(p % 10);
        }
    }
    foreach (int p in hexInt)
    {
        Console.WriteLine("PVV(hex) Value: {0} ", p);
    }

}

3.測試結果: 依序取出前4位數值,PVV值就是9365

4.用BP-Tools驗算(eftlab網站)

PVV值也是9365!!!

小結:

  • 根據ISO7813,通常PVV都會錄製在磁軌二中,變更密碼時也會重新錄製在磁條。
  • 國外也有儲存在資料庫中的作法,好在PCI DSS也沒有特別的規定,卡片真偽還是可以使用CVV驗證。

 

參考:
 
Personal identification number 

Discretionary data from magnetic strip credit card, how to parse?

ISO7811、ISO7813、ISO8583