Skip to content

Instantly share code, notes, and snippets.

@SciresM
Last active February 23, 2019 02:29
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save SciresM/dba70bc2ee7eca11e1bd777ecb58ff16 to your computer and use it in GitHub Desktop.
Save SciresM/dba70bc2ee7eca11e1bd777ecb58ff16 to your computer and use it in GitHub Desktop.
Script for decrypting Splatoon 2 resources.
import sys, os, struct, zlib
from Crypto.Cipher import AES
def u32(x):
return (x & 0xFFFFFFFF)
KEY_MATERIAL = 'e413645fa69cafe34a76192843e48cbd691d1f9fba87e8a23d40e02ce13b0d534d10301576f31bc70b763a60cf07149cfca50e2a6b3955b98f26ca84a5844a8aeca7318f8d7dba406af4e45c4806fa4d7b736d51cceaaf0e96f657bb3a8af9b175d51b9bddc1ed475677260f33c41ddbc1ee30b46c4df1b24a25cf7cb6019794'
class sead_rand:
'''Implements Splatoon 2's mersenne random generator.'''
def __init__(self, seed):
self.seed = u32(seed)
self.state = [self.seed]
for i in xrange(1, 5):
self.state.append(u32(0x6C078965 * (self.state[-1] ^ (self.state[-1] >> 30)) + i))
self.state = self.state[1:]
def get_u32(self):
a = u32(self.state[0] ^ (self.state[0] << 11))
self.state[0] = self.state[1]
b = u32(self.state[3])
c = u32(a ^ (a >> 8) ^ b ^ (b >> 19))
self.state[1] = self.state[2]
self.state[2] = b
self.state[3] = c
return c
def decrypt_resource(path, fn, out_path = None):
if not out_path:
out_path = '%s.dec' % path
with open(path, 'rb') as f:
dat = f.read()
if dat[-8:] != 'nisasyst':
raise ValueError('Error: Input appears not to be an encrypted Splatoon 2 archive!')
seed = u32(zlib.crc32(fn))
print 'Seed = 0x%08x = crc32(%s)' % (seed, fn)
key_iv = ''
rnd = sead_rand(seed)
for _ in xrange(0x40):
key_iv += KEY_MATERIAL[(rnd.get_u32() >> 24)]
key_iv = key_iv.decode('hex')
key, iv = key_iv[:0x10], key_iv[0x10:]
print 'Key: %s' % key.encode('hex')
print 'IV: %s' % iv.encode('hex')
with open(out_path, 'wb') as f:
f.write(AES.new(key, AES.MODE_CBC, iv).decrypt(dat[:-8]))
print 'Decrypted %s to %s!' % (path, out_path)
def main(argc, argv):
if argc == 3:
decrypt_resource(argv[1], argv[2])
elif argc == 4:
decrypt_resource(argv[1], argv[2], argv[3])
else:
print 'Usage: %s in_file resource_path [out_file]' % argv[0]
print 'Example: %s TankInfo.byml Mush/TankInfo.byml' % argv[0]
if __name__ == '__main__':
main(len(sys.argv), sys.argv)
@khang06
Copy link

khang06 commented Jun 19, 2018

Here's a hint on using this.

Splatoon 2's resource encryption generates a key off of the path of the file. To decrypt CommonMsg_USen.szs, it would look something like

python nisasyst.py path/to/CommonMsg_USen.szs Message/CommonMsg_USen.szs

where path/to/CommonMsg_USen.szs is the path to where you have that file on your system. Don't change the second part unless you're decrypting a different file!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment