Girocard Maestro智能卡读卡器发出,读取持卡人姓名和IBAN
本文关键字:持卡人 IBAN 读取 智能卡 Maestro 读卡器 Girocard | 更新日期: 2023-09-27 18:27:22
按照这个读卡器项目中描述的例程,并使用这个AID列表,我能够读取VISA卡,而不会出现任何强制AID列表的问题。现在我有一个问题,虽然阅读EC Karten(Sparkasse Girocard)从德国。
-
当我试图使用强制读取AID列表时
foreach (byte[] aid in aidList) { byte[] atrValue = this.cardUpdater.GetAttribute(SCARD_ATTR_VALUE.ATR_STRING); string strATR = ByteArrayToString(atrValue); APDUCommand apduSelectEMVApl = null; APDUResponse apdu2 = null; apduSelectEMVApl = new APDUCommand(0x00, 0xA4, 0x04, 0x00, aid, 95); apdu2 = this.cardUpdater.Transmit(apduSelectEMVApl); if (apdu2.SW1 == 0x90) { //Label = ASCIIEncoding.ASCII.GetString(apdu2.Data, 15, apdu2.Data[14]); //found it! m_EMVAID = aid; if (apdu2.Data[0] == 0x6f) //fci template { ExtractData(ReadTagData(apdu2.Data, 0)); } return true; } } return false;
注:AID成功读取选择为A00000003591010028001
如果我没有将APDU命令的长度参数专门设置为95,而不是所有项目中的标准0(以获得最大长度),它将不会响应90-00(成功)。我只是通过一次迭代来发现这个值,看看哪个长度是可以接受的。为什么?
通过这个程序,我能够读取BIC和卡类型("girocard"),以及PDOL:等数据
9F33029F35019F4001
然后我试着根据这篇帖子提高安全级别。但在我的情况下,那些用于选择和读取的APDU命令不会抛出90-00(而是6700)。
-
我试图通过获取SFI记录
APDUCommand apduGPO = new APDUCommand(0x80, 0xa8, 0, 0, new byte[] { 0x83, 0 }, 0); APDUResponse apdu1 = this.cardUpdater.Transmit(apduGPO); if (apdu1.SW1 != 0x90) throw new Exception("Read GPO Data fail"); //two possible forms, 0x80 and 0x77 if (apdu1.Data[0] == 0x80) { for (int i = 4; i < apdu1.Data.Length; i += 4) { byte sfi = (byte)((apdu1.Data[i] >> 3) & 0xf); byte lowRange = apdu1.Data[i + 1]; byte hiRange = apdu1.Data[i + 2]; byte[] records = new byte[hiRange - lowRange + 1]; for (int j = lowRange; j <= hiRange; j++) records[j - lowRange] = (byte)j; sfiRecords.Add(new SFIRecords(sfi, records)); } } else if (apdu1.Data[0] == 0x77) { //look for the application file locator AFL int a, tag; for (a = 2; (tag = ReadTag(apdu1.Data, a)) != 0x94; a = SkipTag(apdu1.Data, a)) ; if (tag == 0x94) { //found it a++; int len = apdu1.Data[a++]; for (int i = a; i < a + len; i += 4) { byte sfi = (byte)((apdu1.Data[i] >> 3) & 0xf); byte lowRange = apdu1.Data[i + 1]; byte hiRange = apdu1.Data[i + 2]; byte[] records = new byte[hiRange - lowRange + 1]; for (int j = lowRange; j <= hiRange; j++) records[j - lowRange] = (byte)j; sfiRecords.Add(new SFIRecords(sfi, records)); } } } else throw new Exception("Unknown GPO template");
正如我从许多其他来源读到的,包括Openscdp的Initiate Application Process,但将PDOL作为发送
APDUCommand apduGPO = new APDUCommand(0x80, 0xa8, 0, 0, pdol, 0);
APDUResponse apdu1 = this.cardUpdater.Transmit(apduGPO);
或
APDUCommand apduGPO = new APDUCommand(0x80, 0xa8, 0, 0, new byte[]{0x83, 0x00}, 0);
APDUResponse apdu1 = this.cardUpdater.Transmit(apduGPO);
在apduGPORresponse上没有进行任何进一步的操作(再次出现错误6700,由于结果不成功而引发异常Fail Reading GPO),因此我无法将SFI记录添加到列表中以进一步迭代Data[0]并查找要读取的记录。没有90-00响应。
有没有想过我错过了什么?
更新
我运行这段代码是为了强制直接读取所有可能的值,而不使用GPO:
APDUCommand apduReadAll = null;
APDUResponse apdu1 = null;
for (var sfi = 1; sfi <= 31; sfi++)
{
for (var rec = 1; rec <= 16; rec++)
{
for (byte le = 0; le < 255; le++)
{
apduReadAll = new APDUCommand(0x00, 0xB2, (byte)rec, (byte)((sfi << 3) | 4), null, le);
apdu1 = this.cardUpdater.Transmit(apduReadAll);
if (apdu1.SW1 == 0x90)
{
Console.WriteLine("SFI " + sfi.ToString() + " record #" + rec);
if (apdu1.Data[0] == 0x70 || apdu1.Data[0] == 0x77)
{
Console.WriteLine("Chalk one here " + sfi.ToString() + " record #" + rec + " len " + le);
try
{
ExtractData(ReadTagData(apdu1.Data, 0));
}
catch
{
}
//if (!String.IsNullOrEmpty(NumberString) && !String.IsNullOrEmpty(Name) &&
// !String.IsNullOrEmpty(ExpiryString) && !String.IsNullOrEmpty(CardType) &&
// !String.IsNullOrEmpty(Label))
// return; //we have all info we need
}
}
}
}
}
foreach (TagData tag in Properties)
{
Console.WriteLine(tag.Name + " " + tag.DataString);
strAllData += tag.Name + " " + tag.DataString + "'r'n";
}
在结果中,我发现了一些我需要的信息(现在我可以直接指向加快过程所需的数据),以及一些其他有趣的信息:
Application Label girocard
Application Priority Indicator 02
Application Identifier (AID) - card A0 00 00 00 59 45 43 01 00
Application Label girocard
Application Priority Indicator 04
Application Identifier (AID) - card A0 00 00 03 59 10 10 02 80 01
Application Label girocard
Application Priority Indicator 04
Application Identifier (AID) - card A0 00 00 00 04 30 60
Application Label Maestro
Application Priority Indicator 07
Application Identifier (AID) - card D2 76 00 00 25 45 50 02 00
Application Label GeldKarte
Application Identifier (AID) - card A0 00 00 04 86 01 01
Application Label girocard
Application Priority Indicator 05
我将对从卡中返回的上述AID值运行相同的程序,以比较结果,并查看会发生什么以更好地理解。谢谢你给我指明了正确的方向。
为什么我需要将Le设置为95而不是0(以获得最大长度)
原因是该项目中Transmit()
的实现存在缺陷。当您传递Le设置为0的APDUCommand对象时,它将错误地将这种情况视为Le不存在,因此不会发送Le字段。请参阅第446行的CardNative.cs。因此,
...Transmit(new APDUCommand(0x00, 0xA4, 0x04, 0x00, new byte[] { 1, 2, 3, 4, 5 }, 0));
导致以下APDU被发送到卡:
00 A4 0400 05 0102030405
然而,您实际想要的是以下APDU(它有一个Le字段):
00 A4 0400 05 0102030405 00
这可以通过区分两种情况来解决:Le不存在(指示没有预期的响应数据,Ne=0)和Le为0(指示预期多达256字节的响应数据(Ne=256))。
接下来是什么命令
0x6700
),这似乎与第一个问题中的问题有关。
由于您引用的AID列表表明Girocard应用程序符合某种形式的EMV,并且您收到的PDOL值为9F33029F35019F4001
,因此您可以尝试发出GET PROCESSING OPTIONS命令(类似于您当前尝试的操作)。由于卡提供了PDOL,您需要在GPO命令中用期望值填充与PDOL相关的数据对象。
PDOL列出了以下元素:
- 9F33(2字节)
- 9F35(1字节)
- 9F40(1字节)
因此,您可以尝试创建一个与PDOL相关的数据对象,用零填充所有这些元素:
0000 00 00
请注意,您的卡可能需要一些特定的值。由于PDOL中的数据对象与其在EMV中的定义不匹配(9F33(终端能力)的长度预计为3,9F40(附加终端能力)长度预计为5),我无法说出它们的实际含义/编码。
GPO命令可能看起来像:
APDUCommand apduGPO = new APDUCommand(0x80, 0xa8, 0, 0, new byte[] { 0x83, 4, 0, 0, 0, 0 }, 0);
同样,只有解决了Le字段的问题,这才有效。