Advertisement
Guest User

amiibo_encrypt.py

a guest
Feb 1st, 2016
395
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.18 KB | None | 0 0
  1. import argparse
  2. import binascii
  3. import collections
  4. import struct
  5. import sys
  6.  
  7. from Crypto.Cipher import AES
  8. from Crypto.Hash import HMAC
  9. from Crypto.Hash import SHA256
  10. from Crypto.Util import Counter
  11.  
  12. DUMP_SIZE = 540
  13. PAGE_SIZE = 4
  14. CT = 0x88
  15. PACK = b'\x80\x80'
  16. CC = b'\xF1\x10\xFF\xEE'
  17. STATIC_LOCK = b'\x00\x0F\xE0'
  18. DYNAMIC_LOCK = b'\x01\x00\x0F\x00'
  19. CFG0 = b'\x00\x00\x00\x04'
  20. CFG1 = b'\x5F\x00\x00\x00'
  21. C_PWD_AUTH = b'\x1B'
  22.  
  23. MasterKeys = collections.namedtuple('MasterKeys',
  24. ('hmac_key', 'type_string', 'magic', 'xor_pad'))
  25.  
  26. DerivedKeys = collections.namedtuple('DerivedKeys',
  27. ('aes_key', 'aes_iv', 'hmac_key'))
  28.  
  29. class FileType(argparse.FileType):
  30. """Fix for binary stdin/stdout on Windows."""
  31. def __call__(self, string):
  32. f = super(FileType, self).__call__(string)
  33. if string == '-' and 'b' in self._mode and sys.platform == 'win32':
  34. import os, msvcrt
  35. msvcrt.setmode(f.fileno(), os.O_BINARY)
  36. return f
  37.  
  38. class Drbg(object):
  39. def __init__(self, hmac_key, seed):
  40. self._hmac_key = hmac_key
  41. self._seed = bytes(seed)
  42. self._iteration = 0
  43. self._cache = None
  44. self._pos = 0
  45.  
  46. def _update(self):
  47. hmac = HMAC.new(self._hmac_key, digestmod=SHA256)
  48. hmac.update(struct.pack('>H', self._iteration))
  49. hmac.update(self._seed)
  50. self._iteration += 1
  51. self._cache = hmac.digest()
  52. self._pos = 0
  53.  
  54. def get_bytes(self, length):
  55. result = bytearray()
  56. while len(result) < length:
  57. if self._cache is None or self._pos >= len(self._cache):
  58. self._update()
  59. l = min(length - len(result), len(self._cache) - self._pos)
  60. result.extend(memoryview(self._cache)[self._pos:self._pos + l])
  61. self._pos += l
  62. return bytes(result)
  63.  
  64. def get_master_keys(keyfile):
  65. hmac_key = keyfile.read(16)
  66. type_string = keyfile.read(14)
  67. keyfile.read(1)
  68. magic_size = ord(keyfile.read(1))
  69. magic = keyfile.read(magic_size)
  70. keyfile.read(16 - magic_size)
  71. xor_pad = bytearray(keyfile.read(32))
  72. return MasterKeys(hmac_key, type_string, magic, xor_pad)
  73.  
  74. def read_uid(uidfile):
  75. uid = uidfile.read(7)
  76. return uid
  77.  
  78. def get_base_seed(data):
  79. base_seed = bytearray()
  80. base_seed.extend(data[0x11:0x13])
  81. base_seed.extend(b'\0' * 0x0E)
  82. for _ in range(2):
  83. base_seed.extend(data[0x00:0x08])
  84. base_seed.extend(data[0x60:0x80])
  85. return base_seed
  86.  
  87. def get_seed(master_keys, base_seed):
  88. seed = bytearray()
  89. seed.extend(master_keys.type_string);
  90. seed.extend(memoryview(base_seed)[0:16 - len(master_keys.magic)])
  91. seed.extend(master_keys.magic)
  92. seed.extend(memoryview(base_seed)[0x10:0x20])
  93. for i in range(0x20):
  94. seed.append(base_seed[0x20 + i] ^ master_keys.xor_pad[i])
  95. return seed
  96.  
  97. def get_derived_keys(master_keys, data):
  98. base_seed = get_base_seed(data)
  99. seed = get_seed(master_keys, base_seed)
  100. drbg = Drbg(master_keys.hmac_key, seed)
  101. aes_key = drbg.get_bytes(16)
  102. aes_iv = drbg.get_bytes(16)
  103. hmac_key = drbg.get_bytes(16)
  104. return DerivedKeys(aes_key, aes_iv, hmac_key)
  105.  
  106. def set_uid(uid):
  107. return bytearray((uid[0],uid[1],uid[2],
  108. CT ^ uid[0] ^ uid[1] ^ uid[2],
  109. uid[3],uid[4],uid[5],uid[6],
  110. uid[3] ^ uid[4] ^ uid[5] ^ uid[6],))
  111.  
  112. def get_pwd(uid):
  113. return bytearray((
  114. 0xAA ^ uid[1] ^ uid[3],
  115. 0x55 ^ uid[2] ^ uid[4],
  116. 0xAA ^ uid[3] ^ uid[5],
  117. 0x55 ^ uid[4] ^ uid[6],
  118. ))
  119.  
  120. def cipher(mode, aes_key, aes_iv, data):
  121. ctr = Counter.new(8 * AES.block_size,
  122. initial_value=int(binascii.hexlify(aes_iv), 16))
  123. aes = AES.new(key=aes_key, mode=AES.MODE_CTR, counter=ctr)
  124. f = getattr(aes, mode)
  125. data[0x014:0x034] = f(data[0x014:0x034].tobytes())
  126. data[0x0A0:0x208] = f(data[0x0A0:0x208].tobytes())
  127.  
  128. def hmac(hmac_key, data):
  129. hmac = HMAC.new(hmac_key, digestmod=SHA256)
  130. hmac.update(data[0x011:0x034].tobytes())
  131. hmac.update(data[0x0A0:0x208].tobytes())
  132. hmac.update(data[0x034:0x054].tobytes())
  133. hmac.update(data[0x000:0x008].tobytes())
  134. hmac.update(data[0x054:0x080].tobytes())
  135. return hmac.digest()
  136.  
  137. def hmac2(hmac_key, data):
  138. hmac = HMAC.new(hmac_key, digestmod=SHA256)
  139. #hmac.update(data[0x011:0x034].tobytes())
  140. #hmac.update(data[0x0A0:0x208].tobytes())
  141. #hmac.update(data[0x034:0x054].tobytes())
  142. hmac.update(data[0x000:0x008].tobytes())
  143. hmac.update(data[0x54:0x080].tobytes())
  144. #hmac.update(data[0x208:0x21C].tobytes())
  145. return hmac.digest()
  146.  
  147. def decrypt(master_keys, data):
  148. derived_keys = get_derived_keys(master_keys, data)
  149. cipher('decrypt', derived_keys.aes_key, derived_keys.aes_iv, data)
  150. if not data[0x80:0xA0] == hmac(derived_keys.hmac_key, data):
  151. raise RuntimeError('Signature check failed')
  152.  
  153. def scan(master_keys):
  154. tag = get_ntag215()
  155. data = bytearray()
  156. for page in range(0, DUMP_SIZE // PAGE_SIZE, 4):
  157. data.extend(tag.read(page))
  158. data = memoryview(data)[0:DUMP_SIZE]
  159. decrypt(master_keys, data)
  160. return data
  161.  
  162. def encrypt(master_keys, data):
  163. data[0x00:0x09]=set_uid(uid)
  164. derived_keys = get_derived_keys(master_keys, data)
  165. derived_keys2 = get_derived_keys(master_keys2, data)
  166. pwd = get_pwd(uid)
  167. data[0x34:0x54] = hmac2(derived_keys2.hmac_key, data)
  168. print (data[0x34])
  169. data[0x0C:0x10]=CC
  170. data[0x09:0x0C]= STATIC_LOCK
  171. data[0x208:0x20C]= DYNAMIC_LOCK
  172. data[0x214:0x218]= pwd
  173. data[0x218:0x21C]= PACK + b'\0\0'
  174. data[0x20C:0x210]= CFG0
  175. data[0x210:0x214]= CFG1
  176.  
  177. data[0x80:0xA0] = hmac(derived_keys.hmac_key, data)
  178. cipher('encrypt', derived_keys.aes_key, derived_keys.aes_iv, data)
  179.  
  180. if __name__ == '__main__':
  181. parent_parser_infile = argparse.ArgumentParser(add_help=False)
  182. parent_parser_infile.add_argument('-i', '--infile', default='-',
  183. type=FileType('rb'),
  184. help='input file; if not specified, stdin will be used')
  185. parent_parser_outfile = argparse.ArgumentParser(add_help=False)
  186. parent_parser_outfile.add_argument('-o', '--outfile', default='-',
  187. type=FileType('wb'),
  188. help='output file; if not specified, stdout will be used')
  189. parser = argparse.ArgumentParser()
  190. parser.add_argument('-k', '--keyfile', required=True,
  191. type=FileType('rb'),
  192. help='key set file; for retail amiibo, use "retail unfixed" key set')
  193. parser.add_argument('-m', '--keyfile2', required=True,
  194. type=FileType('rb'),
  195. help='masterkey set file; for retail amiibo, use "locked secret" key set')
  196. parser.add_argument('-u', '--uid', required=True,type=FileType('rb'),
  197. help='UUID of blank tag')
  198. subparsers = parser.add_subparsers(dest='command')
  199. parser_scan = subparsers.add_parser('decrypt',
  200. parents=(parent_parser_infile, parent_parser_outfile),
  201. help='decrypt and check amiibo dump')
  202. parser_scan = subparsers.add_parser('encrypt',
  203. parents=(parent_parser_infile, parent_parser_outfile),
  204. help='encrypt and sign amiibo dump')
  205. args = parser.parse_args()
  206. master_keys2 = get_master_keys(args.keyfile2)
  207. master_keys = get_master_keys(args.keyfile)
  208. uid = read_uid(args.uid)
  209. if hasattr(args, 'infile'):
  210. data = memoryview(bytearray(args.infile.read(DUMP_SIZE)))
  211. if args.command == 'decrypt':
  212. decrypt(master_keys, data)
  213. elif args.command == 'encrypt':
  214. encrypt(master_keys, data)
  215. if hasattr(args, 'outfile'):
  216. args.outfile.write(data.tobytes())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement