mirror of
https://github.com/codestation/mhtools
synced 2024-12-05 01:19:28 +00:00
Updated CryptoEngine.
This commit is contained in:
parent
ad6d6b059c
commit
568e009ff0
1 changed files with 501 additions and 136 deletions
|
@ -53,6 +53,9 @@ public class CryptoEngine {
|
||||||
private static final int[] kirkAESKey17 = {0x11, 0x5A, 0x5D, 0x20, 0xD5, 0x3A, 0x8D, 0xD3, 0x9C, 0xC5, 0xAF, 0x41, 0x0F, 0x0F, 0x18, 0x6F};
|
private static final int[] kirkAESKey17 = {0x11, 0x5A, 0x5D, 0x20, 0xD5, 0x3A, 0x8D, 0xD3, 0x9C, 0xC5, 0xAF, 0x41, 0x0F, 0x0F, 0x18, 0x6F};
|
||||||
private static final int[] kirkAESKey18 = {0x9C, 0x9B, 0x13, 0x72, 0xF8, 0xC6, 0x40, 0xCF, 0x1C, 0x62, 0xF5, 0xD5, 0x92, 0xDD, 0xB5, 0x82};
|
private static final int[] kirkAESKey18 = {0x9C, 0x9B, 0x13, 0x72, 0xF8, 0xC6, 0x40, 0xCF, 0x1C, 0x62, 0xF5, 0xD5, 0x92, 0xDD, 0xB5, 0x82};
|
||||||
private static final int[] kirkAESKey19 = {0x03, 0xB3, 0x02, 0xE8, 0x5F, 0xF3, 0x81, 0xB1, 0x3B, 0x8D, 0xAA, 0x2A, 0x90, 0xFF, 0x5E, 0x61};
|
private static final int[] kirkAESKey19 = {0x03, 0xB3, 0x02, 0xE8, 0x5F, 0xF3, 0x81, 0xB1, 0x3B, 0x8D, 0xAA, 0x2A, 0x90, 0xFF, 0x5E, 0x61};
|
||||||
|
|
||||||
|
// KIRK CMD16 key.
|
||||||
|
private static final int[] kirkAESKey20 = {0x47, 0x5E, 0x09, 0xF4, 0xA2, 0x37, 0xDA, 0x9B, 0xEF, 0xFF, 0x3B, 0xC0, 0x77, 0x14, 0x3D, 0x8A};
|
||||||
|
|
||||||
// CHNNLSV SD keys.
|
// CHNNLSV SD keys.
|
||||||
private static final int[] sdHashKey1 = {0x40, 0xE6, 0x53, 0x3F, 0x05, 0x11, 0x3A, 0x4E, 0xA1, 0x4B, 0xDA, 0xD6, 0x72, 0x7C, 0x53, 0x4C};
|
private static final int[] sdHashKey1 = {0x40, 0xE6, 0x53, 0x3F, 0x05, 0x11, 0x3A, 0x4E, 0xA1, 0x4B, 0xDA, 0xD6, 0x72, 0x7C, 0x53, 0x4C};
|
||||||
|
@ -71,41 +74,52 @@ public class CryptoEngine {
|
||||||
private static final int[] amHashKey5 = {0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E};
|
private static final int[] amHashKey5 = {0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E};
|
||||||
|
|
||||||
// KIRK error values.
|
// KIRK error values.
|
||||||
private static final int PSP_KIRK_NOT_ENABLED = 1;
|
private static final int PSP_KIRK_NOT_ENABLED = 0x1;
|
||||||
private static final int PSP_KIRK_INVALID_MODE = 2;
|
private static final int PSP_KIRK_INVALID_MODE = 0x2;
|
||||||
private static final int PSP_KIRK_INVALID_HEADER_HASH = 3;
|
private static final int PSP_KIRK_INVALID_HEADER_HASH = 0x3;
|
||||||
private static final int PSP_KIRK_INVALID_DATA_HASH = 4;
|
private static final int PSP_KIRK_INVALID_DATA_HASH = 0x4;
|
||||||
private static final int PSP_KIRK_INVALID_SIG_CHECK = 5;
|
private static final int PSP_KIRK_INVALID_SIG_CHECK = 0x5;
|
||||||
private static final int PSP_KIRK_UNK1 = 6;
|
private static final int PSP_KIRK_UNK1 = 0x6;
|
||||||
private static final int PSP_KIRK_UNK2 = 7;
|
private static final int PSP_KIRK_UNK2 = 0x7;
|
||||||
private static final int PSP_KIRK_UNK3 = 8;
|
private static final int PSP_KIRK_UNK3 = 0x8;
|
||||||
private static final int PSP_KIRK_UNK4 = 9;
|
private static final int PSP_KIRK_UNK4 = 0x9;
|
||||||
private static final int PSP_KIRK_UNK5 = 10;
|
private static final int PSP_KIRK_UNK5 = 0xA;
|
||||||
private static final int PSP_KIRK_UNK6 = 11;
|
private static final int PSP_KIRK_UNK6 = 0xB;
|
||||||
private static final int PSP_KIRK_NOT_INIT = 12;
|
private static final int PSP_KIRK_NOT_INIT = 0xC;
|
||||||
private static final int PSP_KIRK_INVALID_OPERATION = 13;
|
private static final int PSP_KIRK_INVALID_OPERATION = 0xD;
|
||||||
private static final int PSP_KIRK_INVALID_SEED = 14;
|
private static final int PSP_KIRK_INVALID_SEED = 0xE;
|
||||||
private static final int PSP_KIRK_INVALID_SIZE = 15;
|
private static final int PSP_KIRK_INVALID_SIZE = 0xF;
|
||||||
private static final int PSP_KIRK_DATA_SIZE_IS_ZERO = 16;
|
private static final int PSP_KIRK_DATA_SIZE_IS_ZERO = 0x10;
|
||||||
|
private static final int PSP_SUBCWR_NOT_16_ALGINED = 0x90A;
|
||||||
|
private static final int PSP_SUBCWR_HEADER_HASH_INVALID = 0x920;
|
||||||
|
private static final int PSP_SUBCWR_BUFFER_TOO_SMALL = 0x1000;
|
||||||
|
|
||||||
// KIRK commands.
|
// KIRK commands.
|
||||||
private static final int PSP_KIRK_CMD_DECRYPT_PRIVATE = 1;
|
private static final int PSP_KIRK_CMD_DECRYPT_PRIVATE = 0x1; // Master decryption command, used by firmware modules. Applies CMAC checking.
|
||||||
private static final int PSP_KIRK_CMD_ENCRYPT_IV_0 = 4;
|
private static final int PSP_KIRK_CMD_ENCRYPT_SIGN = 0x2; // Used for key type 3 (blacklisting), encrypts and signs data with a ECDSA signature.
|
||||||
private static final int PSP_KIRK_CMD_ENCRYPT_IV_FUSE = 5;
|
private static final int PSP_KIRK_CMD_DECRYPT_SIGN = 0x3; // Used for key type 3 (blacklisting), decrypts and signs data with a ECDSA signature.
|
||||||
private static final int PSP_KIRK_CMD_ENCRYPT_IV_USER = 6;
|
private static final int PSP_KIRK_CMD_ENCRYPT = 0x4; // Key table based encryption used for general purposes by several modules.
|
||||||
private static final int PSP_KIRK_CMD_DECRYPT_IV_0 = 7;
|
private static final int PSP_KIRK_CMD_ENCRYPT_FUSE = 0x5; // Fuse ID based encryption used for general purposes by several modules.
|
||||||
private static final int PSP_KIRK_CMD_DECRYPT_IV_FUSE = 8;
|
private static final int PSP_KIRK_CMD_ENCRYPT_USER = 0x6; // User specified ID based encryption used for general purposes by several modules.
|
||||||
private static final int PSP_KIRK_CMD_DECRYPT_IV_USER = 9;
|
private static final int PSP_KIRK_CMD_DECRYPT = 0x7; // Key table based decryption used for general purposes by several modules.
|
||||||
private static final int PSP_KIRK_CMD_PRIV_SIG_CHECK = 10;
|
private static final int PSP_KIRK_CMD_DECRYPT_FUSE = 0x8; // Fuse ID based decryption used for general purposes by several modules.
|
||||||
private static final int PSP_KIRK_CMD_SHA1_HASH = 11;
|
private static final int PSP_KIRK_CMD_DECRYPT_USER = 0x9; // User specified ID based decryption used for general purposes by several modules.
|
||||||
private static final int PSP_KIRK_CMD_RANDOM_GEN = 14;
|
private static final int PSP_KIRK_CMD_PRIV_SIG_CHECK = 0xA; // Private signature (SCE) checking command.
|
||||||
|
private static final int PSP_KIRK_CMD_SHA1_HASH = 0xB; // SHA1 hash generating command.
|
||||||
|
private static final int PSP_KIRK_CMD_ECDSA_GEN_KEYS = 0xC; // ECDSA key generating mul1 command.
|
||||||
|
private static final int PSP_KIRK_CMD_ECDSA_MULTIPLY_POINT = 0xD; // ECDSA key generating mul2 command.
|
||||||
|
private static final int PSP_KIRK_CMD_PRNG = 0xE; // Random number generating command.
|
||||||
|
private static final int PSP_KIRK_CMD_INIT = 0xF; // KIRK initialization command.
|
||||||
|
private static final int PSP_KIRK_CMD_ECDSA_SIGN = 0x10; // ECDSA signing command.
|
||||||
|
private static final int PSP_KIRK_CMD_ECDSA_VERIFY = 0x11; // ECDSA checking command.
|
||||||
|
private static final int PSP_KIRK_CMD_CERT_VERIFY = 0x12; // Certificate checking command.
|
||||||
|
|
||||||
// KIRK command modes.
|
// KIRK command modes.
|
||||||
private static final int PSP_KIRK_CMD_MODE_CMD1 = 1;
|
private static final int PSP_KIRK_CMD_MODE_CMD1 = 0x1;
|
||||||
private static final int PSP_KIRK_CMD_MODE_CMD2 = 2;
|
private static final int PSP_KIRK_CMD_MODE_CMD2 = 0x2;
|
||||||
private static final int PSP_KIRK_CMD_MODE_CMD3 = 3;
|
private static final int PSP_KIRK_CMD_MODE_CMD3 = 0x3;
|
||||||
private static final int PSP_KIRK_CMD_MODE_ENCRYPT_CBC = 4;
|
private static final int PSP_KIRK_CMD_MODE_ENCRYPT_CBC = 0x4;
|
||||||
private static final int PSP_KIRK_CMD_MODE_DECRYPT_CBC = 5;
|
private static final int PSP_KIRK_CMD_MODE_DECRYPT_CBC = 0x5;
|
||||||
|
|
||||||
// PRXDecrypter 16-byte tag keys.
|
// PRXDecrypter 16-byte tag keys.
|
||||||
int[] keys260_0 = {0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E, 0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1};
|
int[] keys260_0 = {0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E, 0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1};
|
||||||
|
@ -162,7 +176,23 @@ public class CryptoEngine {
|
||||||
int[] keys636_k1 = {0x07, 0xE3, 0x08, 0x64, 0x7F, 0x60, 0xA3, 0x36, 0x6A, 0x76, 0x21, 0x44, 0xC9, 0xD7, 0x06, 0x83};
|
int[] keys636_k1 = {0x07, 0xE3, 0x08, 0x64, 0x7F, 0x60, 0xA3, 0x36, 0x6A, 0x76, 0x21, 0x44, 0xC9, 0xD7, 0x06, 0x83};
|
||||||
int[] keys636_k2 = {0x91, 0xF2, 0x02, 0x9E, 0x63, 0x32, 0x30, 0xA9, 0x1D, 0xDA, 0x0B, 0xA8, 0xB7, 0x41, 0xA3, 0xCC};
|
int[] keys636_k2 = {0x91, 0xF2, 0x02, 0x9E, 0x63, 0x32, 0x30, 0xA9, 0x1D, 0xDA, 0x0B, 0xA8, 0xB7, 0x41, 0xA3, 0xCC};
|
||||||
int[] keys638_k4 = {0x98, 0x43, 0xFF, 0x85, 0x68, 0xB2, 0xDB, 0x3B, 0xD4, 0x22, 0xD0, 0x4F, 0xAB, 0x5F, 0x0A, 0x31};
|
int[] keys638_k4 = {0x98, 0x43, 0xFF, 0x85, 0x68, 0xB2, 0xDB, 0x3B, 0xD4, 0x22, 0xD0, 0x4F, 0xAB, 0x5F, 0x0A, 0x31};
|
||||||
int[] keys639_k3 = {0x01, 0x7B, 0xF0, 0xE9, 0xBE, 0x9A, 0xDD, 0x54, 0x37, 0xEA, 0x0E, 0xC4, 0xD6, 0x4D, 0x8E, 0x9E};
|
int[] keys639_k3 = {0x01, 0x7B, 0xF0, 0xE9, 0xBE, 0x9A, 0xDD, 0x54, 0x37, 0xEA, 0x0E, 0xC4, 0xD6, 0x4D, 0x8E, 0x9E};
|
||||||
|
int[] keys660_k1 = {0x76, 0xF2, 0x6C, 0x0A, 0xCA, 0x3A, 0xBA, 0x4E, 0xAC, 0x76, 0xD2, 0x40, 0xF5, 0xC3, 0xBF, 0xF9};
|
||||||
|
int[] keys660_k2 = {0x7A, 0x3E, 0x55, 0x75, 0xB9, 0x6A, 0xFC, 0x4F, 0x3E, 0xE3, 0xDF, 0xB3, 0x6C, 0xE8, 0x2A, 0x82};
|
||||||
|
int[] keys660_k3 = {0xFA, 0x79, 0x09, 0x36, 0xE6, 0x19, 0xE8, 0xA4, 0xA9, 0x41, 0x37, 0x18, 0x81, 0x02, 0xE9, 0xB3};
|
||||||
|
int[] keys660_v1 = {0xBA, 0x76, 0x61, 0x47, 0x8B, 0x55, 0xA8, 0x72, 0x89, 0x15, 0x79, 0x6D, 0xD7, 0x2F, 0x78, 0x0E};
|
||||||
|
int[] keys660_v2 = {0xF9, 0x4A, 0x6B, 0x96, 0x79, 0x3F, 0xEE, 0x0A, 0x04, 0xC8, 0x8D, 0x7E, 0x5F, 0x38, 0x3A, 0xCF};
|
||||||
|
int[] keys660_v3 = {0x88, 0xAF, 0x18, 0xE9, 0xC3, 0xAA, 0x6B, 0x56, 0xF7, 0xC5, 0xA8, 0xBF, 0x1A, 0x84, 0xE9, 0xF3};
|
||||||
|
int[] keys660_v4 = {0xD1, 0xB0, 0xAE, 0xC3, 0x24, 0x36, 0x13, 0x49, 0xD6, 0x49, 0xD7, 0x88, 0xEA, 0xA4, 0x99, 0x86};
|
||||||
|
int[] keys660_v5 = {0xCB, 0x93, 0x12, 0x38, 0x31, 0xC0, 0x2D, 0x2E, 0x7A, 0x18, 0x5C, 0xAC, 0x92, 0x93, 0xAB, 0x32};
|
||||||
|
int[] keys660_v6 = {0x92, 0x8C, 0xA4, 0x12, 0xD6, 0x5C, 0x55, 0x31, 0x5B, 0x94, 0x23, 0x9B, 0x62, 0xB3, 0xDB, 0x47};
|
||||||
|
int[] keys660_k4 = {0xC8, 0xA0, 0x70, 0x98, 0xAE, 0xE6, 0x2B, 0x80, 0xD7, 0x91, 0xE6, 0xCA, 0x4C, 0xA9, 0x78, 0x4E};
|
||||||
|
int[] keys660_k5 = {0xBF, 0xF8, 0x34, 0x02, 0x84, 0x47, 0xBD, 0x87, 0x1C, 0x52, 0x03, 0x23, 0x79, 0xBB, 0x59, 0x81};
|
||||||
|
int[] keys660_k6 = {0xD2, 0x83, 0xCC, 0x63, 0xBB, 0x10, 0x15, 0xE7, 0x7B, 0xC0, 0x6D, 0xEE, 0x34, 0x9E, 0x4A, 0xFA};
|
||||||
|
int[] keys660_k7 = {0xEB, 0xD9, 0x1E, 0x05, 0x3C, 0xAE, 0xAB, 0x62, 0xE3, 0xB7, 0x1F, 0x37, 0xE5, 0xCD, 0x68, 0xC3};
|
||||||
|
int[] keys660_v7 = {0xC5, 0x9C, 0x77, 0x9C, 0x41, 0x01, 0xE4, 0x85, 0x79, 0xC8, 0x71, 0x63, 0xA5, 0x7D, 0x4F, 0xFB};
|
||||||
|
int[] keys660_v8 = {0x86, 0xA0, 0x7D, 0x4D, 0xB3, 0x6B, 0xA2, 0xFD, 0xF4, 0x15, 0x85, 0x70, 0x2D, 0x6A, 0x0D, 0x3A};
|
||||||
|
int[] keys660_k8 = {0x85, 0x93, 0x1F, 0xED, 0x2C, 0x4D, 0xA4, 0x53, 0x59, 0x9C, 0x3F, 0x16, 0xF3, 0x50, 0xDE, 0x46};
|
||||||
int[] key_21C0 = {0x6A, 0x19, 0x71, 0xF3, 0x18, 0xDE, 0xD3, 0xA2, 0x6D, 0x3B, 0xDE, 0xC7, 0xBE, 0x98, 0xE2, 0x4C};
|
int[] key_21C0 = {0x6A, 0x19, 0x71, 0xF3, 0x18, 0xDE, 0xD3, 0xA2, 0x6D, 0x3B, 0xDE, 0xC7, 0xBE, 0x98, 0xE2, 0x4C};
|
||||||
int[] key_2250 = {0x50, 0xCC, 0x03, 0xAC, 0x3F, 0x53, 0x1A, 0xFA, 0x0A, 0xA4, 0x34, 0x23, 0x86, 0x61, 0x7F, 0x97};
|
int[] key_2250 = {0x50, 0xCC, 0x03, 0xAC, 0x3F, 0x53, 0x1A, 0xFA, 0x0A, 0xA4, 0x34, 0x23, 0x86, 0x61, 0x7F, 0x97};
|
||||||
int[] key_22E0 = {0x66, 0x0F, 0xCB, 0x3B, 0x30, 0x75, 0xE3, 0x10, 0x0A, 0x95, 0x65, 0xC7, 0x3C, 0x93, 0x87, 0x22};
|
int[] key_22E0 = {0x66, 0x0F, 0xCB, 0x3B, 0x30, 0x75, 0xE3, 0x10, 0x0A, 0x95, 0x65, 0xC7, 0x3C, 0x93, 0x87, 0x22};
|
||||||
|
@ -388,7 +418,23 @@ public class CryptoEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TAG_INFO g_tagInfo[] = {
|
private TAG_INFO g_tagInfo[] = {
|
||||||
|
new TAG_INFO(0x4C9494F0, keys660_k1, 0x43),
|
||||||
|
new TAG_INFO(0x4C9495F0, keys660_k2, 0x43),
|
||||||
|
new TAG_INFO(0x4C9490F0, keys660_k3, 0x43),
|
||||||
|
new TAG_INFO(0x4C9491F0, keys660_k8, 0x43),
|
||||||
|
new TAG_INFO(0x4C9493F0, keys660_k4, 0x43),
|
||||||
|
new TAG_INFO(0x4C9497F0, keys660_k5, 0x43),
|
||||||
|
new TAG_INFO(0x4C9492F0, keys660_k6, 0x43),
|
||||||
|
new TAG_INFO(0x4C9496F0, keys660_k7, 0x43),
|
||||||
|
new TAG_INFO(0x457B90F0, keys660_v1, 0x5B),
|
||||||
|
new TAG_INFO(0x457B91F0, keys660_v7, 0x5B),
|
||||||
|
new TAG_INFO(0x457B92F0, keys660_v6, 0x5B),
|
||||||
|
new TAG_INFO(0x457B93F0, keys660_v3, 0x5B),
|
||||||
|
new TAG_INFO(0x380290F0, keys660_v2, 0x5A),
|
||||||
|
new TAG_INFO(0x380291F0, keys660_v8, 0x5A),
|
||||||
|
new TAG_INFO(0x380292F0, keys660_v4, 0x5A),
|
||||||
|
new TAG_INFO(0x380293F0, keys660_v5, 0x5A),
|
||||||
new TAG_INFO(0x4C948CF0, keys639_k3, 0x43),
|
new TAG_INFO(0x4C948CF0, keys639_k3, 0x43),
|
||||||
new TAG_INFO(0x4C948DF0, keys638_k4, 0x43),
|
new TAG_INFO(0x4C948DF0, keys638_k4, 0x43),
|
||||||
new TAG_INFO(0x4C948BF0, keys636_k2, 0x43),
|
new TAG_INFO(0x4C948BF0, keys636_k2, 0x43),
|
||||||
|
@ -564,7 +610,8 @@ public class CryptoEngine {
|
||||||
private byte[] CMACDataHash = new byte[16];
|
private byte[] CMACDataHash = new byte[16];
|
||||||
private byte[] unk1 = new byte[32];
|
private byte[] unk1 = new byte[32];
|
||||||
private int mode;
|
private int mode;
|
||||||
private byte[] unk2 = new byte[12];
|
private byte useECDSAhash;
|
||||||
|
private byte[] unk2 = new byte[11];
|
||||||
private int dataSize;
|
private int dataSize;
|
||||||
private int dataOffset;
|
private int dataOffset;
|
||||||
private byte[] unk3 = new byte[8];
|
private byte[] unk3 = new byte[8];
|
||||||
|
@ -577,13 +624,107 @@ public class CryptoEngine {
|
||||||
buf.get(CMACDataHash, 0, 16);
|
buf.get(CMACDataHash, 0, 16);
|
||||||
buf.get(unk1, 0, 32);
|
buf.get(unk1, 0, 32);
|
||||||
mode = buf.getInt();
|
mode = buf.getInt();
|
||||||
buf.get(unk2, 0, 12);
|
useECDSAhash = buf.get();
|
||||||
|
buf.get(unk2, 0, 11);
|
||||||
dataSize = buf.getInt();
|
dataSize = buf.getInt();
|
||||||
dataOffset = buf.getInt();
|
dataOffset = buf.getInt();
|
||||||
buf.get(unk3, 0, 8);
|
buf.get(unk3, 0, 8);
|
||||||
buf.get(unk4, 0, 16);
|
buf.get(unk4, 0, 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ECDSASig {
|
||||||
|
private byte[] r = new byte[0x14];
|
||||||
|
private byte[] s = new byte[0x14];
|
||||||
|
|
||||||
|
private ECDSASig () {
|
||||||
|
r = new byte[0x14];
|
||||||
|
s = new byte[0x14];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ECDSAPoint {
|
||||||
|
private byte[] x;
|
||||||
|
private byte[] y;
|
||||||
|
|
||||||
|
private ECDSAPoint() {
|
||||||
|
x = new byte[0x14];
|
||||||
|
y = new byte[0x14];
|
||||||
|
}
|
||||||
|
|
||||||
|
private ECDSAPoint(byte[] data) {
|
||||||
|
x = new byte[0x14];
|
||||||
|
y = new byte[0x14];
|
||||||
|
System.arraycopy(data, 0, x, 0, 0x14);
|
||||||
|
System.arraycopy(data, 0x14, y, 0, 0x14);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] toByteArray() {
|
||||||
|
byte[] point = new byte[0x28];
|
||||||
|
System.arraycopy(point, 0, x, 0, 0x14);
|
||||||
|
System.arraycopy(point, 0x14, y, 0, 0x14);
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ECDSAKeygenCtx {
|
||||||
|
private byte[] private_key;
|
||||||
|
private ECDSAPoint public_key;
|
||||||
|
private ByteBuffer out;
|
||||||
|
|
||||||
|
private ECDSAKeygenCtx (ByteBuffer output) {
|
||||||
|
private_key = new byte[0x14];
|
||||||
|
public_key = new ECDSAPoint();
|
||||||
|
out = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write() {
|
||||||
|
out.put(private_key);
|
||||||
|
out.put(public_key.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ECDSAMultiplyCtx {
|
||||||
|
private byte[] multiplier = new byte[0x14];
|
||||||
|
private ECDSAPoint public_key = new ECDSAPoint();
|
||||||
|
private ByteBuffer out;
|
||||||
|
|
||||||
|
private ECDSAMultiplyCtx (ByteBuffer input, ByteBuffer output) {
|
||||||
|
out = output;
|
||||||
|
input.get(multiplier, 0, 0x14);
|
||||||
|
input.get(public_key.x, 0, 0x14);
|
||||||
|
input.get(public_key.y, 0, 0x14);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write() {
|
||||||
|
out.put(multiplier);
|
||||||
|
out.put(public_key.toByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ECDSASignCtx {
|
||||||
|
private byte[] enc = new byte[0x20];
|
||||||
|
private byte[] hash = new byte[0x14];
|
||||||
|
|
||||||
|
private ECDSASignCtx (ByteBuffer buf) {
|
||||||
|
buf.get(enc, 0, 0x20);
|
||||||
|
buf.get(hash, 0, 0x14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ECDSAVerifyCtx {
|
||||||
|
private ECDSAPoint public_key;
|
||||||
|
private byte[] hash = new byte[0x14];
|
||||||
|
private ECDSASig sig;
|
||||||
|
|
||||||
|
private ECDSAVerifyCtx (ByteBuffer buf) {
|
||||||
|
buf.get(public_key.x, 0, 0x14);
|
||||||
|
buf.get(public_key.y, 0, 0x14);
|
||||||
|
buf.get(hash, 0, 0x14);
|
||||||
|
buf.get(sig.r, 0, 0x14);
|
||||||
|
buf.get(sig.s, 0, 0x14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CHNNLSV SD context structs.
|
// CHNNLSV SD context structs.
|
||||||
private class SDCtx1 {
|
private class SDCtx1 {
|
||||||
|
@ -761,9 +902,7 @@ public class CryptoEngine {
|
||||||
// full data decryption.
|
// full data decryption.
|
||||||
if (decryptedKeys != null) {
|
if (decryptedKeys != null) {
|
||||||
byte[] aesBuf = new byte[16];
|
byte[] aesBuf = new byte[16];
|
||||||
for (int i = 0; i < 16; i++) {
|
System.arraycopy(decryptedKeys, 0, aesBuf, 0, 16);
|
||||||
aesBuf[i] = decryptedKeys[i];
|
|
||||||
}
|
|
||||||
// Skip the CMD1 header.
|
// Skip the CMD1 header.
|
||||||
int headerSize = 0x90;
|
int headerSize = 0x90;
|
||||||
int headerOffset = 0x40;
|
int headerOffset = 0x40;
|
||||||
|
@ -1068,6 +1207,53 @@ public class CryptoEngine {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int executeKIRKCmd12(ByteBuffer out, int size) {
|
||||||
|
// Return an error if the crypto engine hasn't been initialized.
|
||||||
|
if (!isCryptoEngineInit) {
|
||||||
|
return PSP_KIRK_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size != 0x3C) {
|
||||||
|
return PSP_KIRK_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the ECDSA context.
|
||||||
|
ECDSA ecdsa = new ECDSA();
|
||||||
|
ECDSAKeygenCtx ctx = new ECDSAKeygenCtx(out);
|
||||||
|
ecdsa.setCurve();
|
||||||
|
|
||||||
|
// Generate the private/public key pair and write it back.
|
||||||
|
ctx.private_key = ecdsa.getPrivateKey();
|
||||||
|
ctx.public_key = new ECDSAPoint(ecdsa.getPublicKey());
|
||||||
|
|
||||||
|
ctx.write();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int executeKIRKCmd13(ByteBuffer out, int outSize, ByteBuffer in, int inSize) {
|
||||||
|
// Return an error if the crypto engine hasn't been initialized.
|
||||||
|
if (!isCryptoEngineInit) {
|
||||||
|
return PSP_KIRK_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((inSize != 0x3C) || (outSize != 0x28)) {
|
||||||
|
return PSP_KIRK_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the ECDSA context.
|
||||||
|
ECDSA ecdsa = new ECDSA();
|
||||||
|
ECDSAMultiplyCtx ctx = new ECDSAMultiplyCtx(in, out);
|
||||||
|
ecdsa.setCurve();
|
||||||
|
|
||||||
|
// Multiply the public key.
|
||||||
|
ecdsa.multiplyPublicKey(ctx.public_key.toByteArray(), ctx.multiplier);
|
||||||
|
|
||||||
|
ctx.write();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate pseudo random number.
|
// Generate pseudo random number.
|
||||||
private int executeKIRKCmd14(ByteBuffer out, int size) {
|
private int executeKIRKCmd14(ByteBuffer out, int size) {
|
||||||
|
@ -1075,16 +1261,56 @@ public class CryptoEngine {
|
||||||
if (!isCryptoEngineInit) {
|
if (!isCryptoEngineInit) {
|
||||||
return PSP_KIRK_NOT_INIT;
|
return PSP_KIRK_NOT_INIT;
|
||||||
}
|
}
|
||||||
Random rd = new Random();
|
|
||||||
byte[] rdBytes = new byte[size];
|
if (size > 0) {
|
||||||
|
Random rd = new Random();
|
||||||
|
byte[] rdBytes = new byte[size];
|
||||||
|
|
||||||
rd.nextBytes(rdBytes);
|
rd.nextBytes(rdBytes);
|
||||||
|
|
||||||
out.clear();
|
out.clear();
|
||||||
out.put(rdBytes);
|
out.put(rdBytes);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int executeKIRKCmd16(ByteBuffer out, int outSize, ByteBuffer in, int inSize) {
|
||||||
|
// Return an error if the crypto engine hasn't been initialized.
|
||||||
|
if (!isCryptoEngineInit) {
|
||||||
|
return PSP_KIRK_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((inSize != 0x34) || (outSize != 0x28)) {
|
||||||
|
return PSP_KIRK_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
ECDSA ecdsa = new ECDSA();
|
||||||
|
ECDSASignCtx ctx = new ECDSASignCtx(in);
|
||||||
|
ECDSASig sig = new ECDSASig();
|
||||||
|
ecdsa.setCurve();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int executeKIRKCmd17(ByteBuffer in, int size) {
|
||||||
|
// Return an error if the crypto engine hasn't been initialized.
|
||||||
|
if (!isCryptoEngineInit) {
|
||||||
|
return PSP_KIRK_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size != 0x64) {
|
||||||
|
return PSP_KIRK_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
ECDSA ecdsa = new ECDSA();
|
||||||
|
ECDSAVerifyCtx ctx = new ECDSAVerifyCtx(in);
|
||||||
|
ecdsa.setCurve();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HLE functions: high level implementation of crypto functions from
|
* HLE functions: high level implementation of crypto functions from
|
||||||
|
@ -1104,20 +1330,28 @@ public class CryptoEngine {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case PSP_KIRK_CMD_DECRYPT_PRIVATE:
|
case PSP_KIRK_CMD_DECRYPT_PRIVATE:
|
||||||
return executeKIRKCmd1(out, in, insize);
|
return executeKIRKCmd1(out, in, insize);
|
||||||
case PSP_KIRK_CMD_ENCRYPT_IV_0:
|
case PSP_KIRK_CMD_ENCRYPT:
|
||||||
return executeKIRKCmd4(out, in, insize);
|
return executeKIRKCmd4(out, in, insize);
|
||||||
case PSP_KIRK_CMD_ENCRYPT_IV_FUSE:
|
case PSP_KIRK_CMD_ENCRYPT_FUSE:
|
||||||
return executeKIRKCmd5(out, in, insize);
|
return executeKIRKCmd5(out, in, insize);
|
||||||
case PSP_KIRK_CMD_DECRYPT_IV_0:
|
case PSP_KIRK_CMD_DECRYPT:
|
||||||
return executeKIRKCmd7(out, in, insize);
|
return executeKIRKCmd7(out, in, insize);
|
||||||
case PSP_KIRK_CMD_DECRYPT_IV_FUSE:
|
case PSP_KIRK_CMD_DECRYPT_FUSE:
|
||||||
return executeKIRKCmd8(out, in, insize);
|
return executeKIRKCmd8(out, in, insize);
|
||||||
case PSP_KIRK_CMD_PRIV_SIG_CHECK:
|
case PSP_KIRK_CMD_PRIV_SIG_CHECK:
|
||||||
return executeKIRKCmd10(in, insize);
|
return executeKIRKCmd10(in, insize);
|
||||||
case PSP_KIRK_CMD_SHA1_HASH:
|
case PSP_KIRK_CMD_SHA1_HASH:
|
||||||
return executeKIRKCmd11(out, in, insize);
|
return executeKIRKCmd11(out, in, insize);
|
||||||
case PSP_KIRK_CMD_RANDOM_GEN:
|
case PSP_KIRK_CMD_ECDSA_GEN_KEYS:
|
||||||
|
return executeKIRKCmd12(out, outsize);
|
||||||
|
case PSP_KIRK_CMD_ECDSA_MULTIPLY_POINT:
|
||||||
|
return executeKIRKCmd13(out, outsize, in, insize);
|
||||||
|
case PSP_KIRK_CMD_PRNG:
|
||||||
return executeKIRKCmd14(out, insize);
|
return executeKIRKCmd14(out, insize);
|
||||||
|
case PSP_KIRK_CMD_ECDSA_SIGN:
|
||||||
|
return executeKIRKCmd16(out, outsize, in, insize);
|
||||||
|
case PSP_KIRK_CMD_ECDSA_VERIFY:
|
||||||
|
return executeKIRKCmd17(in, insize);
|
||||||
default:
|
default:
|
||||||
return PSP_KIRK_INVALID_OPERATION; // Dummy.
|
return PSP_KIRK_INVALID_OPERATION; // Dummy.
|
||||||
}
|
}
|
||||||
|
@ -1393,8 +1627,7 @@ public class CryptoEngine {
|
||||||
ctx.result[i] = (byte) (ctx.result[i] ^ key[i]);
|
ctx.result[i] = (byte) (ctx.result[i] ^ key[i]);
|
||||||
}
|
}
|
||||||
System.arraycopy(ctx.result, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
System.arraycopy(ctx.result, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
||||||
//ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
||||||
ScrambleSD(scrambleResultKeyBuf, 0x10, seed, 0x4, 0x04);
|
|
||||||
System.arraycopy(scrambleResultKeyBuf, 0, ctx.result, 0, 0x10);
|
System.arraycopy(scrambleResultKeyBuf, 0, ctx.result, 0, 0x10);
|
||||||
System.arraycopy(ctx.result, 0, hash, 0, 0x10);
|
System.arraycopy(ctx.result, 0, hash, 0, 0x10);
|
||||||
|
|
||||||
|
@ -1404,8 +1637,7 @@ public class CryptoEngine {
|
||||||
ctx.result[i] = (byte) (ctx.result[i] ^ key[i]);
|
ctx.result[i] = (byte) (ctx.result[i] ^ key[i]);
|
||||||
}
|
}
|
||||||
System.arraycopy(ctx.result, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
System.arraycopy(ctx.result, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
||||||
//ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
||||||
ScrambleSD(scrambleResultKeyBuf, 0x10, seed, 0x4, 0x04);
|
|
||||||
System.arraycopy(scrambleResultKeyBuf, 0, ctx.result, 0, 0x10);
|
System.arraycopy(scrambleResultKeyBuf, 0, ctx.result, 0, 0x10);
|
||||||
System.arraycopy(ctx.result, 0, hash, 0, 0x10);
|
System.arraycopy(ctx.result, 0, hash, 0, 0x10);
|
||||||
|
|
||||||
|
@ -1539,37 +1771,63 @@ public class CryptoEngine {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int hleDrmBBMacUpdate(BBMacCtx ctx, byte[] data, int length) {
|
private int hleDrmBBMacUpdate(BBMacCtx ctx, byte[] data, int length) {
|
||||||
if (ctx.keyLength > 0x11 || (length <= 0)) {
|
if (ctx.keyLength > 0x11 || (length < 0)) {
|
||||||
// Invalid key or length.
|
// Invalid key or length.
|
||||||
return -1;
|
return -1;
|
||||||
} else if (((ctx.keyLength + length) < 0x11)) {
|
} else if (((ctx.keyLength + length) < 0x11)) {
|
||||||
// The key hasn't been set yet.
|
// The key hasn't been set yet.
|
||||||
// Extract the hash from the data and set it as the key.
|
// Extract the hash from the data and set it as the key.
|
||||||
System.arraycopy(data, 0, ctx.key, 0, length);
|
System.arraycopy(data, 0, ctx.key, ctx.keyLength, length);
|
||||||
ctx.keyLength = length;
|
ctx.keyLength += length;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
int seed = 0;
|
// Calculate the seed (mode 2 == 0x3A / mode 1 and 3 == 0x3A).
|
||||||
switch (ctx.mode) {
|
int seed = 0x38;
|
||||||
case 0x1:
|
if (ctx.mode == 0x2) {
|
||||||
seed = 0x3A;
|
seed = 0x3A;
|
||||||
break;
|
|
||||||
case 0x2:
|
|
||||||
seed = 0x38;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the data's footer as the new key.
|
// Setup the buffers.
|
||||||
System.arraycopy(data, length - 0x10, ctx.key, 0, 0x10);
|
byte[] scrambleBuf = new byte[(length + ctx.keyLength) + 0x14];
|
||||||
|
|
||||||
// Setup a new buffer and re-encrypt the data with KIRK CMD4.
|
// Copy the previous key to the buffer.
|
||||||
byte[] dataBuf = new byte[length + 0x14];
|
System.arraycopy(ctx.key, 0, scrambleBuf, 0x14, ctx.keyLength);
|
||||||
System.arraycopy(data, 0, dataBuf, 0x14, length);
|
|
||||||
ScrambleSD(dataBuf, length, seed, 0x4, 0x04);
|
// Calculate new key length.
|
||||||
|
int kLen = ctx.keyLength;
|
||||||
// Save the data's footer to ctx.result and write back the data to the original buffer.
|
|
||||||
System.arraycopy(dataBuf, length + 4, ctx.result, 0, 0x10);
|
ctx.keyLength += length;
|
||||||
|
ctx.keyLength &= 0x0F;
|
||||||
|
if(ctx.keyLength == 0) {
|
||||||
|
ctx.keyLength = 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate new data length.
|
||||||
|
length -= ctx.keyLength;
|
||||||
|
|
||||||
|
// Copy data's footer to make a new key.
|
||||||
|
System.arraycopy(data, length, ctx.key, 0, ctx.keyLength);
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
// Process the encryption in 0x800 blocks.
|
||||||
|
int blockSize = (length + kLen >= 0x0800) ? 0x0800 : length + kLen;
|
||||||
|
int dataOffset = 0;
|
||||||
|
|
||||||
|
System.arraycopy(data, dataOffset, scrambleBuf, 0x14 + kLen, blockSize - kLen);
|
||||||
|
|
||||||
|
// Encrypt with KIRK CMD 4 and XOR with result.
|
||||||
|
for (int i = 0; i < 0x10; i++) {
|
||||||
|
scrambleBuf[0x14 + i] = (byte) (scrambleBuf[0x14 + i] ^ ctx.result[i]);
|
||||||
|
}
|
||||||
|
ScrambleSD(scrambleBuf, blockSize, seed, 0x4, 0x04);
|
||||||
|
System.arraycopy(scrambleBuf, (blockSize + 0x4) - 0x14, ctx.result, 0, 0x10);
|
||||||
|
|
||||||
|
// Adjust data length, data offset and reset any key length.
|
||||||
|
length -= (blockSize - kLen);
|
||||||
|
dataOffset += (blockSize - kLen);
|
||||||
|
kLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1580,77 +1838,122 @@ public class CryptoEngine {
|
||||||
// Invalid key length.
|
// Invalid key length.
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
// Setup the buffers.
|
// Setup the buffers.
|
||||||
byte[] keyBuf = new byte[0x10];
|
byte[] scrambleEmptyBuf = new byte[0x10 + 0x14];
|
||||||
byte[] scrambleKeyBuf = new byte[0x10 + 0x14];
|
byte[] keyBuf = new byte[0x10];
|
||||||
byte[] scrambleResultBuf = new byte[0x10 + 0x14];
|
byte[] scrambleKeyBuf = new byte[0x10 + 0x14];
|
||||||
|
byte[] resultBuf = new byte[0x10];
|
||||||
|
byte[] scrambleResultBuf = new byte[0x10 + 0x14];
|
||||||
byte[] scrambleResultKeyBuf = new byte[0x10 + 0x14];
|
byte[] scrambleResultKeyBuf = new byte[0x10 + 0x14];
|
||||||
|
|
||||||
// Calculate the seed.
|
// Calculate the seed (mode 2 == 0x3A / mode 1 and 3 == 0x3A).
|
||||||
int seed = 0;
|
int seed = 0x38;
|
||||||
switch (ctx.mode) {
|
if (ctx.mode == 0x2) {
|
||||||
case 0x1:
|
seed = 0x3A;
|
||||||
seed = 0x3A;
|
|
||||||
break;
|
|
||||||
case 0x2:
|
|
||||||
seed = 0x38;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the key with KIRK CMD4 and copy it to keyBuf.
|
// Encrypt an empty buffer with KIRK CMD 4.
|
||||||
ScrambleSD(key, 0x10, seed, 0x4, 0x04);
|
ScrambleSD(scrambleEmptyBuf, 0x10, seed, 0x4, 0x04);
|
||||||
System.arraycopy(key, 0, keyBuf, 0, 0x10);
|
System.arraycopy(scrambleEmptyBuf, 0, keyBuf, 0, 0x10);
|
||||||
|
|
||||||
// Apply a custom alogrithm and copy the contents of keyBuf to ctx.key and scrambleKeyBuf.
|
// Apply custom padding management.
|
||||||
for (int i = 0xE; i >= 0; i--) {
|
byte b = ((keyBuf[0] & (byte) 0x80) != 0) ? (byte) 0x87 : 0;
|
||||||
keyBuf[i] = (byte) ((keyBuf[i + 1] >> 7) | (keyBuf[i] << 1));
|
for(int i = 0; i < 0xF; i++) {
|
||||||
|
keyBuf[i] = (byte) ((keyBuf[i] << 1) | (keyBuf[i + 1] >> 7));
|
||||||
|
}
|
||||||
|
keyBuf[0xF] = (byte) ((keyBuf[0xF] << 1) ^ b);
|
||||||
|
|
||||||
|
if (ctx.keyLength < 0x10) {
|
||||||
|
byte bb = ((keyBuf[0] & (byte) 0x80) != 0) ? (byte) 0x87 : 0;
|
||||||
|
for(int i = 0; i < 0xF; i++) {
|
||||||
|
keyBuf[i] = (byte) ((keyBuf[i] << 1) | (keyBuf[i + 1] >> 7));
|
||||||
|
}
|
||||||
|
keyBuf[0xF] = (byte) ((keyBuf[0xF] << 1) ^ bb);
|
||||||
|
|
||||||
|
ctx.key[ctx.keyLength] = (byte) 0x80;
|
||||||
|
if ((ctx.keyLength + 1) < 0x10) {
|
||||||
|
for (int i = 0; i < (0x10 - ctx.keyLength - 1); i++) {
|
||||||
|
ctx.key[ctx.keyLength + 1 + i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XOR previous key with new one.
|
||||||
for (int i = 0; i < 0x10; i++) {
|
for (int i = 0; i < 0x10; i++) {
|
||||||
ctx.key[i] = (byte) (ctx.key[i] ^ keyBuf[i]);
|
ctx.key[i] = (byte) (ctx.key[i] ^ keyBuf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.arraycopy(ctx.key, 0, scrambleKeyBuf, 0x14, 0x10);
|
System.arraycopy(ctx.key, 0, scrambleKeyBuf, 0x14, 0x10);
|
||||||
|
System.arraycopy(ctx.result, 0, resultBuf, 0, 0x10);
|
||||||
|
|
||||||
|
// Encrypt with KIRK CMD 4 and XOR with result.
|
||||||
for (int i = 0; i < 0x10; i++) {
|
for (int i = 0; i < 0x10; i++) {
|
||||||
scrambleKeyBuf[i] = (byte) (scrambleKeyBuf[i] ^ ctx.result[i]);
|
scrambleKeyBuf[0x14 + i] = (byte) (scrambleKeyBuf[0x14 + i] ^ resultBuf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt scrambleKeyBuf with KIRK CMD4 again and copy the result to ctx.result.
|
|
||||||
ScrambleSD(scrambleKeyBuf, 0x10, seed, 0x4, 0x04);
|
ScrambleSD(scrambleKeyBuf, 0x10, seed, 0x4, 0x04);
|
||||||
System.arraycopy(scrambleKeyBuf, ctx.keyLength, ctx.result, 0, 0x10);
|
System.arraycopy(scrambleKeyBuf, (0x10 + 0x4) - 0x14, resultBuf, 0, 0x10);
|
||||||
|
|
||||||
// XOR with AMCTRL key 3.
|
// XOR with amHashKey3.
|
||||||
for (int i = 0; i < 0x10; i++) {
|
for (int i = 0; i < 0x10; i++) {
|
||||||
ctx.result[i] = (byte) (ctx.result[i] ^ amHashKey3[i]);
|
resultBuf[i] = (byte) (resultBuf[i] ^ amHashKey3[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If ctx.mode is 0x2, encrypt with KIRK CMD5, then with KIRK CMD4,
|
// If mode is 2, encrypt again with KIRK CMD 5 and then KIRK CMD 4.
|
||||||
// XOR with the original key and encrypt again with KIRK CMD4.
|
if (ctx.mode == 0x2) {
|
||||||
// Modes 0x0, 0x1 and 0x3 don't need the KIRK CMD5 step.
|
System.arraycopy(resultBuf, 0, scrambleResultBuf, 0x14, 0x10);
|
||||||
if ((ctx.mode == 0x2)) {
|
ScrambleSD(scrambleResultBuf, 0x10, 0x100, 0x4, 0x05);
|
||||||
System.arraycopy(ctx.result, 0, scrambleResultBuf, 0x14, 0x10);
|
|
||||||
ScrambleSD(scrambleResultBuf, 0x10, 0x100, 0x4, 0x05);
|
|
||||||
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
||||||
System.arraycopy(scrambleResultBuf, 0, ctx.result, 0, 0x10);
|
System.arraycopy(scrambleResultBuf, 0, resultBuf, 0, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR with the supplied key and encrypt with KIRK CMD 4.
|
||||||
|
if (key != null) {
|
||||||
for (int i = 0; i < 0x10; i++) {
|
for (int i = 0; i < 0x10; i++) {
|
||||||
ctx.result[i] = (byte) (ctx.result[i] ^ key[i]);
|
resultBuf[i] = (byte) (resultBuf[i] ^ key[i]);
|
||||||
}
|
}
|
||||||
System.arraycopy(ctx.result, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
System.arraycopy(resultBuf, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
||||||
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
ScrambleSD(scrambleResultKeyBuf, 0x10, seed, 0x4, 0x04);
|
||||||
System.arraycopy(scrambleResultKeyBuf, 0, ctx.result, 0, 0x10);
|
System.arraycopy(scrambleResultKeyBuf, 0, resultBuf, 0, 0x10);
|
||||||
System.arraycopy(ctx.result, 0, hash, 0, 0x10);
|
}
|
||||||
|
|
||||||
return 0;
|
// Copy back the generated hash.
|
||||||
} else {
|
System.arraycopy(resultBuf, 0, hash, 0, 0x10);
|
||||||
for (int i = 0; i < 0x10; i++) {
|
|
||||||
ctx.result[i] = (byte) (ctx.result[i] ^ key[i]);
|
// Clear the context fields.
|
||||||
}
|
ctx.mode = 0;
|
||||||
System.arraycopy(ctx.result, 0, scrambleResultKeyBuf, 0x14, 0x10);
|
ctx.keyLength = 0;
|
||||||
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
|
for (int i = 0; i < 0x10; i++) {
|
||||||
System.arraycopy(scrambleResultKeyBuf, 0, ctx.result, 0, 0x10);
|
ctx.key[i] = 0;
|
||||||
System.arraycopy(ctx.result, 0, hash, 0, 0x10);
|
}
|
||||||
|
for (int i = 0; i < 0x10; i++) {
|
||||||
return 0;
|
ctx.result[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int hleDrmBBMacFinal2(BBMacCtx ctx, byte[] hash, byte[] key) {
|
||||||
|
byte[] resBuf = new byte[0x10];
|
||||||
|
byte[] hashBuf = new byte[0x10];
|
||||||
|
|
||||||
|
// If mode is 3, decrypt hash first and then call hleDrmBBMacFinal on an empty buffer.
|
||||||
|
if (ctx.mode == 0x3) {
|
||||||
|
hashBuf = DecryptEDATAKey(hash);
|
||||||
|
} else {
|
||||||
|
hashBuf = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
hleDrmBBMacFinal(ctx, resBuf, key);
|
||||||
|
|
||||||
|
// Compare the hashes.
|
||||||
|
for (int i = 0; i < 0x10; i++) {
|
||||||
|
if (hashBuf[i] != resBuf[i]) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int hleDrmBBCipherInit(BBCipherCtx ctx, int encMode, int genMode, byte[] data, byte[] key) {
|
private int hleDrmBBCipherInit(BBCipherCtx ctx, int encMode, int genMode, byte[] data, byte[] key) {
|
||||||
|
@ -2425,7 +2728,7 @@ public class CryptoEngine {
|
||||||
System.arraycopy(dataBuf, 0x10, outbuf, 0, alignedSize - 0x10);
|
System.arraycopy(dataBuf, 0x10, outbuf, 0, alignedSize - 0x10);
|
||||||
hleSdRemoveValue(ctx2, outbuf, alignedSize - 0x10);
|
hleSdRemoveValue(ctx2, outbuf, alignedSize - 0x10);
|
||||||
hleSdSetMember(ctx1, outbuf, alignedSize - 0x10);
|
hleSdSetMember(ctx1, outbuf, alignedSize - 0x10);
|
||||||
|
|
||||||
return outbuf;
|
return outbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2484,8 +2787,7 @@ public class CryptoEngine {
|
||||||
hleSdGetLastIndex(ctx2, hash, key);
|
hleSdGetLastIndex(ctx2, hash, key);
|
||||||
|
|
||||||
// Store this hash at 0x20 in the savedataParams' struct.
|
// Store this hash at 0x20 in the savedataParams' struct.
|
||||||
//System.arraycopy(savedataParams, 0x20, hash, 0, 0x10);
|
System.arraycopy(savedataParams, 0x20, hash, 0, 0x10);
|
||||||
System.arraycopy(hash, 0, savedataParams, 0x20, 0x10);
|
|
||||||
savedataParams[0] |= 0x01;
|
savedataParams[0] |= 0x01;
|
||||||
|
|
||||||
// If encMode is 4, calculate a new hash with a blank key, but with mode 3.
|
// If encMode is 4, calculate a new hash with a blank key, but with mode 3.
|
||||||
|
@ -2497,8 +2799,7 @@ public class CryptoEngine {
|
||||||
hleSdGetLastIndex(ctx2, hash, key);
|
hleSdGetLastIndex(ctx2, hash, key);
|
||||||
|
|
||||||
// Store this hash at 0x70 in the savedataParams' struct.
|
// Store this hash at 0x70 in the savedataParams' struct.
|
||||||
//System.arraycopy(savedataParams, 0x70, hash, 0, 0x10);
|
System.arraycopy(savedataParams, 0x70, hash, 0, 0x10);
|
||||||
System.arraycopy(hash, 0, savedataParams, 0x70, 0x10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, generate a last hash using a blank key and mode 1.
|
// Finally, generate a last hash using a blank key and mode 1.
|
||||||
|
@ -2507,8 +2808,7 @@ public class CryptoEngine {
|
||||||
hleSdGetLastIndex(ctx2, hash, key);
|
hleSdGetLastIndex(ctx2, hash, key);
|
||||||
|
|
||||||
// Store this hash at 0x10 in the savedataParams' struct.
|
// Store this hash at 0x10 in the savedataParams' struct.
|
||||||
//System.arraycopy(savedataParams, 0x10, hash, 0, 0x10);
|
System.arraycopy(savedataParams, 0x10, hash, 0, 0x10);
|
||||||
System.arraycopy(hash, 0, savedataParams, 0x10, 0x10);
|
|
||||||
|
|
||||||
return savedataParams;
|
return savedataParams;
|
||||||
}
|
}
|
||||||
|
@ -2559,4 +2859,69 @@ public class CryptoEngine {
|
||||||
// Call the SD functions.
|
// Call the SD functions.
|
||||||
hleDrmBBCipherFinal(pgdCipherContext);
|
hleDrmBBCipherFinal(pgdCipherContext);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public int CheckEDATANameKey(byte[] data, byte[] hash, byte[] name, int nameLength) {
|
||||||
|
// Setup the crypto and keygen modes and initialize both context structs.
|
||||||
|
int sdEncMode = 3;
|
||||||
|
pgdMacContext = new BBMacCtx();
|
||||||
|
|
||||||
|
int dataSize = 0x30;
|
||||||
|
|
||||||
|
byte[] renameKey = {(byte)0xEB, (byte)0x71, (byte)0x5D, (byte)0xB8, (byte)0xD3, (byte)0x73,
|
||||||
|
(byte)0xCE, (byte)0xA4, (byte)0x6F, (byte)0xE7, (byte)0x1D, (byte)0xCF,
|
||||||
|
(byte)0xFF, (byte)0x63, (byte)0xFA, (byte)0xEA};
|
||||||
|
|
||||||
|
// Call the BBMac functions.
|
||||||
|
hleDrmBBMacInit(pgdMacContext, sdEncMode);
|
||||||
|
hleDrmBBMacUpdate(pgdMacContext, data, dataSize);
|
||||||
|
hleDrmBBMacUpdate(pgdMacContext, name, nameLength);
|
||||||
|
hleDrmBBMacFinal2(pgdMacContext, hash, renameKey);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int VerifyEDATA(byte[] data, byte[] hash) {
|
||||||
|
// Setup the crypto and keygen modes and initialize both context structs.
|
||||||
|
int sdEncMode = 3;
|
||||||
|
pgdMacContext = new BBMacCtx();
|
||||||
|
|
||||||
|
int dataSize = 0x80;
|
||||||
|
|
||||||
|
// Call the BBMac functions.
|
||||||
|
hleDrmBBMacInit(pgdMacContext, sdEncMode);
|
||||||
|
hleDrmBBMacUpdate(pgdMacContext, data, dataSize);
|
||||||
|
hleDrmBBMacFinal2(pgdMacContext, hash, null);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] DecryptEDATAKey(byte[] key) {
|
||||||
|
byte[] scrambleBuf = new byte[0x10 + 0x14];
|
||||||
|
byte[] decKey = new byte[0x10];
|
||||||
|
|
||||||
|
System.arraycopy(key, 0, scrambleBuf, 0x14, 0x10);
|
||||||
|
ScrambleSD(scrambleBuf, 0x10, 0x63, 0x5, 0x07);
|
||||||
|
System.arraycopy(scrambleBuf, 0, decKey, 0, 0x10);
|
||||||
|
|
||||||
|
return decKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] MakeEDATAFixedKey(byte[] data, byte[] hash) {
|
||||||
|
// Setup the crypto and keygen modes and initialize both context structs.
|
||||||
|
int sdEncMode = 1;
|
||||||
|
pgdMacContext = new BBMacCtx();
|
||||||
|
|
||||||
|
int dataSize = 0x30;
|
||||||
|
|
||||||
|
byte[] fixedKey = {(byte)0x38, (byte)0x20, (byte)0xD0, (byte)0x11, (byte)0x07, (byte)0xA3,
|
||||||
|
(byte)0xFF, (byte)0x3E, (byte)0x0A, (byte)0x4C, (byte)0x20, (byte)0x85,
|
||||||
|
(byte)0x39, (byte)0x10, (byte)0xB5, (byte)0x54};
|
||||||
|
|
||||||
|
// Call the BBMac functions.
|
||||||
|
hleDrmBBMacInit(pgdMacContext, sdEncMode);
|
||||||
|
hleDrmBBMacUpdate(pgdMacContext, data, dataSize);
|
||||||
|
hleDrmBBMacFinal(pgdMacContext, hash, fixedKey);
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue