https://gbatemp.net/threads/aes-key-scrambler.406951/
lol it's your thread. I think I'm confused of which keys are we searching.
EDIT: checked it, and the ncch keyx is missing anyways...
We know the xorpad, C, and the keyY, can't we get keyX using the keyscrambler normalkey equation? (If not, please don't kill me and explain why)
We can't solve for two unknowns (which are: 'KeyX' and 'NormalKey'), we only have the 'Constant' + 'KeyY'
We need to know THREE of these: KeyX / KeyY / NormalKey / Constant.
To get 'NormalKey' we need: KeyX + KeyY + Constant.
To get 'KeyX' we need: NormalKey + Constant + KeyY.
To get 'KeyY' we need: KeyX + NormalKey + Constant.
To get 'Constant' we need: NormalKey + KeyX + KeyY.
The formulas to get the missing data when the other three parts are known are:
NormalKey = rol((rol(KeyX, 2, 128) ^ KeyY) + Constant, 87, 128)
KeyX = rol(((rol(NormalKey, 41, 128) - Constant) ^ KeyY), 126, 128)
KeyY = rol(KeyX, 2, 128) ^ (rol(NormalKey, 41, 128) - Constant)
Constant = rol(NormalKey, 41, 128) - (rol(KeyX, 2, 128) ^ KeyY)
Note: rol is a 'Rotate Left': (Value, NumberOfBitsToRotate, SizeOfValueInBits), and the '^' is a bitwise XOR
The XORPAD is made by repeatedly decrypting 16 bytes of 00's with AES CTR Mode (which we cannot reverse) and writing the output to a file.
This output data can then be XORED with the Encrypted data to Decrypt it (or XORED with Decrypted data to Encrypt it)
To get the XORPAD you need to know the NormalKey + IV, to know the NormalKey you need to know the: KeyX + KeyY + Constant.
For 3DS Game Cards, I think the 'IV' is generated using the Gamecard 'TitleID' and the KeyY is the first 16 bytes of the NCCH RSA-2048 Signature.
KeyX (Slot 0x2C) is set by the 3DS BootRom and the Constant is in the AES Hardware Engine.
This is why we need to use the 3DS to encrypt / decrypt things, If we had the bootrom, we would then know KeyX so then we
could use it to generate the NormalKey which will allow us to encrypt/decrypt anything we wanted on our PCs instead of the 3DS.
Example Python 2.7 Code:
Code:
from Crypto.Cipher import AES
from Crypto.Util import Counter
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def to_bytes(num):
numstr = ''
tmp = num
while len(numstr) < 16:
numstr += chr(tmp & 0xFF)
tmp >>= 8
return numstr[::-1]
# Random Data, not real Keys :P
KeyX = 0xBCC4162C2A0691EE471886B8EB2FB548
KeyY = 0x6B42BFBBE653CB83B5C579D8A2E7AA1D
Const = 0x2A0DDE349C3AC1E50670D5740CC83658
IV = 0xEE259C9A27DD55983DEC4F4568D6975C
Data = 0xD9C4605307FE37BD02746E7DD40586F1
# Get the Normal Key Using KeyX + KeyY + Constant
NormalKey = rol((rol(KeyX, 2, 128) ^ KeyY) + Const, 87, 128)
# Setup AES to get XORPAD
ctr = Counter.new(128, initial_value=IV)
ctrmode = AES.new(to_bytes(NormalKey), AES.MODE_CTR, counter = ctr)
# The XORPAD is just 16 decrypted 0x00 bytes, decrypting data increases the counter
# so you can repeat the decrypt operation as many times as you need.
# This data can then be XORED with Encrypted data to get Decrypted data and vice-versa.
Xorpad = ctrmode.decrypt(b'\x00' * 16)
# Setup AES again - This time to Decrypt Data
ctr = Counter.new(128, initial_value=IV)
ctrmode = AES.new(to_bytes(NormalKey), AES.MODE_CTR, counter = ctr)
# Decrypt the Data with AES.
DecData = ctrmode.decrypt(to_bytes(Data))
#Setup AES again - This time to Encrypt previously Decrypted Data.
ctr = Counter.new(128, initial_value=IV)
ctrmode = AES.new(to_bytes(NormalKey), AES.MODE_CTR, counter = ctr)
# Encrypt the previously Decrypted Data with AES.
EncData = ctrmode.encrypt(to_bytes(long(DecData.encode('hex'), 16)))
print "Key X : %032X" % (KeyX)
print "Key Y : %032X" % (KeyY)
print "Normal Key : %032X" % (NormalKey)
print "Counter/IV : %032X" % (IV)
print ""
print "Input Data : %032X" % (Data)
print "Xorpad : %032X" % long(Xorpad.encode('hex'), 16)
print "Decrypted : %032X" % long(DecData.encode('hex'), 16)
print ""
print "Decrypted : %032X" % long(DecData.encode('hex'), 16)
print "Xorpad : %032X" % long(Xorpad.encode('hex'), 16)
print "Encrypted : %032X" % long(EncData.encode('hex'), 16)
print ""
raw_input('Press Enter to Exit...')