/dev/crypto
/dev/crypto is the IOSU device node for the cryptographic engine. It can only be opened by the IOSU and it also provides a stripped down library (IOSC) that is implemented on most IOSU modules under the name "crypto_ios_interface". Requests are issued via ioctl()/ioctlv() commands which are then mapped to internal functions inside the IOS-CRYPTO process. This is done using different message queues, each one mapping a subset of commands in a jump table:
0x00: Mapped by the 3rd message queue 0x01: Mapped by the 3rd message queue 0x02: Mapped by the 4th message queue 0x03: Mapped by the 4th message queue 0x04: Mapped by the 4th message queue 0x05: Mapped by the 4th message queue 0x06: Mapped by the 3rd message queue 0x07: Mapped by the 4th message queue 0x08: Mapped by the 4th message queue 0x09: Mapped by the 3rd message queue 0x0A: Mapped by the 3rd message queue 0x0B: Mapped by the 2nd message queue | Mapped by the 4th message queue (async version) 0x0C: Mapped by the 2nd message queue 0x0D: Mapped by the 2nd message queue 0x0E: Mapped by the 4th message queue 0x0F: Mapped by the 2nd message queue | Mapped by the 4th message queue (async version) 0x10: Mapped by the 4th message queue 0x11: Mapped by the 3rd message queue 0x12: Mapped by the 4th message queue 0x13: Mapped by the 4th message queue 0x14: Mapped by the 1st message queue 0x15: Mapped by the 3rd message queue 0x16: Mapped by the 4th message queue 0x17: Mapped by the 4th message queue 0x18: Not mapped 0x19: Mapped by the 2nd message queue 0x1A: Mapped by the 2nd message queue 0x1B: Mapped by the 1st message queue 0x1C: Mapped by the 2nd message queue 0x1D: Mapped by the 1st message queue 0x1E: Mapped by the 1st message queue 0x1F: Mapped by the 4th message queue 0x20: Mapped by the 4th message queue 0x21: Mapped by the 1st message queue 0x22: Mapped by the 3rd message queue
List of functions (ioctl/ioctlv)
Command | Function | Call | Description | Notes | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
0x01 | IOSCError IOSC_CreateObject(u32* key_handle, IOSCObjectType type, IOSCObjectSubType subtype); | IOS_Ioctl(FD, 0x01, in_buf, 0x10, out_buf, 4); | Creates a new crypto object and returns a handle for it. | |||||||||
0x02 | IOSCError IOSC_DeleteObject(u32 key_handle); | IOS_Ioctl(FD, 0x02, in_buf, 4, 0, 0); | Deletes a crypto object. | |||||||||
0x03 | IOSCError IOSC_ImportSecretKey(IOSCSecretKeyHandle importedHandle, IOSCSecretKeyHandle verifyHandle, IOSCSecretKeyHandle decryptHandle, IOSCSecretKeySecurity flag, u8 * signbuffer, u32 signbufferSize, u8 * ivData, u32 ivSize, u8 * keybuffer, u32 keybufferSize); | IOS_Ioctlv(FD, 0x03, 4, 0, vector); | ||||||||||
0x04 | IOSCError IOSC_ExportSecretKey(IOSCSecretKeyHandle exportedHandle, IOSCSecretKeyHandle signHandle, IOSCSecretKeyHandle encryptHandle, IOSCSecretKeySecurity security_flag, u8 * signbuffer, u32 signbufferSize, u8 * ivData, u32 ivSize, u8 * keybuffer, u32 keybufferSize); | IOS_Ioctlv(FD, 0x04, 1, 3, vector); | ||||||||||
0x05 | IOSCError IOSC_ImportPublicKey(u8 * publicKeyData, u32 dataSize, u8 * exponent, u32 exponentSize, IOSCPublicKeyHandle publicKeyHandle); | IOS_Ioctlv(FD, 0x05, 3, 0, vector); | ||||||||||
0x06 | IOSCError IOSC_ExportPublicKey(u8 * publicKeyData, u32 dataSize, u8 * exponent, u32 exponentSize, IOSCPublicKeyHandle publicKeyHandle); | IOS_Ioctlv(FD, 0x06, 1, 3, vector); | ||||||||||
0x07 | IOSCError IOSC_ComputeSharedKey(IOSCSecretKeyHandle privateHandle, IOSCPublicKeyHandle publicHandle, IOSCSecretKeyHandle sharedHandle); | IOS_Ioctl(FD, 0x07, in_buf, 0x10, 0, 0); | ||||||||||
0x08 | IOSCError IOSC_SetData(IOSCDataHandle dataHandle, u32 value); | IOS_Ioctlv(FD, 0x08, 2, 0, vector); | ||||||||||
0x09 | IOSCError IOSC_GetData(IOSCDataHandle dataHandle, u32 * value); | IOS_Ioctlv(FD, 0x09, 1, 1, vector); | ||||||||||
0x0A | IOSCError IOSC_GetKeySize(u32 * keySize, IOSCKeyHandle handle); | IOS_Ioctl(FD, 0x0A, in_buf, 4, out_buf, 4); | ||||||||||
0x0B | IOSCError IOSC_GetSignatureSize(u32 * signSize, int handle); | IOS_Ioctl(FD, 0x0B, in_buf, 4, out_buf, 4); | ||||||||||
0x0C | IOSCError IOSC_GenerateHash(u8 * context, u32 contextSize, u8 * inputData, u32 inputSize, u32 chainingFlag, u8 * hashData, u32 outputSize); int IOSC_GenerateHashAsync(u8 * context, u32 contextSize, u8 * inputData, u32 inputSize, u32 chainingFlag, u8 * hashData, u32 outputSize, int message_queue_id, IOSRequest* reply); |
IOS_Ioctlv(FD, 0x0C, 3, 1, vector); IOS_IoctlvAsync(FD, 0x0C, 3, 1, vector, queueid, message); |
This function has 2 different implementations, one async and the other not. | |||||||||
0x0D | IOSCError IOSC_Encrypt(IOSCSecretKeyHandle encryptHandle, u8 * ivData, u32 ivSize, u8 * inputData, u32 inputSize, u8 * outputData, u32 outputSize); int IOSC_EncryptAsync(IOSCSecretKeyHandle encryptHandle, u8 * ivData, u32 ivSize, u8 * inputData, u32 inputSize, u8 * outputData, u32 outputSize, int message_queue_id, IOSRequest* reply); |
IOS_Ioctlv(FD, 0x0D, 3, 1, vector); IOS_IoctlvAsync(FD, 0x0D, 3, 1, vector, queueid, message); |
This function has 2 different implementations, one async and the other not. | |||||||||
0x0E | IOSCError IOSC_Decrypt(IOSCSecretKeyHandle decryptHandle, u8 * ivData, u32 ivSize, u8 * inputData, u32 inputSize, u8 * outputData, u32 outputSize); int IOSC_DecryptAsync((IOSCSecretKeyHandle decryptHandle, u8 * ivData, u32 ivSize, u8 * inputData, u32 inputSize, u8 * outputData, u32 outputSize, int message_queue_id, IOSRequest* request); |
IOS_Ioctlv(FD, 0x0E, 3, 1, vector); IOS_IoctlvAsync(FD, 0x0E, 3, 1, vector, queueid, message); |
This function has 2 different implementations, one async and the other not. | |||||||||
0x0F | IOSCError IOSC_VerifyPublicKeySign(u8 * inputData, u32 inputSize, IOSCPublicKeyHandle publicHandle, u8 * signData, u32 signSize); | IOS_Ioctlv(FD, 0x0F, 3, 0, vector); | ||||||||||
0x10 | IOSCError IOSC_GenerateBlockMAC(u8 * context, u32 contextSize, u8 * inputData, u32 inputSize, u8 * customData, u32 customDataSize, IOSCSecretKeyHandle signerHandle, u32 chainingFlag, u8 * signData, u32 signDataSize); IOSCError IOSC_GenerateBlockMACAsync(u8 * context, u32 contextSize, u8 * inputData, u32 inputSize, u8 * customData, u32 customDataSize, IOSCSecretKeyHandle signerHandle, u32 chainingFlag, u8 * signData, u32 signDataSize, int message_queue_id, IOSRequest* reply); |
IOS_Ioctlv(FD, 0x10, 4, 1, vector); IOS_IoctlvAsync(FD, 0x10, 4, 1, vector, queueid, message); |
This function has 2 different implementations, one async and the other not. | |||||||||
0x11 | IOSCError IOSC_ImportCertificate(u8 * certData, u32 certSize, IOSCPublicKeyHandle signerHandle, IOSCPublicKeyHandle publicKeyHandle); | IOS_Ioctlv(FD, 0x11, 2, 0, vector); | ||||||||||
0x12 | IOSCError IOSC_GetDeviceCertificate(IOSCEccSignedCert * certificate, u32 certificateSize); | IOS_Ioctl(FD, 0x12, 0, 0, out_buf, 0x180); | ||||||||||
0x13 | IOSCError IOSC_SetOwnership(u32 handle, u32 users); | IOS_Ioctlv(FD, 0x13, 2, 0, vector); | ||||||||||
0x14 | IOSCError IOSC_GetOwnership(u32 handle, u32 * users); | IOS_Ioctlv(FD, 0x14, 1, 1, vector); | ||||||||||
0x15 | IOSCError IOSC_GenerateRand(u8 * randBytes, u32 numBytes); | IOS_Ioctl(FD, 0x15, 0, 0, out_buf, out_size); | Generate random data of an arbitrary size. | |||||||||
0x16 | IOSCError IOSC_GenerateKey(IOSCKeyHandle handle); | IOS_Ioctl(FD, 0x16, in_buf, 4, 0, 0); | ||||||||||
0x17 | IOSCError IOSC_GeneratePublicKeySign(u8 * hash, u32 hashLength, IOSCSecretKeyHandle signerHandle, u8 * eccSignature, u32 signatureSize); | IOS_Ioctlv(FD, 0x17, 2, 1, vector); | ||||||||||
0x18 | IOSCError IOSC_GenerateCertificate(IOSCSecretKeyHandle privateHandle, IOSCCertName certname, IOSCEccSignedCert * certificate, u32 certSize); | IOS_Ioctlv(FD, 0x18, 2, 1, vector); | ||||||||||
0x19 | IOSCError IOSC_CheckDiHashes(u8 * destAddr, u8 * diskRdBuf, u32 h1Index, u32 h2Index, u8 * h3Ptr); | IOS_Ioctl(FD, 0x19, ???, ???, ???, ???); | This command is not mapped by the IOS-CRYPTO process and has been superseded by IOSC_ReadHashedBlock. | |||||||||
0x1A | odm_encrypt(); | IOS_Ioctlv(FD, 0x1A, 3, 2, vector); | ||||||||||
0x1B | odm_generate_session_key(); | IOS_Ioctlv(FD, 0x1B, 3, 1, vector); | ||||||||||
0x1C | get_security_level(); | IOS_Ioctl(FD, 0x1C, 0, 0, out_buf, 4); | Gets the security level flag from the OTP. | |||||||||
0x1D | IOSCError IOSC_ReadHashedBlock(u8 * destAddr, u8 * diskRdBuf, u32 h1Index, u32 h2Index, u8 * h3Ptr); | IOS_Ioctlv(FD, 0x1D, 5, 1, vector); | ||||||||||
0x1E | read_wii_seeprom_data(); | IOS_Ioctl(FD, 0x1E, 0, 0, out_buf, 0x60); | Reads the old Wii SEEPROM certificate data from OTP's bank 6. | |||||||||
0x1F | generate_wagonu_key(); | IOS_Ioctl(FD, 0x1F, in_buf, 0x10, 0, 0); | Generates the 0x12-keyhandle keydata used to encrypt/decrypt data for Wii U to Wii U system transfers. | If in_buf is NULL, a key from SEEPROM is used. If in_buf is not NULL, then it must be a pointer to a user supplied key. | ||||||||
0x20 | IOSC_EncryptBlocks(IOSCSecretKeyHandle keyHandle, int mode, u8 * ivOrNonce, u32 ivOrNonceSize, u8 * inData, u32 inSize, u8 * outData, u8 * outSize); | IOS_Ioctlv(FD, 0x20, 3, 1, vector); | Software AES encryption, this supports multiple AES-modes (AES-CTR, ...). Used by IOS-PAD to encrypt amiibo data.
|
|||||||||
0x21 | IOSC_DecryptBlocks(IOSCSecretKeyHandle keyHandle, int mode, u8 * ivOrNonce, u32 ivOrNonceSize, u8 * inData, u32 inSize, u8 * outData, u8 * outSize); | IOS_Ioctlv(FD, 0x21, 3, 1, vector); | Software AES decryption version of the above ioctlv. Used by IOS-PAD to decrypt amiibo data. | |||||||||
0x22 | set_crypto_thread_priority(); | IOS_Ioctl(FD, 0x22, in_buf, 4, 0, 0); | Modifies the IOS-CRYPTO main thread's priority. | |||||||||
0x23 | get_wagon_certificate_data(); | IOS_Ioctl(FD, 0x23, in_buf, 0x10, out_buf, out_size); | Gets Wagon certificate data stored inside IOS-CRYPTO. | If the first word in in_buf is 0x00000000, a Root-CA00000003 with 0x400 bytes of size is written to out_buf. If the first word in in_buf is 0x00000001, a Root-CA00000003 MS00000012 with 0x240 bytes of size is written to out_buf. |
Key object handles
The above crypto commands use key/crypto object handles. These handles can be either from IOSC_CreateObject (which can then be initialized with IOSC_ImportSecretKey in the case of AES), or a built-in handle. The available built-in handles are listed below.
The maximum number of keyobject-handles is 0x80, hence the highest valid keyobject-handle is 0x7F. Keyobject-handles <=0x40 are reserved for built-in handles, the rest are available for user-processes. Commands which write keyobjects' keydata are only allowed to use handles with value >0x40 (user-process handles).
Handle | Type | Owner | Description |
---|---|---|---|
0x00 | ECC-B233 | IOS-MCP | IOSC_DEV_SIGNING_KEY_HANDLE
Wii U device private key. |
0x01 | NONE | ALL | IOSC_DEV_ID_HANDLE
Wii U device ID. |
0x02 | AES-128 | IOS-FS | IOSC_FS_ENC_HANDLE
SLC NAND key. |
0x03 | HMAC-SHA-1 | IOS-FS | IOSC_FS_MAC_HANDLE
SLC NAND HMAC key. |
0x04 | AES-128 | IOS-MCP | IOSC_COMMON_ENC_HANDLE
Wii common key. |
0x05 | AES-128 | IOS-MCP | IOSC_BACKUP_ENC_HANDLE
Wii U backup key. Used by commands 0x15, 0x16, 0x17 and 0x18. |
0x06 | AES-128 | ALL | IOSC_APP_ENC_HANDLE
Wii SD key. |
0x07 | AES-128 | IOS-MCP | IOSC_BOOTOSVER_ENC_HANDLE
SEEPROM key. |
0x08 | NONE | NONE | IOSC_CACRLVER_HANDLE
Unused. |
0x09 | NONE | NONE | IOSC_SIGNERCRLVER_HANDLE
Unused. |
0x0A | NONE | NONE | IOSC_FSVER_HANDLE
Unused. |
0x0B | AES-128 | IOS-MCP | IOSC_COMMON2_ENC_HANDLE
Wii common2 key. |
0x0C | AES-128 | IOS-FS | Drive key |
0x0D | AES-128 | IOS-MCP | Starbuck ancast key |
0x0E | RSA-2048 | IOS-MCP | Starbuck ancast modulus |
0x0F | RSA-2048 | IOS-MCP | Boot1 ancast modulus |
0x10 | AES-128 | IOS-MCP | Wii U common key |
0x11 | AES-128 | IOS-FS | MLC NAND key |
0x12 | AES-128 | IOS-MCP
IOS-FS |
STRM key
Generated by ECB-encrypting the IVS seed from SEEPROM with the IVS key from the OTP. Used for USB WFS and WagonU file streaming. |
0x13 | AES-128 | IOS-FS | SLCCMPT NAND key |
0x14 | HMAC-SHA-1 | IOS-FS | SLCCMPT NAND HMAC key |
0x15 | AES-128 | IOS-MCP | vWii common key |
0x16 | AES-128 | IOS-PAD | DRH WLAN data key |
0x17 | AES-128 | IOS-NET | UDS local-WLAN CCMP key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. Shared with the 3DS. |
0x18 | AES-128 | IOS-NET | DLP key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. Shared with the 3DS. |
0x19 | AES-128 | ALL | APT wrap key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. Shared with the 3DS. |
0x1A | AES-128 | IOS-FS | Wii media title key |
0x1B | AES-128 | IOS-NSEC | SSL RSA key encryption key |
0x1C | ECC-B233 | IOS-NSEC | Wii U device unique certificate private key |
0x1D | ECC-B233 | IOS-NSEC | Wii U device authentication common certificate private key |
0x1E | AES-128 | IOS-NSEC | APPSTORE objinfo/objdata key
Generated by copying the first 0x10 bytes of the Wii U device unique certificate private key. |
0x1F | AES-128 | IOS-NIM-BOSS | SpotPass data file key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x20 | HMAC-SHA-256 | IOS-NIM-BOSS | SpotPass data file HMAC key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x21 | HMAC-SHA-256 | IOS-NIM-BOSS | VersionList HMAC key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x22 | HMAC-SHA-256 | IOS-PAD | Amiibo HMAC key 1
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x23 | HMAC-SHA-256 | IOS-PAD | Amiibo HMAC key 2
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x24 | AES-128 | IOS-PAD | NFC key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x25 | AES-128 | IOS-PAD | Wii U NFC key block key
Generated by XORing the XOR key with static data inside IOS-CRYPTO. Used for decrypting the Wii U specific "unfixed infos" and "locked secret" keys. |
0x26 | AES-128 | IOS-FS | Unknown
Generated by XORing the XOR key with static data inside IOS-CRYPTO. |
0x27 | AES-128 | IOS-NIM-BOSS | Pushmore link key
Generated by XORing the XOR key with static data inside IOS-CRYPTO |
0x28 | AES-128 | IOS-FS | SHDD key
This key is only set for board types IH or ID. If the ShddConfig flag in SEEPROM is 0x0000 and the system is a development unit, it is the same as the MLC NAND key. If the ShddConfig flag in SEEPROM is 0xFFFF, it is generated by decrypting the SHDD seed from SEEPROM with the SHDD key from eFuses. |
0x29-0x40 | NONE | NONE | Unused |