-         

Ergebnis 1 bis 6 von 6

Thema: SLE4442-Emulation (Smartcard) - Geschwindigkeitsproblem?

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    30.05.2004
    Ort
    Detmold
    Alter
    30
    Beiträge
    557

    SLE4442-Emulation (Smartcard) - Geschwindigkeitsproblem?

    Anzeige

    Hallo zusammen,

    ich versuche gerade, mittels eines ATmega8 eine SLE4442-Emulation zu entwerfen. Gleich vorweg: Nein, ich versuche nicht, irgendwelche Sonnenstudios, TV-Receiver, Waschautomaten oder sonstiges zu hacken. Die Emulation ist Teil einer freiwilligen Projektarbeit an der Uni (Thema "Sicherheit und Datenschutz").

    Jedenfalls bin ich soweit eigentlich fertig, die Programmierung anhand des Datenblattes zur Karte war rein von der funktionalen Seite betrachtet kein großes Drama, allerdings befürchte ich, dass mein Code schlicht zu langsam ist. Mit dem USB-Kartenleser funktioniert meine "Karte" nämlich wunderbar, im Zielsystem (welches etwa 3.5 mal so schnell arbeitet) geht nichts mehr.

    Ein mit 8 MHz getakteter ATmega8 sollte mit den 71.4 KHz Taktfrequenz des Systems meiner Meinung nach ohne jegliche Probleme zurechtkommen. Eventuell hab' ich auch einfach irgendwo etwas übersehen oder Mist gebaut, das will ich natürlich nicht ausschließen...

    Der Code ist zugegebenermaßen nicht überufernd kommentiert, aber alle wichtigen Funktionen des Datenblattes sollten sofort ersichtlich sein.

    Falls jemand eine Idee oder allgemeine Kritik zum Code hat, bin ich für jeden Beitrag dankbar.


    Gruß und gute Nacht!
    Trabukh

    Code:
    // main.c
    //
    // cpu: ATMega8
    // speed: 8 MHz
    
    #include "sle4442.h"
    #include "memory.h"
    
    void edgeFalling() {
    
    	switch (mode) {
    		case MODE_ATR:
    			// Answer-to-Reset
    			if (pointerByte <= 3) {
    				setOutput();
    				setIO(memoryMain[pointerByte] & (1 << pointerBit));
    			} else { // ATR finished
    				setInput();
    				setMode(MODE_IDLE);
    			}
    			break;
    		case MODE_DATA:
    			// Outgoing Data Mode
    			switch (command[0]) {
    				case 0x30: // Read Main Memory
    					if (pointerByte <= 255) {
    						setIO(memoryMain[pointerByte] & (1 << pointerBit));
    						setOutput();
    					} else { // Reading finished
    						setInput();
    						setMode(MODE_IDLE);
    					}
    					break;
    				case 0x34: // Read Protection Memory
    					if (pointerByte <= 3) {
    						setIO(memoryProtected[pointerByte * 8 + pointerBit]);
    						setOutput();
    					} else { // Reading finished
    						setInput();
    						setMode(MODE_IDLE);
    					}
    					break;
    				case 0x31: // Read Security Memory
    					if (pointerByte <= 3) {
    						if ((unlocked == 3) | (pointerByte == 0x00))
    							setIO(memorySecurity[pointerByte] & (1 << pointerBit));
    						else
    							setIO(0);
    						setOutput();
    					} else { // Reading finished
    						setInput();
    						setMode(MODE_IDLE);
    					}
    					break;
    			}
    			break;
    		case MODE_PROC:
    			// Processing Mode
    			switch (command[0]) {
    				case 0x39: // Update Security Memory
    					setIO(0);
    					setOutput();
    					if (unlocked == 3) {
    						memorySecurity[command[1]] = command[2];
    						memorySecurity[0x00] &= 0x07;
    					} else if ((command[1] == 0x00) & (command[2] < memorySecurity[0x00]))
    						memorySecurity[0x00] = command[2];
    					waitCycles(124);
    					setInput();
    					setMode(MODE_IDLE);
    					break;
    				case 0x33: // Compare Verification Data
    					setIO(0);
    					setOutput();
    					if ((memorySecurity[command[1]] == command[2]) & (memorySecurity[0x00] != 0x00)) {
    						unlocked++;
    						if (unlocked >= 3) {
    							unlocked = 3;
    							memorySecurity[0x00] = 0x07;
    						}
    					} else
    						unlocked = 0;
    					waitCycles(2);
    					setInput();
    					setMode(MODE_IDLE);
    					break;
    				case 0x3C: // Write Protection Memory
    					setIO(0);
    					setOutput();
    					if ((unlocked == 3) & (memoryMain[command[1]] == command[2])) {
    						memoryProtected[command[1]] = 1;
    					}
    					waitCycles(124);
    					setInput();
    					setMode(MODE_IDLE);
    					break;
    				case 0x38: // Update Main Memory
    					setIO(0);
    					setOutput();
    					if (unlocked == 3)
    						memoryMain[command[1]] = command[2];
    					waitCycles(124);
    					setInput();
    					setMode(MODE_IDLE);
    					break;
    			}
    			break;
    	}
    }
    
    void edgeRising(bool bit) {
    	// Increase pointers
    	pointerBit++;
    	if (pointerBit > 7) {
    		pointerByte++;
    		pointerBit = 0;
    	}
    
    	switch (mode) {
    		case MODE_IDLE:
    			// Idle Mode - Waiting for command
    			loop_until_bit_is_clear(PIN,PIN_IO);
    			pointerByte = 0;
    			pointerBit = -1;
    			setMode(MODE_CMD);
    			break;
    		case MODE_CMD:
    			// Command Mode
    			if (pointerByte <= 2) {
    				if (bit)
    					command[pointerByte] |= (1 << pointerBit);
    				else
    					command[pointerByte] &= ~(1 << pointerBit);
    			} else {
    				loop_until_bit_is_set(PIN,PIN_IO);
    				pointerByte = 0;
    				pointerBit = 0;
    				switch (command[0]) {
    					case 0x30: // Read Main Memory
    						pointerByte = command[1];
    					case 0x34: // Read Protection Memory
    					case 0x31: // Read Security Memory
    						setMode(MODE_DATA);
    						break;
    					case 0x39: // Update Security Memory
    					case 0x33: // Compare Verification Data
    					case 0x3C: // Write Protection Memory
    					case 0x38: // Update Main Memory
    						setMode(MODE_PROC);
    						break;
    				}
    			}
    			break;
    	}
    }
    
    // Clock interrupt
    ISR(INT0_vect)
    {
    	if (!(PIN & (1 << PIN_CLK)))
    		edgeFalling();
    	else
    		edgeRising(PIN & (1 << PIN_IO));
    }
    
    // Reset interrupt
    ISR(INT1_vect)
    {
    	setMode(MODE_ATR);
    	pointerByte = 0;
    	pointerBit = 0;
    	unlocked = 0;
    	edgeFalling();
    }
    
    int main(void) {
    	// Activate interrupts
    	MCUCR |= (1 << ISC00) | (1 << ISC11);
    	GICR |= (1 << INT0) | (1 << INT1);
    	sei();
    
    	// Initialize port
    	PORT = 0x00;
    	DDR = 0x00;
    	PIN = 0x00;
    	setMode(MODE_ATR);
    
    	for (;;) {
    		;
    	}
    }
    Code:
    // sle4442.h
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdbool.h>
    
    // Global variables
    volatile unsigned char mode;
    volatile unsigned char unlocked = 0;
    
    // Pin/Port configuration
    #define PIN_CLK		PD2	// INT0
    #define PIN_RST		PD3 // INT1
    #define PIN_IO		PD4
    #define PORT		PORTD
    #define PIN			PIND
    #define DDR 		DDRD
    
    // Some helpful functions
    bool getReset() {
    	return PIN & (1 << PIN_RST);
    }
    void setOutput() {
    	DDR |= (1 << PIN_IO);
    }
    void setInput() {
    	DDR &= ~(1 << PIN_IO);
    }
    void setIO(bool b) {
    	if (b)
    		PORT |= (1 << PIN_IO);
    	else
    		PORT &= ~(1 << PIN_IO);
    }
    void setMode(unsigned char m) {
    	mode = m;
    }
    void waitCycles(unsigned char c) {
    	for (unsigned char i = 0; i < c; i++) {
    		loop_until_bit_is_set(PIN,PIN_CLK);
    		loop_until_bit_is_clear(PIN,PIN_CLK);
    	}
    }
    
    // Mode constants
    #define MODE_ATR	1
    #define MODE_CMD	2
    #define MODE_DATA	3
    #define MODE_PROC	4
    #define MODE_IDLE	5
    
    // Memory pointers
    volatile unsigned int pointerByte = 0;
    volatile signed char pointerBit = 0;
    
    // Command bytes
    unsigned char command[3];
    Code:
    // memory.h
    
    unsigned char memoryMain[256] = {
    		0xA2, 0x13, 0x10, 0x91, 0x46, 0x0B, 0x81, 0x15, 0x42, 0x45, 0x00, 0x30, 0x03, 0x09, 0xED, 0xEA, 0x40, 0x12, 0xFF, 0xFF, 0xFF, 0xD2, 0x76,
    		0x00, 0x00, 0x63, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x30, 0x32, 0x37, 0x33, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x0A,
    		0x00, 0xBC, 0x64, 0x64, 0x00, 0x01, 0x00, 0x35, 0xF8, 0xD6, 0x19, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x1A, 0x7C, 0x02, 0x05,
    		0x10, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x66, 0x09, 0x01, 0x14, 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x10, 0xDA,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    		0xFF, 0xFF, 0xFF };
    
    bool memoryProtected[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 };
    
    unsigned char memorySecurity[] = { 0b00000111, 0xCD, 0x95, 0xE4 }; // Last 3 bytes = PSC

  2. #2
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672

    Re: SLE4442-Emulation (Smartcard) - Geschwindigkeitsproblem?

    Zitat Zitat von Trabukh
    Ein mit 8 MHz getakteter ATmega8 sollte mit den 71.4 KHz Taktfrequenz des Systems meiner Meinung nach ohne jegliche Probleme zurechtkommen.
    Im Prinzip ja, aber bei deinem Code bestimmt nicht. Du hast 112 System-Takte pro IO-Takt. Ich bezweifle, dass jeder Pfad durch deinen ISR-Code innerhalb dieser Laufzeitgrenze bleibt, zumal du ja sogar 2 Interrupts pro IO-Takt hast.
    MfG
    Stefan

  3. #3
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    30.05.2004
    Ort
    Detmold
    Alter
    30
    Beiträge
    557
    Du hast 112 System-Takte pro IO-Takt.
    Hmm, das ist natürlich ein Argument. Also nochmal neu aufziehen ohne Interrupts? Dafür müsste ich das meiste quasi neuschreiben, aber so lernt man wohl am besten...

    Jedenfalls schonmal Danke, ich hätte nicht gedacht, dass soviel Zeit in meinem Code verloren geht.

    EDIT: Hättest du eventuell auf den ersten Blick direkt Ideen, was man verbessern könnte? Ich bin leider kein C-Experte.

  4. #4
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Trabukh
    Also nochmal neu aufziehen ohne Interrupts?
    Nö, du musst aber den Interrupt deutlich verschlanken. Erster Schritt wäre z.B. im Interrupt keine Funktionen aufzurufen, sondern den kompletten Code direkt in die ISR zu packen (oder alternativ dafür sorgen, dass die Funktionen auf jeden Fall ge-inlined werden). Zweiter Schritt wäre Konstrukte der Art "(1 << pointerBit)" rauszuschmeißen. Die sind auf einem AVR sehr ineffektiv, weil der AVR keinen Assembler-Befehl hat für das Verschieben um mehrere Stellen, also wird daraus eine Schleife. Besser ist es direkt mit Masken zu arbeiten und immer nur um ein Bit zu verschieben.
    Code:
    Also statt
    
    pointerBit++;
    ... |= (1 << pointerBit);
    
    eher sowas
    
    pointerMask <<= 1;
    ... |= pointerMask;
    (Das nur so auf die Schnelle. Da gibt es mit Sicherheit noch mehr "Verschlankungs-Potential")
    MfG
    Stefan

  5. #5
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    30.05.2004
    Ort
    Detmold
    Alter
    30
    Beiträge
    557
    Selbst mit inline-Funktionen und Bitmasken ist das Programm noch zu langsam. Ich fürchte, mit einem Mega8 und den internen 8 MHz werd' ich wohl nicht an den benötigten Speed rankommen, zumal ich tatsächlich nur grob geschätzte 56 Takte für die Reaktion zur Verfügung habe... Wirklich schade

  6. #6
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    30.05.2004
    Ort
    Detmold
    Alter
    30
    Beiträge
    557
    So, Studium und Arbeit lassen im Augenblick wieder ein wenig Luft für Freizeit. Auch wenn das Uni-Projekt inzwischen abgeschlossen ist (als Ersatzprojekt habe ich eine AES-Implementierung mit der CUDA-Plattform für NVIDIA-Grafikkarten entwickelt), so würde ich doch gerne weiterhin versuchen, einen funktionierenden Code hinzubekommen.

    Der allgemeine Stand ist jetzt mit Bitmasken und "ge-inlineten" Funktionen, aber auch damit erreiche ich keine ausreichende Reaktionszeit für die geforderten knapp 72 KHz... Eventuell hat jemand noch Anmerkungen, Kritik, Vorschläge etc.?

    Gruß
    Trabukh
    Geändert von Trabukh (12.12.2011 um 20:08 Uhr) Grund: Typo

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •