-
Notifications
You must be signed in to change notification settings - Fork 3
/
7B_DI_Converter.py
167 lines (141 loc) · 4.93 KB
/
7B_DI_Converter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import argparse
import os
import pathlib
from typing import Tuple
import time
import binascii
import hashlib
import re
import sys
# mifare classic mini DI 7b uid binary to flipper .nfc converter.
# Created by Equipter with code portions borrowed from Lucaslhm/AmiiboFlipperConverter
# V1.07
# Modified by FalsePhilospher to work with DI toys
# Function from infsha.py
uidre = re.compile('^04[0-9a-f]{12}$', re.IGNORECASE)
magic_nums = [3, 5, 7, 23, 9985861487287759675192201655940647, 38844225342798321268237511320137937]
def calc_keya(uid, sector):
if uidre.match(uid) is None:
raise ValueError('invalid UID (seven hex bytes)')
if sector < 0 or sector > 4:
raise ValueError('invalid sector (0-4)')
PRE = format(magic_nums[0] * magic_nums[1] * magic_nums[3] * magic_nums[5], '032x')
POST = format(magic_nums[0] * magic_nums[2] * magic_nums[4], '030x')
sha1 = hashlib.sha1()
sha1.update(binascii.unhexlify(PRE + uid + POST))
key = sha1.digest()
return binascii.hexlify(key[3::-1] + key[7:5:-1]).decode()
# Functions from 7B_Converter.py
def write_output(name: str, assemble: str, out_dir: str):
with open(os.path.join(out_dir, f"{name}.nfc"), "wt") as f:
f.write(assemble)
def convert(contents: bytes) -> Tuple[str, int, int]:
buffer = []
Block_count = 0
Mf_size = 0
Block = []
key_a = None
uid = get_uid(contents).replace(' ', '')
key_a = calc_keya(uid, 0).upper()
formatted_key_a = ' '.join([key_a[i:i+2] for i in range(0, len(key_a), 2)])
for i in range(len(contents)):
byte = contents[i : i + 1].hex()
Block.append(byte)
if len(Block) == 16:
if Block_count in [2, 3, 7, 11, 15, 19]: # Insert Key A in these blocks
Block[0:6] = formatted_key_a.split() # Insert Key A
Block[10:16] = formatted_key_a.split() # Insert Key B
buffer.append(f"Block {Block_count}: {' '.join(Block).upper()}")
Block = []
Block_count += 1
if Block_count == 64:
Mf_size = 1
elif Block_count == 128:
Mf_size = 2
elif Block_count == 256:
Mf_size = 4
return "\n".join(buffer), Block_count, Mf_size
def get_uid(contents: bytes) -> str:
Block = []
for i in range(7):
byte = contents[i : i + 1].hex()
Block.append(byte)
return " ".join(Block).upper()
def get_sak(contents: bytes) -> str:
Block = []
for i in range (7,8):
sak = contents[i : i + 1].hex()
Block.append(sak)
return " ".join(Block).upper()
def get_atqa(contents: bytes) -> str:
Block = []
for i in range (8,10):
atqa = contents[i : i + 1].hex()
Block.append(atqa)
return " ".join(Block).upper()
def assemble_code(contents: bytes) -> str:
conversion, Block_count, Mf_size = convert(contents)
uid = get_uid(contents)
key_a = calc_keya(uid.replace(' ', ''), 0) # Calculate key A
return f"""Filetype: Flipper NFC device
Version: 4
# Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card
Device type: Mifare Classic
# UID, ATQA and SAK are common for all formats
UID: {uid}
ATQA: 00 44
SAK: 09
# Mifare Classic specific data
Mifare Classic type: MINI
Data format version: 2
# Mifare Classic Blocks, '??' means unknown data
# Key A: {key_a}
{conversion}
"""
def convert_file(input_path: str, output_path: str):
input_extension = os.path.splitext(input_path)[1]
if input_extension == ".bin":
with open(input_path, "rb") as file:
contents = file.read()
name = os.path.split(input_path)[1]
write_output(name.split(".bin")[0], assemble_code(contents), output_path)
def process(path: str, output_path: str):
if os.path.isfile(path):
convert_file(path, output_path)
else:
for filename in os.listdir(path):
new_path = os.path.join(path, filename)
if os.path.isfile(new_path):
convert_file(new_path, output_path)
else:
process(new_path, output_path)
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"-i",
"--input-path",
required=True,
type=pathlib.Path,
help="Single file or directory path to convert",
)
parser.add_argument(
"-o",
"--output-path",
required=False,
type=pathlib.Path,
help="Output path, if not specified, the output .nfc file will be created in the same directory the .bin file exists within.",
)
args = parser.parse_args()
return args
def main():
args = get_args()
if os.path.isfile(args.input_path):
if not args.output_path:
args.output_path = os.path.split(args.input_path)[0]
os.makedirs(args.output_path, exist_ok=True)
process(args.input_path, args.output_path)
if __name__ == "__main__":
main()
print("Converting...")
time.sleep(0.3)
print("Completed Conversion")