2016-12-09 14 views
2

我尝试从奥地利电子卡片上读取信息以获取名字和姓氏。如何将来自奥地利电子卡的ResponseAPDU解码为XML?

现在有效的是:访问该卡,发送APDU命令并获取字节数组的信息。

如何将接收到的字节数组转换为XML以提取所需的数据?

下面是代码:

import java.util.List; 

import javax.smartcardio.Card; 
import javax.smartcardio.CardChannel; 
import javax.smartcardio.CardException; 
import javax.smartcardio.CardTerminal; 
import javax.smartcardio.CommandAPDU; 
import javax.smartcardio.ResponseAPDU; 
import javax.smartcardio.TerminalFactory; 

public class Main2 { 
    public static void main(String[] args) { 
     TerminalFactory factory = TerminalFactory.getDefault(); 
     List<CardTerminal> terminals; 
     try { 
      terminals = factory.terminals().list(); 
      CardTerminal terminal = terminals.get(0); 
      Card card = terminal.connect("*"); 
      CardChannel channel = card.getBasicChannel(); 
      // Select the MF 
      byte[] aid = { (byte) 0xD0, 0x40, 0x00, 0x00, 0x17, 0x01, 0x01, 0x01 }; 
      ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x04, 0x00, aid)); 
      System.out.println("Response: " + resp.toString()); 
      // Select the Personaladata-file 
      byte[] aid2 = { (byte) 0xEF, 0x01 }; 
      resp = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x02, 0x04, aid2)); 
      System.out.println("Response: " + resp.toString()); 
      // Get the data from the file 
      resp = channel.transmit(new CommandAPDU(0x00, 0xB0, 0x00, 0x00, 0xFF)); 
      System.out.println("Response: " + resp.toString()); 
      System.out.println("Response String: " + new String(resp.getData())); 
      card.disconnect(false); 
     } catch (CardException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

回答

3

我不知道如何将这些数据转换为XML结构(以及按照什么模式)。但是,我从我的SV卡接收的字节数组看起来像一个ASN.1 DER编码TLV结构:

 
30 xxxx 
SEQUENCE 
    30 18 
    SEQUENCE 
     06 08 
     OBJECT IDENTIFIER 
      2A28000A01040101 
      => OID 1.2.40.0.10.1.4.1.1 (SV number) 
     31 0C 
     SET 
      12 0A 
      NumericString 
       nnnnnnnnddddmmmmyyyy 
       => SV number: NNNN DDMMYY 
    30 0F 
    SEQUENCE 
     06 08 
     OBJECT IDENTIFIER 
      2A28000A01040103 
      => OID 1.2.40.0.10.1.4.1.3 (Card sequence number) 
     31 03 
     SET 
      02 01 
      INTEGER 
       xx 
       => Card sequence number: xx 
    30 xx 
    SEQUENCE 
     [...] 
    30 xx 
     SEQUENCE 
     06 03 
     OBJECT IDENTIFIER 
      55042A 
      => OID 2.5.4.42 ({joint-iso-itu-t(2) ds(5) attributeType(4) givenName(42)}) 
     31 xx 
     SET 
      0C xx 
      UTF8String 
       4D69636861656C 
       => Given name: "Michael" 
    30 xx 
    SEQUENCE 
     06 03 
     OBJECT IDENTIFIER 
      550404 
      => OID 2.5.4.4 ({joint-iso-itu-t(2) ds(5) attributeType(4) surname(4)}) 
     31 xx 
     SET 
      0C xx 
      UTF8String 
       526F6C616E64 
       => Surname: "Roland" 
    30 xx 
    SEQUENCE 
     [...] 
    30 1D 
    SEQUENCE 
     06 08 
     OBJECT IDENTIFIER 
      2B06010505070901 
      => OID 1.3.6.1.5.5.7.9.1 ({iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) pda(9) dateOfBirth(1)}) 
     31 11 
     SET 
      18 0F 
      GeneralizedTime 
       yyyyyyyymmmmdddd3132303030305A 
       => Date of birth: YYYY-MM-DD 12:00:00Z 
    30 0F 
    SEQUENCE 
     06 08 
     OBJECT IDENTIFIER 
      2B06010505070903 
      => OID 1.3.6.1.5.5.7.9.3 ({iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) pda(9) gender(3)}) 
     31 03 
     SET 
      13 01 
      PrintableString 
       4D 
       => Gender: M (male) 

所以这似乎遵循类似下面的ASN.1表示法:

SVPersonGrunddaten ::= SEQUENCE OF Attribute 
Attribute ::= SEQUENCE { 
    attributeName OBJECT IDENTIFIER, 
    attributeValue SET OF AttributeType } 
AttributeType ::= CHOICE { 
    numericString NumericString, 
    integer INTEGER, 
    utf8String UTF8String, 
    time GeneralizedTime, 
    printableString PrintableString } 

凡给定的名字和姓氏的属性

givenName Attribute ::= { 
    attributeName 2.5.4.42, 
    attributeValue { utf8String "Given Name" } 
} 
surname Attribute ::= { 
    attributeName 2.5.4.4, 
    attributeValue { utf8String "Surname" } 
} 

因此,为了获得给定的名称和姓,你会解析TLV结构,寻找这两个元素的OID,并将相关值解码为UTF8字符串。

请注意,简单地假设字段在确切的位置,似乎不是一个好主意。例如,在给定名称字段之前有一个字段30 xx ...(类型为Attribute的字段),似乎只有在卡片上打印有学术/职业头衔(例如我的情况下为“Dr.”)时才存在。同样,学术后缀还有另一个可选字段(例如“M.Sc.”),只有在卡上印有这样的后缀时才存在。虽然所有其他字段在我的卡片上总是以相同的顺序排列,但我不确定这是否甚至是必需的。

1

谢谢你的提示,这里是代码为DER字节数组解码为字符串

ASN1InputStream input = new ASN1InputStream(resp.getData()); 
      ASN1Primitive p; 
      try { 
       while ((p = input.readObject()) != null) { 
        // System.out.println("DEBUG: " + ASN1Dump.dumpAsString(p)); 
        // Sozialversicherungsnummer 
        ASN1Sequence asn1 = ASN1Sequence.getInstance(p); 
        ASN1Sequence seq = DLSequence.getInstance(asn1.getObjectAt(0)); 
        ASN1Set svn = DLSet.getInstance(seq.getObjectAt(1)); 
        DERNumericString svnObject = DERNumericString.getInstance(svn.getObjectAt(0)); 
        System.out.println("SVN: " + svnObject.getString()); 

        // Vorname 
        seq = DLSequence.getInstance(asn1.getObjectAt(2)); 
        svn = DLSet.getInstance(seq.getObjectAt(1)); 
        DERUTF8String stringObject = DERUTF8String.getInstance(svn.getObjectAt(0)); 
        System.out.println("Vorname: " + stringObject.getString()); 

        // Nachname 
        seq = DLSequence.getInstance(asn1.getObjectAt(3)); 
        svn = DLSet.getInstance(seq.getObjectAt(1)); 
        stringObject = DERUTF8String.getInstance(svn.getObjectAt(0)); 
        System.out.println("Vorname: " + stringObject.getString()); 

        // Geschlecht 
        seq = DLSequence.getInstance(asn1.getObjectAt(5)); 
        svn = DLSet.getInstance(seq.getObjectAt(1)); 
        DERPrintableString charObject = DERPrintableString.getInstance(svn.getObjectAt(0)); 
        System.out.println("Geschlecht: " + charObject.getString()); 
       } 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
+0

要知道,给定名称的索引,姓和性别领域可能会有所不同,所以'asn1.getObjectAt (2)''不会总是给你指定的名字等等。例如,这是一个前缀的学术名称或后缀学术学位的附加字段的情况。我只是检查了我以前的卡片,如果没有标题或后缀,这些字段根本不存在。 –