1 #include <algorithm>
2 #include <array>
3 #include <string.h>
4 
5 extern "C"
6 {
7 #include "ext/libkirk/kirk_engine.h"
8 #include "ext/libkirk/SHA1.h"
9 }
10 #include "Common/Common.h"
11 #include "Common/Log.h"
12 #include "Common/Swap.h"
13 #include "Core/ELF/PrxDecrypter.h"
14 
15 #define ROUNDUP16(x)  (((x)+15)&~15)
16 
17 // Thank you PSARDUMPER & JPCSP keys
18 
19 // PRXDecrypter 16-byte tag keys.
20 static const u8 keys260_0[] = {0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E, 0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1};
21 static const u8 keys260_1[] = {0xF3, 0xAC, 0x6E, 0x7C, 0x04, 0x0A, 0x23, 0xE7, 0x0D, 0x33, 0xD8, 0x24, 0x73, 0x39, 0x2B, 0x4A};
22 static const u8 keys260_2[] = {0x72, 0xB4, 0x39, 0xFF, 0x34, 0x9B, 0xAE, 0x82, 0x30, 0x34, 0x4A, 0x1D, 0xA2, 0xD8, 0xB4, 0x3C};
23 static const u8 keys280_0[] = {0xCA, 0xFB, 0xBF, 0xC7, 0x50, 0xEA, 0xB4, 0x40, 0x8E, 0x44, 0x5C, 0x63, 0x53, 0xCE, 0x80, 0xB1};
24 static const u8 keys280_1[] = {0x40, 0x9B, 0xC6, 0x9B, 0xA9, 0xFB, 0x84, 0x7F, 0x72, 0x21, 0xD2, 0x36, 0x96, 0x55, 0x09, 0x74};
25 static const u8 keys280_2[] = {0x03, 0xA7, 0xCC, 0x4A, 0x5B, 0x91, 0xC2, 0x07, 0xFF, 0xFC, 0x26, 0x25, 0x1E, 0x42, 0x4B, 0xB5};
26 static const u8 keys300_0[] = {0x9F, 0x67, 0x1A, 0x7A, 0x22, 0xF3, 0x59, 0x0B, 0xAA, 0x6D, 0xA4, 0xC6, 0x8B, 0xD0, 0x03, 0x77};
27 static const u8 keys300_1[] = {0x15, 0x07, 0x63, 0x26, 0xDB, 0xE2, 0x69, 0x34, 0x56, 0x08, 0x2A, 0x93, 0x4E, 0x4B, 0x8A, 0xB2};
28 static const u8 keys300_2[] = {0x56, 0x3B, 0x69, 0xF7, 0x29, 0x88, 0x2F, 0x4C, 0xDB, 0xD5, 0xDE, 0x80, 0xC6, 0x5C, 0xC8, 0x73};
29 static const u8 keys303_0[] = {0x7b, 0xa1, 0xe2, 0x5a, 0x91, 0xb9, 0xd3, 0x13, 0x77, 0x65, 0x4a, 0xb7, 0xc2, 0x8a, 0x10, 0xaf};
30 static const u8 keys310_0[] = {0xa2, 0x41, 0xe8, 0x39, 0x66, 0x5b, 0xfa, 0xbb, 0x1b, 0x2d, 0x6e, 0x0e, 0x33, 0xe5, 0xd7, 0x3f};
31 static const u8 keys310_1[] = {0xA4, 0x60, 0x8F, 0xAB, 0xAB, 0xDE, 0xA5, 0x65, 0x5D, 0x43, 0x3A, 0xD1, 0x5E, 0xC3, 0xFF, 0xEA};
32 static const u8 keys310_2[] = {0xE7, 0x5C, 0x85, 0x7A, 0x59, 0xB4, 0xE3, 0x1D, 0xD0, 0x9E, 0xCE, 0xC2, 0xD6, 0xD4, 0xBD, 0x2B};
33 static const u8 keys310_3[] = {0x2E, 0x00, 0xF6, 0xF7, 0x52, 0xCF, 0x95, 0x5A, 0xA1, 0x26, 0xB4, 0x84, 0x9B, 0x58, 0x76, 0x2F};
34 static const u8 keys330_0[] = {0x3B, 0x9B, 0x1A, 0x56, 0x21, 0x80, 0x14, 0xED, 0x8E, 0x8B, 0x08, 0x42, 0xFA, 0x2C, 0xDC, 0x3A};
35 static const u8 keys330_1[] = {0xE8, 0xBE, 0x2F, 0x06, 0xB1, 0x05, 0x2A, 0xB9, 0x18, 0x18, 0x03, 0xE3, 0xEB, 0x64, 0x7D, 0x26};
36 static const u8 keys330_2[] = {0xAB, 0x82, 0x25, 0xD7, 0x43, 0x6F, 0x6C, 0xC1, 0x95, 0xC5, 0xF7, 0xF0, 0x63, 0x73, 0x3F, 0xE7};
37 static const u8 keys330_3[] = {0xA8, 0xB1, 0x47, 0x77, 0xDC, 0x49, 0x6A, 0x6F, 0x38, 0x4C, 0x4D, 0x96, 0xBD, 0x49, 0xEC, 0x9B};
38 static const u8 keys330_4[] = {0xEC, 0x3B, 0xD2, 0xC0, 0xFA, 0xC1, 0xEE, 0xB9, 0x9A, 0xBC, 0xFF, 0xA3, 0x89, 0xF2, 0x60, 0x1F};
39 static const u8 keys360_0[] = {0x3C, 0x2B, 0x51, 0xD4, 0x2D, 0x85, 0x47, 0xDA, 0x2D, 0xCA, 0x18, 0xDF, 0xFE, 0x54, 0x09, 0xED};
40 static const u8 keys360_1[] = {0x31, 0x1F, 0x98, 0xD5, 0x7B, 0x58, 0x95, 0x45, 0x32, 0xAB, 0x3A, 0xE3, 0x89, 0x32, 0x4B, 0x34};
41 static const u8 keys370_0[] = {0x26, 0x38, 0x0A, 0xAC, 0xA5, 0xD8, 0x74, 0xD1, 0x32, 0xB7, 0x2A, 0xBF, 0x79, 0x9E, 0x6D, 0xDB};
42 static const u8 keys370_1[] = {0x53, 0xE7, 0xAB, 0xB9, 0xC6, 0x4A, 0x4B, 0x77, 0x92, 0x17, 0xB5, 0x74, 0x0A, 0xDA, 0xA9, 0xEA};
43 static const u8 keys370_2[] = {0x71, 0x10, 0xF0, 0xA4, 0x16, 0x14, 0xD5, 0x93, 0x12, 0xFF, 0x74, 0x96, 0xDF, 0x1F, 0xDA, 0x89};
44 static const u8 keys390_0[] = {0x45, 0xEF, 0x5C, 0x5D, 0xED, 0x81, 0x99, 0x84, 0x12, 0x94, 0x8F, 0xAB, 0xE8, 0x05, 0x6D, 0x7D};
45 static const u8 keys390_1[] = {0x70, 0x1B, 0x08, 0x25, 0x22, 0xA1, 0x4D, 0x3B, 0x69, 0x21, 0xF9, 0x71, 0x0A, 0xA8, 0x41, 0xA9};
46 static const u8 keys500_0[] = {0xEB, 0x1B, 0x53, 0x0B, 0x62, 0x49, 0x32, 0x58, 0x1F, 0x83, 0x0A, 0xF4, 0x99, 0x3D, 0x75, 0xD0};
47 static const u8 keys500_1[] = {0xBA, 0xE2, 0xA3, 0x12, 0x07, 0xFF, 0x04, 0x1B, 0x64, 0xA5, 0x11, 0x85, 0xF7, 0x2F, 0x99, 0x5B};
48 static const u8 keys500_2[] = {0x2C, 0x8E, 0xAF, 0x1D, 0xFF, 0x79, 0x73, 0x1A, 0xAD, 0x96, 0xAB, 0x09, 0xEA, 0x35, 0x59, 0x8B};
49 static const u8 keys500_c[] = {0xA3, 0x5D, 0x51, 0xE6, 0x56, 0xC8, 0x01, 0xCA, 0xE3, 0x77, 0xBF, 0xCD, 0xFF, 0x24, 0xDA, 0x4D};
50 static const u8 keys505_a[] = {0x7B, 0x94, 0x72, 0x27, 0x4C, 0xCC, 0x54, 0x3B, 0xAE, 0xDF, 0x46, 0x37, 0xAC, 0x01, 0x4D, 0x87};
51 static const u8 keys505_0[] = {0x2E, 0x8E, 0x97, 0xA2, 0x85, 0x42, 0x70, 0x73, 0x18, 0xDA, 0xA0, 0x8A, 0xF8, 0x62, 0xA2, 0xB0};
52 static const u8 keys505_1[] = {0x58, 0x2A, 0x4C, 0x69, 0x19, 0x7B, 0x83, 0x3D, 0xD2, 0x61, 0x61, 0xFE, 0x14, 0xEE, 0xAA, 0x11};
53 static const u8 keys570_5k[] = {0x6D, 0x72, 0xA4, 0xBA, 0x7F, 0xBF, 0xD1, 0xF1, 0xA9, 0xF3, 0xBB, 0x07, 0x1B, 0xC0, 0xB3, 0x66};
54 static const u8 keys600_1[] = {0xE3, 0x52, 0x39, 0x97, 0x3B, 0x84, 0x41, 0x1C, 0xC3, 0x23, 0xF1, 0xB8, 0xA9, 0x09, 0x4B, 0xF0};
55 static const u8 keys600_2[] = {0xE1, 0x45, 0x93, 0x2C, 0x53, 0xE2, 0xAB, 0x06, 0x6F, 0xB6, 0x8F, 0x0B, 0x66, 0x91, 0xE7, 0x1E};
56 static const u8 keys620_0[] = {0xD6, 0xBD, 0xCE, 0x1E, 0x12, 0xAF, 0x9A, 0xE6, 0x69, 0x30, 0xDE, 0xDA, 0x88, 0xB8, 0xFF, 0xFB};
57 static const u8 keys620_1[] = {0x1D, 0x13, 0xE9, 0x50, 0x04, 0x73, 0x3D, 0xD2, 0xE1, 0xDA, 0xB9, 0xC1, 0xE6, 0x7B, 0x25, 0xA7};
58 static const u8 keys620_a[] = {0xAC, 0x34, 0xBA, 0xB1, 0x97, 0x8D, 0xAE, 0x6F, 0xBA, 0xE8, 0xB1, 0xD6, 0xDF, 0xDF, 0xF1, 0xA2};
59 static const u8 keys620_e[] = {0xB1, 0xB3, 0x7F, 0x76, 0xC3, 0xFB, 0x88, 0xE6, 0xF8, 0x60, 0xD3, 0x35, 0x3C, 0xA3, 0x4E, 0xF3};
60 static const u8 keys620_5[] = {0xF1, 0xBC, 0x17, 0x07, 0xAE, 0xB7, 0xC8, 0x30, 0xD8, 0x34, 0x9D, 0x40, 0x6A, 0x8E, 0xDF, 0x4E};
61 static const u8 keys620_5k[] = {0x41, 0x8A, 0x35, 0x4F, 0x69, 0x3A, 0xDF, 0x04, 0xFD, 0x39, 0x46, 0xA2, 0x5C, 0x2D, 0xF2, 0x21};
62 static const u8 keys620_5v[] = {0xF2, 0x8F, 0x75, 0xA7, 0x31, 0x91, 0xCE, 0x9E, 0x75, 0xBD, 0x27, 0x26, 0xB4, 0xB4, 0x0C, 0x32};
63 static const u8 keys630_k1[] = {0x36, 0xB0, 0xDC, 0xFC, 0x59, 0x2A, 0x95, 0x1D, 0x80, 0x2D, 0x80, 0x3F, 0xCD, 0x30, 0xA0, 0x1B};
64 static const u8 keys630_k2[] = {0xd4, 0x35, 0x18, 0x02, 0x29, 0x68, 0xfb, 0xa0, 0x6a, 0xa9, 0xa5, 0xed, 0x78, 0xfd, 0x2e, 0x9d};
65 static const u8 keys630_k3[] = {0x23, 0x8D, 0x3D, 0xAE, 0x41, 0x50, 0xA0, 0xFA, 0xF3, 0x2F, 0x32, 0xCE, 0xC7, 0x27, 0xCD, 0x50};
66 static const u8 keys630_k4[] = {0xAA, 0xA1, 0xB5, 0x7C, 0x93, 0x5A, 0x95, 0xBD, 0xEF, 0x69, 0x16, 0xFC, 0x2B, 0x92, 0x31, 0xDD};
67 static const u8 keys630_k5[] = {0x87, 0x37, 0x21, 0xCC, 0x65, 0xAE, 0xAA, 0x5F, 0x40, 0xF6, 0x6F, 0x2A, 0x86, 0xC7, 0xA1, 0xC8};
68 static const u8 keys630_k6[] = {0x8D, 0xDB, 0xDC, 0x5C, 0xF2, 0x70, 0x2B, 0x40, 0xB2, 0x3D, 0x00, 0x09, 0x61, 0x7C, 0x10, 0x60};
69 static const u8 keys630_k7[] = {0x77, 0x1C, 0x06, 0x5F, 0x53, 0xEC, 0x3F, 0xFC, 0x22, 0xCE, 0x5A, 0x27, 0xFF, 0x78, 0xA8, 0x48};
70 static const u8 keys630_k8[] = {0x81, 0xD1, 0x12, 0x89, 0x35, 0xC8, 0xEA, 0x8B, 0xE0, 0x02, 0x2D, 0x2D, 0x6A, 0x18, 0x67, 0xB8};
71 static const u8 keys636_k1[] = {0x07, 0xE3, 0x08, 0x64, 0x7F, 0x60, 0xA3, 0x36, 0x6A, 0x76, 0x21, 0x44, 0xC9, 0xD7, 0x06, 0x83};
72 static const u8 keys636_k2[] = {0x91, 0xF2, 0x02, 0x9E, 0x63, 0x32, 0x30, 0xA9, 0x1D, 0xDA, 0x0B, 0xA8, 0xB7, 0x41, 0xA3, 0xCC};
73 static const u8 keys638_k4[] = {0x98, 0x43, 0xFF, 0x85, 0x68, 0xB2, 0xDB, 0x3B, 0xD4, 0x22, 0xD0, 0x4F, 0xAB, 0x5F, 0x0A, 0x31};
74 static const u8 keys639_k3[] = {0x01, 0x7B, 0xF0, 0xE9, 0xBE, 0x9A, 0xDD, 0x54, 0x37, 0xEA, 0x0E, 0xC4, 0xD6, 0x4D, 0x8E, 0x9E};
75 static const u8 keys660_k1[] = {0x76, 0xF2, 0x6C, 0x0A, 0xCA, 0x3A, 0xBA, 0x4E, 0xAC, 0x76, 0xD2, 0x40, 0xF5, 0xC3, 0xBF, 0xF9};
76 static const u8 keys660_k2[] = {0x7A, 0x3E, 0x55, 0x75, 0xB9, 0x6A, 0xFC, 0x4F, 0x3E, 0xE3, 0xDF, 0xB3, 0x6C, 0xE8, 0x2A, 0x82};
77 static const u8 keys660_k3[] = {0xFA, 0x79, 0x09, 0x36, 0xE6, 0x19, 0xE8, 0xA4, 0xA9, 0x41, 0x37, 0x18, 0x81, 0x02, 0xE9, 0xB3};
78 static const u8 keys660_v1[] = {0xBA, 0x76, 0x61, 0x47, 0x8B, 0x55, 0xA8, 0x72, 0x89, 0x15, 0x79, 0x6D, 0xD7, 0x2F, 0x78, 0x0E};
79 static const u8 keys660_v2[] = {0xF9, 0x4A, 0x6B, 0x96, 0x79, 0x3F, 0xEE, 0x0A, 0x04, 0xC8, 0x8D, 0x7E, 0x5F, 0x38, 0x3A, 0xCF};
80 static const u8 keys660_v3[] = {0x88, 0xAF, 0x18, 0xE9, 0xC3, 0xAA, 0x6B, 0x56, 0xF7, 0xC5, 0xA8, 0xBF, 0x1A, 0x84, 0xE9, 0xF3};
81 static const u8 keys660_v4[] = {0xD1, 0xB0, 0xAE, 0xC3, 0x24, 0x36, 0x13, 0x49, 0xD6, 0x49, 0xD7, 0x88, 0xEA, 0xA4, 0x99, 0x86};
82 static const u8 keys660_v5[] = {0xCB, 0x93, 0x12, 0x38, 0x31, 0xC0, 0x2D, 0x2E, 0x7A, 0x18, 0x5C, 0xAC, 0x92, 0x93, 0xAB, 0x32};
83 static const u8 keys660_v6[] = {0x92, 0x8C, 0xA4, 0x12, 0xD6, 0x5C, 0x55, 0x31, 0x5B, 0x94, 0x23, 0x9B, 0x62, 0xB3, 0xDB, 0x47};
84 static const u8 keys660_k4[] = {0xC8, 0xA0, 0x70, 0x98, 0xAE, 0xE6, 0x2B, 0x80, 0xD7, 0x91, 0xE6, 0xCA, 0x4C, 0xA9, 0x78, 0x4E};
85 static const u8 keys660_k5[] = {0xBF, 0xF8, 0x34, 0x02, 0x84, 0x47, 0xBD, 0x87, 0x1C, 0x52, 0x03, 0x23, 0x79, 0xBB, 0x59, 0x81};
86 static const u8 keys660_k6[] = {0xD2, 0x83, 0xCC, 0x63, 0xBB, 0x10, 0x15, 0xE7, 0x7B, 0xC0, 0x6D, 0xEE, 0x34, 0x9E, 0x4A, 0xFA};
87 static const u8 keys660_k7[] = {0xEB, 0xD9, 0x1E, 0x05, 0x3C, 0xAE, 0xAB, 0x62, 0xE3, 0xB7, 0x1F, 0x37, 0xE5, 0xCD, 0x68, 0xC3};
88 static const u8 keys660_v7[] = {0xC5, 0x9C, 0x77, 0x9C, 0x41, 0x01, 0xE4, 0x85, 0x79, 0xC8, 0x71, 0x63, 0xA5, 0x7D, 0x4F, 0xFB};
89 static const u8 keys660_v8[] = {0x86, 0xA0, 0x7D, 0x4D, 0xB3, 0x6B, 0xA2, 0xFD, 0xF4, 0x15, 0x85, 0x70, 0x2D, 0x6A, 0x0D, 0x3A};
90 static const u8 keys660_k8[] = {0x85, 0x93, 0x1F, 0xED, 0x2C, 0x4D, 0xA4, 0x53, 0x59, 0x9C, 0x3F, 0x16, 0xF3, 0x50, 0xDE, 0x46};
91 static const u8 key_21C0[] = {0x6A, 0x19, 0x71, 0xF3, 0x18, 0xDE, 0xD3, 0xA2, 0x6D, 0x3B, 0xDE, 0xC7, 0xBE, 0x98, 0xE2, 0x4C};
92 static const u8 key_2250[] = {0x50, 0xCC, 0x03, 0xAC, 0x3F, 0x53, 0x1A, 0xFA, 0x0A, 0xA4, 0x34, 0x23, 0x86, 0x61, 0x7F, 0x97};
93 static const u8 key_22E0[] = {0x66, 0x0F, 0xCB, 0x3B, 0x30, 0x75, 0xE3, 0x10, 0x0A, 0x95, 0x65, 0xC7, 0x3C, 0x93, 0x87, 0x22};
94 static const u8 key_2D80[] = {0x40, 0x02, 0xC0, 0xBF, 0x20, 0x02, 0xC0, 0xBF, 0x5C, 0x68, 0x2B, 0x95, 0x5F, 0x40, 0x7B, 0xB8};
95 static const u8 key_2D90[] = {0x55, 0x19, 0x35, 0x10, 0x48, 0xD8, 0x2E, 0x46, 0xA8, 0xB1, 0x47, 0x77, 0xDC, 0x49, 0x6A, 0x6F};
96 static const u8 key_2DA8[] = {0x80, 0x02, 0xC0, 0xBF, 0x00, 0x0A, 0xC0, 0xBF, 0x40, 0x03, 0xC0, 0xBF, 0x40, 0x00, 0x00, 0x00};
97 static const u8 key_2DB8[] = {0x4C, 0x2D, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xB8, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
98 static const u8 key_D91605F0[] = {0xB8, 0x8C, 0x45, 0x8B, 0xB6, 0xE7, 0x6E, 0xB8, 0x51, 0x59, 0xA6, 0x53, 0x7C, 0x5E, 0x86, 0x31};
99 static const u8 key_D91606F0[] = {0xED, 0x10, 0xE0, 0x36, 0xC4, 0xFE, 0x83, 0xF3, 0x75, 0x70, 0x5E, 0xF6, 0xA4, 0x40, 0x05, 0xF7};
100 static const u8 key_D91608F0[] = {0x5C, 0x77, 0x0C, 0xBB, 0xB4, 0xC2, 0x4F, 0xA2, 0x7E, 0x3B, 0x4E, 0xB4, 0xB4, 0xC8, 0x70, 0xAF};
101 static const u8 key_D91609F0[] = {0xD0, 0x36, 0x12, 0x75, 0x80, 0x56, 0x20, 0x43, 0xC4, 0x30, 0x94, 0x3E, 0x1C, 0x75, 0xD1, 0xBF};
102 static const u8 key_D9160AF0[] = {0x10, 0xA9, 0xAC, 0x16, 0xAE, 0x19, 0xC0, 0x7E, 0x3B, 0x60, 0x77, 0x86, 0x01, 0x6F, 0xF2, 0x63};
103 static const u8 key_D9160BF0[] = {0x83, 0x83, 0xF1, 0x37, 0x53, 0xD0, 0xBE, 0xFC, 0x8D, 0xA7, 0x32, 0x52, 0x46, 0x0A, 0xC2, 0xC2};
104 static const u8 key_D91611F0[] = {0x61, 0xB0, 0xC0, 0x58, 0x71, 0x57, 0xD9, 0xFA, 0x74, 0x67, 0x0E, 0x5C, 0x7E, 0x6E, 0x95, 0xB9};
105 static const u8 key_D91612F0[] = {0x9E, 0x20, 0xE1, 0xCD, 0xD7, 0x88, 0xDE, 0xC0, 0x31, 0x9B, 0x10, 0xAF, 0xC5, 0xB8, 0x73, 0x23};
106 static const u8 key_D91613F0[] = {0xEB, 0xFF, 0x40, 0xD8, 0xB4, 0x1A, 0xE1, 0x66, 0x91, 0x3B, 0x8F, 0x64, 0xB6, 0xFC, 0xB7, 0x12};
107 static const u8 key_D91614F0[] = {0xFD, 0xF7, 0xB7, 0x3C, 0x9F, 0xD1, 0x33, 0x95, 0x11, 0xB8, 0xB5, 0xBB, 0x54, 0x23, 0x73, 0x85};
108 static const u8 key_D91615F0[] = {0xC8, 0x03, 0xE3, 0x44, 0x50, 0xF1, 0xE7, 0x2A, 0x6A, 0x0D, 0xC3, 0x61, 0xB6, 0x8E, 0x5F, 0x51};
109 static const u8 key_D91616F0[] = {0x53, 0x03, 0xB8, 0x6A, 0x10, 0x19, 0x98, 0x49, 0x1C, 0xAF, 0x30, 0xE4, 0x25, 0x1B, 0x6B, 0x28};
110 static const u8 key_D91617F0[] = {0x02, 0xFA, 0x48, 0x73, 0x75, 0xAF, 0xAE, 0x0A, 0x67, 0x89, 0x2B, 0x95, 0x4B, 0x09, 0x87, 0xA3};
111 static const u8 key_D91618F0[] = {0x96, 0x96, 0x7C, 0xC3, 0xF7, 0x12, 0xDA, 0x62, 0x1B, 0xF6, 0x9A, 0x9A, 0x44, 0x44, 0xBC, 0x48};
112 static const u8 key_D91619F0[] = {0xE0, 0x32, 0xA7, 0x08, 0x6B, 0x2B, 0x29, 0x2C, 0xD1, 0x4D, 0x5B, 0xEE, 0xA8, 0xC8, 0xB4, 0xE9};
113 static const u8 key_D9161AF0[] = {0x27, 0xE5, 0xA7, 0x49, 0x52, 0xE1, 0x94, 0x67, 0x35, 0x66, 0x91, 0x0C, 0xE8, 0x9A, 0x25, 0x24};
114 static const u8 key_D91620F0[] = {0x52, 0x1C, 0xB4, 0x5F, 0x40, 0x3B, 0x9A, 0xDD, 0xAC, 0xFC, 0xEA, 0x92, 0xFD, 0xDD, 0xF5, 0x90};
115 static const u8 key_D91621F0[] = {0xD1, 0x91, 0x2E, 0xA6, 0x21, 0x14, 0x29, 0x62, 0xF6, 0xED, 0xAE, 0xCB, 0xDD, 0xA3, 0xBA, 0xFE};
116 static const u8 key_D91622F0[] = {0x59, 0x5D, 0x78, 0x4D, 0x21, 0xB2, 0x01, 0x17, 0x6C, 0x9A, 0xB5, 0x1B, 0xDA, 0xB7, 0xF9, 0xE6};
117 static const u8 key_D91623F0[] = {0xAA, 0x45, 0xEB, 0x4F, 0x62, 0xFB, 0xD1, 0x0D, 0x71, 0xD5, 0x62, 0xD2, 0xF5, 0xBF, 0xA5, 0x2F};
118 static const u8 key_D91624F0[] = {0x61, 0xB7, 0x26, 0xAF, 0x8B, 0xF1, 0x41, 0x58, 0x83, 0x6A, 0xC4, 0x92, 0x12, 0xCB, 0xB1, 0xE9};
119 static const u8 key_D91628F0[] = {0x49, 0xA4, 0xFC, 0x66, 0xDC, 0xE7, 0x62, 0x21, 0xDB, 0x18, 0xA7, 0x50, 0xD6, 0xA8, 0xC1, 0xB6};
120 static const u8 key_D91680F0[] = {0x2C, 0x22, 0x9B, 0x12, 0x36, 0x74, 0x11, 0x67, 0x49, 0xD1, 0xD1, 0x88, 0x92, 0xF6, 0xA1, 0xD8};
121 static const u8 key_D91681F0[] = {0x52, 0xB6, 0x36, 0x6C, 0x8C, 0x46, 0x7F, 0x7A, 0xCC, 0x11, 0x62, 0x99, 0xC1, 0x99, 0xBE, 0x98};
122 static const u8 key_2E5E10F0[] = {0x9D, 0x5C, 0x5B, 0xAF, 0x8C, 0xD8, 0x69, 0x7E, 0x51, 0x9F, 0x70, 0x96, 0xE6, 0xD5, 0xC4, 0xE8};
123 static const u8 key_2E5E12F0[] = {0x8A, 0x7B, 0xC9, 0xD6, 0x52, 0x58, 0x88, 0xEA, 0x51, 0x83, 0x60, 0xCA, 0x16, 0x79, 0xE2, 0x07};
124 static const u8 key_2E5E13F0[] = {0xFF, 0xA4, 0x68, 0xC3, 0x31, 0xCA, 0xB7, 0x4C, 0xF1, 0x23, 0xFF, 0x01, 0x65, 0x3D, 0x26, 0x36};
125 static const u8 key_2FD30BF0[] = {0xD8, 0x58, 0x79, 0xF9, 0xA4, 0x22, 0xAF, 0x86, 0x90, 0xAC, 0xDA, 0x45, 0xCE, 0x60, 0x40, 0x3F};
126 static const u8 keys02G_E[] = {0x9D, 0x09, 0xFD, 0x20, 0xF3, 0x8F, 0x10, 0x69, 0x0D, 0xB2, 0x6F, 0x00, 0xCC, 0xC5, 0x51, 0x2E};
127 static const u8 keys03G_E[] = {0x4F, 0x44, 0x5C, 0x62, 0xB3, 0x53, 0xC4, 0x30, 0xFC, 0x3A, 0xA4, 0x5B, 0xEC, 0xFE, 0x51, 0xEA};
128 static const u8 keys05G_E[] = {0x5D, 0xAA, 0x72, 0xF2, 0x26, 0x60, 0x4D, 0x1C, 0xE7, 0x2D, 0xC8, 0xA3, 0x2F, 0x79, 0xC5, 0x54};
129 static const u8 oneseg_310[] = {0xC7, 0x27, 0x72, 0x85, 0xAB, 0xA7, 0xF7, 0xF0, 0x4C, 0xC1, 0x86, 0xCC, 0xE3, 0x7F, 0x17, 0xCA};
130 static const u8 oneseg_300[] = {0x76, 0x40, 0x9E, 0x08, 0xDB, 0x9B, 0x3B, 0xA1, 0x47, 0x8A, 0x96, 0x8E, 0xF3, 0xF7, 0x62, 0x92};
131 static const u8 oneseg_280[] = {0x23, 0xDC, 0x3B, 0xB5, 0xA9, 0x82, 0xD6, 0xEA, 0x63, 0xA3, 0x6E, 0x2B, 0x2B, 0xE9, 0xE1, 0x54};
132 static const u8 oneseg_260_271[] = {0x22, 0x43, 0x57, 0x68, 0x2F, 0x41, 0xCE, 0x65, 0x4C, 0xA3, 0x7C, 0xC6, 0xC4, 0xAC, 0xF3, 0x60};
133 static const u8 oneseg_slim[] = {0x12, 0x57, 0x0D, 0x8A, 0x16, 0x6D, 0x87, 0x06, 0x03, 0x7D, 0xC8, 0x8B, 0x62, 0xA3, 0x32, 0xA9};
134 static const u8 ms_app_main[] = {0x1E, 0x2E, 0x38, 0x49, 0xDA, 0xD4, 0x16, 0x08, 0x27, 0x2E, 0xF3, 0xBC, 0x37, 0x75, 0x80, 0x93};
135 static const u8 demokeys_280[] = {0x12, 0x99, 0x70, 0x5E, 0x24, 0x07, 0x6C, 0xD0, 0x2D, 0x06, 0xFE, 0x7E, 0xB3, 0x0C, 0x11, 0x26};
136 static const u8 demokeys_3XX_1[] = {0x47, 0x05, 0xD5, 0xE3, 0x56, 0x1E, 0x81, 0x9B, 0x09, 0x2F, 0x06, 0xDB, 0x6B, 0x12, 0x92, 0xE0};
137 static const u8 demokeys_3XX_2[] = {0xF6, 0x62, 0x39, 0x6E, 0x26, 0x22, 0x4D, 0xCA, 0x02, 0x64, 0x16, 0x99, 0x7B, 0x9A, 0xE7, 0xB8};
138 static const u8 ebootbin_271_new[] = {0xF4, 0xAE, 0xF4, 0xE1, 0x86, 0xDD, 0xD2, 0x9C, 0x7C, 0xC5, 0x42, 0xA6, 0x95, 0xA0, 0x83, 0x88};
139 static const u8 gameshare_260_271[] = {0xF9, 0x48, 0x38, 0x0C, 0x96, 0x88, 0xA7, 0x74, 0x4F, 0x65, 0xA0, 0x54, 0xC2, 0x76, 0xD9, 0xB8};
140 static const u8 gameshare_280[] = {0x2D, 0x86, 0x77, 0x3A, 0x56, 0xA4, 0x4F, 0xDD, 0x3C, 0x16, 0x71, 0x93, 0xAA, 0x8E, 0x11, 0x43};
141 static const u8 gameshare_300[] = {0x78, 0x1A, 0xD2, 0x87, 0x24, 0xBD, 0xA2, 0x96, 0x18, 0x3F, 0x89, 0x36, 0x72, 0x90, 0x92, 0x85};
142 static const u8 gameshare_310[] = {0xC9, 0x7D, 0x3E, 0x0A, 0x54, 0x81, 0x6E, 0xC7, 0x13, 0x74, 0x99, 0x74, 0x62, 0x18, 0xE7, 0xDD};
143 static const u8 key_380210F0[] = {0x32, 0x2C, 0xFA, 0x75, 0xE4, 0x7E, 0x93, 0xEB, 0x9F, 0x22, 0x80, 0x85, 0x57, 0x08, 0x98, 0x48};
144 static const u8 key_380280F0[] = {0x97, 0x09, 0x12, 0xD3, 0xDB, 0x02, 0xBD, 0xD8, 0xE7, 0x74, 0x51, 0xFE, 0xF0, 0xEA, 0x6C, 0x5C};
145 static const u8 key_380283F0[] = {0x34, 0x20, 0x0C, 0x8E, 0xA1, 0x86, 0x79, 0x84, 0xAF, 0x13, 0xAE, 0x34, 0x77, 0x6F, 0xEA, 0x89};
146 static const u8 key_407810F0[] = {0xAF, 0xAD, 0xCA, 0xF1, 0x95, 0x59, 0x91, 0xEC, 0x1B, 0x27, 0xD0, 0x4E, 0x8A, 0xF3, 0x3D, 0xE7};
147 static const u8 drmkeys_6XX_1[] = {0x36, 0xEF, 0x82, 0x4E, 0x74, 0xFB, 0x17, 0x5B, 0x14, 0x14, 0x05, 0xF3, 0xB3, 0x8A, 0x76, 0x18};
148 static const u8 drmkeys_6XX_2[] = {0x21, 0x52, 0x5D, 0x76, 0xF6, 0x81, 0x0F, 0x15, 0x2F, 0x4A, 0x40, 0x89, 0x63, 0xA0, 0x10, 0x55};
149 static const u8 pauth_98b83b5d_1[] = {0xB0, 0x24, 0xC8, 0x16, 0x43, 0xE8, 0xF0, 0x1C, 0x8C, 0x30, 0x67, 0x73, 0x3E, 0x96, 0x35, 0xEF};
150 static const u8 pauth_98b83b5d_xor[] = {0xA9, 0x1E, 0xDD, 0x7B, 0x09, 0xBB, 0x22, 0xB5, 0x9D, 0xA3, 0x30, 0x69, 0x13, 0x6E, 0x0E, 0xD8};
151 static const u8 pauth_f7aa47f6_1[] = {0xC5, 0xFB, 0x69, 0x03, 0x20, 0x7A, 0xCF, 0xBA, 0x2C, 0x90, 0xF8, 0xB8, 0x4D, 0xD2, 0xF1, 0xDE};
152 static const u8 pauth_f7aa47f6_2[] = {0x3A, 0x6B, 0x48, 0x96, 0x86, 0xA5, 0xC8, 0x80, 0x69, 0x6C, 0xE6, 0x4B, 0xF6, 0x04, 0x17, 0x44};
153 static const u8 pauth_f7aa47f6_xor[] = {0xA9, 0x1E, 0xDD, 0x7B, 0x09, 0xBB, 0x22, 0xB5, 0x9D, 0xA3, 0x30, 0x69, 0x13, 0x6E, 0x0E, 0xD8};
154 
155 // PRXDecrypter 144-byte tag keys.
156 static const u32 g_key0[] = {
157 		0x7b21f3be, 0x299c5e1d, 0x1c9c5e71, 0x96cb4645, 0x3c9b1be0, 0xeb85de3d,
158 		0x4a7f2022, 0xc2206eaa, 0xd50b3265, 0x55770567, 0x3c080840, 0x981d55f2,
159 		0x5fd8f6f3, 0xee8eb0c5, 0x944d8152, 0xf8278651, 0x2705bafa, 0x8420e533,
160 		0x27154ae9, 0x4819aa32, 0x59a3aa40, 0x2cb3cf65, 0xf274466d, 0x3a655605,
161 		0x21b0f88f, 0xc5b18d26, 0x64c19051, 0xd669c94e, 0xe87035f2, 0x9d3a5909,
162 		0x6f4e7102, 0xdca946ce, 0x8416881b, 0xbab097a5, 0x249125c6, 0xb34c0872};
163 static const u32 g_key2[] = {
164 		0xccfda932, 0x51c06f76, 0x046dcccf, 0x49e1821e, 0x7d3b024c, 0x9dda5865,
165 		0xcc8c9825, 0xd1e97db5, 0x6874d8cb, 0x3471c987, 0x72edb3fc, 0x81c8365d,
166 		0xe161e33a, 0xfc92db59, 0x2009b1ec, 0xb1a94ce4, 0x2f03696b, 0x87e236d8,
167 		0x3b2b8ce9, 0x0305e784, 0xf9710883, 0xb039db39, 0x893bea37, 0xe74d6805,
168 		0x2a5c38bd, 0xb08dc813, 0x15b32375, 0x46be4525, 0x0103fd90, 0xa90e87a2,
169 		0x52aba66a, 0x85bf7b80, 0x45e8ce63, 0x4dd716d3, 0xf5e30d2d, 0xaf3ae456};
170 static const u32 g_key3[] = {
171 		0xa6c8f5ca, 0x6d67c080, 0x924f4d3a, 0x047ca06a, 0x08640297, 0x4fd4a758,
172 		0xbd685a87, 0x9b2701c2, 0x83b62a35, 0x726b533c, 0xe522fa0c, 0xc24b06b4,
173 		0x459d1cac, 0xa8c5417b, 0x4fea62a2, 0x0615d742, 0x30628d09, 0xc44fab14,
174 		0x69ff715e, 0xd2d8837d, 0xbeed0b8b, 0x1e6e57ae, 0x61e8c402, 0xbe367a06,
175 		0x543f2b5e, 0xdb3ec058, 0xbe852075, 0x1e7e4dcc, 0x1564ea55, 0xec7825b4,
176 		0xc0538cad, 0x70f72c7f, 0x49e8c3d0, 0xeda97ec5, 0xf492b0a4, 0xe05eb02a};
177 static const u32 g_key44[] = {
178 		0xef80e005, 0x3a54689f, 0x43c99ccd, 0x1b7727be, 0x5cb80038, 0xdd2efe62,
179 		0xf369f92c, 0x160f94c5, 0x29560019, 0xbf3c10c5, 0xf2ce5566, 0xcea2c626,
180 		0xb601816f, 0x64e7481e, 0x0c34debd, 0x98f29cb0, 0x3fc504d7, 0xc8fb39f0,
181 		0x0221b3d8, 0x63f936a2, 0x9a3a4800, 0x6ecc32e3, 0x8e120cfd, 0xb0361623,
182 		0xaee1e689, 0x745502eb, 0xe4a6c61c, 0x74f23eb4, 0xd7fa5813, 0xb01916eb,
183 		0x12328457, 0xd2bc97d2, 0x646425d8, 0x328380a5, 0x43da8ab1, 0x4b122ac9};
184 static const u32 g_key20[] = {
185 		0x33b50800, 0xf32f5fcd, 0x3c14881f, 0x6e8a2a95, 0x29feefd5, 0x1394eae3,
186 		0xbd6bd443, 0x0821c083, 0xfab379d3, 0xe613e165, 0xf5a754d3, 0x108b2952,
187 		0x0a4b1e15, 0x61eadeba, 0x557565df, 0x3b465301, 0xae54ecc3, 0x61423309,
188 		0x70c9ff19, 0x5b0ae5ec, 0x989df126, 0x9d987a5f, 0x55bc750e, 0xc66eba27,
189 		0x2de988e8, 0xf76600da, 0x0382dccb, 0x5569f5f2, 0x8e431262, 0x288fe3d3,
190 		0x656f2187, 0x37d12e9c, 0x2f539eb4, 0xa492998e, 0xed3958f7, 0x39e96523};
191 static const u32 g_key3A[] = {
192 		0x67877069, 0x3abd5617, 0xc23ab1dc, 0xab57507d, 0x066a7f40, 0x24def9b9,
193 		0x06f759e4, 0xdcf524b1, 0x13793e5e, 0x0359022d, 0xaae7e1a2, 0x76b9b2fa,
194 		0x9a160340, 0x87822fba, 0x19e28fbb, 0x9e338a02, 0xd8007e9a, 0xea317af1,
195 		0x630671de, 0x0b67ca7c, 0x865192af, 0xea3c3526, 0x2b448c8e, 0x8b599254,
196 		0x4602e9cb, 0x4de16cda, 0xe164d5bb, 0x07ecd88e, 0x99ffe5f8, 0x768800c1,
197 		0x53b091ed, 0x84047434, 0xb426dbbc, 0x36f948bb, 0x46142158, 0x749bb492};
198 static const u32 g_keyEBOOT1xx[] = {
199 		0x18CB69EF, 0x158E8912, 0xDEF90EBB, 0x4CB0FB23, 0x3687EE18, 0x868D4A6E,
200 		0x19B5C756, 0xEE16551D, 0xE7CB2D6C, 0x9747C660, 0xCE95143F, 0x2956F477,
201 		0x03824ADE, 0x210C9DF1, 0x5029EB24, 0x81DFE69F, 0x39C89B00, 0xB00C8B91,
202 		0xEF2DF9C2, 0xE13A93FC, 0x8B94A4A8, 0x491DD09D, 0x686A400D, 0xCED4C7E4,
203 		0x96C8B7C9, 0x1EAADC28, 0xA4170B84, 0x505D5DDC, 0x5DA6C3CF, 0x0E5DFA2D,
204 		0x6E7919B5, 0xCE5E29C7, 0xAAACDB94, 0x45F70CDD, 0x62A73725, 0xCCE6563D};
205 static const u32 g_keyEBOOT2xx[] = {
206 		0xDA8E36FA, 0x5DD97447, 0x76C19874, 0x97E57EAF, 0x1CAB09BD, 0x9835BAC6,
207 		0x03D39281, 0x03B205CF, 0x2882E734, 0xE714F663, 0xB96E2775, 0xBD8AAFC7,
208 		0x1DD3EC29, 0xECA4A16C, 0x5F69EC87, 0x85981E92, 0x7CFCAE21, 0xBAE9DD16,
209 		0xE6A97804, 0x2EEE02FC, 0x61DF8A3D, 0xDD310564, 0x9697E149, 0xC2453F3B,
210 		0xF91D8456, 0x39DA6BC8, 0xB3E5FEF5, 0x89C593A3, 0xFB5C8ABC, 0x6C0B7212,
211 		0xE10DD3CB, 0x98D0B2A8, 0x5FD61847, 0xF0DC2357, 0x7701166A, 0x0F5C3B68};
212 static const u32 g_demokeys_280[] = {
213                 0x2A5282B4, 0x8706DDA5, 0x4C88EC1C, 0xD504708E, 0x72634DD2, 0xDD2E2F60,
214                 0xE3D5FDB5, 0xE050637D, 0x295C69AC, 0x7B61F57D, 0x594412B0, 0x13D925CE,
215                 0x2A6BE8DD, 0xBC9594E6, 0x1F4A8A39, 0xC56B5909, 0x52CFB2F7, 0x03EE089F,
216                 0x5CA57A21, 0xDB64090F, 0x5E9A56F3, 0x13C56633, 0xD9C48D1D, 0xCDA05972,
217                 0xD09E13B2, 0x7DEDD3DF, 0x364387BB, 0xCB207488, 0xBEC14B3F, 0x7C9C0D11,
218                 0x9916ED40, 0x65909519, 0xC55BB1B3, 0xE997E084, 0xB483438B, 0xB8A2D255};
219 static const u32 g_keyUPDATER[] = {
220 		0xA5603CBF, 0xD7482441, 0xF65764CC, 0x1F90060B, 0x4EA73E45, 0xE551D192,
221 		0xE7B75D8A, 0x465A506E, 0x40FB1022, 0x2C273350, 0x8096DA44, 0x9947198E,
222 		0x278DEE77, 0x745D062E, 0xC148FA45, 0x832582AF, 0x5FDB86DA, 0xCB15C4CE,
223 		0x2524C62F, 0x6C2EC3B1, 0x369BE39E, 0xF7EB1FC4, 0x1E51CE1A, 0xD70536F4,
224 		0xC34D39D8, 0x7418FB13, 0xE3C84DE1, 0xB118F03C, 0xA2018D4E, 0xE6D8770D,
225 		0x5720F390, 0x17F96341, 0x60A4A68F, 0x1327DD28, 0x05944C64, 0x0C2C4C12};
226 static const u32 g_keyMEIMG250[] = {
227 		0xA381FEBC, 0x99B9D5C9, 0x6C560A8D, 0x30309F95, 0x792646CC, 0x82B64E5E,
228 		0x1A3951AD, 0x0A182EC4, 0xC46131B4, 0x77C50C8A, 0x325F16C6, 0x02D1942E,
229 		0x0AA38AC4, 0x2A940AC6, 0x67034726, 0xE52DB133, 0xD2EF2107, 0x85C81E90,
230 		0xC8D164BA, 0xC38DCE1D, 0x948BA275, 0x0DB84603, 0xE2473637, 0xCD74FCDA,
231 		0x588E3D66, 0x6D28E822, 0x891E548B, 0xF53CF56D, 0x0BBDDB66, 0xC4B286AA,
232 		0x2BEBBC4B, 0xFC261FF4, 0x92B8E705, 0xDCEE6952, 0x5E0442E5, 0x8BEB7F21};
233 static const u32 g_keyMEIMG260[] = {
234 		0x11BFD698, 0xD7F9B324, 0xDD524927, 0x16215B86, 0x504AC36D, 0x5843B217,
235 		0xE5A0DA47, 0xBB73A1E7, 0x2915DB35, 0x375CFD3A, 0xBB70A905, 0x272BEFCA,
236 		0x2E960791, 0xEA0799BB, 0xB85AE6C8, 0xC9CAF773, 0x250EE641, 0x06E74A9E,
237 		0x5244895D, 0x466755A5, 0x9A84AF53, 0xE1024174, 0xEEBA031E, 0xED80B9CE,
238 		0xBC315F72, 0x5821067F, 0xE8313058, 0xD2D0E706, 0xE6D8933E, 0xD7D17FB4,
239 		0x505096C4, 0xFDA50B3B, 0x4635AE3D, 0xEB489C8A, 0x422D762D, 0x5A8B3231};
240 static const u32 g_keyDEMOS27X[] = {
241 		0x1ABF102F, 0xD596D071, 0x6FC552B2, 0xD4F2531F, 0xF025CDD9, 0xAF9AAF03,
242 		0xE0CF57CF, 0x255494C4, 0x7003675E, 0x907BC884, 0x002D4EE4, 0x0B687A0D,
243 		0x9E3AA44F, 0xF58FDA81, 0xEC26AC8C, 0x3AC9B49D, 0x3471C037, 0xB0F3834D,
244 		0x10DC4411, 0xA232EA31, 0xE2E5FA6B, 0x45594B03, 0xE43A1C87, 0x31DAD9D1,
245 		0x08CD7003, 0xFA9C2FDF, 0x5A891D25, 0x9B5C1934, 0x22F366E5, 0x5F084A32,
246 		0x695516D5, 0x2245BE9F, 0x4F6DD705, 0xC4B8B8A1, 0xBC13A600, 0x77B7FC3B};
247 static const u32 g_keyUNK1[] = {
248 		0x33B50800, 0xF32F5FCD, 0x3C14881F, 0x6E8A2A95, 0x29FEEFD5, 0x1394EAE3,
249 		0xBD6BD443, 0x0821C083, 0xFAB379D3, 0xE613E165, 0xF5A754D3, 0x108B2952,
250 		0x0A4B1E15, 0x61EADEBA, 0x557565DF, 0x3B465301, 0xAE54ECC3, 0x61423309,
251 		0x70C9FF19, 0x5B0AE5EC, 0x989DF126, 0x9D987A5F, 0x55BC750E, 0xC66EBA27,
252 		0x2DE988E8, 0xF76600DA, 0x0382DCCB, 0x5569F5F2, 0x8E431262, 0x288FE3D3,
253 		0x656F2187, 0x37D12E9C, 0x2F539EB4, 0xA492998E, 0xED3958F7, 0x39E96523};
254 static const u32 g_key_GAMESHARE1xx[] = {
255 		0x721B53E8, 0xFC3E31C6, 0xF85BA2A2, 0x3CF0AC72, 0x54EEA7AB, 0x5959BFCB,
256 		0x54B8836B, 0xBC431313, 0x989EF2CF, 0xF0CE36B2, 0x98BA4CF8, 0xE971C931,
257 		0xA0375DC8, 0x08E52FA0, 0xAC0DD426, 0x57E4D601, 0xC56E61C7, 0xEF1AB98A,
258 		0xD1D9F8F4, 0x5FE9A708, 0x3EF09D07, 0xFA0C1A8C, 0xA91EEA5C, 0x58F482C5,
259 		0x2C800302, 0x7EE6F6C3, 0xFF6ABBBB, 0x2110D0D0, 0xD3297A88, 0x980012D3,
260 		0xDC59C87B, 0x7FDC5792, 0xDB3F5DA6, 0xFC23B787, 0x22698ED3, 0xB680E812};
261 static const u32 g_key_GAMESHARE2xx[] = {
262 		0x94A757C7, 0x9FD39833, 0xF8508371, 0x328B0B29, 0x2CBCB9DA, 0x2918B9C6,
263 		0x944C50BA, 0xF1DCE7D0, 0x640C3966, 0xC90B3D08, 0xF4AD17BA, 0x6CA0F84B,
264 		0xF7767C67, 0xA4D3A55A, 0x4A085C6A, 0x6BB27071, 0xFA8B38FB, 0x3FDB31B8,
265 		0x8B7196F2, 0xDB9BED4A, 0x51625B84, 0x4C1481B4, 0xF684F508, 0x30B44770,
266 		0x93AA8E74, 0x90C579BC, 0x246EC88D, 0x2E051202, 0xC774842E, 0xA185D997,
267 		0x7A2B3ADD, 0xFE835B6D, 0x508F184D, 0xEB4C4F13, 0x0E1993D3, 0xBA96DFD2};
268 static const u32 g_key_INDEXDAT1xx[] = {
269 		0x76CB00AF, 0x111CE62F, 0xB7B27E36, 0x6D8DE8F9, 0xD54BF16A, 0xD9E90373,
270 		0x7599D982, 0x51F82B0E, 0x636103AD, 0x8E40BC35, 0x2F332C94, 0xF513AAE9,
271 		0xD22AFEE9, 0x04343987, 0xFC5BB80C, 0x12349D89, 0x14A481BB, 0x25ED3AE8,
272 		0x7D500E4F, 0x43D1B757, 0x7B59FDAD, 0x4CFBBF34, 0xC3D17436, 0xC1DA21DB,
273 		0xA34D8C80, 0x962B235D, 0x3E420548, 0x09CF9FFE, 0xD4883F5C, 0xD90E9CB5,
274 		0x00AEF4E9, 0xF0886DE9, 0x62A58A5B, 0x52A55546, 0x971941B5, 0xF5B79FAC};
275 
276 struct TAG_INFO
277 {
278 	u32 tag; // 4 byte value at offset 0xD0 in the PRX file
279 	const u32 *key; // "step1_result" use for XOR step
280 	u8 code;
281 	u8 codeExtra;
282 };
283 
284 static const TAG_INFO g_tagInfo[] =
285 {
286 	{ 0x00000000, g_key0, 0x42 },
287 	{ 0x02000000, g_key2, 0x45 },
288 	{ 0x03000000, g_key3, 0x46 },
289 	{ 0x4467415d, g_key44, 0x59, 0x59 },
290 	{ 0x207bbf2f, g_key20, 0x5A, 0x5A },
291 	{ 0x3ace4dce, g_key3A, 0x5B, 0x5B },
292 	{ 0x07000000, g_key_INDEXDAT1xx, 0x4A },
293 	{ 0x08000000, g_keyEBOOT1xx, 0x4B },
294 	{ 0xC0CB167C, g_keyEBOOT2xx, 0x5D, 0x5D },
295 	{ 0x7F24BDCD, g_demokeys_280, 0x60, 0x60 },
296 	{ 0x0B000000, g_keyUPDATER, 0x4E },
297 	{ 0x0C000000, g_keyDEMOS27X, 0x4F },
298 	{ 0x0F000000, g_keyMEIMG250, 0x52 },
299 	{ 0x862648D1, g_keyMEIMG260, 0x52, 0x52 },
300 	{ 0x207BBF2F, g_keyUNK1, 0x5A, 0x5A },
301 	{ 0x09000000, g_key_GAMESHARE1xx, 0x4C },
302 	{ 0xBB67C59F, g_key_GAMESHARE2xx, 0x5E, 0x5E }
303 };
304 
GetTagInfo(u32 tagFind)305 static const TAG_INFO *GetTagInfo(u32 tagFind)
306 {
307 	for (u32 iTag = 0; iTag < sizeof(g_tagInfo)/sizeof(TAG_INFO); iTag++)
308 		if (g_tagInfo[iTag].tag == tagFind)
309 			return &g_tagInfo[iTag];
310 	return NULL; // not found
311 }
312 
313 ////////// Decryption 2 //////////
314 
315 struct TAG_INFO2
316 {
317 	u32 tag; // 4 byte value at offset 0xD0 in the PRX file
318 	const u8 *key; // 16 bytes keys
319 	u8 code; // code for scramble
320 	u8 type;
321 	const u8 *seed;
322 };
323 
324 static const TAG_INFO2 g_tagInfo2[] =
325 {
326 	{ 0x4C9494F0, keys660_k1, 0x43 },
327 	{ 0x4C9495F0, keys660_k2, 0x43 },
328 	{ 0x4C9490F0, keys660_k3, 0x43 },
329 	{ 0x4C9491F0, keys660_k8, 0x43 },
330 	{ 0x4C9493F0, keys660_k4, 0x43 },
331 	{ 0x4C9497F0, keys660_k5, 0x43 },
332 	{ 0x4C9492F0, keys660_k6, 0x43 },
333 	{ 0x4C9496F0, keys660_k7, 0x43 },
334 	{ 0x457B90F0, keys660_v1, 0x5B },
335 	{ 0x457B91F0, keys660_v7, 0x5B },
336 	{ 0x457B92F0, keys660_v6, 0x5B },
337 	{ 0x457B93F0, keys660_v3, 0x5B },
338 	{ 0x380290F0, keys660_v2, 0x5A },
339 	{ 0x380291F0, keys660_v8, 0x5A },
340 	{ 0x380292F0, keys660_v4, 0x5A },
341 	{ 0x380293F0, keys660_v5, 0x5A },
342 	{ 0x4C948CF0, keys639_k3, 0x43 },
343 	{ 0x4C948DF0, keys638_k4, 0x43 },
344 	{ 0x4C948BF0, keys636_k2, 0x43 },
345 	{ 0x4C948AF0, keys636_k1, 0x43 },
346 	{ 0x4C9487F0, keys630_k8, 0x43 },
347 	{ 0x457B83F0, keys630_k7, 0x5B },
348 	{ 0x4C9486F0, keys630_k6, 0x43 },
349 	{ 0x457B82F0, keys630_k5, 0x5B },
350 	{ 0x457B81F0, keys630_k4, 0x5B },
351 	{ 0x4C9485F0, keys630_k3, 0x43 },
352 	{ 0x457B80F0, keys630_k2, 0x5B },
353 	{ 0x4C9484F0, keys630_k1, 0x43 },
354 	{ 0x457B28F0, keys620_e, 0x5B },
355 	{ 0x457B0CF0, keys620_a, 0x5B },
356 	{ 0x380228F0, keys620_5v, 0x5A },
357 	{ 0x4C942AF0, keys620_5k, 0x43 },
358 	{ 0x4C9428F0, keys620_5, 0x43 },
359 	{ 0x4C941DF0, keys620_1, 0x43 },
360 	{ 0x4C941CF0, keys620_0, 0x43 },
361 	{ 0x4C9422F0, keys600_2, 0x43 },
362 	{ 0x4C941EF0, keys600_1, 0x43 },
363 	{ 0x4C9429F0, keys570_5k, 0x43 },
364 	{ 0x457B0BF0, keys505_a, 0x5B },
365 	{ 0x4C9419F0, keys505_1, 0x43 },
366 	{ 0x4C9418F0, keys505_0, 0x43 },
367 	{ 0x457B1EF0, keys500_c, 0x5B },
368 	{ 0x4C941FF0, keys500_2, 0x43 },
369 	{ 0x4C9417F0, keys500_1, 0x43 },
370 	{ 0x4C9416F0, keys500_0, 0x43 },
371 	{ 0x4C9414F0, keys390_0, 0x43 },
372 	{ 0x4C9415F0, keys390_1, 0x43 },
373 	{ 0x4C9412F0, keys370_0, 0x43 },
374 	{ 0x4C9413F0, keys370_1, 0x43 },
375 	{ 0x457B10F0, keys370_2, 0x5B },
376 	{ 0x4C940DF0, keys360_0, 0x43 },
377 	{ 0x4C9410F0, keys360_1, 0x43 },
378 	{ 0x4C940BF0, keys330_0, 0x43 },
379 	{ 0x457B0AF0, keys330_1, 0x5B },
380 	{ 0x38020AF0, keys330_2, 0x5A },
381 	{ 0x4C940AF0, keys330_3, 0x43 },
382 	{ 0x4C940CF0, keys330_4, 0x43 },
383 	{ 0xcfef09f0, keys310_0, 0x62 },
384 	{ 0x457b08f0, keys310_1, 0x5B },
385 	{ 0x380208F0, keys310_2, 0x5A },
386 	{ 0xcfef08f0, keys310_3, 0x62 },
387 	{ 0xCFEF07F0, keys303_0, 0x62 },
388 	{ 0xCFEF06F0, keys300_0, 0x62 },
389 	{ 0x457B06F0, keys300_1, 0x5B },
390 	{ 0x380206F0, keys300_2, 0x5A },
391 	{ 0xCFEF05F0, keys280_0, 0x62 },
392 	{ 0x457B05F0, keys280_1, 0x5B },
393 	{ 0x380205F0, keys280_2, 0x5A },
394 	{ 0x16D59E03, keys260_0, 0x62 },
395 	{ 0x76202403, keys260_1, 0x5B },
396 	{ 0x0F037303, keys260_2, 0x5A },
397 	{ 0x4C940FF0, key_2DA8, 0x43 },
398 	{ 0x4467415D, key_22E0, 0x59 },
399 	{ 0x00000000, key_21C0, 0x42 },
400 	{ 0x01000000, key_2250, 0x43 },
401 	{ 0x2E5E10F0, key_2E5E10F0, 0x48 },
402 	{ 0x2E5E12F0, key_2E5E12F0, 0x48 },
403 	{ 0x2E5E13F0, key_2E5E13F0, 0x48 },
404 	{ 0x2FD30BF0, key_2FD30BF0, 0x47 },
405 	{ 0xD91605F0, key_D91605F0, 0x5D, 2},
406 	{ 0xD91606F0, key_D91606F0, 0x5D, 2},
407 	{ 0xD91608F0, key_D91608F0, 0x5D, 2},
408 	{ 0xD91609F0, key_D91609F0, 0x5D, 2},
409 	{ 0xD9160AF0, key_D9160AF0, 0x5D, 2},
410 	{ 0xD9160BF0, key_D9160BF0, 0x5D, 2},
411 	{ 0xD91611F0, key_D91611F0, 0x5D, 2},
412 	{ 0xD91612F0, key_D91612F0, 0x5D, 2},
413 	{ 0xD91613F0, key_D91613F0, 0x5D, 2},
414 	{ 0xD91614F0, key_D91614F0, 0x5D, 2},
415 	{ 0xD91615F0, key_D91615F0, 0x5D, 2},
416 	{ 0xD91616F0, key_D91616F0, 0x5D, 2},
417 	{ 0xD91617F0, key_D91617F0, 0x5D, 2},
418 	{ 0xD91618F0, key_D91618F0, 0x5D, 2},
419 	{ 0xD91619F0, key_D91619F0, 0x5D, 2},
420 	{ 0xD9161AF0, key_D9161AF0, 0x5D, 2},
421 	{ 0xD91620F0, key_D91620F0, 0x5D, 2},
422 	{ 0xD91621F0, key_D91621F0, 0x5D, 2},
423 	{ 0xD91622F0, key_D91622F0, 0x5D, 2},
424 	{ 0xD91623F0, key_D91623F0, 0x5D, 2},
425 	{ 0xD91624F0, key_D91624F0, 0x5D, 2},
426 	{ 0xD91628F0, key_D91628F0, 0x5D, 2},
427 	{ 0xD91680F0, key_D91680F0, 0x5D, 6},
428 	{ 0xD91681F0, key_D91681F0, 0x5D, 6},
429 	{ 0xD82310F0, keys02G_E, 0x51 },
430 	{ 0xD8231EF0, keys03G_E, 0x51 },
431 	{ 0xD82328F0, keys05G_E, 0x51 },
432 	{ 0x279D08F0, oneseg_310, 0x61 },
433 	{ 0x279D06F0, oneseg_300, 0x61 },
434 	{ 0x279D05F0, oneseg_280, 0x61 },
435 	{ 0xD66DF703, oneseg_260_271, 0x61 },
436 	{ 0x279D10F0, oneseg_slim, 0x61 },
437 	{ 0x3C2A08F0, ms_app_main, 0x67 },
438 	{ 0xADF305F0, demokeys_280, 0x60 },
439 	{ 0xADF306F0, demokeys_3XX_1, 0x60 },
440 	{ 0xADF308F0, demokeys_3XX_2, 0x60 },
441 	{ 0x8004FD03, ebootbin_271_new, 0x5D, 2 },
442 	{ 0x0A35EA03, gameshare_260_271, 0x5E },
443 	{ 0x7B0505F0, gameshare_280, 0x5E },
444 	{ 0x7B0506F0, gameshare_300, 0x5E },
445 	{ 0x7B0508F0, gameshare_310, 0x5E },
446 	{ 0x380210F0, key_380210F0, 0x5A },
447 	{ 0x380280F0, key_380280F0, 0x5A },
448 	{ 0x380283F0, key_380283F0, 0x5A },
449 	{ 0x407810F0, key_407810F0, 0x6A },
450 	{ 0xE92410F0, drmkeys_6XX_1, 0x40 },
451 	{ 0x692810F0, drmkeys_6XX_2, 0x40 },
452 	{ 0x2FD313F0, pauth_98b83b5d_1, 0x47, 5, pauth_98b83b5d_xor },
453 	{ 0x2FD312F0, pauth_f7aa47f6_1, 0x47, 5, pauth_f7aa47f6_xor },
454 	{ 0x2FD311F0, pauth_f7aa47f6_2, 0x47, 5, pauth_f7aa47f6_xor },
455 };
456 
GetTagInfo2(u32 tagFind)457 static const TAG_INFO2 *GetTagInfo2(u32 tagFind)
458 {
459 	for (u32 iTag = 0; iTag < sizeof(g_tagInfo2) / sizeof(TAG_INFO2); iTag++)
460 	{
461 		if (g_tagInfo2[iTag].tag == tagFind)
462 		{
463 			return &g_tagInfo2[iTag];
464 		}
465 	}
466 
467 	return NULL; // not found
468 }
469 
expandSeed(const u8 * seed,int key,const u8 * bonusSeed=nullptr)470 static std::array<u8, 0x90> expandSeed(const u8 *seed, int key, const u8 *bonusSeed = nullptr)
471 {
472 	std::array<u8, 0x90> expandedSeed;
473 
474 	// perform some AES-CTR like encryption of seed
475 	for (auto i = 0u; i < expandedSeed.size(); i += 0x10)
476 {
477 		memcpy(expandedSeed.data()+i, seed, 0x10);
478 		expandedSeed[i] = i/0x10;
479 	}
480 
481 	kirk7(expandedSeed.data(), expandedSeed.data(), expandedSeed.size(), key);
482 
483 	if (bonusSeed)
484 	{
485 		for (auto i = 0u; i < expandedSeed.size(); ++i)
486 		{
487 			expandedSeed[i] ^= bonusSeed[i % 0x10];
488 		}
489 	}
490 
491 	return expandedSeed;
492 }
493 
494 template<typename It>
decryptKirkHeader(u8 * outbuf,const u8 * inbuf,It xorbuf,int key)495 static void decryptKirkHeader(u8 *outbuf, const u8 *inbuf, It xorbuf, int key)
496 {
497 	for (auto i = 0; i < 0x40; ++i)
498 	{
499 		outbuf[i] = inbuf[i] ^ *xorbuf++;
500 	}
501 
502 	kirk7(outbuf, outbuf, 0x40, key);
503 
504 	for (auto i = 0; i < 0x40; ++i)
505 	{
506 		outbuf[i] = outbuf[i] ^ *xorbuf++;
507 	}
508 }
509 
510 template <typename T>
decryptKirkHeaderType0(u8 * outbuf,const u8 * inbuf,T xorbuf,int key)511 static void decryptKirkHeaderType0(u8 *outbuf, const u8 *inbuf, T xorbuf, int key)
512 {
513 	for (auto i = 0; i < 0x70; ++i)
514 	{
515 		outbuf[i] = inbuf[i] ^ xorbuf[i+0x14];
516 	}
517 
518 	kirk7(outbuf, outbuf, 0x70, key);
519 
520 	for (auto i = 0; i < 0x70; ++i)
521 	{
522 		outbuf[i] = outbuf[i] ^ xorbuf[i+0x20];
523 	}
524 }
525 
526 struct PRXType0
527 {
PRXType0PRXType0528 	explicit PRXType0(const u8 *prx)
529 	{
530 		memcpy(tag, prx+0xD0, sizeof(tag));
531 		memcpy(sha1, prx+0xD4, sizeof(sha1));
532 		memcpy(unused, prx+0xE8, sizeof(unused));
533 		memcpy(kirkBlock, prx+0x110, 0x40); // key data
534 		memcpy(kirkBlock+0x40, prx+0x80, sizeof(kirkBlock)-0x40);
535 		memcpy(prxHeader, prx, sizeof(prxHeader));
536 	}
537 
538 	u8 tag[4];
539 	u8 sha1[0x14];
540 	u8 unused[0x28];
541 	u8 kirkBlock[0x90];
542 	u8 prxHeader[0x80];
543 };
544 
545 static_assert(sizeof(PRXType0) == 0x150, "inconsistent size of PRX Type 0");
546 
547 struct PRXType1
548 {
PRXType1PRXType1549 	explicit PRXType1(const u8 *prx)
550 	{
551 		memcpy(tag, prx+0xD0, sizeof(tag));
552 		memcpy(sha1, prx+0xD4, sizeof(sha1));
553 		memcpy(unused, prx+0xE8, sizeof(unused));
554 		memcpy(kirkBlock, prx+0x110, 0x40); // key data
555 		memcpy(kirkBlock+0x40, prx+0x80, sizeof(kirkBlock)-0x40);
556 		memcpy(prxHeader, prx, sizeof(prxHeader));
557 	}
558 
decryptPRXType1559 	void decrypt(int key)
560 	{
561 		kirk7(sha1+0xC, sha1+0xC, 0xA0, key);
562 	}
563 
564 	u8 tag[4];
565 	u8 sha1[0x14];
566 	u8 unused[0x28];
567 	u8 kirkBlock[0x90];
568 	u8 prxHeader[0x80];
569 };
570 
571 static_assert(sizeof(PRXType1) == 0x150, "inconsistent size of PRX Type 1");
572 
573 struct PRXType2
574 {
PRXType2PRXType2575 	explicit PRXType2(const u8 *prx)
576 	{
577 		memcpy(tag, prx+0xD0, sizeof(tag));
578 		memset(empty, 0, sizeof(empty));
579 		memcpy(id, prx+0x140, sizeof(id));
580 		memcpy(sha1, prx+0x12C, sizeof(sha1));
581 		// kirk header is split between 0x80->0xB0 and 0xC0->0xD0
582 		memcpy(kirkHeader, prx+0x80, sizeof(kirkHeader)-0x10);
583 		memcpy(kirkHeader+0x30, prx+0xC0, 0x10);
584 		memcpy(kirkMetadata, prx+0xB0, sizeof(kirkMetadata));
585 		memcpy(prxHeader, prx, sizeof(prxHeader));
586 	}
587 
decryptPRXType2588 	void decrypt(int key)
589 	{
590 		kirk7(id, id, 0x60, key);
591 	}
592 
593 	u8 tag[4];
594 	u8 empty[0x58];
595 	u8 id[0x10];
596 	u8 sha1[0x14];
597 	u8 kirkHeader[0x40];
598 	u8 kirkMetadata[0x10];
599 	u8 prxHeader[0x80];
600 };
601 static_assert(sizeof(PRXType2) == 0x150, "inconsistent size of PRX Type 2");
602 
603 struct PRXType5
604 {
PRXType5PRXType5605 	explicit PRXType5(const u8 *prx)
606 	{
607 		memcpy(tag, prx+0xD0, sizeof(tag));
608 		memset(empty, 0, sizeof(empty));
609 		memcpy(id, prx+0x140, sizeof(id));
610 		memcpy(sha1, prx+0x12C, sizeof(sha1));
611 		// kirk header is split between 0x80->0xB0 and 0xC0->0xD0
612 		memcpy(kirkHeader, prx+0x80, sizeof(kirkHeader)-0x10);
613 		memcpy(kirkHeader+0x30, prx+0xC0, 0x10);
614 		memcpy(kirkMetadata, prx+0xB0, sizeof(kirkMetadata));
615 		memcpy(prxHeader, prx, sizeof(prxHeader));
616 	}
617 
decryptPRXType5618 	void decrypt(int key, const u8 *xor1, const u8 *xor2)
619 	{
620 		// first step is to decrypt kirk header + SHA1
621 		u8 data[0x50];
622 		memcpy(data, kirkHeader, sizeof(kirkHeader));
623 		memcpy(data+sizeof(kirkHeader), sha1, 0x10);
624 
625 		for (auto i = 0; i < 0x50; ++i)
626 		{
627 			if (xor1)
628 			{
629 				data[i] ^= xor1[i % 0x10];
630 			}
631 
632 			if (xor2)
633 			{
634 				data[i] ^= xor2[i % 0x10];
635 			}
636 		}
637 
638 		kirk7(data, data, 0x50, key);
639 
640 		// copy the result back
641 		memcpy(kirkHeader, data, sizeof(kirkHeader));
642 		memcpy(sha1, data+sizeof(kirkHeader), 0x10);
643 
644 		// second step is a XOR then decrypt id through to kirk header
645 		if (xor1)
646 		{
647 			u8 *p = id;
648 			for (auto i = 0; i < 0x60; ++i)
649 			{
650 				p[i] ^= xor1[i % 0x10];
651 			}
652 		}
653 
654 		kirk7(id, id, 0x60, key);
655 	}
656 
657 	u8 tag[4];
658 	u8 empty[0x58];
659 	u8 id[0x10];
660 	u8 sha1[0x14];
661 	u8 kirkHeader[0x40];
662 	u8 kirkMetadata[0x10];
663 	u8 prxHeader[0x80];
664 };
665 static_assert(sizeof(PRXType5) == 0x150, "inconsistent size of PRX Type 5");
666 
667 struct PRXType6
668 {
PRXType6PRXType6669 	explicit PRXType6(const u8 *prx)
670 	{
671 		memcpy(tag, prx+0xD0, sizeof(tag));
672 		memset(empty, 0, sizeof(empty));
673 		memcpy(ecdsaSignatureTail, prx+0x10C, sizeof(ecdsaSignatureTail));
674 		memcpy(id, prx+0x140, sizeof(id));
675 		memcpy(sha1, prx+0x12C, sizeof(sha1));
676 		// kirk header is split between 0x80->0xB0 and 0xC0->0xD0
677 		memcpy(kirkHeader, prx+0x80, sizeof(kirkHeader)-0x10);
678 		memcpy(kirkHeader+0x30, prx+0xC0, 0x10);
679 		memcpy(kirkMetadata, prx+0xB0, sizeof(kirkMetadata));
680 		memcpy(prxHeader, prx, sizeof(prxHeader));
681 	}
682 
decryptPRXType6683 	void decrypt(int key)
684 	{
685 		kirk7(id, id, 0x60, key);
686 	}
687 
688 	u8 tag[4];
689 	u8 empty[0x38];
690 	u8 ecdsaSignatureTail[0x20];
691 	u8 id[0x10];
692 	u8 sha1[0x14];
693 	u8 kirkHeader[0x40];
694 	u8 kirkMetadata[0x10];
695 	u8 prxHeader[0x80];
696 };
697 static_assert(sizeof(PRXType6) == 0x150, "inconsistent size of PRX Type 6");
698 
pspDecryptType0(const u8 * inbuf,u8 * outbuf,u32 size)699 static int pspDecryptType0(const u8 *inbuf, u8 *outbuf, u32 size)
700 {
701 	INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
702 	const auto decryptSize = *(s32_le*)&inbuf[0xB0];
703 	const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]);
704 
705 	if (!pti)
706 	{
707 		return -1;
708 	}
709 
710 	// no need to expand seed, and no need to decrypt
711 	// normally this would be a kirk7 op, but we have the seed pre-decrypted
712 	std::array<u8, 0x90> xorbuf;
713 	memcpy(xorbuf.data(), reinterpret_cast<const u8 *>(pti->key), xorbuf.size());
714 
715 	// construct the header format for a type 0 prx
716 	PRXType0 type0(inbuf);
717 
718 	SHA_CTX ctx;
719 	SHAInit(&ctx);
720 	SHAUpdate(&ctx, xorbuf.data(), 0x14);
721 	SHAUpdate(&ctx, type0.unused, sizeof(type0.unused));
722 	SHAUpdate(&ctx, type0.kirkBlock, sizeof(type0.kirkBlock));
723 	SHAUpdate(&ctx, type0.prxHeader, sizeof(type0.prxHeader));
724 
725 	u8 sha1[0x14];
726 	SHAFinal(sha1, &ctx);
727 
728 	if (memcmp(sha1, type0.sha1, sizeof(sha1)) != 0)
729 	{
730 		return -3;
731 	}
732 
733 	constexpr auto offset = sizeof(PSP_Header)-sizeof(KIRK_CMD1_HEADER)-sizeof(type0.prxHeader);
734 	KIRK_CMD1_HEADER *header = reinterpret_cast<KIRK_CMD1_HEADER *>(outbuf+offset);
735 
736 	if (outbuf != inbuf)
737 	{
738 		memcpy(outbuf, inbuf, size);
739 	}
740 
741 	memcpy(header, type0.kirkBlock, sizeof(KIRK_CMD1_HEADER));
742 	memcpy(reinterpret_cast<u8*>(header)+sizeof(KIRK_CMD1_HEADER), type0.prxHeader, sizeof(type0.prxHeader));
743 	decryptKirkHeaderType0(reinterpret_cast<u8*>(header), type0.kirkBlock, xorbuf, pti->code);
744 
745 	if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast<const u8*>(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0)
746 	{
747 		return -4;
748 	}
749 
750 	return decryptSize;
751 }
752 
pspDecryptType1(const u8 * inbuf,u8 * outbuf,u32 size)753 static int pspDecryptType1(const u8 *inbuf, u8 *outbuf, u32 size)
754 {
755 	INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
756 	const auto decryptSize = *(s32_le*)&inbuf[0xB0];
757 	const auto pti = GetTagInfo((u32)*(u32_le *)&inbuf[0xD0]);
758 
759 	if (!pti)
760 	{
761 		return -1;
762 	}
763 
764 	// no need to expand seed, and no need to decrypt
765 	// normally this would be a kirk7 op, but we have the seed pre-decrypted
766 	std::array<u8, 0x90> xorbuf;
767 	memcpy(xorbuf.data(), reinterpret_cast<const u8 *>(pti->key), xorbuf.size());
768 
769 	// construct the header format for a type 1 prx
770 	PRXType1 type1(inbuf);
771 	type1.decrypt(pti->code);
772 
773 	SHA_CTX ctx;
774 	SHAInit(&ctx);
775 	SHAUpdate(&ctx, xorbuf.data(), 0x14);
776 	SHAUpdate(&ctx, type1.unused, sizeof(type1.unused));
777 	SHAUpdate(&ctx, type1.kirkBlock, sizeof(type1.kirkBlock));
778 	SHAUpdate(&ctx, type1.prxHeader, sizeof(type1.prxHeader));
779 
780 	u8 sha1[0x14];
781 	SHAFinal(sha1, &ctx);
782 
783 	if (memcmp(sha1, type1.sha1, sizeof(sha1)) != 0)
784 	{
785 		return -3;
786 	}
787 
788 	constexpr auto offset = sizeof(PSP_Header)-sizeof(KIRK_CMD1_HEADER)-sizeof(type1.prxHeader);
789 	KIRK_CMD1_HEADER *header = reinterpret_cast<KIRK_CMD1_HEADER *>(outbuf+offset);
790 
791 	if (outbuf != inbuf)
792 	{
793 		memcpy(outbuf, inbuf, size);
794 	}
795 
796 	memcpy(header, type1.kirkBlock, sizeof(KIRK_CMD1_HEADER));
797 	memcpy(reinterpret_cast<u8*>(header)+sizeof(KIRK_CMD1_HEADER), type1.prxHeader, sizeof(type1.prxHeader));
798 	decryptKirkHeaderType0(reinterpret_cast<u8*>(header), type1.kirkBlock, xorbuf, pti->code);
799 
800 	if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast<const u8*>(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0)
801 	{
802 		return -4;
803 	}
804 
805 	return decryptSize;
806 }
807 
pspDecryptType2(const u8 * inbuf,u8 * outbuf,u32 size)808 static int pspDecryptType2(const u8 *inbuf, u8 *outbuf, u32 size)
809 {
810 	INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
811 	const auto decryptSize = *(s32_le*)&inbuf[0xB0];
812 	const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
813 
814 	if (!pti)
815 	{
816 		return -1;
817 	}
818 
819 	// check if range is non-zero
820 	if (std::any_of(inbuf+0xD4, inbuf+0xD4+0x58, [](u8 x) { return x != 0; }))
821 	{
822 		return -2;
823 	}
824 
825 	// expand the seed into a xor buffer
826 	auto xorbuf = expandSeed(pti->key, pti->code);
827 
828 	// construct the header format for a type 2 prx
829 	PRXType2 type2(inbuf);
830 	type2.decrypt(pti->code);
831 
832 	SHA_CTX ctx;
833 	SHAInit(&ctx);
834 	SHAUpdate(&ctx, type2.tag, sizeof(type2.tag));
835 	SHAUpdate(&ctx, xorbuf.data(), 0x10);
836 	SHAUpdate(&ctx, type2.empty, sizeof(type2.empty));
837 	SHAUpdate(&ctx, type2.id, sizeof(type2.id));
838 	SHAUpdate(&ctx, type2.kirkHeader, sizeof(type2.kirkHeader));
839 	SHAUpdate(&ctx, type2.kirkMetadata, sizeof(type2.kirkMetadata));
840 	SHAUpdate(&ctx, type2.prxHeader, sizeof(type2.prxHeader));
841 
842 	u8 sha1[0x14];
843 	SHAFinal(sha1, &ctx);
844 
845 	if (memcmp(sha1, type2.sha1, sizeof(sha1)) != 0)
846 	{
847 		return -3;
848 	}
849 
850 	constexpr auto offset = sizeof(PSP_Header)-sizeof(KIRK_CMD1_HEADER)-sizeof(type2.prxHeader);
851 	KIRK_CMD1_HEADER *header = reinterpret_cast<KIRK_CMD1_HEADER *>(outbuf+offset);
852 
853 	if (outbuf != inbuf)
854 	{
855 		memcpy(outbuf, inbuf, size);
856 	}
857 
858 	memset(header, 0, sizeof(KIRK_CMD1_HEADER));
859 	memcpy(reinterpret_cast<u8*>(&header->data_size), type2.kirkMetadata, sizeof(type2.kirkMetadata));
860 	memcpy(reinterpret_cast<u8*>(header)+sizeof(KIRK_CMD1_HEADER), type2.prxHeader, sizeof(type2.prxHeader));
861 	decryptKirkHeader(reinterpret_cast<u8*>(header), type2.kirkHeader, xorbuf.cbegin()+0x10, pti->code);
862 	header->mode = 1;
863 
864 	if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast<const u8*>(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0)
865 	{
866 		return -4;
867 	}
868 
869 	return decryptSize;
870 }
871 
pspDecryptType5(const u8 * inbuf,u8 * outbuf,u32 size,const u8 * seed)872 static int pspDecryptType5(const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed)
873 	{
874 	INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
875 	const auto decryptSize = *(s32_le*)&inbuf[0xB0];
876 	const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
877 
878 	if (!pti)
879 	{
880 		return -1;
881 	}
882 
883 	// check if range is non-zero
884 	if (std::any_of(inbuf+0xD4+1, inbuf+0xD4+0x58, [](u8 x) { return x != 0; }))
885 	{
886 		return -2;
887 	}
888 
889 	// expand the seed into a xor buffer
890 	auto xorbuf = expandSeed(pti->key, pti->code, seed);
891 
892 	// construct the header format for a type 2 prx
893 	PRXType5 type5(inbuf);
894 	type5.decrypt(pti->code, pti->seed, seed);
895 
896 	SHA_CTX ctx;
897 	SHAInit(&ctx);
898 	SHAUpdate(&ctx, type5.tag, sizeof(type5.tag));
899 	SHAUpdate(&ctx, xorbuf.data(), 0x10);
900 	SHAUpdate(&ctx, type5.empty, sizeof(type5.empty));
901 	SHAUpdate(&ctx, type5.id, sizeof(type5.id));
902 	SHAUpdate(&ctx, type5.kirkHeader, sizeof(type5.kirkHeader));
903 	SHAUpdate(&ctx, type5.kirkMetadata, sizeof(type5.kirkMetadata));
904 	SHAUpdate(&ctx, type5.prxHeader, sizeof(type5.prxHeader));
905 
906 	u8 sha1[0x14];
907 	SHAFinal(sha1, &ctx);
908 
909 	if (memcmp(sha1, type5.sha1, sizeof(sha1)) != 0)
910 	{
911 		return -3;
912 	}
913 
914 	constexpr auto offset = sizeof(PSP_Header)-sizeof(KIRK_CMD1_HEADER)-sizeof(type5.prxHeader);
915 	KIRK_CMD1_HEADER *header = reinterpret_cast<KIRK_CMD1_HEADER *>(outbuf+offset);
916 
917 	if (outbuf != inbuf)
918 	{
919 		memcpy(outbuf, inbuf, size);
920 	}
921 
922 	memset(header, 0, sizeof(KIRK_CMD1_HEADER));
923 	memcpy(reinterpret_cast<u8*>(&header->data_size), type5.kirkMetadata, sizeof(type5.kirkMetadata));
924 	memcpy(reinterpret_cast<u8*>(header)+sizeof(KIRK_CMD1_HEADER), type5.prxHeader, sizeof(type5.prxHeader));
925 	decryptKirkHeader(reinterpret_cast<u8*>(header), type5.kirkHeader, xorbuf.cbegin()+0x10, pti->code);
926 	header->mode = 1;
927 
928 	if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast<const u8*>(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0)
929 	{
930 		return -4;
931 	}
932 
933 	return decryptSize;
934 	}
935 
pspDecryptType6(const u8 * inbuf,u8 * outbuf,u32 size)936 static int pspDecryptType6(const u8 *inbuf, u8 *outbuf, u32 size)
937 {
938 	INFO_LOG(LOADER, "Decrypting tag %02X", (u32)*(u32_le *)&inbuf[0xD0]);
939 	const auto decryptSize = *(s32_le*)&inbuf[0xB0];
940 	const auto pti = GetTagInfo2((u32)*(u32_le *)&inbuf[0xD0]);
941 
942 	if (!pti)
943 	{
944 		return -1;
945 	}
946 
947 	// check if range is non-zero
948 	if (std::any_of(inbuf+0xD4, inbuf+0xD4+0x38, [](u8 x) { return x != 0; }))
949 	{
950 		return -2;
951 	}
952 
953 	// expand the seed into a xor buffer
954 	auto xorbuf = expandSeed(pti->key, pti->code);
955 
956 	// construct the header format for a type 2 prx
957 	PRXType6 type6(inbuf);
958 	type6.decrypt(pti->code);
959 
960 	SHA_CTX ctx;
961 	SHAInit(&ctx);
962 	SHAUpdate(&ctx, type6.tag, sizeof(type6.tag));
963 	SHAUpdate(&ctx, xorbuf.data(), 0x10);
964 	SHAUpdate(&ctx, type6.empty, sizeof(type6.empty));
965 	SHAUpdate(&ctx, type6.ecdsaSignatureTail, sizeof(type6.ecdsaSignatureTail));
966 	SHAUpdate(&ctx, type6.id, sizeof(type6.id));
967 	SHAUpdate(&ctx, type6.kirkHeader, sizeof(type6.kirkHeader));
968 	SHAUpdate(&ctx, type6.kirkMetadata, sizeof(type6.kirkMetadata));
969 	SHAUpdate(&ctx, type6.prxHeader, sizeof(type6.prxHeader));
970 
971 	u8 sha1[0x14];
972 	SHAFinal(sha1, &ctx);
973 
974 	if (memcmp(sha1, type6.sha1, sizeof(sha1)) != 0)
975 	{
976 		return -3;
977 }
978 
979 	constexpr auto offset = sizeof(PSP_Header)-sizeof(KIRK_CMD1_ECDSA_HEADER)-sizeof(type6.prxHeader);
980 	KIRK_CMD1_ECDSA_HEADER *header = reinterpret_cast<KIRK_CMD1_ECDSA_HEADER *>(outbuf+offset);
981 
982 	if (outbuf != inbuf)
983 	{
984 		memcpy(outbuf, inbuf, size);
985 	}
986 
987 	memset(header, 0, sizeof(KIRK_CMD1_ECDSA_HEADER));
988 	memcpy(outbuf+offset+0x40, type6.ecdsaSignatureTail, sizeof(type6.ecdsaSignatureTail));
989 	memcpy(reinterpret_cast<u8*>(&header->data_size), type6.kirkMetadata, sizeof(type6.kirkMetadata));
990 	memcpy(reinterpret_cast<u8*>(header)+sizeof(KIRK_CMD1_ECDSA_HEADER), type6.prxHeader, sizeof(type6.prxHeader));
991 	decryptKirkHeader(reinterpret_cast<u8*>(header), type6.kirkHeader, xorbuf.cbegin()+0x10, pti->code);
992 	header->mode = 1;
993 	header->ecdsa_hash = 1;
994 
995 	if (kirk_sceUtilsBufferCopyWithRange(outbuf, size, reinterpret_cast<const u8*>(header), size - offset, KIRK_CMD_DECRYPT_PRIVATE) != 0)
996 	{
997 		return -4;
998 	}
999 
1000 	return decryptSize;
1001 }
1002 
pspDecryptPRX(const u8 * inbuf,u8 * outbuf,u32 size,const u8 * seed)1003 int pspDecryptPRX(const u8 *inbuf, u8 *outbuf, u32 size, const u8 *seed)
1004 {
1005 	kirk_init();
1006 
1007 	// this would be significantly better if we had a log of the tags
1008 	// and their appropriate prx types
1009 	// since we don't know the PRX type we attempt a decrypt using all
1010 	auto res = pspDecryptType0(inbuf, outbuf, size);
1011 
1012 	if (res >= 0)
1013 		return res;
1014 
1015 	res = pspDecryptType1(inbuf, outbuf, size);
1016 
1017 	if (res >= 0)
1018 		return res;
1019 
1020 	res = pspDecryptType2(inbuf, outbuf, size);
1021 
1022 	if (res >= 0)
1023 		return res;
1024 
1025 	res = pspDecryptType5(inbuf, outbuf, size, seed);
1026 
1027 	if (res >= 0)
1028 		return res;
1029 
1030 	return pspDecryptType6(inbuf, outbuf, size);
1031 }
1032