觀察上一篇運算密碼驗證值(PVV)最後取值的機制,PVV不太可能反算回PIN,但你知道的,防君子不防暴力!
暴力破解法分別將PIN從0000~9999再加上原先的卡號PAN:11位 + PVKI:1位去運算出1萬組PVV與磁條PVV比對,
的確"有可能"可以猜對原本的PIN!!
從BP-Tool工具也驗證了我們的假設,下方左邊畫面中依序輸入PVK、 PAN、PVV及PVKI就可以算出右邊的PIN結果!
我們來寫一小段程式碼反算看看
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.我們使用上一篇的PVV結果9365來反算
明文項目 | 明文組成 |
PAN | 1234567899876543 |
PVKI | 1 |
PIN | 0000-9999 |
[TestMethod]
public void TesPINFromPVV()
{
//PVKA + PVKB
string Deskey = "0123456789ABCDEFFEDCBA9876543210";
//不含PIN的明文資料
string plainText = "567899876541";
//輸入的PVV值
string TrackPVV = "9365";
StringBuilder sb = new StringBuilder();
for (int j = 0; j < 10000; j++)
{
sb.Clear();
sb.Append(plainText);
sb.Append(j.ToString().PadLeft(4, '0'));
//取得加密演算結果
byte[] b = Encryption(Deskey.HexToByte(), sb.ToString().HexToByte());
string ComputePVV = "";
//依序取出除以10之後的餘數作為PVV值
for (int i = 0; i < b.BToHex().Length; i++)
{
int p = Convert.ToInt32(b.BToHex().Substring(i, 1), 16);
if (p < 10)
{
ComputePVV = ComputePVV + p.ToString();
}
if (ComputePVV.Equals(TrackPVV))
{
Console.WriteLine("計算次數:{0},正確密碼值:{1}", j + 1, j);
Console.WriteLine("Track PVV:{0} PVV:{1}", TrackPVV, ComputePVV);
break;
}
else
//若計算出的PIN長度=4,但未通過驗證,跳出
if (ComputePVV.Length == 4)
{
break;
}
}
}
}
果然反算出密碼PIN 1234,運算時間也在1秒內。
(在.NET運算1萬筆只要0.5秒就可以運算完畢!)
3.試試看其他密碼,假設用PIN密碼值5678,
這邊我們直接用BP-TOOL幫我們用相同PAN、PVKI+PVK資料算PVV
取出1830的PVV值
4.接著把反算程式中的輸入PVV值換成1830
//輸入的PVV值
string TrackPVV = "1830";
反算後,也算出我們輸入的5678,但卻發現有兩組PIN(5678或是5884)會算出相同的PVV!!!
相同PAN及PVKI可能會有幾組PIN會算出相同的PVV,有時候是1組,有的時候則可能2組以上。
這邊的2個案例,第一個案例PVV只有一個PIN符合,第二個案例卻有兩個PIN符合!!!
很遺憾的,會過!!
增列第二道關卡PIN Offset:
假設上面案例的Natural PIN是1111,目前PIN6666,則系統內保留的PIN Offset是5555。
驗證時,用持卡人輸入的PIN6666/7777去運算出PIN Offset,透過這道關卡,錯誤PIN7777就可以正確的驗證出錯誤。
至於是否要增加第二道關卡來效能來預防微小的風險機會,就看安全上的需求了。
小結:
- PVK加密金鑰的保護至關重要!!!。
- 2010年曾到中華電信研究所參與手機信用卡的SE(Secure Element)討論,討論到目前台灣支付產業的安全儲存機制時,發現在卡片製卡或是交易過程中的傳遞及儲存都有些不足,過去在主機封閉型的網路也許我們不用太清楚自己的弱點,但這幾年慢慢從主機系統轉換到開放的網路系統,除了倚靠內網及防火牆,保護機制需要更更被重視。
- 2004年第一版支付卡產業資料安全標準PCI DSS推出,源自五大信用卡組織(Visa、Mastercard、JCB、AE及Diner)安全計畫,對於密碼PIN的安全更有密碼交易安全(PTS)、硬體安全模組HSM及交互點終端(POI)有多項規範。
參考:
Discretionary data from magnetic strip credit card, how to parse?
ISO7811、ISO7813、ISO8583
ISO 11568: Banking – Key Management (Retail)