pyctr.crypto.engine module

Provides various tools to perform cryptographic operations with Nintendo 3DS data.

exception pyctr.crypto.engine.CryptoError[source]

Bases: PyCTRError

Generic exception for cryptography operations.

exception pyctr.crypto.engine.OTPLengthError[source]

Bases: CryptoError

OTP is the wrong length.

exception pyctr.crypto.engine.CorruptBootromError[source]

Bases: CryptoError

ARM9 bootROM hash does not match.

exception pyctr.crypto.engine.KeyslotMissingError[source]

Bases: CryptoError

Normal key is not set up for the keyslot.

exception pyctr.crypto.engine.TicketLengthError(length)[source]

Bases: CryptoError

Ticket is too small.

exception pyctr.crypto.engine.BootromNotFoundError[source]

Bases: CryptoError

ARM9 bootROM was not found. Main argument is a tuple of checked paths.

exception pyctr.crypto.engine.CorruptOTPError[source]

Bases: CryptoError

OTP hash does not match.

class pyctr.crypto.engine.Keyslot(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: IntEnum

AES engine keyslots used by the Nintendo 3DS. Values above 0x3F (63) are used by PyCTR, and do not exist on the actual hardware. Each value explains what the keyslot is used to decrypt or encrypt.

TWLNAND = 3

Entire TWL region, including twln, twlp, and the header.

CTRNANDOld = 4

CTRNAND for Old Nintendo 3DS.

CTRNANDNew = 5

CTRNAND for New Nintendo 3DS.

FIRM = 6

FIRM partitions.

AGB = 7

AGBSAVE partition if a GBA VC title was played.

CMACNANDDB = 11

CMAC for NAND dbs.

NCCH93 = 24

NCCH extra keyslot for titles exclusive to New Nintendo 3DS released after System Menu 9.3.0-21.

CMACCardSaveNew = 25
CardSaveNew = 26
NCCH96 = 27

NCCH extra keyslot for titles exclusive to New Nintendo 3DS released after System Menu 9.6.0-24.

CMACAGB = 36

CMAC for the AGBSAVE partition contents.

NCCH70 = 37

NCCH extra keyslot for titles released after System Menu 7.0.0-13.

NCCH = 44

NCCH original keyslot.

UDSLocalWLAN = 45
StreetPass = 46
Save60 = 47

Save key for retail games released after System Menu 6.0.0-11.

CMACSDNAND = 48
CMACCardSave = 51
SD = 52

SD card contents under “Nintendo 3DS”.

CardSave = 55
BOSS = 56

Used to encrypt SpotPass data.

DownloadPlay = 57
DSiWareExport = 58

Used when exporting DSiWare to the SD card.

CommonKey = 61

Titlekeys in tickets.

Boot9Internal = 63

Used for internal operations in the ARM9 BootROM, including decrypting OTP, FIRM sections from non-NAND sources, and generating console-unique keys.

DecryptedTitlekey = 64

CIA and CDN contents.

ZeroKey = 65

All zero key for NCCH titles using fixed crypto.

FixedSystemKey = 66

Special key for NCCH system titles using fixed crypto.

New3DSKeySector = 67

Used to decrypt the secret key sector (sector 0x96) for the New Nintendo 3DS.

NCCHExtraKey = 68

Stores a version of another keyslot used for NCCH titles. For titles without a seed, KeyY is taken from the NCCH header. For titles with a seed, KeyY is seeded. KeyX is always the same as the source keyslot.

class pyctr.crypto.engine.CryptoEngine(boot9=None, dev=False, setup_b9_keys=True)[source]

Bases: object

Emulates the AES engine of the Nintendo 3DS, including keyslots and the key scrambler.

Parameters:
  • boot9 (str) – Path to a dump of the protected region of the ARM9 BootROM. Defaults to None, which causes it to search a predefined list of paths.

  • dev (bool) – Whether to use devunit keys.

  • setup_b9_keys (bool) – Whether to automatically load keys from boot9.

key_x: Dict[int, int]
key_y: Dict[int, int]
key_normal: Dict[int, bytes]
dev: bool

Uses devunit keys.

b9_keys_set: bool

Keys have been set from the ARM9 BootROM.

b9_path: str | None

Path that the ARM9 BootROM was loaded from. Set when setup_keys_from_boot9_file() is called, which is automatically called on object creation if setup_b9_keys was True.

otp_keys_set: bool

Keys have been set from a dumped OTP region.

property b9_extdata_otp: bytes
property b9_extdata_keygen: bytes
property otp_key: bytes
property otp_iv: bytes
property otp_device_id: int
property otp_dec: bytes
property otp_enc: bytes
property id0: bytes

ID0 generated from a movable.sed. One must be loaded first with setup_sd_key() or setup_sd_key_from_file().

create_cbc_cipher(keyslot, iv)[source]

Create AES-CBC cipher with the given keyslot.

Parameters:
Returns:

An AES-CBC cipher object from PyCryptodome.

Return type:

CbcMode

create_ctr_cipher(keyslot, ctr)[source]

Create an AES-CTR cipher with the given keyslot.

Normal and DSi crypto will be automatically chosen depending on keyslot.

Parameters:
Returns:

An AES-CTR cipher object from PyCryptodome, or a wrapper for DSi keyslots.

Return type:

CtrMode | _TWLCryptoWrapper

create_ecb_cipher(keyslot)[source]

Create an AES-ECB cipher with the given keyslot.

Parameters:

keyslot (Keyslot) – Keyslot to use.

Returns:

An AES-ECB cipher object from PyCryptodome.

Return type:

EcbMode

create_cmac_object(keyslot)[source]

Create a CMAC object with the given keyslot.

Parameters:

keyslot (Keyslot) – Keyslot to use.

Returns:

A CMAC object from PyCryptodome.

Return type:

CMAC

create_ctr_io(keyslot, fh, ctr, closefd=False)[source]

Create an AES-CTR read-write file object with the given keyslot.

Parameters:
  • keyslot (Keyslot) – Keyslot to use.

  • fh (BinaryIO) – File-like object to wrap.

  • ctr (int) – Counter to start with.

  • closefd (bool) – Close underlying file object when closed.

Returns:

A file-like object that does decryption and encryption on the fly.

Return type:

CTRFileIO

create_cbc_io(keyslot, fh, iv, closefd=False)[source]

Create an AES-CBC read-only file object with the given keyslot.

Parameters:
  • keyslot (Keyslot) – Keyslot to use.

  • fh (BinaryIO) – File-like object to wrap.

  • iv (bytes) – Initialization vector.

  • closefd (bool) – Close underlying file object when closed.

Returns:

A file-like object that does decryption on the fly.

Return type:

CBCFileIO

static sd_path_to_iv(path)[source]

Generate an IV from an SD file path relevant to the root of an ID1 directory (e.g. /title/00040000/0f70c600/content/00000000.app). Both Unix- and Windows-style paths are accepted.

Parameters:

path (str) – SD file path.

Returns:

IV as an integer.

Return type:

int

load_encrypted_titlekey(titlekey, common_key_index, title_id)[source]

Decrypt an encrypted titlekey and store in keyslot 0x40 (Keyslot.DecryptedTitlekey).

Parameters:
  • titlekey (bytes) – Encrypted titlekey

  • common_key_index (int) – Common key Y to use. 0 for eShop, 1 for System.

  • title_id (Union[str, bytes]) – Title ID.

load_from_ticket(ticket)[source]

Load a titlekey from a ticket and set keyslot 0x40 to the decrypted titlekey.

Parameters:

ticket (bytes) –

set_keyslot(xy, keyslot, key)[source]

Sets a keyslot to the specified key.

Parameters:
set_normal_key(keyslot, key)[source]

Set the normal key for a keyslot.

Parameters:
  • keyslot (int) – Keyslot to set normal key of.

  • key (bytes) – 128-bit AES key in bytes.

keygen(keyslot)[source]

Generate a normal key based on the KeyX and KeyY for the keyslot.

Parameters:

keyslot (int) – Keyslot to load KeyX and KeyY from.

Returns:

Generated normal key.

Return type:

bytes

static keygen_manual(key_x, key_y)[source]

Generate a normal key using the 3DS AES key scrambler.

Parameters:
  • key_x (int) –

  • key_y (int) –

Return type:

bytes

static keygen_twl_manual(key_x, key_y)[source]

Generate a normal key using the DSi AES key scrambler.

Parameters:
  • key_x (int) –

  • key_y (int) –

Return type:

bytes

setup_keys_from_boot9(b9)[source]

Set up certain keys from an ARM9 bootROM dump.

Parameters:

b9 (bytes) –

setup_keys_from_boot9_file(path=None)[source]

Set up certain keys from an ARM9 bootROM file.

Parameters:

path (FilePath) –

setup_keys_from_otp(otp)[source]

Set up console-unique keys from an OTP dump. Encrypted and decrypted are supported.

Parameters:

otp (bytes) – OTP data, encrypted or decrypted.

setup_keys_from_otp_file(path)[source]

Set up console-unique keys from an OTP file. Encrypted and decrypted are supported.

Parameters:

path (FilePath) –

setup_sd_key(data)[source]

Set up the SD key from movable.sed. Must be 0x10 (only key), 0x120 (no cmac), or 0x140 (with cmac).

Parameters:

data (bytes) –

setup_sd_key_from_file(path)[source]

Set up the SD key from a movable.sed file.

Parameters:

path (FilePath) –

class pyctr.crypto.engine.CTRFileIO(file, crypto, keyslot, counter, closefd=False)[source]

Bases: _CryptoFileBase

Provides transparent read-write AES-CTR encryption as a file-like object.

Parameters:
read(size=-1)[source]
Parameters:

size (int) –

Return type:

bytes

write(data)[source]
Parameters:

data (bytes) –

Return type:

int

seek(seek, whence=0)[source]

Change stream position.

Change the stream position to the given byte offset. The offset is interpreted relative to the position indicated by whence. Values for whence are:

  • 0 – start of stream (the default); offset should be zero or positive

  • 1 – current stream position; offset may be negative

  • 2 – end of stream; offset is usually negative

Return the new absolute position.

Parameters:
  • seek (int) –

  • whence (int) –

Return type:

int

truncate(size=None)[source]

Truncate file to size bytes.

File pointer is left unchanged. Size defaults to the current IO position as reported by tell(). Returns the new size.

Parameters:

size (Optional[int]) –

Return type:

int

class pyctr.crypto.engine.TWLCTRFileIO(file, crypto, keyslot, counter, closefd=False)[source]

Bases: CTRFileIO

Provides transparent read-write TWL AES-CTR encryption as a file-like object.

Parameters:
read(size=-1)[source]
Parameters:

size (int) –

Return type:

bytes

write(data)[source]
Parameters:

data (bytes) –

Return type:

int

class pyctr.crypto.engine.CBCFileIO(file, crypto, keyslot, iv, closefd=False)[source]

Bases: _CryptoFileBase

Provides transparent read-only AES-CBC encryption as a file-like object.

Parameters:
read(size=-1)[source]
Parameters:

size (int) –

seek(seek, whence=0)[source]

Change stream position.

Change the stream position to the given byte offset. The offset is interpreted relative to the position indicated by whence. Values for whence are:

  • 0 – start of stream (the default); offset should be zero or positive

  • 1 – current stream position; offset may be negative

  • 2 – end of stream; offset is usually negative

Return the new absolute position.

Parameters:
  • seek (int) –

  • whence (int) –

writable()[source]

Return whether object was opened for writing.

If False, write() will raise OSError.

Return type:

bool