Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 3 | # Code ported from simtrace host program apdu_split.c |
| 4 | # |
| 5 | # (C) 2010 by Harald Welte <hwelte@hmw-consulting.de> |
| 6 | # |
| 7 | # This program is free software; you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License version 2 |
| 9 | # as published by the Free Software Foundation |
| 10 | # |
| 11 | # This program is distributed in the hope that it will be useful, |
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | # GNU General Public License for more details. |
| 15 | |
| 16 | from enum import Enum |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 17 | from util import HEX |
| 18 | from array import array |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 19 | |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 20 | class apdu_states(Enum): |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 21 | APDU_S_CLA = 1 |
| 22 | APDU_S_INS = 2 |
| 23 | APDU_S_P1 = 3 |
| 24 | APDU_S_P2 = 4 |
| 25 | APDU_S_P3 = 5 |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 26 | APDU_S_SEND_DATA = 6 |
| 27 | APDU_S_DATA = 7 |
| 28 | APDU_S_DATA_SINGLE = 8 |
| 29 | APDU_S_SW1 = 9 |
| 30 | APDU_S_SW2 = 10 |
| 31 | APDU_S_FIN = 11 |
Christina Quast | 0d98b9f | 2015-05-03 14:22:51 +0200 | [diff] [blame] | 32 | PTS = 12 |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 33 | |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 34 | class Apdu_splitter: |
| 35 | |
| 36 | def __init__(self): |
| 37 | self.state = apdu_states.APDU_S_CLA |
Christina Quast | 20e89af | 2015-05-14 16:55:35 +0200 | [diff] [blame] | 38 | self.buf = array('B', []) |
| 39 | self.pts_buf = array('B', []) |
| 40 | self.data = array('B', []) |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 41 | self.ins = array('B', []) |
| 42 | self.data_remainig = 0 |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 43 | |
| 44 | def func_APDU_S_INS(self, c): |
| 45 | self.ins = c |
Christina Quast | 51925a6 | 2015-04-14 21:04:14 +0200 | [diff] [blame] | 46 | self.buf.append(c) |
| 47 | self.state = apdu_states(self.state.value + 1) |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 48 | |
Christina Quast | 0d98b9f | 2015-05-03 14:22:51 +0200 | [diff] [blame] | 49 | def func_PTS(self, c): |
| 50 | self.pts_buf.append(c) |
| 51 | print("PTS: ", self.pts_buf) |
| 52 | if self.pts_buf == [0xff, 0x00, 0xff]: |
| 53 | self.state = apdu_states.APDU_S_FIN |
| 54 | |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 55 | def func_APDU_S_CLA_P1_P2(self, c): |
Christina Quast | 0d98b9f | 2015-05-03 14:22:51 +0200 | [diff] [blame] | 56 | if self.state == apdu_states.APDU_S_CLA and c == 0xff: |
| 57 | self.state = apdu_states.PTS |
| 58 | self.pts_buf = [c] |
| 59 | else: |
| 60 | self.buf.append(c) |
| 61 | self.state = apdu_states(self.state.value + 1) |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 62 | |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 63 | def func_APDU_S_P3(self, c): |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 64 | self.buf.append(c) |
Christina Quast | 51925a6 | 2015-04-14 21:04:14 +0200 | [diff] [blame] | 65 | self.data_remaining = 256 if c == 0 else c |
Christina Quast | 59dae92 | 2015-05-14 16:58:37 +0200 | [diff] [blame] | 66 | self.state = apdu_states.APDU_S_SW1 |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 67 | |
| 68 | def func_APDU_S_DATA(self, c): |
| 69 | self.buf.append(c) |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 70 | self.data.append(c) |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 71 | self.data_remaining -= 1 |
Christina Quast | 51925a6 | 2015-04-14 21:04:14 +0200 | [diff] [blame] | 72 | if self.data_remaining == 0: |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 73 | self.state = apdu_states.APDU_S_SW1 |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 74 | |
| 75 | def func_APDU_S_DATA_SINGLE(self, c): |
| 76 | self.buf.append(c) |
| 77 | self.data_remaining -= 1 |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 78 | self.state = apdu_states.APDU_S_SW1 |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 79 | |
| 80 | def func_APDU_S_SW1(self, c): |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 81 | if (c == 0x60): |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 82 | print("APDU_S_SW1: NULL") |
| 83 | else: |
| 84 | # check for 'all remaining' type ACK |
| 85 | if c == self.ins or c == self.ins + 1 or c == ~(self.ins+1): |
| 86 | print("ACK") |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 87 | self.data = [] |
Christina Quast | 59dae92 | 2015-05-14 16:58:37 +0200 | [diff] [blame] | 88 | if self.ins in self.INS_data_expected: |
| 89 | self.state = apdu_states.APDU_S_SEND_DATA |
| 90 | else: |
| 91 | self.state = apdu_states.APDU_S_DATA |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 92 | else: |
| 93 | # check for 'only next byte' type ACK */ |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 94 | if c == ~(self.ins): |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 95 | self.state = apdu_states.APDU_S_DATA_SINGLE |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 96 | else: |
| 97 | # must be SW1 |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 98 | self.sw1 = c |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 99 | self.buf.append(c) |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 100 | self.state = apdu_states.APDU_S_SW2 |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 101 | |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 102 | def func_APDU_S_SW2(self, c): |
Christina Quast | 79c2a3a | 2015-04-14 14:55:13 +0200 | [diff] [blame] | 103 | self.buf.append(c) |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 104 | self.sw2 = c |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 105 | print("APDU:", HEX(self.ins), HEX(self.buf)) |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 106 | self.state = apdu_states.APDU_S_FIN |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 107 | |
| 108 | Apdu_S = { |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 109 | apdu_states.APDU_S_CLA : func_APDU_S_CLA_P1_P2, |
| 110 | apdu_states.APDU_S_INS : func_APDU_S_INS, |
| 111 | apdu_states.APDU_S_P1 : func_APDU_S_CLA_P1_P2, |
| 112 | apdu_states.APDU_S_P2 : func_APDU_S_CLA_P1_P2, |
| 113 | apdu_states.APDU_S_P3 : func_APDU_S_P3, |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 114 | apdu_states.APDU_S_SEND_DATA : func_APDU_S_DATA, |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 115 | apdu_states.APDU_S_DATA : func_APDU_S_DATA, |
| 116 | apdu_states.APDU_S_DATA_SINGLE : func_APDU_S_DATA_SINGLE, |
| 117 | apdu_states.APDU_S_SW1 : func_APDU_S_SW1, |
Christina Quast | 0d98b9f | 2015-05-03 14:22:51 +0200 | [diff] [blame] | 118 | apdu_states.APDU_S_SW2 : func_APDU_S_SW2, |
| 119 | apdu_states.PTS : func_PTS } |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 120 | |
Christina Quast | 19ed529 | 2015-06-24 15:23:59 +0200 | [diff] [blame] | 121 | INS_data_expected = [0xC0, 0xB0, 0xB2, 0x12, 0xF2] |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 122 | |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 123 | def split(self, c): |
Christina Quast | 19ed529 | 2015-06-24 15:23:59 +0200 | [diff] [blame] | 124 | # if c == 0xA0: |
| 125 | # self.state = apdu_states.APDU_S_CLA |
| 126 | print("state: ", self.state, hex(c)) |
Christina Quast | d4c8b51 | 2015-04-14 15:53:13 +0200 | [diff] [blame] | 127 | self.Apdu_S[self.state](self, c) |
Christina Quast | e64aa5b | 2015-04-14 15:07:33 +0200 | [diff] [blame] | 128 | |
| 129 | |
| 130 | if __name__ == '__main__': |
Christina Quast | 51925a6 | 2015-04-14 21:04:14 +0200 | [diff] [blame] | 131 | msg1 = [0xA0, 0xA4, 0x00, 0x00, 0x02, 0xA4, 0x7F, 0x20, 0x9F, 0x16] |
| 132 | msg2 = [0xA0, 0xC0, 0x00, 0x00, 0x16, 0xC0, |
| 133 | 0x00, 0x00, 0x00, 0x00, 0x7F, 0x20, |
| 134 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 135 | 0x09, 0x91, 0x00, 0x17, 0x04, 0x00, 0x00, 0x00, |
| 136 | 0x83, 0x8A, 0x90, 0x00] |
Christina Quast | 59dae92 | 2015-05-14 16:58:37 +0200 | [diff] [blame] | 137 | msg3 = [0xa0, 0xc0, 0x00, 0x00, 0x16, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x7f, |
| 138 | 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x91, 0x00, 0x17, |
| 139 | 0x04, 0x00, 0x83, 0x8a, 0x83, 0x8a, 0x90] |
| 140 | |
Christina Quast | 0d98b9f | 2015-05-03 14:22:51 +0200 | [diff] [blame] | 141 | pts = [0xff, 0x00, 0xff] |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 142 | apdus = [] |
| 143 | apdu = Apdu_splitter() |
Christina Quast | 59dae92 | 2015-05-14 16:58:37 +0200 | [diff] [blame] | 144 | for c in pts + msg2 + msg1 + msg3: |
Christina Quast | 9547e9f | 2015-04-14 22:18:30 +0200 | [diff] [blame] | 145 | apdu.split(c) |
| 146 | if apdu.state == apdu_states.APDU_S_FIN: |
| 147 | apdus.append(apdu) |
| 148 | apdu = Apdu_splitter() |
| 149 | for a in apdus: |
Christina Quast | fb91bb7 | 2015-04-18 13:31:42 +0200 | [diff] [blame] | 150 | print(HEX(a.buf)) |