The private key for the KIRK 0x10 functionality is known to be stored in a encrypted buffer of 0x20 bytes. Proxima discovered that the KIRK 0x10 operates as this:
Kirk 0x10 - ECDSA Sign hash Invocation:
u8 buffer[0x34]
u8 encryptedprivatekey[0x20] - the private key returned by KIRK 0xC must be AES encrypted somehow
u8 SHA1hashofmessagetosign[0x14]
memcpy(buffer,encryptedprivatekey,0x20)
memcpy(buffer+0x20,SHA1hashofmessagetosign,0x14)
sceUtilsBufferCopyWithRange(newsig,0x28,buffer,0x34,0x10);
newsig will have the r and s values for an ECDSA signature
This isn’t that useful since it is not clear how to encrypt the private key to sign the message. There are some examples in IDStorage where a pre-encrypted private key and public key pair can be used, but no general cases yet.
With a bit more reading and working with Proxima, we have discovered how to encrypt and decrypt these keys! Below is code:
typedef struct
{
u8 fuseid[8]; //0
u8 mesh[0x40]; //0x8
} keygen_data; //0x48
u8 g_idstorage_dA_key[] =
{
0x47, 0x5E, 0x09, 0xF4, 0xA2, 0x37, 0xDA, 0x9B,
0xEF, 0xFF, 0x3B, 0xC0, 0x77, 0x14, 0x3D, 0x8A
};
void decrypt_kirk10_private(u8 *dA_out, u8 *dA_enc)
{
int i, k;
keygen_data keydata;
u8 subkey_1[0x10], subkey_2[0x10];
rijndael_ctx aes_ctx;
/* get the fuse id */
for (i = 0; i < 4; i++)
{
keydata.fuseid[3 - i] = ((u8 *)0xBC100090)[i+4];
keydata.fuseid[7 - i] = ((u8 *)0xBC100090)[i];
}
/* set encryption key */
rijndael_set_key(&aes_ctx, g_idstorage_dA_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, dA_enc, dA_out, 0x20, NULL);
}
void encrypt_kirk10_private(u8 *dA_out, u8 *dA_dec)
{
int i, k;
keygen_data keydata;
u8 subkey_1[0x10], subkey_2[0x10];
rijndael_ctx aes_ctx;
/* get the fuse id */
for (i = 0; i < 4; i++)
{
keydata.fuseid[3 - i] = ((u8 *)0xBC100090)[i+4];
keydata.fuseid[7 - i] = ((u8 *)0xBC100090)[i];
}
/* set encryption key */
rijndael_set_key(&aes_ctx, g_idstorage_dA_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 encrypt the dA */
aes_cbc_encrypt(&aes_ctx, dA_dec, dA_out, 0x20, NULL);
}
As you can see, there is common key generation code, you could make it into it’s own subroutine but I’ve laid out the code for clarity.