Guest User

Untitled

a guest
Sep 10th, 2020
163
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #This is for Python 2
  2. from Crypto.Cipher import AES #pycrypto. If on windows, http://www.voidspace.org.uk/python/modules.shtml#pycrypto
  3. import os, sys, struct
  4. import hashlib
  5.  
  6. def roundUp(v, align):
  7. return ((v + align - 1) / align) * align
  8.  
  9. dsidevcommonkey = 'a1604a6a7123b529ae8bec32c816fcaa'.decode('hex')
  10.  
  11. if len(sys.argv) == 1:
  12. print 'Usage: %s poop.tad' % (os.path.basename(__file__))
  13. raise SystemExit()
  14.  
  15. with open(sys.argv[1], 'rb') as f:
  16. if f.read(6) != '\x00\x00\x00\x20\x49\x73':
  17. print 'Likely not a tad file'
  18. raise SystemExit()
  19. f.read(2)
  20. certsize = struct.unpack('>I', f.read(4))[0]
  21. crlsize = struct.unpack('>I', f.read(4))[0]
  22. ticketsize = struct.unpack('>I', f.read(4))[0]
  23. tmdsize = struct.unpack('>I', f.read(4))[0]
  24. contentsize = struct.unpack('>I', f.read(4))[0]
  25. metasize = struct.unpack('>I', f.read(4))[0]
  26.  
  27. certOffset = roundUp(0x20, 64)
  28. crlOffset = roundUp(certOffset + certsize, 64)
  29. ticketOffset = roundUp(crlOffset + crlsize, 64)
  30. tmdOffset = roundUp(ticketOffset + ticketsize, 64)
  31. contentOffset= roundUp(tmdOffset + tmdsize, 64)
  32. metaOffset = roundUp(contentOffset + contentsize, 64)
  33. fileSize = roundUp(metaOffset + metasize, 64)
  34.  
  35. f.seek(ticketOffset+0x1BF) #encrypted title key
  36. enckey = f.read(16)
  37. f.seek(ticketOffset+0x1DC) #title id
  38. iv = f.read(8) + '\x00'*8
  39. titlekey = AES.new(dsidevcommonkey, AES.MODE_CBC, iv).decrypt(enckey)
  40.  
  41. f.seek(tmdOffset+0x1DE)
  42. numcontents = struct.unpack('>H', f.read(2))[0]
  43.  
  44. contents = []
  45. for i in xrange(numcontents): #parsing the tmd
  46. content = {}
  47. f.seek(tmdOffset+0x1E4+36*i)
  48. f.read(4) #content id
  49. content['idx'] = f.read(2) #content index
  50. f.read(2) #content type
  51. f.read(4) #first 4 bytes of content size. Not needed.
  52. content['size'] = struct.unpack('>I', f.read(4))[0]
  53. content['hash'] = f.read(20)
  54. contents.append(content)
  55.  
  56. offset = 0
  57. for content in contents:
  58. f.seek(contentOffset+offset)
  59. encdata = f.read(content['size'])
  60. iv = '\x00'*14 + content['idx']
  61. decdata = AES.new(titlekey, AES.MODE_CBC, iv).decrypt(encdata)
  62. hash = hashlib.sha1(decdata).digest()
  63. if hash != content['hash']:
  64. print 'Hash mismatch! Decryption error!'
  65. raise SystemExit()
  66. with open('%s_dec_%d.srl' % (os.path.splitext(os.path.basename(sys.argv[1]))[0], struct.unpack('>H', content['idx'])[0]), 'wb') as outf:
  67. outf.write(decdata)
  68. offset += roundUp(content['size'], 64)
RAW Paste Data