diff options
Diffstat (limited to 'src/magnetic/magnetic.ino')
-rwxr-xr-x | src/magnetic/magnetic.ino | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/src/magnetic/magnetic.ino b/src/magnetic/magnetic.ino new file mode 100755 index 0000000..a9c4d03 --- /dev/null +++ b/src/magnetic/magnetic.ino @@ -0,0 +1,487 @@ +/* Magnetic card emulator for ATMEL + * + * This sould work with the original 'MagSpoof' out of the box! + * In this case you should add a second switch, to allow test card and progrmming mode. + * + * (C) 2021 by Andreas Eversberg <jolly@eversberg.eu> + * 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 <http://www.gnu.org/licenses/>. + */ + +/* to set fused for ATTINY85: (This is default when shipped!) + * avrdude -c usbasp-clone -p t85 -U lfuse:w:0xc0:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m + */ + +/* Use a clock speed of 8 MHz. If you change it, also change the fuses!!!! + * The CLKPS bits are set to 0 by software, so that 8 MHz clock is not divided. + */ + +/* Press switch 1 to emulate card, press switch 2 to emulate BSA44 service card. + * The LED will do short flashs, to indicate that power is on. + * + * Hold a switch while powering on, to enter test mode. The LED will light up. + * Press switch 1 to send continuous 0-bits. + * Press switch 2 to send continuous 1-bits. + * Press switch 1 and 2 to send continuos alternating 0- and 1-bits. + * WARNING: In test mode, H-bridge IC becomes quickly very hot. Don't fry it! + * + * To enter programming mode, press both buttons simultaniously. + * The LED will continously blink, to indicate programming mode. + * Press switch 1 to change subscriber number or switch 2 to change security code. + * The LED will then show the digit values by blinking. It can be aborted with any switch. + * After short blinking, a long blink shows that the first digit can be entered. + * Press switch 1 1-10 times to enter the digit. When done, press switch 2 and continue + * with the next digit. When all digits are entered, press switch 2 twice to confirm. + * A soft flash of the LED (fading in and out) will indicate that the new digits are stored. + * A false input will abort the programming procedure and restart with continuous blinking. + * To abort programming mode, press both buttuns simultaniously. + */ + +#define F_CPU 8000000 // Oscillator frequency + +extern "C" +{ + #include "iso7811.h" +} +#include <avr/eeprom.h> + +#define PORT_ENABLE 3 // PIN 2 -> connect to 1-2EN of L293D and to LED with 1K resistor to ground +#define PORT_COIL1 0 // PIN 5 -> connect to 1A of L293D +#define PORT_COIL2 1 // PIN 6 -> connect to 2A of L293D +#define PORT_SWITCH1 2 // PIN 7 -> connect via switch 1 to ground +#define PORT_SWITCH2 4 // PIN 3 -> connect via switch 2 to ground (optional, leave open when unused) +#define PORT_RESET 5 // PIN 1 -> unused, leave open (Don't disable reset when programming fuses!!!) + +/* see main.c for more info */ +#define CNETZ_LEAD_IN 12 +#define CNETZ_LEAD_OUT 150 + +#define CLOCK_US 200 // Time to wait for half a bit + +#define EEPROM_MAGIC 'c' // not equal to sim emulator, this has a capital 'C' +#define EEPROM_VERSION '0' + +#define SWITCH1 (digitalRead(PORT_SWITCH1) == LOW) +#define SWITCH2 (digitalRead(PORT_SWITCH2) == LOW) + +static char number[9] = "1234567\0"; +static char sicherung[6] = "12345"; +static char string[19]; +static uint8_t flux = 0; + +/* enable H-bridge, but set it to neutral */ +void enable_h_bridge(uint8_t enable) +{ + /* enable H-bridge and LED */ + digitalWrite(PORT_ENABLE, enable); + + /* set bridge to neutral */ + digitalWrite(PORT_COIL1, LOW); + digitalWrite(PORT_COIL2, LOW); +} + +/* send single bit with clock */ +void send_bit(uint8_t bit) +{ + digitalWrite(PORT_COIL1, flux); + flux ^= 1; + digitalWrite(PORT_COIL2, flux); + delayMicroseconds(CLOCK_US); + + if (bit & 1) { + digitalWrite(PORT_COIL1, flux); + flux ^= 1; + digitalWrite(PORT_COIL2, flux); + } + delayMicroseconds(CLOCK_US); +} + +/* blink exactly one second to confirm correct clock speed */ +void blink_led() +{ + int i; + + for (i = 0; i < 3; i++) { + delay(200); + if (SWITCH1 || SWITCH2) + break; + enable_h_bridge(1); + delay(200); + if (SWITCH1 || SWITCH2) + break; + enable_h_bridge(0); + } +} + +/* wait until release of single key, but abort when pressing both keys. + * if 2 is given, wait for release of all keys, don't abort when pressing both keys. + * compensate contact shattering (German: Tastenprellen) + */ +void wait_release(int keys) +{ + int i = 0; + while (i < 50) { + delay(1); + if (keys < 2) { + if (SWITCH1 && SWITCH2) + break; + } + if (SWITCH1 || SWITCH2) + i = 0; + else + i++; + } +} + +/* test mode */ +void test_pattern(void) +{ + /* test pattern */ + while (42) { + if (!SWITCH1 && !SWITCH2) + enable_h_bridge(1); + if (SWITCH1) + send_bit(0); + if (SWITCH2) + send_bit(1); + } +} + +/* read eeprom, if version is correct */ +void read_eeprom(void) +{ + int i; + + if (eeprom_read_byte(0) == EEPROM_MAGIC + && eeprom_read_byte(1) == EEPROM_VERSION) { + for (i = 0; i < 8; i++) + number[i] = eeprom_read_byte(i + 2); + number[i] = '\0'; + for (i = 0; i < 5; i++) + sicherung[i] = eeprom_read_byte(i + 10); + sicherung[i] = '\0'; + } +} + +/* write eeprom, */ +void write_eeprom(void) +{ + int i; + + eeprom_write_byte(0, EEPROM_MAGIC); + eeprom_write_byte(1, EEPROM_VERSION); + for (i = 0; i < 8; i++) + eeprom_write_byte(i + 2, number[i]); + for (i = 0; i < 5; i++) + eeprom_write_byte(i + 10, sicherung[i]); + + /* show soft flash */ + for (i = 0; i < 55; i++) { + enable_h_bridge(1); + delay(i/5); + enable_h_bridge(0); + delay(10 - i/5); + } + for (i = 54; i >= 0; i--) { + enable_h_bridge(1); + delay(i/5); + enable_h_bridge(0); + delay(10 - i/5); + } +} + +void setup() { + /* setup clock speed to 8 MHz */ + CLKPR = _BV(CLKPCE); + CLKPR = 0; + + /* setup ports */ + pinMode(PORT_ENABLE, OUTPUT); + digitalWrite(PORT_ENABLE, LOW); + pinMode(PORT_COIL1, OUTPUT); + digitalWrite(PORT_COIL1, LOW); + pinMode(PORT_COIL2, OUTPUT); + digitalWrite(PORT_COIL2, LOW); + pinMode(PORT_SWITCH1, INPUT_PULLUP); + pinMode(PORT_SWITCH2, INPUT_PULLUP); + + /* blink with LED */ + blink_led(); + + /* transmit test pattern */ + if (SWITCH1 || SWITCH2) { + wait_release(1); + test_pattern(); + } + + /* read subscriber data from eeprom */ + read_eeprom(); +} + +/* send card data */ +void send_string(const char *string) +{ + uint8_t data[CNETZ_LEAD_IN + 21 + CNETZ_LEAD_OUT]; + int length, i; + uint8_t digit; + + length = encode_track(data, string, CNETZ_LEAD_IN, CNETZ_LEAD_OUT); + + /* enable H-bridge and LED */ + enable_h_bridge(1); + + /* send bits */ + for (i = 0; i < length; i++) { + digit = data[i]; + send_bit((digit >> 0) & 1); + send_bit((digit >> 1) & 1); + send_bit((digit >> 2) & 1); + send_bit((digit >> 3) & 1); + send_bit((digit >> 4) & 1); + /* abort when pressing both switches */ + if (SWITCH1 && SWITCH2) + break; + } + + /* disable H-bridge */ + enable_h_bridge(0); +} + +/* send zeros or ones depending on the key pressed, stop by pressing both keys */ +void program_mode(void) +{ + uint8_t blink; + uint8_t edit; + char io[9]; + int i, b, d; + +error: + blink = 0; + edit = 0; + /* flash LED, wait for key press */ + while (!edit) { + blink ^= 1; + enable_h_bridge(blink); + for (d = 0; d < 50; d++) { + delay(1); + if (SWITCH1) { + edit = 1; + break; + } + if (SWITCH2) { + edit = 2; + break; + } + } + } + enable_h_bridge(0); + wait_release(1); + if (SWITCH1 && SWITCH2) + goto done; + + /* copy subscriber data to io-buffer */ + switch (edit) { + case 1: + for (i = 0; i < 8; i++) + io[i] = number[i]; + io[i] = '\0'; + break; + case 2: + for (i = 0; i < 5; i++) + io[i] = sicherung[i]; + io[i] = '\0'; + break; + } + + /* blink the io-buffer data */ + for (i = 0; io[i]; i++) { + for (d = 0; d < 1000; d++) { + delay(1); + if (SWITCH1 || SWITCH2) + goto stop_blink; + } + if (io[i] > '0') + blink = io[i] - '0'; + else + blink = 10; + for (b = 0; b < blink; b++) { + enable_h_bridge(1); + for (d = 0; d < 100; d++) { + delay(1); + if (SWITCH1 || SWITCH2) { + enable_h_bridge(0); + goto stop_blink; + } + } + enable_h_bridge(0); + for (d = 0; d < 400; d++) { + delay(1); + if (SWITCH1 || SWITCH2) + goto stop_blink; + } + } + } + for (d = 0; d < 1000; d++) { + delay(1); + if (SWITCH1 && SWITCH2) + goto stop_blink; + } + stop_blink: + wait_release(1); + if (SWITCH1 && SWITCH2) + goto done; + enable_h_bridge(1); + for (d = 0; d < 500; d++) { + delay(1); + if (SWITCH1 && SWITCH2) + goto done; + } + enable_h_bridge(0); + + /* key in the data to io-buffer */ + i = 0; + b = 0; + while (42) { + if (SWITCH1) { + enable_h_bridge(1); + for (d = 0; d < 100; d++) { + delay(1); + if (SWITCH1 && SWITCH2) + goto done; + } + enable_h_bridge(0); + wait_release(1); + if (SWITCH1 && SWITCH2) + goto done; + b++; + if (b > 10) + goto error; + } + if (SWITCH2) { + wait_release(1); + if (SWITCH1 && SWITCH2) + goto done; + if (b == 0) { + while (i < 9) + io[i++] = '\0'; + break; + } + if (b == 10) + b = 0; + io[i++] = '0' + b; + b = 0; + if (i > 8) + goto error; + enable_h_bridge(1); + for (d = 0; d < 500; d++) { + delay(1); + if (SWITCH1 && SWITCH2) + goto done; + } + enable_h_bridge(0); + } + } + + /* verify input */ + switch (edit) { + case 1: + if (strlen(io) < 7) + goto error; + if (io[0] > '7') + goto error; + if (strlen(io) == 8) { + if ((io[1] - '0') * 10 + io[2] - '0' > 31) + goto error; + if (atoi(io + 3) > 65535) + goto error; + } else { + if (atoi(io + 2) > 65535) + goto error; + } + break; + case 2: + if (strlen(io) > 5) + goto error; + if (!io[0]) + goto error; + if (io[0] == '0' && io[1] != '\0') + goto error; + if (atoi(io) > 65535) + goto error; + break; + } + + /* copy io-buffer data to subscriber data */ + switch (edit) { + case 1: + for (i = 0; i < 8; i++) + number[i] = io[i]; + number[i] = '\0'; + break; + case 2: + for (i = 0; i < 5; i++) + sicherung[i] = io[i]; + sicherung[i] = '\0'; + break; + } + + /* write subscriber data to eeprom */ + write_eeprom(); + +done: + enable_h_bridge(0); + return; +} + +static uint16_t flash = 0; + +void loop() { + /* go programming */ + if (SWITCH1 && SWITCH2) { + flash = 0; + wait_release(2); + program_mode(); + wait_release(2); + return; + } + + /* send card */ + if (SWITCH1) { + flash = 0; + cnetz_card(string, number, sicherung); + send_string(string); + wait_release(1); + return; + } + + /* send service card */ + if (SWITCH2) { + flash = 0; + bsa44_service(string); + send_string(string); + wait_release(1); + return; + } + + /* slow blink to show that the device is powered on */ + delay(1); + flash++; + if (flash == 1980) + enable_h_bridge(1); + if (flash == 2000) { + enable_h_bridge(0); + flash = 0; + } +} |