Editing Kirk
Jump to navigation
Jump to search
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 20: | Line 20: | ||
Both use the usual Weierstrass form. | Both use the usual Weierstrass form. | ||
== Elliptic curve for Kirk commands 1/2/3/ | == Elliptic curve for Kirk commands 1/2/3/10 == | ||
This curve is used for the ECDSA verification of Kirk commands 1, 2, 3 and | This curve is used for the ECDSA verification of Kirk commands 1, 2, 3 and 10. | ||
<pre> | <pre> | ||
Line 36: | Line 36: | ||
== Elliptic curve for the other commands == | == Elliptic curve for the other commands == | ||
This curved is used for Kirk commands | This curved is used for Kirk commands 12, 13, 14, 16 and 17. | ||
<pre> | <pre> | ||
Line 46: | Line 46: | ||
</pre> | </pre> | ||
The public key is variable. For the latest Pre-IPL version which add an additional ECDSA verification of the XOR of the block hashes, the public key is (0xBC660611A70BD7F2D140A48215C096D11D2D4112, 0xF0E9379AC4E0D387C542D091349DD15169DD5A87). | |||
== Code sample == | == Code sample == | ||
Line 116: | Line 116: | ||
|No | |No | ||
|- | |- | ||
|4~ | |4~131 | ||
|KIRK commands 4/7 decryption keys (128 possible ones) | |KIRK commands 4/7 decryption keys (128 possible ones) | ||
|Yes | |Yes | ||
Line 146: | Line 146: | ||
|} | |} | ||
= | = Per-console keys = | ||
Some Kirk commands like commands 16 and 18 use individual (per-console) seeds. The base per-console seed is the Fuse ID (6 bytes), which is transformed into a 0x30 bytes buffer ("key mesh"). This buffer is used to generate different keys depending on a seed. | |||
{| class="wikitable" | {| class="wikitable" | ||
|+ | |+ | ||
!Seed | !Seed | ||
!Usage | !Usage | ||
|- | |- | ||
|0 | |0 | ||
|Kirk commands 2 (encryption) & 3 (decryption) (the real encryption | |Kirk commands 2 (encryption) & 3 (decryption) (the real encryption & CMAC keys are random, but this per-console key is used to encrypt them) | ||
|- | |- | ||
|1 | |1 | ||
Line 313: | Line 175: | ||
|RNG buffer reseeding | |RNG buffer reseeding | ||
|} | |} | ||
<source lang="c"> | |||
typedef struct ScePspKeyMesh { // size is 0x30 | |||
SceUInt8 aes128cbc_key_1[0x10]; // used by Kirk commands 5 & 8 and 16 | |||
SceUInt8 aes128cbc_key_2[0x10]; // used by Kirk command 2 & 3, 6 & 9 and 18 | |||
SceUInt8 derivation_key[0x10]; // used to derive the 2 other keys | |||
} ScePspKeyMesh; | |||
<source lang=" | |||
typedef struct | |||
SceUInt8 | |||
SceUInt8 | |||
} | |||
</source> | </source> | ||
To generate the key mesh of a PSP, provided the Fuse ID (0xBC100090 and 0xBC100094 hardware registers), execute the following code. | |||
<source lang="c"> | |||
void gen_psp_individual_seed() { | |||
<source lang=" | int i, k; | ||
void | ScePspKeyMesh seed; | ||
u8 subkey_1[0x10], subkey_2[0x10]; | |||
rijndael_ctx aes_ctx; | |||
u8 fuseid[8]; | |||
// Byte-reverse the Fuse ID | |||
u32 g_fuse90 = *(u32 *)0xBC100090; | |||
u32 g_fuse94 = *(u32 *)0xBC100094; | |||
fuseid[7] = g_fuse90 &0xFF; | |||
fuseid[6] = (g_fuse90>>8) &0xFF; | |||
fuseid[5] = (g_fuse90>>16) &0xFF; | |||
fuseid[4] = (g_fuse90>>24) &0xFF; | |||
fuseid[3] = g_fuse94 &0xFF; | |||
fuseid[2] = (g_fuse94>>8) &0xFF; | |||
fuseid[1] = (g_fuse94>>16) &0xFF; | |||
fuseid[0] = (g_fuse94>>24) &0xFF; | |||
rijndael_set_key(&aes_ctx, ids_master_key, 128); // set ids_master_key as AES key | |||
for (i = 0; i < 0x10; i++) // initialize the subkeys using the Fuse ID | |||
subkey_2[i] = subkey_1[i] = fuseid[i % 8]; | |||
for (i = 0; i < 3; i++) { // encrypt first subkey three times, and decrypt second subkey three times | |||
rijndael_encrypt(&aes_ctx, subkey_1, subkey_1); | |||
rijndael_decrypt(&aes_ctx, subkey_2, subkey_2); | |||
} | |||
} | |||
rijndael_set_key(&aes_ctx, subkey_1, 128); // set subkey_1 as AES key | |||
for (i = 0; i < 3; i++) { // encrypt 3, 6 and 9 times the subkey_2 to obtain the final keymesh | |||
for (k = 0; k < 3; k++) | |||
rijndael_encrypt(&aes_ctx, subkey_2, subkey_2); | |||
memcpy(&seed[i * 0x10], subkey_2, 0x10); | |||
} | |||
} | |||
} | } | ||
</source>The key mesh can then be used along with a seed to generate a key using the following algorithm:<syntaxhighlight lang="c"> | |||
void | void make_perconsole_key(u8 output[16], int seed, ScePspKeyMesh keymesh) | ||
{ | |||
if (seed & 1) { | |||
memcpy(output, keymesh.aes128cbc_key_2, 16); | |||
} else { | |||
memcpy(output, keymesh.aes128cbc_key_1, 16); | |||
} | |||
// Encrypt the result several times depending on the seed | |||
rijndael_set_key(&aes_ctx, keymesh.aes128cbc_derivation_key); | |||
seed = (seed / 2) + 1; | |||
while ((seed--) >= 0) { | |||
rijndael_encrypt(&aes_ctx, output); | |||
} | |||
} | } | ||
</syntaxhighlight> | |||
</ | |||
= Commands = | = Commands = | ||
Line 601: | Line 351: | ||
| 10 (0xA) | | 10 (0xA) | ||
| KIRK_CMD_PRIV_SIGVRY | | KIRK_CMD_PRIV_SIGVRY | ||
| Private Signature Verify (checks for private SCE | | Private Signature Verify (checks for private SCE sig) | ||
| buf_size+0x90 | | buf_size+0x90 | ||
| 0 | | 0 | ||
Line 645: | Line 395: | ||
|- | |- | ||
| 15 (0xF) | | 15 (0xF) | ||
| | | KIRK_CMD_INIT_FUSE_SEEDS | ||
| | | Initializes Kirk Fuse Seeds. | ||
| 0x1C | | 0x1C | ||
| 0x1C | | 0x1C | ||
Line 658: | Line 408: | ||
| 0x34 | | 0x34 | ||
| 0x28 | | 0x28 | ||
| memab, openpsid | | memab, openpsid | ||
| {{yes}} | | {{yes}} | ||
| {{no}} | | {{no}} | ||
Line 664: | Line 414: | ||
| 17 (0x11) | | 17 (0x11) | ||
| KIRK_CMD_SIGVRY | | KIRK_CMD_SIGVRY | ||
| | | Signature Verification (checks for generated signatures) | ||
| 0x64 | | 0x64 | ||
| 0 | | 0 | ||
| memab, memlmd, mesg_led, openpsid | | memab, memlmd, mesg_led, openpsid | ||
| {{no}} | | {{no}} | ||
| {{no}} | | {{no}} | ||
Line 673: | Line 423: | ||
| 18 (0x12) | | 18 (0x12) | ||
| KIRK_CMD_CERTVRY | | KIRK_CMD_CERTVRY | ||
| Certificate Verification | | Certificate Verification (IDStorage Certificates CMAC) | ||
| 0xB8 | | 0xB8 | ||
| 0 | | 0 | ||
| openpsid, memab, chkreg | | openpsid, memab, chkreg | ||
| {{yes}} | | {{yes}} | ||
| {{no}} | | {{no}} | ||
|} | |} | ||
== Command | == Command 0: decrypt kbooti == | ||
This command is only used by devkits to decrypt the kbooti, ie the devkit's | This command is only used by devkits to decrypt the kbooti, ie the devkit's Pre-IPL. It supposedly can only be run at a very early stage. The very short header is as follows. | ||
{| class="wikitable" | {| class="wikitable" | ||
|+ | |+ | ||
Line 709: | Line 459: | ||
# Decrypt body using AES slotted key 0 | # Decrypt body using AES slotted key 0 | ||
== Commands | == Commands 1, 2, 3 & 10: decryption and authentication == | ||
=== Overview === | === Overview === | ||
Line 718: | Line 468: | ||
* Command 2 is used to decrypt DRMBB and reencrypt them using a (random key encrypted with a) per-console key to generate data to pass to command 3. | * Command 2 is used to decrypt DRMBB and reencrypt them using a (random key encrypted with a) per-console key to generate data to pass to command 3. | ||
* Command 3 decrypts data encrypted by command 2. | * Command 3 decrypts data encrypted by command 2. | ||
* Command | * Command 10 takes the same data as commands 1, 2 and 3 but only does the signature verification for the header (not for the body) and no decryption (or reencryption). It is used to verify IdStorage IDPS certificates. | ||
There are two versions of this service: AES CMAC verification, and ECDSA verification. They use the header section of the input buffer slightly differently. | There are two versions of this service: AES CMAC verification, and ECDSA verification. They use the header section of the input buffer slightly differently. | ||
Line 822: | Line 572: | ||
# Generate a valid CMAC or ECDSA signature for the output. For ECDSA, this uses the private key stored in key slot 4 (and is the private counterpart of slots 5/6 used by command 3). | # Generate a valid CMAC or ECDSA signature for the output. For ECDSA, this uses the private key stored in key slot 4 (and is the private counterpart of slots 5/6 used by command 3). | ||
=== Command | === Command 10 === | ||
Its behavior is very simple: | Its behavior is very simple: | ||
Line 831: | Line 581: | ||
== Commands 4~9: AES encrypt & decrypt == | == Commands 4~9: AES encrypt & decrypt == | ||
All these commands do AES128-CBC encryption/decryption with an IV equal to 0. | All these commands do AES128-CBC encryption/decryption with an IV equal to 0. | ||
- Commands 4 (encryption) and 7 (decryption) use a one of the 128 keys stored in the Kirk chip and available on the [[Keys]] page, index being given by the keyseed field (which must be between 0x00 and 0x7F) | |||
- Commands 5 (encryption) and 8 (decryption) use an unknown per-console key (it is unknown if it is derived from other data, or just stored as-is on the chip) | |||
- Commands 6 (encryption) and 9 (decryption) use a key derived from the keyseed using an unknown key derivation function | |||
In all cases, data is prefixed with a 0x14-byte long header: | |||
In all cases, data is prefixed with a 0x14-byte long header | |||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Address !! Size !! Description | ! Address !! Size !! Description | ||
|- | |- | ||
| 0x00 || 4 || Mode: must be 4 for encryption | | 0x00 || 4 || Mode: must be 4 for encryption, 5 for decryption | ||
|- | |- | ||
| | | 0x04 || 8 || Unknown (0?) | ||
|- | |- | ||
| | | 0x0C || 4 || Keyseed | ||
| | |||
| | |||
| | |||
| | |||
|- | |- | ||
| 0x10 || 4 || Size of the following data | | 0x10 || 4 || Size of the following data | ||
|} | |} | ||
== | == Command 11: SHA1 == | ||
This command computes the SHA1 of the input. The input must be prefixed with a 4-byte header giving the length of the buffer. Output is 0x14-byte long. | This command computes the SHA1 of the input. The input must be prefixed with a 4-byte header giving the length of the buffer. Output is 0x14-byte long. | ||
== Command | == Command 12: ECDSA key pair generation == | ||
This command generates a random private key and computes the associated public key. See above for the parameters of the elliptic curve. | This command generates a random private key and computes the associated public key. See above for the parameters of the elliptic curve. | ||
Line 914: | Line 613: | ||
*0x28 - Public Key point y value | *0x28 - Public Key point y value | ||
== Command | == Command 13: ECDSA point multiplication == | ||
This command multiplies an elliptic curve point by a scalar. See above for the parameters of the elliptic curve. | This command multiplies an elliptic curve point by a scalar. See above for the parameters of the elliptic curve. | ||
Line 927: | Line 626: | ||
*0x14 - point y value (kP).y | *0x14 - point y value (kP).y | ||
The result is a new point (x and y are each 0x14 bytes long). | The result is a new point(x and y are each 0x14 bytes long). | ||
== Command | == Command 14: PRNG == | ||
This function takes no input and generates | This function takes no input and generates random data of the given size (depending on the specified size of the output buffer). | ||
== Command | == Command 15: Init Fuse Seeds == | ||
Kirk initialization of Fuse Seeds. Takes a 0x1C data as input and 0x1C data as output. | |||
== Command 16: ECDSA signature generation == | |||
This command generates an ECDSA signature of a SHA1 hash (0x14 buffer) using an encrypted private key. | |||
Input is: | |||
*0x00: 0x20-byte long encrypted buffer containing the private key | |||
*0x20: the message hash. | |||
The output is a 0x28-byte long signature (r and s, both 0x14-byte long). | |||
The private key buffer is encrypted with a device-specific encryption using the FuseID. | |||
Here is the code of the decryption, thanks to Davee & Proxima. g_fuse90 and g_fuse94 are the two words composing the FuseID (present at the 0xBC100090 and 0xBC100094 hardware registers). | |||
Output is 0x20-byte long, but the last 0xC bytes are ignored (and possibly always equal to zero) for the private key. | |||
<pre> | |||
void decrypt_kirk16_private(u8 *dA_out, u8 *dA_enc) | |||
{ | |||
int i, k; | |||
kirk16_data keydata; | |||
u8 subkey_1[0x10], subkey_2[0x10]; | |||
rijndael_ctx aes_ctx; | |||
keydata.fuseid[7] = g_fuse90 &0xFF; | |||
keydata.fuseid[6] = (g_fuse90>>8) &0xFF; | |||
keydata.fuseid[5] = (g_fuse90>>16) &0xFF; | |||
keydata.fuseid[4] = (g_fuse90>>24) &0xFF; | |||
keydata.fuseid[3] = g_fuse94 &0xFF; | |||
keydata.fuseid[2] = (g_fuse94>>8) &0xFF; | |||
keydata.fuseid[1] = (g_fuse94>>16) &0xFF; | |||
keydata.fuseid[0] = (g_fuse94>>24) &0xFF; | |||
/* set encryption key */ | |||
rijndael_set_key(&aes_ctx, kirk16_key, 128); | |||
/* set the subkeys */ | |||
for (i = 0; i < 0x10; i++) | |||
{ | |||
/* set to the fuseid */ | |||
subkey_2[i] = subkey_1[i] = keydata.fuseid[i % 8]; | |||
} | |||
/* do aes crypto */ | |||
* | for (i = 0; i < 3; i++) | ||
* | { | ||
/* encrypt + decrypt */ | |||
rijndael_encrypt(&aes_ctx, subkey_1, subkey_1); | |||
rijndael_decrypt(&aes_ctx, subkey_2, subkey_2); | |||
} | |||
/* set new key */ | |||
rijndael_set_key(&aes_ctx, subkey_1, 128); | |||
/* now lets make the key mesh */ | |||
for (i = 0; i < 3; i++) | |||
{ | |||
/* do encryption in group of 3 */ | |||
for (k = 0; k < 3; k++) | |||
{ | |||
/* crypto */ | |||
rijndael_encrypt(&aes_ctx, subkey_2, subkey_2); | |||
} | |||
/* copy to out block */ | |||
memcpy(&keydata.mesh[i * 0x10], subkey_2, 0x10); | |||
} | |||
/* set the key to the mesh */ | |||
rijndael_set_key(&aes_ctx, &keydata.mesh[0x20], 128); | |||
/* do the encryption routines for the aes key */ | |||
for (i = 0; i < 2; i++) | |||
{ | |||
/* encrypt the data */ | |||
rijndael_encrypt(&aes_ctx, &keydata.mesh[0x10], &keydata.mesh[0x10]); | |||
} | |||
/* set the key to that mesh shit */ | |||
rijndael_set_key(&aes_ctx, &keydata.mesh[0x10], 128); | |||
/* cbc decrypt the dA */ | |||
AES_cbc_decrypt((AES_ctx *)&aes_ctx, dA_enc, dA_out, 0x20); | |||
} | |||
</pre> | |||
== Command | == Command 17: ECDSA signature verification == | ||
This command verifies an ECDSA signature | This command verifies an ECDSA signature using the ECDSA curve described above. | ||
It takes no output, and takes as an input: | It takes no output, and takes as an input: | ||
Line 978: | Line 731: | ||
* 0x50: signature s | * 0x50: signature s | ||
The result of the operation is given by the return value (0 on success, | The result of the operation is given by the return value (0 on success, 5 on failure to verify the signature). | ||
== Command 18: verify certificate == | |||
This command has most likely no output header. | |||
It takes as an input a 0xB8-long buffer: | |||
*0x00: certificate data (either ConsoleID or OpenPSID) | |||
*0x10: certificate public key (x and y) | |||
*0x38: ECDSA signature (r and s) | |||
*0x60: ECDSA public key used for the signature | |||
*0x88: certificate encrypted private key (padded) | |||
*0xA8: AES-CMAC hash of the rest of the header. | |||
Details are on PS Vita wiki. See also DespertarDelCementerio and CEX2DEX programs source codes. | |||
= Error codes = | = Error codes = | ||
Line 1,002: | Line 753: | ||
0×01: Kirk not enabled | 0×01: Kirk not enabled | ||
0×02: Invalid mode | 0×02: Invalid mode | ||
0×03: Invalid header | 0×03: Invalid header digest | ||
0×04: Invalid data | 0×04: Invalid data digest | ||
0×05: Invalid | 0×05: Invalid signature | ||
0x0C: | 0x0C: isInCriticalSection violation | ||
0x0D: Invalid operation (out of 1-18 range) | 0x0D: Invalid operation (out of 1-18 range) | ||
0x0E: Invalid | 0x0E: Invalid seed/code (cipher operations) | ||
0x0F: Invalid | 0x0F: Invalid ?header size? (cipher operations) | ||
0×10: Invalid data size (equals 0) (sign/cipher operations) | 0×10: Invalid data size (equals 0) (sign/cipher operations) | ||
</pre> | </pre> | ||
Line 1,025: | Line 776: | ||
* The private key corresponding to the latest version Bootrom public key is unknown. | * The private key corresponding to the latest version Bootrom public key is unknown. | ||
* | * Commands 0, 2, 3 are mostly unknown and need testing/documentation. | ||