Last active
December 11, 2024 12:31
-
-
Save SocraticBliss/4410790b6e5a27161f521c45d1eb2684 to your computer and use it in GitHub Desktop.
CertNXtractionPack
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Using these commands generates an invalid PFX for me.