Skip to content

Instantly share code, notes, and snippets.

@SocraticBliss
Last active February 3, 2021 16:58
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SocraticBliss/4410790b6e5a27161f521c45d1eb2684 to your computer and use it in GitHub Desktop.
Save SocraticBliss/4410790b6e5a27161f521c45d1eb2684 to your computer and use it in GitHub Desktop.
CertNXtractionPack
@ECHO OFF
TITLE CertNXtractionPack by SocraticBliss and SimonMKWii (R)
ECHO: && ECHO PRE-REQUISITES:
ECHO -- Get your BIS Keys (via biskeydump)
ECHO -- Dump your SYSNAND (via hekate)
ECHO -- Decrypt your PRODINFO (BIS 0 Key) and Save to file - PRODINFO.bin to your working directory (via HacDiskMount)
ECHO -- keys.txt (ie. key = 32 digit hex value) file with the following keys...
ECHO --- master_key_00
ECHO --- rsa_private_kek_generation_source
ECHO --- ssl_rsa_kek_source_x
ECHO --- ssl_rsa_kek_source_y
ECHO:
REM Check the file dependencies
FOR %%G IN (CertNXtractionPack.py keys.txt openssl.exe PRODINFO.bin) DO (
IF NOT EXIST %%G (ECHO Error: Place %%G in this directory then run again! && SET ERRORLEVEL=1)
)
IF %ERRORLEVEL% NEQ 0 (ECHO: && PAUSE && EXIT /B)
REM Check if python is installed
ECHO ;%PATH%; | FIND /C /I "python" >NUL
IF %ERRORLEVEL% NEQ 0 (ECHO: && PAUSE && ECHO Error: Install Python to your path then run again! && EXIT /B)
REM Install dependencies (if needed)
ECHO Checking python module dependencies...
python.exe -m pip -q install -U pip setuptools pycryptodome enum34 future asn1
IF %ERRORLEVEL% NEQ 0 (ECHO: && PAUSE && EXIT /B)
REM Run Python Script
python.exe -W ignore::DeprecationWarning CertNXtractionPack.py
IF %ERRORLEVEL% NEQ 0 (ECHO: && PAUSE && EXIT /B)
REM Finish up!
openssl.exe x509 -inform DER -in certificate.der -outform PEM -out certificate.pem >NUL 2>&1
IF %ERRORLEVEL% NEQ 0 (ECHO: && PAUSE && EXIT /B)
openssl.exe rsa -inform DER -in privatekey.der -outform PEM -out privatekey.pem >NUL 2>&1
TYPE certificate.pem privatekey.pem > nx_tls_client_cert.pem 2>&1
openssl.exe pkcs12 -export -in nx_tls_client_cert.pem -out nx_tls_client_cert.pfx -passout pass:switch >NUL 2>&1
DEL certificate.der >NUL 2>&1
DEL privatekey.der >NUL 2>&1
ECHO:
ECHO Saved certificate.pem, privatekey.pem, nx_tls_client_cert.pem, and nx_tls_client_cert.pfx to your working directory.
ECHO pfx password = switch
ECHO:
PAUSE >NUL | SET/P=Press the any key to exit...
# Getting your SSL Private Key and Certificate
# Thanks again SciresM <3
# SocraticBliss and SimonMKWii (R)
from Crypto.Cipher import AES
from Crypto.Util import Counter
from binascii import unhexlify as uhx, hexlify as hx
from fractions import gcd
from hashlib import sha256
import asn1
import random
import sys
keys = {'master_key_00' : '0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA',
'rsa_private_kek_generation_source' : 'F3A68FC81509A41372EC479FD79019FE719A6DA7804B5557432A78F27DD74E49',
'ssl_rsa_kek_source_x' : '69A08E62E0AE507BB5DA0E65179AE3BE051FED3C49941DF4EF2956D36D30110C',
'ssl_rsa_kek_source_y' : '1C86F363265417D499229EB1C4ADC7479B2A15F931261F31EE6776AEB4C76542'}
def modinv(Q, P):
lastremainder, remainder = abs(Q), abs(P)
x, lastx, y, lasty = 0, 1, 1, 0
while remainder:
lastremainder, (quotient, remainder) = remainder, divmod(lastremainder, remainder)
x, lastx = lastx - quotient*x, x
y, lasty = lasty - quotient*y, y
if lastremainder != 1:
raise ValueError
return lastx * (-1 if Q < 0 else 1) % lasty * (-1 if P < 0 else 1)
def get_primes(D, N, E = 0x10001):
'''Computes P, Q given E,D where pow(pow(X, D, N), E, N) == X'''
assert(pow(pow(0xCAFEBABE, D, N), E, N) == 0xCAFEBABE) # Check privk validity
# code taken from https://stackoverflow.com/a/28299742
k = E*D - 1
if k & 1:
raise ValueError('\nError: Could not compute factors. Is private exponent incorrect?')
t = 0
while not k & 1:
k >>= 1;
t += 1
r = k
while True:
g = random.randint(0, N)
y = pow(g, r, N)
if y == 1 or y == N - 1:
continue
for j in range(1, t):
x = pow(y, 2, N)
if x == 1 or x == N - 1:
break
y = x
if x == 1:
break
elif x == N - 1:
continue
x = pow(y, 2, N)
if x == 1:
break
p = gcd(y - 1, N)
q = N // p
assert N % p == 0
if p < q:
p, q = q, p
return (p, q)
def write(input, data):
try:
with open(input, 'wb') as f:
f.write(data)
except:
raise SystemExit('\nError: Failed to write %s!' % input)
def read_at(fp, off, len):
fp.seek(off)
return fp.read(len)
def process(CAL0):
# Get your certificate...
certificate = read_at(CAL0, 0x0AE0, 0x800)
write('certificate.der', certificate)
# Generate the SSL RSA Kek...
unwrapped_kek = AES.new(keys['master_key_00'], AES.MODE_ECB).decrypt(keys['rsa_private_kek_generation_source'])
unwrapped_kekek = AES.new(unwrapped_kek, AES.MODE_ECB).decrypt(keys['ssl_rsa_kek_source_x'])
ssl_rsa_kek = AES.new(unwrapped_kekek, AES.MODE_ECB).decrypt(keys['ssl_rsa_kek_source_y'])
# Decrypt the Encrypted SSL Key...
enc_privatekey = read_at(CAL0, 0x3AE0, 0x10)
dec = AES.new(ssl_rsa_kek, AES.MODE_CTR, counter=Counter.new(128, initial_value=int(hx(enc_privatekey), 16))) \
.decrypt(read_at(CAL0, 0x3AF0, 0x120))
dec_privatekey = hx(dec[:0x100])
cert_dec = asn1.Decoder()
cert_dec.start(certificate)
cert_dec.enter() # Seq, 3 elem
cert_dec.enter() # Seq, 8 elem
cert_dec.read()
cert_dec.read()
cert_dec.read()
cert_dec.read()
cert_dec.read()
cert_dec.read()
cert_dec.enter()
cert_dec.enter()
t, v = cert_dec.read()
assert(v == '1.2.840.113549.1.1.1') # rsaEncryption(PKCS #1)
cert_dec.leave()
t, v = cert_dec.read()
rsa_decoder = asn1.Decoder()
rsa_decoder.start(v[1:])
rsa_decoder.enter()
t, N = rsa_decoder.read()
t, E = rsa_decoder.read()
D = int(dec_privatekey, 0x10)
if pow(pow(0xDEADCAFE, E, N), D, N) != 0xDEADCAFE:
raise SystemExit('\nError: Private key does not appear to be inverse of public key!')
P, Q = get_primes(D, N, E)
enc = asn1.Encoder()
enc.start()
enc.enter(0x10)
enc.write(0)
enc.write(N)
enc.write(E)
enc.write(D)
enc.write(P)
enc.write(Q)
enc.write(D % (P - 1))
enc.write(D % (Q - 1))
enc.write(modinv(Q, P))
enc.leave()
write('privatekey.der', enc.output())
def main():
hashes = dict((k,v) for k,v in keys.items())
sys.stdout.write('\nVerifying keys... ')
# Import Keys File...
try:
with open('keys.txt', 'r') as keysfile:
for line in keysfile:
for key in keys:
if key in line:
keys[key] = uhx(line.split('=')[1].strip())
except:
raise SystemExit('\nError: Failed to process keys.txt!')
# Compare Key Hashes...
for key, value in keys.items():
if (sha256(value.encode('utf-8')).hexdigest().upper() != hashes[key]):
raise SystemExit('\nError: %s was not found in keys.txt!' % key)
print('Success')
# Decrypted PRODINFO test...
try:
with open('PRODINFO.bin', 'rb') as CAL0:
if read_at(CAL0, 0x0, 0x4) == b'CAL0':
process(CAL0)
else:
raise Exception
except:
raise SystemExit('''
Error: Your PRODINFO.bin is not decrypted!
0) Get your BIS Keys (via biskeydump)
1) Save your SYSNAND backup (via hekate)
2) Decrypt your PRODINFO (via HacDiskMount) with BIS Key 0
3) Save to file -> PRODINFO.bin (to your working directory)
4) Run the CertNXtractionPack.cmd script again!
Error: Failed to properly read PRODINFO.bin!''')
if __name__=='__main__':
main()
@ioistired
Copy link

Using these commands generates an invalid PFX for me.

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