diff --git a/.gitignore b/.gitignore index 217d78e..c0b4528 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ libcolorize.pc libtool ltmain.sh missing +compile *.o *.lo *.la @@ -25,6 +26,7 @@ src/bnetz/bnetz src/cnetz/cnetz src/nmt/nmt src/amps/amps +sim/cnetz_sim src/test/test_compandor src/test/test_emphasis src/test/test_dms diff --git a/Makefile.am b/Makefile.am index 4c3e7c3..1073c14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = src +SUBDIRS = src sim diff --git a/configure.ac b/configure.ac index c7eb648..591c548 100644 --- a/configure.ac +++ b/configure.ac @@ -35,6 +35,7 @@ AC_OUTPUT( src/amps/Makefile src/test/Makefile src/Makefile + sim/Makefile Makefile) diff --git a/sim/Makefile.am b/sim/Makefile.am new file mode 100644 index 0000000..35808e7 --- /dev/null +++ b/sim/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = -Wall -g $(all_includes) + +bin_PROGRAMS = \ + cnetz_sim + +cnetz_sim_SOURCES = \ + sim.c +cnetz_sim_LDADD = \ + $(COMMON_LA) + diff --git a/sim/README b/sim/README new file mode 100644 index 0000000..adbae3b --- /dev/null +++ b/sim/README @@ -0,0 +1,15 @@ +This is a generator for the C-Netz Sim Card +"Berechtigungskarte als Speicherkarte". + +The Smart Card "Berechtigungskarte als Prozessorkarte" is not supported. + +After generation, the hex data can be copied to the data array of simcard.ino +and written to an SLE4428 or compatible. + +Note: The SLE card must not have protected serial number area. (ATR area) +Also the card must show all 416 written bits via ATR, not only 32 bits. + +Tested: +Works with BSA 51 +Does not work with all other phones I have. + diff --git a/sim/sim.c b/sim/sim.c new file mode 100644 index 0000000..02e9bc6 --- /dev/null +++ b/sim/sim.c @@ -0,0 +1,144 @@ +/* SIM Card for C-Netz "Berechtigungskarte als Speicherkarte" + * + * (C) 2016 by Andreas Eversberg + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +/* return 1, if 1-bits are odd, so parity becomes even */ +static int gen_parity(uint8_t *bits) +{ + int i; + uint8_t parity = 0; + + for (i = 0; i < 8; i++) + parity ^= (bits[i] & 1); + + return parity; +} + +static uint8_t *gen_memory(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, uint16_t sicherungscode, uint16_t sonderheitsschluessel) +{ + static uint8_t memory[416]; + int i; + + /* meaningless data */ + for (i = 0; i <= 10; i++) + memory[i] = 1; + + /* magic data */ + memory[11] = 0; + memory[12] = 1; + memory[13] = 1; + memory[14] = 1; + memory[15] = 1; + + /* meaningless data */ + for (i = 16; i <= 17; i++) + memory[i] = 0; + + /* magic data */ + memory[18] = 1; + memory[19] = 1; + memory[20] = 1; + + /* magic data */ + memory[21] = 0; + memory[22] = 1; + memory[23] = 0; + + /* meaningless data */ + for (i = 24; i <= 113; i++) + memory[i] = 1; + + /* number */ + for (i = 114; i <= 116; i++) + memory[i] = (futln_nat >> (i - 114)) & 1; + for (i = 117; i <= 121; i++) + memory[i] = (futln_fuvst >> (i - 117)) & 1; + memory[122] = gen_parity(memory + 114); + for (i = 123; i <= 130; i++) + memory[i] = (futln_rest >> (i - 123)) & 1; + memory[131] = gen_parity(memory + 123); + for (i = 132; i <= 139; i++) + memory[i] = (futln_rest >> (i - 132 + 8)) & 1; + memory[140] = gen_parity(memory + 132); + + /* sicherungscode */ + for (i = 141; i <= 148; i++) + memory[i] = (sicherungscode >> (i - 141)) & 1; + memory[149] = gen_parity(memory + 141); + for (i = 150; i <= 157; i++) + memory[i] = (sicherungscode >> (i - 150 + 8)) & 1; + memory[158] = gen_parity(memory + 150); + + /* sonderheitsschluessel */ + for (i = 159; i <= 166; i++) + memory[i] = (sonderheitsschluessel >> (i - 159)) & 1; + memory[167] = gen_parity(memory + 159); + for (i = 168; i <= 175; i++) + memory[i] = (sonderheitsschluessel >> (i - 168 + 8)) & 1; + memory[176] = gen_parity(memory + 168); + + /* meaningless data */ + for (i = 177; i <= 351; i++) + memory[i] = 1; + + /* all zero */ + for (i = 352; i <= 415; i++) + memory[i] = 0; + + return memory; +} + +int main(int argc, char *argv[]) +{ + + if (argc <= 5) { + printf("Usage: %s \n", argv[0]); + return 0; + } + int i; + uint8_t futln_nat = atoi(argv[1]); + uint8_t futln_fuvst = atoi(argv[2]); + uint16_t futln_rest = atoi(argv[3]); + uint16_t sicherungscode = atoi(argv[4]); + uint16_t sonderheitsschluessel = atoi(argv[5]); + printf("nat=%d\n", futln_nat); + printf("fufvt=%d\n", futln_fuvst); + printf("rest=%d\n", futln_rest); + printf("sicherungscode=%d\n", sicherungscode); + printf("sonderheitsschluessel=%d\n", sonderheitsschluessel); + + printf("Telefonnummer: %d%d%05d\n", futln_nat, futln_fuvst, futln_rest); + + uint8_t *bits = gen_memory(futln_nat, futln_fuvst, futln_rest, sicherungscode, sonderheitsschluessel); + for (i = 0; i < 52; i++) { +//printf("%d %d %d %d %d %d %d %d\n", bits[0], bits[1], bits[2] ,bits[3] ,bits[4] ,bits[5] ,bits[6] ,bits[7]); + printf("0x%02x, ", bits[0] + (bits[1] << 1) + (bits[2] << 2) + (bits[3] << 3) + (bits[4] << 4) + (bits[5] << 5) + (bits[6] << 6) + (bits[7] << 7)); +//printf("\n"); + bits += 8; + if ((i & 7) == 7) + printf("\n"); + } + printf("\n"); + + return 0; +} + diff --git a/sim/simcard.ino b/sim/simcard.ino new file mode 100644 index 0000000..0bb01d6 --- /dev/null +++ b/sim/simcard.ino @@ -0,0 +1,231 @@ + +#define RST 8 +#define CLK 9 +#define DATA 10 + +#define PSC1 0xff +#define PSC2 0xff + +uint8_t card_data[] = { + +0xff, 0xf7, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x38, +0x78, 0x28, 0x07, 0x8c, 0xc1, 0x03, 0xfe, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, + +}; + +void setup() +{ + digitalWrite(RST, LOW); + pinMode(RST, OUTPUT); + digitalWrite(CLK, LOW); + pinMode(CLK, OUTPUT); + pinMode(DATA, INPUT_PULLUP); + digitalWrite(DATA, HIGH); + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + Serial.readStringUntil('\m'); +} + +void loop() +{ +again: + Serial.println("Press 'a' for ATR, 'r' to read card, 'w' to program card, 'u' to unlock card"); + Serial.println("-> You must read card ('r') before you are able to write to card."); + while (42) { + if (Serial.available() == 0) + continue; + char inChar = Serial.read(); + if (inChar == 'a') { + Serial.println("ATR..."); + card_atr(52); + goto again; + } else if (inChar == 'r') { + Serial.println("reading..."); + card_read(52, 0); + goto again; + } else if (inChar == 'w') { + Serial.println("writing..."); + card_write(card_data, sizeof(card_data), 0); + goto again; + } else if (inChar == 'u') { + Serial.println("unlocking..."); + card_unlock(PSC1, PSC2); + goto again; + } else { + goto again; + } + } +} + +void card_atr(int num) +{ + uint8_t data[num]; + + digitalWrite(RST, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + digitalWrite(RST, LOW); + delayMicroseconds(100); + card_read_bytes(data, num); +} + +void card_read(int num, int address) +{ + uint8_t data[num]; + + card_command(((address >> 2) & 0xc0) | 0x0e, address & 0xff, 0); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + card_read_bytes(data, num); +} + +void card_write(uint8_t *data, int num, int address) +{ + int i, cnt; + + for (i = 0; i < num; i++) { + card_command(((address >> 2) & 0xc0) | 0x33, address & 0xff, *data); + cnt = card_erase_and_write(); + if (cnt <= 2) { + Serial.println("write failed!"); +// break; + } + address++; + data++; + } +} + +void card_unlock(uint8_t psc1, uint8_t psc2) +{ + int i; + uint8_t data[3]; + + // read error counter + card_command(0xce, 253, 0); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + Serial.println("3 bytes: error counter mask, first PSC code, second psc code"); + card_read_bytes(data, 3); + // check bit to erase + for (i = 0; i < 8; i++) { + if ((data[0] & (1 << i))) + break; + } + if (i == 8) { + Serial.println("SORRY NO MORE BITS TO ERASE TO UNLOCK, YOUR CARD IS BRICKED!"); + return; + } + data[0] = data[0] - (1 << i); + // ease bit to unlock + card_command(0xf2, 253, data[0]); + card_erase_and_write(); + // unlock + Serial.println("unlock bit has been erased, sending PSC code"); + card_command(0xcd, 254, psc1); + card_erase_and_write(); + card_command(0xcd, 255, psc2); + card_erase_and_write(); + // read error counter mask + card_command(0xce, 253, 0); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + Serial.println("checking error counter mask, one bit shall be erased..."); + card_read_bytes(data, 1); + // reset unlock mask + Serial.println("PSC code has been sent, resetting error counter mask"); + card_command(0xf3, 253, 0xff); + card_erase_and_write(); + // read error counter mask + card_command(0xce, 253, 0); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + Serial.println("reading: error counter mask, all bits should be reset"); + card_read_bytes(data, 1); +} + +void card_command(uint8_t c1, uint8_t c2, uint8_t c3) +{ + int i, j; + uint8_t c[3]; + + c[0] = c1; + c[1] = c2; + c[2] = c3; + Serial.println("card command:"); + Serial.println(c1); + Serial.println(c2); + Serial.println(c3); + + digitalWrite(RST, HIGH); + delayMicroseconds(100); + pinMode(DATA, OUTPUT); + for (i = 0; i < 3; i++) { + for (j = 0; j < 8; j++) { + digitalWrite(DATA, ((c[i] >> j) & 1) ? HIGH : LOW); + delayMicroseconds(100); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + } + } + pinMode(DATA, INPUT_PULLUP); + digitalWrite(DATA, HIGH); + digitalWrite(RST, LOW); + delayMicroseconds(100); +} + +void card_read_bytes(uint8_t *data, int num) { + int i, j; + + for (i = 0; i < num; i++) { + for (j = 0; j < 8; j++) { + data[i] = (data[i] >> 1) | ((digitalRead(DATA) != LOW) ? 128 : 0); + Serial.print((digitalRead(DATA) != LOW) ? '1' : '0'); + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); + } + Serial.print(" 0x"); + Serial.println(data[i], HEX); + } +} + +int card_erase_and_write(void) +{ + int i; + + for (i = 0; i < 203; i++) { + digitalWrite(CLK, HIGH); + delayMicroseconds(100); + digitalWrite(CLK, LOW); + delayMicroseconds(100); +if (0) if (digitalRead(DATA) == LOW) { + Serial.print(" -> write pulses:"); + Serial.println(i); + break; + } + } + return i; +} +