Laden...

Zugriff auf KVK & eGK via CTAPI

Erstellt von erazor vor 11 Jahren Letzter Beitrag vor 9 Jahren 35.747 Views
E
erazor Themenstarter:in
19 Beiträge seit 2010
vor 11 Jahren
Zugriff auf KVK & eGK via CTAPI

Hi,

ich versuche gerade eine Anwendung zu schreiben, die eine eGK Karte über eine Cherry G87-1504 Tastatur ausliest.

Soweit bin ich schon:


[DllImport("ctcym.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern sbyte CT_data(int ausCtn, ref int apucDad, ref int apucSad,
int ausLenc, byte[] apucCommand, ref int apucLenr, byte[] response);

[DllImport("ctcym.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern sbyte CT_close(int ausCtn);

[DllImport("ctcym.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern sbyte CT_init(int ausCtn, int ausPn);



byte[] command = { 0x20, 0x11, 0x00, 0x00 };
byte[] response = new byte[1000];
int DAD = 1;
int SAD = 2;
int respLen = 1000;

// intitialisieren
sbyte cmdreturn = CT_init(1, 1);

//Reset CT 
cmdreturn = CT_data(1, ref DAD, ref SAD, command.Length, command, ref respLen, response);

// Verbindung schließen
cmdreturn = CT_close(1);


Soweit mir bekannt, soll ich nun als Rückgabewert 09 00 erhalten. Bekomme aber ständig 144 als Rückgabewert.

Was mache ich falsch?

Grüße

2.891 Beiträge seit 2004
vor 11 Jahren

Soweit mir bekannt, soll ich nun als Rückgabewert 09 00 erhalten. Bekomme aber ständig 144 als Rückgabewert.

Du musst beachten, was die Rückgabe "09 00" eigentlich darstellt: Nämlich die letzten zwei Bytes in Hexadezimal-Darstellung.
Deine 144 passt da nicht in dieses Darstellungssystem. Daher: Was genau ist bei dir 144? Und bei welchem Befehl?

Ansonsten: Ich habe das ganze mal für ein Cherry MTK+ ST-2052 gemacht. Das Gerät mag es scheinbar nicht, wenn man nicht immer CT_close aufruft (z.B. weil man beim Debuggen zwischendrin einfach mal auf Stopp klickt). Danach hat es bei RequestICC immer eine 9001 zurück gegeben (ansonsten ist nirgendwo ein Fehlercode zu erkennen). Da half dann immer nur ziehen des USB-Kabels und wieder verbinden.

Soweit bin ich schon

Da hast du aber noch einiges vor dir...
Wenn man weiß, was man wie machen muss, ist es eigentlich nicht so schwer. Allerdings muss man erstmal an die Infos dazu kommen - da braucht man immer die richtigen Dokumente zum richtigen Thema zu.

EDIT: Im Dokumentationsbereich der KVK- & eGK-API gibt es nun die zugehörigen Spezifikationen zusammen mit entsprechendem C#-Code.

E
erazor Themenstarter:in
19 Beiträge seit 2010
vor 11 Jahren

Schon mal vielen Dank für die Antwort.

Also die 144 bekomme ich im array response zurück übermittelt, nämlich beim Befehl:

cmdreturn = CT_data(1, ref DAD, ref SAD, command.Length, command, ref respLen, response);

Konvertiert in einen String ist das ein Fragezeichen. Vermutlich wird also mein command nicht korrekt abgearbeitet.

2.891 Beiträge seit 2004
vor 11 Jahren

Du bekommst also ein Array mit nur einem einzelnen Element zurück?
Und die ganzen cmdreturn-Werte sind in Ordnung (also immer 0)?

Konvertiert in einen String ist das ein Fragezeichen. Vermutlich wird also mein command nicht korrekt abgearbeitet.

Du kannst die (Roh-)Antwort so gut wie nie in einen String konvertieren. Die letzten beiden(!) Bytes sind immer die Statusbytes (die du wie gesagt in Hex umwandeln musst), der Rest ist bei der eGK erstens gezippt und zweitens mit Metainformationen codiert.

E
erazor Themenstarter:in
19 Beiträge seit 2010
vor 11 Jahren

Ja, das cmdreturn ist zu jedem Zeitpunkt immer 0. auch auf dem Display der Tastatur sehe, dass die CTAPI akiv ist.
So sieht es im Array aus:

2.891 Beiträge seit 2004
vor 11 Jahren

Erstens: Du musst deine response noch entsprechend der zurückgegebenen Länge kürzen.


byte[] result = new byte[respLen];
Array.Copy(response,result,respLen);
return result;

Zweitens: Der Status wird durch die letzten beiden Bytes im result dargestellt. In deinem Fall also (144,0)10. Und wie gesagt musst du dir die Werte in der Hexadezimal-Darstellung angucken. Macht (90,00)16 - also genau das, was zurückgegeben werden muss. (ResetCT muss 9000 oder 9500 zurückgeben, nicht 0900.

Hier noch eine Erweiterungsmethode zum einfachen Bestimmen des Statuscodes (Aufruf wäre z.B. string statusCode = result.GetStatusBytes()):


public static class Extensions
{
	public static string ToHexString(this byte value)
	{
		return Convert.ToString(value,16).PadLeft(2,'0');
	}

	public static string GetStatusBytes(this byte[] bytes)
	{
		if (bytes==null || bytes.Length<2)
			return null;
		else
			return bytes[bytes.Length-2].ToHexString()+bytes[bytes.Length-1].ToHexString();
	}
}

E
erazor Themenstarter:in
19 Beiträge seit 2010
vor 11 Jahren

Zweitens: Der Status wird durch die letzten beiden Bytes im result dargestellt. In deinem Fall also (144,0)10. Und wie gesagt musst du dir die Werte in der Hexadezimal-Darstellung angucken. Macht (90,00)16 - also genau das, was zurückgegeben werden muss. :::

Tausend Dank!
Das war dann ein Denkfehler von mir! Bin nun ein ganzes Stück weiter gekommen! 😃

V
16 Beiträge seit 2012
vor 11 Jahren

Ich habe auch eine frage dazu:

Was steht denn in dem response drin ?
Die Position, an dem die Daten in der Karte stehen oder ist das schon z.B. der krankenkassenname ?

2.891 Beiträge seit 2004
vor 11 Jahren

Was steht denn in dem response drin? Die Position, an dem die Daten in der Karte stehen oder ist das schon z.B. der krankenkassenname?

Man bekommt die kompletten Daten. Also bei der KVK liefert ReadKVK alle auf der Karte vorhandenen Daten; bei der eGK liefert ReadPD die persönlichen Versichertendaten und ReadVD die allgemeinen Versicherungsdaten und die geschützten Versichertendaten.

Allerdings kann man das Result-Array nicht einfach so in einen String umwandeln:

Bei der KVK ist das Result eine Aneinanderreihung von 1 Byte Tag (z.B 8016 für "KrankenkassenName"), 1-3 Bytes Länge des Elements und Wert des Elements (DIN_66003-codiert).

Bei der eGK:
PD enthält 2 Bytes Längenabgabe für den Inhalt, dann ein ZIP-Komprimiertes XML-Dokument (ISO-8859-15 codiert).
VD enthält jeweils 2 Bytes Offset für Start & Ende der VD, sowie je 2 Bytes Offset für Start & Ende der GVD. (Die GVD lassen sich in den Musterkarten noch Auslesen, bei den "echten" eGKarten kommt man aber nicht ran.

Zu beachten sind jeweils noch die zusätzlichen beiden Status-Bytes am Ende des Results.

2.891 Beiträge seit 2004
vor 11 Jahren

Woran erkenne ich eine eGK und eine KVK worin liegen die Unterschiede?

Das Vorgehen KVK vs. eGK mit der CTAPI ist folgendermaßen:


using (var cardTerminalClient = new CardTerminalClient(...))
{
	cardTerminalClient.ResetCT();
				
	string result = cardTerminalClient.RequestICC();
	if (result=="9000")
	{
		cardTerminalClient.SelectKVK();
		KvkResult kvkResult = cardTerminalClient.ReadKVK();
	}
	else
	{
		cardTerminalClient.SelectEGK();
		EgkResult egkResult = cardTerminalClient.ReadEGK();
	}

	cardTerminalClient.EjectICC();
}

Grundlegende Unterschiede gibt es in der Codierung der Daten der Karten (siehe auch mein vorheriger Beitrag).
Die Daten auf der KVK und der eGK sind so ziemlich die gleichen, wobei sie auf der eGK potentiell noch etwas detaillierter dargestellt sind. Und auf die eGK kann man auch schreiben - wobei das aber noch ein ganz anderes Thema ist.

V
16 Beiträge seit 2012
vor 11 Jahren

Ahh ok, vielen Dank für die Info !

Ist der Ablauf richtig:

  1. RESET ICC 0x20, 0x11, 0x00, 0x00, 0x00
  2. REQUEST ICC 0x20, 0x12, 0x01, 0x00, 0x00
  3. GET STATUS 0x20, 0x13, 0x00, 0x46, 0x00
  4. SELECT FILE 0x00, 0xA4, 0x04, 0x00, 0x06, 0xD2, 0x76, 0x00, 0x00, 0x01, 0x01
  5. READ BINARY 0x00, 0xB0, 0x00, 0x00, 0x00
  6. EJECT ICC 0x20, 0x15, 0x01, 0x00

Hierbei handelt es sich um eine KVK !

2.891 Beiträge seit 2004
vor 11 Jahren

Ist der Ablauf richtig?

Ja, sollte so stimmen. (Als Ergänzung noch: Destination ist bei 1,2,3,6 das Terminal (1) und bei 4,5 die Karte (0).

V
16 Beiträge seit 2012
vor 11 Jahren

Dann verstehe ich nicht, warum ich nach Get Status im response 18 Daten bekomme, diese aber nicht richtig auslesen kann, weil ich nicht weiß wie ich diese umkonventieren muss oder sonstiges...

Vielen Dank für die Hilfe !

Hat sich schon erledigt, dank deiner ergänzung mit der Destination Adress, bekomme ich nun alle Daten !

Vielen Dank 😃

Jetzt muss ich nur noch die Länge der einzelnen Daten herausfinden, dann kann ich die Daten z.B. in einer Datenbank speichern.

Technische Spezifikation der Arztausstattung - Lesegeräte - (PDF)

Dort stehen die Längen der einzelnen Tags.

2.891 Beiträge seit 2004
vor 11 Jahren

Jetzt muss ich nur noch die Länge der einzelnen Daten herausfinden, dann kann ich die Daten z.B. in einer Datenbank speichern.

Welche Längen meinst du? Die maximal möglichen Längen oder die tatsächlichen Längen in den Nutzdaten?

V
16 Beiträge seit 2012
vor 11 Jahren

Die tatsächlichen Längen in den Nutzdaten.

Nur wie finde ich diese heraus ?
In dem response stehen ja nur die Bytes oder ?

2.891 Beiträge seit 2004
vor 11 Jahren
Krankenversicherungskarte (KVK)

In dem response stehen ja nur die Bytes oder?

Ja. Und diese Bytes enthalten sowohl Metadaten (Tag, Länge) als auch die eigentlichen Nutzdaten.
Den konkreten Quellcode findest du unter KVK- & eGK-API (via CTAPI) - Source Code - KvkResult.cs.
Das Konzept ist folgendes (Dokumentation siehe Multifunktionale Kartenterminals - MKT):

Falls das erste Byte 8216, 9216 oder A216 ist, kommt als erstes ATR und Directory (Anhang 3 MKT-Anforderungen für Versichertenkarten, 1.6.2 Bit- und Hexadezimal-Struktur des ATR und Directory).
Die (also die ersten 30 Bytes) können dann ignoriert/übersprungen werden.

Dann kommen die eigentlichen Daten:

Zitat von: MKT-Teil 5: SYN – ATR und Datenbereiche 4 Codierungstechnik 4.1.
Als Codierungstechnik für Datenobjekte werden die "Basic Encoding Rules (BER)" der ISO-Codierungskonvention "Abstract Syntax Notation One (ASN.1)" verwendet. Ein Datenobjekt besteht danach aus:
einem Datenobjekt-Kennzeichen ("Tag")

einem Längenangabe ("Length") und

einem Datenobjekt-Wert ("Value").

Die Länge ist recht tricky in 1-3 Bytes codiert (hat mich einiges an Zeit gekostet, das rauszubekommen):

Zitat von: MKT-Teil 5: SYN – ATR und Datenbereiche 4 Codierungstechnik 4.1.

Length 0 .. 127:
one byte coding the length

Length 128 .. 255:
1st byte: bit b8 = 1, b7-b1= 0000001 (number of subsequent length bytes); 2nd byte: Length

Length 256 .. 65535:
1st byte: bit b8 = 1,b7-b1= 0000010; 2nd + 3rd byte: Length

Man muss also das Byte-Array durchgehen, sich den Tag merken, dann die Länge ermitteln, und entsprechend der Länge dann die nächsten n Bytes auslesen. Dann kann man diese in einen String konvertieren (DIN_66003-codiert). Danach kommt dann das nächte Tag, Länge, usw. - bis man am Ende angekommen ist.

Die Auflistung der Tags mit Bedeutungen und Min-/Max-Längen findet man in Anhang 3 MKT-Anforderungen für Versichertenkarten, 1.6.3 Datenstruktur des Application-file und Prüfvorgaben

2.891 Beiträge seit 2004
vor 11 Jahren
elektronische Gesundheitskarte (eGK)

Der Vollständigkeit halber noch das Prinzip für die eGK:
Doku gibt's unter Implementierungsleitfaden zur Einbindung der eGK in die Primärsysteme der Leistungserbringer.
Unter 4.2.3 "Datei EF.PD" und 4.2.4 "Datei EF.VD" steht, wie jeweils das Byte-Array aufgebaut ist.

Zitat von: Implementierungsleitfaden
Die [Daten] selbst werden als XML-Daten gemäß vorgegebenem XML-Schema, gzip-komprimiert und nicht verschlüsselt innerhalb der Datei abgelegt. Der zu verwendende Zeichensatz für die fachlichen Inhalte ist ISO8859-15

Die Schemadateien kann man z.B. unter Release 0.5.3 Basis-Rollout herunterladen (ganz unten "Für Hersteller bietet die gematik zudem Schnittstellendefinitionen im XSD- und WSDL-Format an").
Aus den xsd-Dateien kann man mit dem XML Schema Definition-Tool (Xsd.exe) entsprechende Klassen generieren lassen.
Das entsprechende Byte-Array mit den Nutzdaten (Achtung: GZip-Komprimiert) kann man dann leicht mit der XmlSerializer-Klasse deserialisieren.

Den C#-Quellcode dazu gibt es unter KVK- & eGK-API (via CTAPI) - Source Code - EgkResult.cs

V
16 Beiträge seit 2012
vor 11 Jahren

Werde mich da mal durchwursteln, in der Hoffnung es zu schaffen !

Danke für die Infos ! 😃

Information von Abt vor 11 Jahren

Beachte [Hinweis] Wie poste ich richtig? 2.3

V
16 Beiträge seit 2012
vor 11 Jahren

Das mit der KVK ist mir gelungen, nur meine Frage geht jetzt an die eGK.

Woher weiß ich ob ich den Root(MF) oder die HCA selektieren muss ?
Welche Read Binarys folgen dann darauf ?

vivilakaphil

2.891 Beiträge seit 2004
vor 11 Jahren

Wie du erkennst, ob es eine KVK oder eine eGK ist, steht ja oben (Rückgabe von RequestICC).

Zum Lesen der eGK werden bei uns folgende Befehle ausgeführt:1.ResetCT 1.RequestICC 1.Select EGK 1.Read PD 1.Read VD 1.EjectICC

Eine recht ausführliche Doku zu den eGK-Kommandos hatte ich in Integrationsanleitung medMobile (via medline - medMobile - Kartenlesegeräte für die Gesundheitskarte (eGK)) gefunden.

V
16 Beiträge seit 2012
vor 11 Jahren

Genauso habe ich es auch aufgebaut.

So sieht mein Select aus:
Select: 0x00, 0xA4, 0x04, 0x0C, 0x06, 0xD2, 0x76, 0x00, 0x00, 0x01, 0x02

Die Read Binarys haben jeweils im P1 81 oder 82...

Dies ist doch richtig oder täusche ich mich da ?

Weil in meinem response speichert er genau 256 Bytes ab.

Und gibt es für das dekomprimieren der Daten ein Script, weil bei meinem kommt immer "Die Magic Number im Header ist nicht richtig. Stellen Sie sicher, dass Sie einen GZip-Stream übergeben".

2.891 Beiträge seit 2004
vor 11 Jahren

So sieht mein Select aus. Die Read Binarys haben jeweils im P1 81 oder 82.

Ich habe hier das gleiche Select. Wie sehen deine Reads komplett aus?
Hast du die Destination (beide Karte) beachtet?
Was gibt es jeweils als Status-Code zurück?

Und gibt es für das dekomprimieren der Daten ein Script, weil bei meinem kommt immer "Die Magic Number im Header ist nicht richtig. Stellen Sie sicher, dass Sie einen GZip-Stream übergeben".

Hast du beachtet, dass du das Response-Array nicht sofort entzippen kannst? Da stehen noch Metadaten drin und du musst erst noch den eigentlichen Datenbereich rauskopieren.
Zeig doch mal her, was du bisher an Code hast, dann kann ich dir Tipps dazu geben.

V
16 Beiträge seit 2012
vor 11 Jahren

CLA INS P1 P2 Le adressierter Container
00 B0 81 00 00 00 00 PD Patientendaten
00 B0 82 00 00 00 00 VD Versicherungsdaten

So sehen meine beiden Read Binarys aus.

Bei der KVK und bei der eGK sind beide Destinations von Select und Read Binary auf 0.

der Status-Code gibt jeweils 9000 bzw. 9001 zurück.

Wie erkennt man denn den eigentlichen Datenbereich ?
Gibt es dafür Tags ?
Den Code möchte ich nicht gerne Preis geben.

2.891 Beiträge seit 2004
vor 11 Jahren

Wie erkennt man denn den eigentlichen Datenbereich?

Hab ich doch schon geschrieben. Musst du nur aufmerksam lesen 😉
In der Doku steht unter 4.2.3 "Datei EF.PD" und 4.2.4 "Datei EF.VD", wie jeweils das Byte-Array aufgebaut ist.
Bei den PD stehen vorn dran zwei Bytes mit der eigentlichen Länge; bei den VD acht Bytes mit vier Offset-Angaben.

V
16 Beiträge seit 2012
vor 11 Jahren

Ahh, vielen Dank !

Werde dann mal versuchen den eigentlichen Datenbereich herauszubekommen.

V
16 Beiträge seit 2012
vor 11 Jahren

Hallo,

bekomme mittlerweile ein XML-Schema heraus.

Nur der Inhalt wird abgeschnitten, ich denke das liegt daran, weil ich in meinem response nur 256 Bytes stehen habe, es aber mehr sein müssen.

Wie kann ich in dem Read Binary nun angeben, dass mehr als 256 Bytes beschrieben werden sollen ?

Also eine Datei kann ja bis zu 850 Bytes groß sein.

Hier mal meine momentane Ausgabe:

<?xml version="1.0" encoding="ISO-8859-15" standalone="yes"?><vsdp:UC_PersoenlicheVersichertendatenXML CDM_VERSION="5.1.0" xmlns:vsdp="http://ws.gematik.de/fa/vsds/UC_PersoenlicheVersi
2.891 Beiträge seit 2004
vor 11 Jahren

Guck dir mal deinen Aufruf von CT_data(ctn,ref dad,ref sad,lenc,ref command,ref ulenr,ref response) an. Du erstellst das Response-Array ja irgendwo selbst und gibst der Methode nur eine Referenz darauf mit. Einfach ein größeres Bytearray anlegen.

Ansonsten einfach nochmal den Abschnitt "5.4.2 Read Binary" in der Doku genau lesen.

V
16 Beiträge seit 2012
vor 11 Jahren
<?xml version="1.0" encoding="ISO-8859-15" standalone="yes"?><vsdp:UC_PersoenlicheVersichertendatenXML CDM_VERSION="5.1.0" xmlns:vsdp="http://ws.gematik.de/fa/vsds/UC_PersoenlicheVersichertendatenXML/v5.1"><vsdp:Versicherter>
<vsdp:Versicherten_ID>#####</vsdp:Versicherten_ID><vsdp:Person><vsdp:Geburtsdatum>#####</vsdp:Geburtsdatum><vsdp:Vorname>#####</vsdp:Vorname><vsdp:Nachname>#####</vsdp:Nachname>burtsdat>
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeee

Mein Ergebnis 😕
Ich glaube das es daran liegt, dass ich den Datenbereich falsch auswähle.

Kann ich dir meinen Code per privat Nachricht zusenden ?

2.891 Beiträge seit 2004
vor 11 Jahren

Reaktion auf den gesendeten Quellcode.

Was mir als erstes auffällt: Du deklarierst für die Antwort ein Array mit der Länge 300. Wie ich schon geschrieben habe, musst du das Response-Array länger machen. Die CTAPI bekommt das Array als Referenz und schreibt da direkt rein. Wenn du das nicht größer machst, kann dir der Kartenleser auch nicht mehr Daten zurückgeben.
Alternativ kannst du beim Statuscode 6200 gucken, welche Länge du tatsächlich brauchst, und musst dann entsprechend den CT_DATA-Aufruf nochmal (mit einem entsprechend großem Response-Array) durchführen.

Zweitens: Die Berechnung der Länge der tatsächlichen PD sieht sehr sehr obskur aus. Bei PD steht in den ersten beiden Bytes die Länge. Danach folgen dann die Nutzdaten.
Du solltest dir da dringend noch einmal die Doku genau durchlesen, wie die Länge codiert ist. Tipp: Binäres Zahlensystem beachten.

Drittens: Um aus den (entzippten) Byte-Array Text zu machen, kannst du nicht einfach alle Bytes durchlaufen und die in Chars konvertieren. Benutze dafür einen StreamReader mit entsprechendem Encoding.

V
16 Beiträge seit 2012
vor 11 Jahren

Was mir als erstes auffällt: Du deklarierst für die Antwort ein Array mit der Länge 300. Wie ich schon geschrieben habe, musst du das Response-Array länger machen. Die CTAPI bekommt das Array als Referenz und schreibt da direkt rein. Wenn du das nicht größer machst, kann dir der Kartenleser auch nicht mehr Daten zurückgeben.
Alternativ kannst du beim Statuscode 6200 gucken, welche Länge du tatsächlich brauchst, und musst dann entsprechend den CT_DATA-Aufruf nochmal (mit einem entsprechend großem Response-Array) durchführen.

Daran wird es nicht liegen, weil wenn ich mein array mit der größe 1000 deklariere, werden auch nur 256 Bytes beschrieben.

Zweitens: Die Berechnung der Länge der tatsächlichen PD sieht sehr sehr obskur aus. Bei PD steht in den ersten beiden Bytes die Länge. Danach folgen dann die Nutzdaten.
Du solltest dir da dringend noch einmal die Doku genau durchlesen, wie die Länge codiert ist. Tipp: Binäres Zahlensystem beachten.

Die ersten beiden Bytes also in dem response: response(0) + response(1).
Das wäre dann response.length - (response(0) + response(1)). Um die Länge der Daten herauszubekommen, nur das Problem ist, das response ja eine Größe von 1000 Bytes hat, aber nur 256 beschrieben werden. Das heißt ich würde in diesem Fall i.was mit 800 als Länge herausbekommen, aber ab response(257) stehen überall nur noch 0len.

Drittens: Um aus den (entzippten) Byte-Array Text zu machen, kannst du nicht einfach alle Bytes durchlaufen und die in Chars konvertieren. Benutze dafür einen StreamReader mit entsprechendem Encoding.

Die konventiere ich in Bytes nachdem ich die Daten komprimiert und Dekomprimiert habe. Danach werden die Bytes in Chars umkonventiert.

2.891 Beiträge seit 2004
vor 11 Jahren

[W]enn ich mein array mit der größe 1000 deklariere[...]

Mit Int32.MaxValue sollte es beim Response-Array keine Probleme geben.

Read Binary liest die gewünschte Anzahl von Bytes aus einer zuvor selektierten Datei. Die Anzahl der Datenbytes, die von diesem Kommando zurückgeliefert werden soll, wird in dem Parameter Ne angegeben und muss aus dem Intervall [1,65535] oder WildcardShort ['00'] bzw. WildcardExtended ['0000'] stammen.** Bei der Verwendung von WildCard-Werten werden maximal 256 bzw. 65536 Bytes zurückgeliefert, sofern das Ende der Daten noch nicht erreicht ist.**

Zudem ist mir aufgefallen, dass du als viertes Byte im Command eine 1 übergibst. Oben hast du dafür eine 0 angegeben.

Die ersten beiden Bytes also in dem response: response(0) + response(1).

Nein! Eben nicht! Deswegen der Tipp mit dem binären Zahlensystem. Noch ein Tipp: int length = (bytes[0]<<8) + bytes[1];

Danach werden die Bytes in Chars umkonventiert.

Das sollst du eben nicht machen. Du musst den GzipStream noch in einen StreamReader mit entsprechendem ISO-8859-15-Encoding geben.

EDIT: Ablauf:1.Ein ausreichend großes Response-Array erstellen (mach ruhig erstmal mit der Länge 65536). 1.Mittels CT_Data das Response-Array füllen lassen. 1.Das Response-Array entsprechend der von CT_Data zurückgegebenen Länge kürzen (also umkopieren). 1.Die beiden Statusbytes am Ende prüfen (sollte 9000 sein). 1.Die ersten beiden Bytes in ein Int16 umwandeln. Das ist die tatsächliche Länge der PD. 1.Aus dem Response-Array den Bereich von 2 mit der PD-Länge rauskopieren.* 1.Dieses Array GZIP-Dekomprimieren. 1.Das Ergebnis ISO-8859-15-Dekodieren.

*Achtung: Mit der Länge x, nicht bis zur Position x!

Hinweis von herbivore vor 11 Jahren

Damit ist wohl alles wesentliche gesagt. Da sich der Thread gegen Ende im Kreis gedreht hatte und die letzten Beiträge nur wiederholt haben, was schon weiter oben steht und zudem unter [Hinweis] Wie poste ich richtig? Punkt 1.1.1 fielen, wurden sie entfernt, um den Thread nicht zu verwässern.

2.891 Beiträge seit 2004
vor 11 Jahren

Noch eine kleine Ergänzung zu eGKs:*In der Spezifikation für Multifunktionale Kartenterminals (MKT) sind in Teil 4 (CT-BCS - Anwendungsunabhängiger CardTerminal Basic Command Set) die Kommandos und möglichen Rückgabe-Codes erklärt. *eGK-Musterkarten können kostenfrei unter gematik (Bestellung Musterkarten) beantragt werden.

M
4 Beiträge seit 2013
vor 11 Jahren

Hallo

Auch ich habe mit der Erstellung einer Application zum auslesen der KVK & eGK meine Probleme.

Meine Hardware: der SCR3310 von Chipdrive (SCM Microsystems), sowie ein SDI011 ebenfalls von Chipdrive.

Ich arbeite im Moment mit der ctpcsc32kv.dll welche mir den Zugriff auf den SCR3310 ermöglicht.

Aktuell scheitere ich beim auslesen der Daten der KVK, die eGK wurde beantragt, habe aber noch kein Textexemplar bekommen.

Die Befehle die ich absetze sind wie beim Vorposter:
*ResetICC *RequestICC *GetStatus *SelectFile *ReadBinary *EjectICC

Und wenn ich diese Befehlsliste ausführe bekomme ich folgende Statusmeldungen:*ResetICC - 9000 *RequestICC - 9000 *GetStatus - 9000 *SelectFile - 64a2 *ReadBinary - 64a2 *EjectICC - 9000

Nun habe ich schon mit dN!3L per PN ein bisschen herumgedoktort da der Thread geschlossen war, und er sagte mir, dass der Status "Card not activated" bedeutet.

Zur vervollständigung hier die Statis ohne Karte:
*ResetICC - 9000 *RequestICC - 6200 (Dieser Request dauert ~10 Sekunden) *GetStatus - 9000 *SelectFile - 64a1 *ReadBinary - 64a1 *EjectICC - 9000

Ich kann bisher nur mit einem der beiden Lesegeräte arbeiten, da mir der Chipdrive Support noch nicht die benötigte CTAPI für den SDI011 zur Verfügung gestellt hat und somit kann ich einen Hardware defekt nicht ausschließen jedoch habe ich mehrere Karten welche ich Teste und habe bei beiden den gleichen output.

Zur verfollständigung: Es sind Tatsächliche Patientenkarten und keine Testkarten jedoch haben die Patienten schon die neuen eGK's bekommen, daher kann es durchaus möglich sein, dass die Karte tatsächlich nicht mehr aktiviert ist.

Gibt es nun noch Möglichkeiten diese Karte(n) auszulesen mit der CTAPI?

Oder muss ich mir andere KVK's besorgen? Woher?

Ich hoffe darauf dass man mir helfen kann 😃

mfg und vielen Dank an dN!3L
Markus

2.891 Beiträge seit 2004
vor 11 Jahren

Die Befehle die ich absetze sind wie beim Vorposter [...]

Die reinen Befehlsnamen sagen aber nicht allzu viel aus. Viel interessanter wären noch die Parameter (Bytecodes und Destination).

[...] dass der Status "Card not activated" bedeutet.

So müsste es sein - wenn du in die MTK-Spezifikation Teil 4 (CardTerminal Basic Command Set) guckst, findest du die Zuordnung.

Hast du mal eGKs ausprobiert? Es gibt sonst niemanden in deiner Umgebung, der (noch) eine KVK hat, die du mal probieren kannst?

Gruß,
dN!3L

M
4 Beiträge seit 2013
vor 11 Jahren

Ich habe gerade 1 Stunde mit dem Kundensupport des Hardware Herstellers telefoniert und wollte hier mal ein Update Posten.

Zuerst zu deiner Frage:


 case "ResetICC":
                    return new CTCommand() { DestinationAddress = 1, SourceAddress = 2, Command = new byte[] { 0x20, 0x11, 0x0, 0x0, 0x0 } };
                case "RequestICC":
                    return new CTCommand() { DestinationAddress = 1, SourceAddress = 2, Command = new byte[] { 0x20, 0x12, 0x1, 0x0, 0x1, 0x5 } };
                case "GetStatus":
                    return new CTCommand() { DestinationAddress = 1, SourceAddress = 2, Command = new byte[] { 0x20, 0x13, 0x0, 0x46, 0x0 } };
                case "SelectFile":
                    return new CTCommand() { DestinationAddress = 0, SourceAddress = 2, Command = new byte[] { 0x0, 0xA4, 0x4, 0x0, 0x6, 0xD2, 0x76, 0x0, 0x0, 0x1, 0x1 } };
                case "ReadBinary":
                    return new CTCommand() { DestinationAddress = 0, SourceAddress = 2, Command = new byte[] { 0x0, 0xB0, 0x0, 0x0, 0x0 } };
                case "EjectICC":
                    return new CTCommand() { DestinationAddress = 1, SourceAddress = 2, Command = new byte[] { 0x20, 0x15, 0x1, 0x0 } };

Bei den befehlen habe ich auch ein File vom Hersteller bekommen welches im Anhang ist und die KVK Befehle für die CTAPI darstellen soll.

Als Österreicher war es recht mühsam überhaupt an eine Deutsche KVK zu kommen und die eGK werde ich testen sobald ich die Karte habe.

Die Meldung vom Hersteller war, dass der Fehler eig. nicht kommen darf, da dieser Fehler von der Version der API garnicht abgesendet wird.

Darauf hin haben wir ein Testprogramm (TestCT32) mit der selben DLL und den Befehlen im angehängten req. File hergenommen und so konnte ich die Daten auslesen.

Nach 2maliger controlle der Bytes hat der Kundensupportler aufgegeben (er war über Team Viewer verbunden) und hat mich gebeten auf die DLL für die andere Hardware zu warten.

Nun weiß ich nicht was ich weiter versuchen soll, da die TestCT32.exe scheinbar problemlos an die Daten kommt mein Programm aber nicht 😦

Hier einmal die einbindung der Befehle:

 const string Library = "C:\\Windows\\System32\\CTPCSC31kv.dll";
        [DllImport(Library, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern sbyte CT_data(ushort CardTerminalNumber, ref byte DestinationAddress, ref byte SourceAddress, ushort CommandLenght, byte[] Command, ref ushort ResponseLenght, IntPtr Response);

        [DllImport(Library, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern sbyte CT_close(ushort CardTerminalNumber);

        [DllImport(Library, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern sbyte CT_init(ushort CardTerminalNumber, ushort COMPort);

Ich habe auch mehrmals Kontrolliert ob an irgendeiner Stelle im Code das Command Byte Array nochmals verändert wird aber ich lasse das 1:1 so wie in der obigen definition des CTCommands.

Hoffentlich kann irgendjemand Licht auf diese Sache werfen.

mfg

M
4 Beiträge seit 2013
vor 11 Jahren

Nach einiger Zeit Abstand zum Problem habe ich mir gestern nochmals den Code angesehen und den Fehler gefunden.

Ich hatte eine Funktion genutzt welche ich im Internet gefunden hatte (ExecCommand) und in jener Funktion wurde vor jedem CT_DATA, ein CT_INIT und danach ein CT_CLOSE durchgeführt.

Dadurch war die Karte beim lesen ja nicht aktiv weshalb der Fehler 100% korrekt war und von mir nur falsch gedeutet wurde.

Ich erhalte nun die Daten richtig Codiert im byte array und kann nun damit arbeiten.

Vielen dank für die Hilfe.

p.s.: Ich habe auch schon eine JNI geschrieben die es mir ermöglicht das ganze in einem Java Applet durchzuführen wodurch ich das auslesen im Browser ohne ActiveX unterstützen kann. Gehört zwar nicht hier her wollte ich aber gesagt haben, falls jemand damit kämpft und hilfe benötigt 😃

mfg
Markus

M
4 Beiträge seit 2013
vor 11 Jahren

Habe heute die eGKs bekommen und das auslesen versucht

Leider bekomme ich nur die Daten des Versicherten (schon entpackt und das ganze XML)

Also:
00 B0 P1 00 00 00 00
ist der Basisbefehl

P1 = 8C ... Ich erhalte Daten (status 9000) kann diese aber (noch) nicht entzippen, Sollte der VersichertenStatus sein
P1 = 81 ... Ich erhalte die Daten (Status 9000) kann diese auch entzipen und sehe darin die Daten des Versicherten
P1 = 82 ... Ich erhalte den Fehler 64A8 und keine Daten, Ich habe anfangs vermutet es liegt an der Fehlenden authentifizierung aber in der Doku ist dieser Fehler nicht angeführt nur 0x6A82 und 0x6983 für fehlende auth.

Brauche ich die Daten mit P1 = 82? Oder stehen im Falle verschiedener Personen als Patient/Versicherter beide in dem ersten XML File?

Ich probier die anderen Karten dann weiß ich das genauer trotzdem finde ich den Fehler komisch und weiß nicht wie ich den Status entzippe ... 😃

kleiner Antoß? Ich such auch im Internet brav aber is ziemlich schwer so ein komplexes Thema nur zu kreuzen und dabei eine gute Software rauszubringen.

mfg

2.891 Beiträge seit 2004
vor 11 Jahren

Ich schreibe mal die Textbezeichnungen der Befehle mit dazu, damit ich da besser durchsehe.

P1 = 8C ... Ich erhalte Daten (status 9000) kann diese aber (noch) nicht entzippen, Sollte der VersichertenStatus sein ReadVST Keine Ahnung, was da genau wie kodiert drin steht. Das haben wir für unseren Einsatzzweck nie benötigt. Auf die Schnelle konnte ich auch nirgends eine brauchbare Doku dazu finden.

P1 = 81 ... Ich erhalte die Daten (Status 9000) kann diese auch entzipen und sehe darin die Daten des Versicherten ReadPD Liefert die persönlichen Versichertendaten (Name, Anschrift)

P1 = 82 ... Ich erhalte den Fehler 64A8 und keine Daten [...] Brauche ich die Daten mit P1 = 82? Oder stehen im Falle verschiedener Personen als Patient/Versicherter beide in dem ersten XML File? ReadVD Liefert die allgemeinen Versicherungsdaten (Kostenträger & Versicherungsschutz) & die geschützten Versichertendaten (Zuzahlungsstatus & besondere Kennzeichen).
In den Musterkarten kann man die geschützten VD problemlos auslesen, aber spätestens bei den "echten" Karten geht es nicht mehr.

Was du davon auslesen willst, hängt vom Anwendungsfall ab. Die PD liefern dir alle "normalen" Daten eines Kunden. Aber sobald du noch Krankenkasseninfos (IK, Versichertennummer, ...) benötigst, musst du an die VD ran. (Welche Daten wo in den XML-Dateien stehen, bekommst du mit den Schema-Beschreibungen heraus).

Ansonsten kann ich dir bei deinem Fehler wenig helfen. Ich nehme an, dass du beim ReadVD alles haargenau so gemacht hast, wie beim ReadVST und ReadPD, und nur die 8C/81/82 ausgetauscht hast?

2.891 Beiträge seit 2004
vor 10 Jahren

Den konkreten Code zum Dekodieren darf ich nicht posten.

Ich durfte und konnte unseren Code zum Auslesen der KVK & eGK jetzt aus den Tiefen der Firmeninterna befreien und veröffentlichen:
KVK- & eGK-API (via CTAPI) - CodePlex

Für den zugehörigen Dokumentationsbereich habe ich mir mal einige meiner vielen Textstellen hier aus dem Thread genommen und zusätzlich zu den dort schon verwiesenen Spezifikationen das ganze mit entsprechendem C#-Code untermalt.

888 Beiträge seit 2007
vor 10 Jahren

@dN!3L

Ganz große Klasse!

P
2 Beiträge seit 2013
vor 10 Jahren

Hallo,
erstmal entschuldigung das ich so ein alten Thread hervorhole.
Nun zu mein Problem:
Ich beschäftige mich zurzeit auch mit der CTAPI wegen der eHealth-BCS Keyboard G87-1, eigentlich bin ich der Meinung das ich alles so richtig hab (auch mit abgleich mit den vorherigen Codebeispielen

Verbinden, trennen und der Erste Command funktionieren immer, nur alle weiteren dannach nicht mehr. Aber scheinbar liegt das nicht am ersten Command, den diesen kann ich austauschen. (Hab da schonmal Reset, Eject_ICC, Request_ICC usw. benutzt wo das Card Terminal wie gewünscht reagiert hat)

Der Fehler ist dann im Return der data, da kommt dann nicht 0 sondern 255 (sagt mir leider nix da kein negativ Value)

Wo kann mein Logik Fehler liegen?

2.891 Beiträge seit 2004
vor 10 Jahren

Der Fehler ist dann im Return der data, da kommt dann nicht 0 sondern 255 (sagt mir leider nix da kein negativ Value)

Mach ein sbyte draus, dann wird's auch negativ 😉 Wenn du mal in CtReturnCode.cs guckst, sollte das auf einen HTSi error hindeuten - was immer das für deinen Fall bedeuten mag...

Mit "scheinbar" und "meiner Meinung nach" können wir aber nur in die Glaskugel gucken, was denn der Fehler sein könnte. Zeig doch mal etwas Code für das Anfordern der Daten.
Hast du die KVK- & eGK-API (via CTAPI) mal ausprobiert?

P
2 Beiträge seit 2013
vor 10 Jahren

Oh erstmal vielen dank, hatte Return Value als BYTE und da lag der Fehler, jetzt erhalt ich wenigstens als Return -1, damit lässt sich wengistens arbeiten.

Zum Code: Ich schreibe immo in C++ daher hatte ich ihn erstmal nicht gepostet.

mfg P@UNI

E
1 Beiträge seit 2014
vor 9 Jahren

Hallo, ich hoffe ihr könnt mir helfen.
Ich habe einen Chipdrive SCR3311 vor mir.

Ziel ist es BLZ und Kontonummer auszulesen.

Ich habe mich lange ins Thema eingelesen, komme aber nicht weiter,
und habe noch mehr Bammel vor dem nächsten Schritt.
Ich benutzen die CTAPI über die DLL CTPCSC31kv.dll (selbes verhalten mit der CTPCSC31.dll).
CT INIT und CT CLOSE funktionieren tadellos.

RESET CT funktioniert auch mit Rückgabe 90 00:

DAD = 1; SAD = 2;
byte[] command = { 0x20, 0x11, 0x00, 0x00 };

REQUEST CT gibt mit 90 01 zurück:

DAD = 1; SAD = 2;
byte[] command2 = { 0x20, 0x12, 0x01, 0x01, 0x01, 0x0A, 0x00};

In der EC-Karten-Doku habe ich mir den SELECT FILE Befehl für "DF_Börse" herausgesucht,
dort bekomme ich leider 6a 82 zurück.

DAD = 0; SAD = 2;
byte[] command3 = {0x00, 0xA4, 0x04, 0x0C, 0x09, 0xD2, 0x76, 0x00, 0x00, 0x25, 0x45, 0x50, 0x01, 0x00};//Select File EC Börse

Aber selbst wenn ich danach den Record EF_BÖRSE auslesen würde, hätte ich nur die BLZ.
Die Verschlüsselung der Kontonummer ist mir völlig unklar.

Gruß,

Ecki