Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import argparse
- import binascii
- import collections
- import struct
- import sys
- from Crypto.Cipher import AES
- from Crypto.Hash import HMAC
- from Crypto.Hash import SHA256
- from Crypto.Util import Counter
- DUMP_SIZE = 540
- PAGE_SIZE = 4
- CT = 0x88
- PACK = b'\x80\x80'
- CC = b'\xF1\x10\xFF\xEE'
- STATIC_LOCK = b'\x00\x0F\xE0'
- DYNAMIC_LOCK = b'\x01\x00\x0F\x00'
- CFG0 = b'\x00\x00\x00\x04'
- CFG1 = b'\x5F\x00\x00\x00'
- C_PWD_AUTH = b'\x1B'
- MasterKeys = collections.namedtuple('MasterKeys',
- ('hmac_key', 'type_string', 'magic', 'xor_pad'))
- DerivedKeys = collections.namedtuple('DerivedKeys',
- ('aes_key', 'aes_iv', 'hmac_key'))
- class FileType(argparse.FileType):
- """Fix for binary stdin/stdout on Windows."""
- def __call__(self, string):
- f = super(FileType, self).__call__(string)
- if string == '-' and 'b' in self._mode and sys.platform == 'win32':
- import os, msvcrt
- msvcrt.setmode(f.fileno(), os.O_BINARY)
- return f
- class Drbg(object):
- def __init__(self, hmac_key, seed):
- self._hmac_key = hmac_key
- self._seed = bytes(seed)
- self._iteration = 0
- self._cache = None
- self._pos = 0
- def _update(self):
- hmac = HMAC.new(self._hmac_key, digestmod=SHA256)
- hmac.update(struct.pack('>H', self._iteration))
- hmac.update(self._seed)
- self._iteration += 1
- self._cache = hmac.digest()
- self._pos = 0
- def get_bytes(self, length):
- result = bytearray()
- while len(result) < length:
- if self._cache is None or self._pos >= len(self._cache):
- self._update()
- l = min(length - len(result), len(self._cache) - self._pos)
- result.extend(memoryview(self._cache)[self._pos:self._pos + l])
- self._pos += l
- return bytes(result)
- def get_master_keys(keyfile):
- hmac_key = keyfile.read(16)
- type_string = keyfile.read(14)
- keyfile.read(1)
- magic_size = ord(keyfile.read(1))
- magic = keyfile.read(magic_size)
- keyfile.read(16 - magic_size)
- xor_pad = bytearray(keyfile.read(32))
- return MasterKeys(hmac_key, type_string, magic, xor_pad)
- def read_uid(uidfile):
- uid = uidfile.read(7)
- return uid
- def get_base_seed(data):
- base_seed = bytearray()
- base_seed.extend(data[0x11:0x13])
- base_seed.extend(b'\0' * 0x0E)
- for _ in range(2):
- base_seed.extend(data[0x00:0x08])
- base_seed.extend(data[0x60:0x80])
- return base_seed
- def get_seed(master_keys, base_seed):
- seed = bytearray()
- seed.extend(master_keys.type_string);
- seed.extend(memoryview(base_seed)[0:16 - len(master_keys.magic)])
- seed.extend(master_keys.magic)
- seed.extend(memoryview(base_seed)[0x10:0x20])
- for i in range(0x20):
- seed.append(base_seed[0x20 + i] ^ master_keys.xor_pad[i])
- return seed
- def get_derived_keys(master_keys, data):
- base_seed = get_base_seed(data)
- seed = get_seed(master_keys, base_seed)
- drbg = Drbg(master_keys.hmac_key, seed)
- aes_key = drbg.get_bytes(16)
- aes_iv = drbg.get_bytes(16)
- hmac_key = drbg.get_bytes(16)
- return DerivedKeys(aes_key, aes_iv, hmac_key)
- def set_uid(uid):
- return bytearray((uid[0],uid[1],uid[2],
- CT ^ uid[0] ^ uid[1] ^ uid[2],
- uid[3],uid[4],uid[5],uid[6],
- uid[3] ^ uid[4] ^ uid[5] ^ uid[6],))
- def get_pwd(uid):
- return bytearray((
- 0xAA ^ uid[1] ^ uid[3],
- 0x55 ^ uid[2] ^ uid[4],
- 0xAA ^ uid[3] ^ uid[5],
- 0x55 ^ uid[4] ^ uid[6],
- ))
- def cipher(mode, aes_key, aes_iv, data):
- ctr = Counter.new(8 * AES.block_size,
- initial_value=int(binascii.hexlify(aes_iv), 16))
- aes = AES.new(key=aes_key, mode=AES.MODE_CTR, counter=ctr)
- f = getattr(aes, mode)
- data[0x014:0x034] = f(data[0x014:0x034].tobytes())
- data[0x0A0:0x208] = f(data[0x0A0:0x208].tobytes())
- def hmac(hmac_key, data):
- hmac = HMAC.new(hmac_key, digestmod=SHA256)
- hmac.update(data[0x011:0x034].tobytes())
- hmac.update(data[0x0A0:0x208].tobytes())
- hmac.update(data[0x034:0x054].tobytes())
- hmac.update(data[0x000:0x008].tobytes())
- hmac.update(data[0x054:0x080].tobytes())
- return hmac.digest()
- def hmac2(hmac_key, data):
- hmac = HMAC.new(hmac_key, digestmod=SHA256)
- #hmac.update(data[0x011:0x034].tobytes())
- #hmac.update(data[0x0A0:0x208].tobytes())
- #hmac.update(data[0x034:0x054].tobytes())
- hmac.update(data[0x000:0x008].tobytes())
- hmac.update(data[0x54:0x080].tobytes())
- #hmac.update(data[0x208:0x21C].tobytes())
- return hmac.digest()
- def decrypt(master_keys, data):
- derived_keys = get_derived_keys(master_keys, data)
- cipher('decrypt', derived_keys.aes_key, derived_keys.aes_iv, data)
- if not data[0x80:0xA0] == hmac(derived_keys.hmac_key, data):
- raise RuntimeError('Signature check failed')
- def scan(master_keys):
- tag = get_ntag215()
- data = bytearray()
- for page in range(0, DUMP_SIZE // PAGE_SIZE, 4):
- data.extend(tag.read(page))
- data = memoryview(data)[0:DUMP_SIZE]
- decrypt(master_keys, data)
- return data
- def encrypt(master_keys, data):
- data[0x00:0x09]=set_uid(uid)
- derived_keys = get_derived_keys(master_keys, data)
- derived_keys2 = get_derived_keys(master_keys2, data)
- pwd = get_pwd(uid)
- data[0x34:0x54] = hmac2(derived_keys2.hmac_key, data)
- print (data[0x34])
- data[0x0C:0x10]=CC
- data[0x09:0x0C]= STATIC_LOCK
- data[0x208:0x20C]= DYNAMIC_LOCK
- data[0x214:0x218]= pwd
- data[0x218:0x21C]= PACK + b'\0\0'
- data[0x20C:0x210]= CFG0
- data[0x210:0x214]= CFG1
- data[0x80:0xA0] = hmac(derived_keys.hmac_key, data)
- cipher('encrypt', derived_keys.aes_key, derived_keys.aes_iv, data)
- if __name__ == '__main__':
- parent_parser_infile = argparse.ArgumentParser(add_help=False)
- parent_parser_infile.add_argument('-i', '--infile', default='-',
- type=FileType('rb'),
- help='input file; if not specified, stdin will be used')
- parent_parser_outfile = argparse.ArgumentParser(add_help=False)
- parent_parser_outfile.add_argument('-o', '--outfile', default='-',
- type=FileType('wb'),
- help='output file; if not specified, stdout will be used')
- parser = argparse.ArgumentParser()
- parser.add_argument('-k', '--keyfile', required=True,
- type=FileType('rb'),
- help='key set file; for retail amiibo, use "retail unfixed" key set')
- parser.add_argument('-m', '--keyfile2', required=True,
- type=FileType('rb'),
- help='masterkey set file; for retail amiibo, use "locked secret" key set')
- parser.add_argument('-u', '--uid', required=True,type=FileType('rb'),
- help='UUID of blank tag')
- subparsers = parser.add_subparsers(dest='command')
- parser_scan = subparsers.add_parser('decrypt',
- parents=(parent_parser_infile, parent_parser_outfile),
- help='decrypt and check amiibo dump')
- parser_scan = subparsers.add_parser('encrypt',
- parents=(parent_parser_infile, parent_parser_outfile),
- help='encrypt and sign amiibo dump')
- args = parser.parse_args()
- master_keys2 = get_master_keys(args.keyfile2)
- master_keys = get_master_keys(args.keyfile)
- uid = read_uid(args.uid)
- if hasattr(args, 'infile'):
- data = memoryview(bytearray(args.infile.read(DUMP_SIZE)))
- if args.command == 'decrypt':
- decrypt(master_keys, data)
- elif args.command == 'encrypt':
- encrypt(master_keys, data)
- if hasattr(args, 'outfile'):
- args.outfile.write(data.tobytes())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement