diff --git a/pkg2zip.c b/pkg2zip.c index 7ee21ce..396db24 100644 --- a/pkg2zip.c +++ b/pkg2zip.c @@ -1,5 +1,7 @@ #include "pkg2zip_aes.h" #include "pkg2zip_zip.h" +#include "pkg2zip_out.h" +#include "pkg2zip_psp.h" #include "pkg2zip_utils.h" #include "pkg2zip_zrif.h" @@ -264,78 +266,6 @@ static const char* get_region(const char* id) } } -static zip out_zip; -static int out_zipped; -static sys_file out_file; -static uint64_t out_file_offset; - -static void out_begin(const char* name, int zipped) -{ - if (zipped) - { - zip_create(&out_zip, name); - } - out_zipped = zipped; -} - -static void out_end(void) -{ - if (out_zipped) - { - zip_close(&out_zip); - } -} - -static void out_add_folder(const char* path) -{ - if (out_zipped) - { - zip_add_folder(&out_zip, path); - } - else - { - sys_mkdir(path); - } -} - -static void out_begin_file(const char* name) -{ - if (out_zipped) - { - zip_begin_file(&out_zip, name); - } - else - { - out_file = sys_create(name); - out_file_offset = 0; - } -} - -static void out_end_file(void) -{ - if (out_zipped) - { - zip_end_file(&out_zip); - } - else - { - sys_close(out_file); - } -} - -static void out_write(const void* buffer, uint32_t size) -{ - if (out_zipped) - { - zip_write_file(&out_zip, buffer, size); - } - else - { - sys_write(out_file, out_file_offset, buffer, size); - out_file_offset += size; - } -} - typedef enum { PKG_TYPE_VITA_APP, PKG_TYPE_VITA_DLC, @@ -347,7 +277,7 @@ typedef enum { int main(int argc, char* argv[]) { - printf("pkg2zip v1.7\n"); + printf("pkg2zip v1.8\n"); int zipped = 1; const char* pkg_arg = NULL; @@ -587,30 +517,21 @@ int main(int argc, char* argv[]) fatal("ERROR: unsupported type"); } - out_begin(root, zipped); - if (zipped) { printf("[*] creating '%s' archive\n", root); - root[0] = 0; - } - else - { - printf("[*] output to '%s' folder\n", root); - if (type == PKG_TYPE_PSP) - { - // until PSP support is done - sys_mkdir(root); - sys_vstrncat(root, sizeof(root), "/"); - } - else - { - root[0] = 0; - } } + out_begin(root, zipped); + root[0] = 0; + if (type == PKG_TYPE_PSP) { + sys_vstrncat(root, sizeof(root), "pspemu"); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/ISO"); + out_add_folder(root); } else if (type == PKG_TYPE_PSX) { @@ -625,8 +546,6 @@ int main(int argc, char* argv[]) sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); - - sys_vstrncat(root, sizeof(root), "/"); } else if (type == PKG_TYPE_VITA_DLC) { @@ -638,8 +557,6 @@ int main(int argc, char* argv[]) sys_vstrncat(root, sizeof(root), "/%s", id2); out_add_folder(root); - - sys_vstrncat(root, sizeof(root), "/"); } else if (type == PKG_TYPE_VITA_PATCH) { @@ -648,8 +565,6 @@ int main(int argc, char* argv[]) sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); - - sys_vstrncat(root, sizeof(root), "/"); } else if (type == PKG_TYPE_VITA_PSM) { @@ -658,8 +573,6 @@ int main(int argc, char* argv[]) sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); - - sys_vstrncat(root, sizeof(root), "/"); } else if (type == PKG_TYPE_VITA_APP) { @@ -668,8 +581,6 @@ int main(int argc, char* argv[]) sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); - - sys_vstrncat(root, sizeof(root), "/"); } else { @@ -735,13 +646,13 @@ int main(int argc, char* argv[]) char* slash = strchr(name, '/'); if (slash != NULL) { - snprintf(path, sizeof(path), "%sRO/%s", root, name + 8); + snprintf(path, sizeof(path), "%s/RO/%s", root, name + 8); out_add_folder(path); } } - else if (type != PKG_TYPE_PSX) + else if (type == PKG_TYPE_VITA_APP || type == PKG_TYPE_VITA_DLC || type == PKG_TYPE_VITA_PATCH) { - snprintf(path, sizeof(path), "%s%s", root, name); + snprintf(path, sizeof(path), "%s/%s", root, name); out_add_folder(path); if (strcmp("sce_sys/package", name) == 0) @@ -758,7 +669,7 @@ int main(int argc, char* argv[]) // TODO: is this really needed? if (!sce_sys_package_created) { - snprintf(path, sizeof(path), "%ssce_sys/package", root); + snprintf(path, sizeof(path), "%s/sce_sys/package", root); out_add_folder(path); sce_sys_package_created = 1; @@ -771,25 +682,34 @@ int main(int argc, char* argv[]) { if (strcmp("USRDIR/CONTENT/DOCUMENT.DAT", name) == 0) { - snprintf(path, sizeof(path), "%sDOCUMENT.DAT", root); + snprintf(path, sizeof(path), "%s/DOCUMENT.DAT", root); } else if (strcmp("USRDIR/CONTENT/EBOOT.PBP", name) == 0) { - snprintf(path, sizeof(path), "%sEBOOT.PBP", root); + snprintf(path, sizeof(path), "%s/EBOOT.PBP", root); } else { continue; } } + else if (type == PKG_TYPE_PSP) + { + if (strcmp("USRDIR/CONTENT/EBOOT.PBP", name) == 0) + { + snprintf(path, sizeof(path), "%s/%s [%.9s].iso", root, title, id); + unpack_psp_eboot(path, item_key, iv, pkg, enc_offset, data_offset, data_size); + } + continue; + } else if (type == PKG_TYPE_VITA_PSM) { // skip "content/" prefix - snprintf(path, sizeof(path), "%sRO/%s", root, name + 8); + snprintf(path, sizeof(path), "%s/RO/%s", root, name + 8); } else { - snprintf(path, sizeof(path), "%s%s", root, name); + snprintf(path, sizeof(path), "%s/%s", root, name); } uint64_t offset = data_offset; @@ -810,7 +730,6 @@ int main(int argc, char* argv[]) offset += size; data_size -= size; } - out_end_file(); } } @@ -820,12 +739,12 @@ int main(int argc, char* argv[]) if (!sce_sys_package_created) { printf("[*] creating sce_sys/package\n"); - snprintf(path, sizeof(path), "%ssce_sys/package", root); + snprintf(path, sizeof(path), "%s/sce_sys/package", root); out_add_folder(path); } printf("[*] creating sce_sys/package/head.bin\n"); - snprintf(path, sizeof(path), "%ssce_sys/package/head.bin", root); + snprintf(path, sizeof(path), "%s/sce_sys/package/head.bin", root); out_begin_file(path); uint64_t head_size = enc_offset + items_size; @@ -842,7 +761,7 @@ int main(int argc, char* argv[]) out_end_file(); printf("[*] creating sce_sys/package/tail.bin\n"); - snprintf(path, sizeof(path), "%ssce_sys/package/tail.bin", root); + snprintf(path, sizeof(path), "%s/sce_sys/package/tail.bin", root); out_begin_file(path); uint64_t tail_offset = enc_offset + enc_size; @@ -857,7 +776,7 @@ int main(int argc, char* argv[]) out_end_file(); printf("[*] creating sce_sys/package/stat.bin\n"); - snprintf(path, sizeof(path), "%ssce_sys/package/stat.bin", root); + snprintf(path, sizeof(path), "%s/sce_sys/package/stat.bin", root); uint8_t stat[768] = { 0 }; out_begin_file(path); @@ -870,16 +789,16 @@ int main(int argc, char* argv[]) if (type == PKG_TYPE_VITA_PSM) { printf("[*] creating RO/License\n"); - snprintf(path, sizeof(path), "%sRO/License", root); + snprintf(path, sizeof(path), "%s/RO/License", root); out_add_folder(path); printf("[*] creating RO/License/FAKE.rif\n"); - snprintf(path, sizeof(path), "%sRO/License/FAKE.rif", root); + snprintf(path, sizeof(path), "%s/RO/License/FAKE.rif", root); } else { printf("[*] creating sce_sys/package/work.bin\n"); - snprintf(path, sizeof(path), "%ssce_sys/package/work.bin", root); + snprintf(path, sizeof(path), "%s/sce_sys/package/work.bin", root); } out_begin_file(path); @@ -890,29 +809,29 @@ int main(int argc, char* argv[]) if (type == PKG_TYPE_VITA_PSM) { printf("[*] creating RW\n"); - snprintf(path, sizeof(path), "%sRW", root); + snprintf(path, sizeof(path), "%s/RW", root); out_add_folder(path); printf("[*] creating RW/Documents\n"); - snprintf(path, sizeof(path), "%sRW/Documents", root); + snprintf(path, sizeof(path), "%s/RW/Documents", root); out_add_folder(path); printf("[*] creating RW/Temp\n"); - snprintf(path, sizeof(path), "%sRW/Temp", root); + snprintf(path, sizeof(path), "%s/RW/Temp", root); out_add_folder(path); printf("[*] creating RW/System\n"); - snprintf(path, sizeof(path), "%sRW/System", root); + snprintf(path, sizeof(path), "%s/RW/System", root); out_add_folder(path); printf("[*] creating RW/System/content_id\n"); - snprintf(path, sizeof(path), "%sRW/System/content_id", root); + snprintf(path, sizeof(path), "%s/RW/System/content_id", root); out_begin_file(path); out_write(pkg_header + 0x30, 0x30); out_end_file(); printf("[*] creating RW/System/pm.dat\n"); - snprintf(path, sizeof(path), "%sRW/System/pm.dat", root); + snprintf(path, sizeof(path), "%s/RW/System/pm.dat", root); uint8_t pm[1 << 16] = { 0 }; out_begin_file(path); diff --git a/pkg2zip_aes.c b/pkg2zip_aes.c index e3fabf1..90c0d9d 100644 --- a/pkg2zip_aes.c +++ b/pkg2zip_aes.c @@ -1,6 +1,9 @@ #include "pkg2zip_aes.h" #include "pkg2zip_utils.h" +#include +#include + #if defined(_MSC_VER) #define PLATFORM_SUPPORTS_AESNI 1 @@ -45,15 +48,19 @@ static int aes128_supported_x86() } void aes128_init_x86(aes128_key* context, const uint8_t* key); +void aes128_init_dec_x86(aes128_key* context, const uint8_t* key); void aes128_ecb_encrypt_x86(const aes128_key* context, const uint8_t* input, uint8_t* output); +void aes128_ecb_decrypt_x86(const aes128_key* context, const uint8_t* input, uint8_t* output); void aes128_ctr_xor_x86(const aes128_key* context, const uint8_t* iv, uint8_t* buffer, size_t size); +void aes128_cmac_process_x86(const aes128_key* ctx, uint8_t* block, const uint8_t *buffer, uint32_t size); +void aes128_psp_decrypt_x86(const aes128_key* ctx, const uint8_t* prev, const uint8_t* block, uint8_t* buffer, uint32_t size); #endif static const uint8_t rcon[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, }; -static const uint8_t Te[256] = { +static const uint8_t Te[] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, @@ -72,7 +79,26 @@ static const uint8_t Te[256] = { 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, }; -static const uint32_t TE[256] = { +static uint8_t Td[] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +}; + +static const uint32_t TE[] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, @@ -107,53 +133,130 @@ static const uint32_t TE[256] = { 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, }; +static const uint32_t TD[] = { + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, + 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, + 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, + 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, + 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, + 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, + 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, + 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, + 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, + 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, + 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, + 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, + 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, + 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, + 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, +}; + static uint8_t byte32(uint32_t x, int n) { return (uint8_t)(x >> (8 * n)); } -static uint32_t setup_mix(uint32_t temp) -{ - return (Te[byte32(temp, 2)] << 24) ^ (Te[byte32(temp, 1)] << 16) ^ (Te[byte32(temp, 0)] << 8) ^ Te[byte32(temp, 3)]; -} - static uint32_t ror32(uint32_t x, int n) { return (x >> n) | (x << (32 - n)); } -void aes128_init(aes128_key* context, const uint8_t* key) +static uint32_t setup_mix(uint32_t x) +{ + return (Te[byte32(x, 2)] << 24) ^ (Te[byte32(x, 1)] << 16) ^ (Te[byte32(x, 0)] << 8) ^ Te[byte32(x, 3)]; +} + +static uint32_t setup_mix2(uint32_t x) +{ + return TD[Te[byte32(x, 3)]] ^ ror32(TD[Te[byte32(x, 2)]], 8) ^ ror32(TD[Te[byte32(x, 1)]], 16) ^ ror32(TD[Te[byte32(x, 0)]], 24); +} + +void aes128_init(aes128_key* ctx, const uint8_t* key) { #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { - aes128_init_x86(context, key); + aes128_init_x86(ctx, key); return; } #endif - uint32_t* rk = context->key; + uint32_t* ekey = ctx->key; - rk[0] = get32be(key + 0); - rk[1] = get32be(key + 4); - rk[2] = get32be(key + 8); - rk[3] = get32be(key + 12); + ekey[0] = get32be(key + 0); + ekey[1] = get32be(key + 4); + ekey[2] = get32be(key + 8); + ekey[3] = get32be(key + 12); for (size_t i=0; i<10; i++) { - uint32_t temp = rk[3]; - rk[4] = rk[0] ^ setup_mix(temp) ^ (rcon[i] << 24); - rk[5] = rk[1] ^ rk[4]; - rk[6] = rk[2] ^ rk[5]; - rk[7] = rk[3] ^ rk[6]; - rk += 4; + uint32_t temp = ekey[3]; + ekey[4] = ekey[0] ^ setup_mix(temp) ^ (rcon[i] << 24); + ekey[5] = ekey[1] ^ ekey[4]; + ekey[6] = ekey[2] ^ ekey[5]; + ekey[7] = ekey[3] ^ ekey[6]; + ekey += 4; } } -static void aes128_encrypt(const aes128_key* context, const uint8_t* input, uint8_t* output) +void aes128_init_dec(aes128_key* ctx, const uint8_t* key) +{ +#if PLATFORM_SUPPORTS_AESNI + if (aes128_supported_x86()) + { + aes128_init_dec_x86(ctx, key); + return; + } +#endif + + aes128_key enc; + aes128_init(&enc, key); + + uint32_t* ekey = enc.key + 40; + uint32_t* dkey = ctx->key; + + *dkey++ = ekey[0]; + *dkey++ = ekey[1]; + *dkey++ = ekey[2]; + *dkey++ = ekey[3]; + ekey -= 4; + + for (size_t i = 0; i < 9; i++) + { + *dkey++ = setup_mix2(ekey[0]); + *dkey++ = setup_mix2(ekey[1]); + *dkey++ = setup_mix2(ekey[2]); + *dkey++ = setup_mix2(ekey[3]); + ekey -= 4; + } + + *dkey++ = ekey[0]; + *dkey++ = ekey[1]; + *dkey++ = ekey[2]; + *dkey++ = ekey[3]; +} + +static void aes128_encrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { uint32_t t0, t1, t2, t3; - const uint32_t* key = context->key; + const uint32_t* key = ctx->key; uint32_t s0 = get32be(input + 0) ^ *key++; uint32_t s1 = get32be(input + 4) ^ *key++; @@ -166,6 +269,7 @@ static void aes128_encrypt(const aes128_key* context, const uint8_t* input, uint t1 = TE[byte32(s1, 3)] ^ ror32(TE[byte32(s2, 2)], 8) ^ ror32(TE[byte32(s3, 1)], 16) ^ ror32(TE[byte32(s0, 0)], 24) ^ *key++; t2 = TE[byte32(s2, 3)] ^ ror32(TE[byte32(s3, 2)], 8) ^ ror32(TE[byte32(s0, 1)], 16) ^ ror32(TE[byte32(s1, 0)], 24) ^ *key++; t3 = TE[byte32(s3, 3)] ^ ror32(TE[byte32(s0, 2)], 8) ^ ror32(TE[byte32(s1, 1)], 16) ^ ror32(TE[byte32(s2, 0)], 24) ^ *key++; + s0 = TE[byte32(t0, 3)] ^ ror32(TE[byte32(t1, 2)], 8) ^ ror32(TE[byte32(t2, 1)], 16) ^ ror32(TE[byte32(t3, 0)], 24) ^ *key++; s1 = TE[byte32(t1, 3)] ^ ror32(TE[byte32(t2, 2)], 8) ^ ror32(TE[byte32(t3, 1)], 16) ^ ror32(TE[byte32(t0, 0)], 24) ^ *key++; s2 = TE[byte32(t2, 3)] ^ ror32(TE[byte32(t3, 2)], 8) ^ ror32(TE[byte32(t0, 1)], 16) ^ ror32(TE[byte32(t1, 0)], 24) ^ *key++; @@ -177,10 +281,10 @@ static void aes128_encrypt(const aes128_key* context, const uint8_t* input, uint t2 = TE[byte32(s2, 3)] ^ ror32(TE[byte32(s3, 2)], 8) ^ ror32(TE[byte32(s0, 1)], 16) ^ ror32(TE[byte32(s1, 0)], 24) ^ *key++; t3 = TE[byte32(s3, 3)] ^ ror32(TE[byte32(s0, 2)], 8) ^ ror32(TE[byte32(s1, 1)], 16) ^ ror32(TE[byte32(s2, 0)], 24) ^ *key++; - s0 = (Te[byte32(t0, 3)] << 24) ^ (Te[byte32(t1, 2)] << 16) ^ (Te[byte32(t2, 1)] << 8) ^ (Te[byte32(t3, 0)]) ^ *key++; - s1 = (Te[byte32(t1, 3)] << 24) ^ (Te[byte32(t2, 2)] << 16) ^ (Te[byte32(t3, 1)] << 8) ^ (Te[byte32(t0, 0)]) ^ *key++; - s2 = (Te[byte32(t2, 3)] << 24) ^ (Te[byte32(t3, 2)] << 16) ^ (Te[byte32(t0, 1)] << 8) ^ (Te[byte32(t1, 0)]) ^ *key++; - s3 = (Te[byte32(t3, 3)] << 24) ^ (Te[byte32(t0, 2)] << 16) ^ (Te[byte32(t1, 1)] << 8) ^ (Te[byte32(t2, 0)]) ^ *key++; + s0 = (Te[byte32(t0, 3)] << 24) ^ (Te[byte32(t1, 2)] << 16) ^ (Te[byte32(t2, 1)] << 8) ^ Te[byte32(t3, 0)] ^ *key++; + s1 = (Te[byte32(t1, 3)] << 24) ^ (Te[byte32(t2, 2)] << 16) ^ (Te[byte32(t3, 1)] << 8) ^ Te[byte32(t0, 0)] ^ *key++; + s2 = (Te[byte32(t2, 3)] << 24) ^ (Te[byte32(t3, 2)] << 16) ^ (Te[byte32(t0, 1)] << 8) ^ Te[byte32(t1, 0)] ^ *key++; + s3 = (Te[byte32(t3, 3)] << 24) ^ (Te[byte32(t0, 2)] << 16) ^ (Te[byte32(t1, 1)] << 8) ^ Te[byte32(t2, 0)] ^ *key++; set32be(output + 0, s0); set32be(output + 4, s1); @@ -188,16 +292,66 @@ static void aes128_encrypt(const aes128_key* context, const uint8_t* input, uint set32be(output + 12, s3); } -void aes128_ecb_encrypt(const aes128_key* context, const uint8_t* input, uint8_t* output) +static void aes128_decrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) +{ + const uint32_t* key = ctx->key; + + uint32_t s0 = get32be(input + 0) ^ *key++; + uint32_t s1 = get32be(input + 4) ^ *key++; + uint32_t s2 = get32be(input + 8) ^ *key++; + uint32_t s3 = get32be(input + 12) ^ *key++; + + uint32_t t0 = TD[byte32(s0, 3)] ^ ror32(TD[byte32(s3, 2)], 8) ^ ror32(TD[byte32(s2, 1)], 16) ^ ror32(TD[byte32(s1, 0)], 24) ^ *key++; + uint32_t t1 = TD[byte32(s1, 3)] ^ ror32(TD[byte32(s0, 2)], 8) ^ ror32(TD[byte32(s3, 1)], 16) ^ ror32(TD[byte32(s2, 0)], 24) ^ *key++; + uint32_t t2 = TD[byte32(s2, 3)] ^ ror32(TD[byte32(s1, 2)], 8) ^ ror32(TD[byte32(s0, 1)], 16) ^ ror32(TD[byte32(s3, 0)], 24) ^ *key++; + uint32_t t3 = TD[byte32(s3, 3)] ^ ror32(TD[byte32(s2, 2)], 8) ^ ror32(TD[byte32(s1, 1)], 16) ^ ror32(TD[byte32(s0, 0)], 24) ^ *key++; + + for (size_t i = 0; i < 4; i++) + { + s0 = TD[byte32(t0, 3)] ^ ror32(TD[byte32(t3, 2)], 8) ^ ror32(TD[byte32(t2, 1)], 16) ^ ror32(TD[byte32(t1, 0)], 24) ^ *key++; + s1 = TD[byte32(t1, 3)] ^ ror32(TD[byte32(t0, 2)], 8) ^ ror32(TD[byte32(t3, 1)], 16) ^ ror32(TD[byte32(t2, 0)], 24) ^ *key++; + s2 = TD[byte32(t2, 3)] ^ ror32(TD[byte32(t1, 2)], 8) ^ ror32(TD[byte32(t0, 1)], 16) ^ ror32(TD[byte32(t3, 0)], 24) ^ *key++; + s3 = TD[byte32(t3, 3)] ^ ror32(TD[byte32(t2, 2)], 8) ^ ror32(TD[byte32(t1, 1)], 16) ^ ror32(TD[byte32(t0, 0)], 24) ^ *key++; + + t0 = TD[byte32(s0, 3)] ^ ror32(TD[byte32(s3, 2)], 8) ^ ror32(TD[byte32(s2, 1)], 16) ^ ror32(TD[byte32(s1, 0)], 24) ^ *key++; + t1 = TD[byte32(s1, 3)] ^ ror32(TD[byte32(s0, 2)], 8) ^ ror32(TD[byte32(s3, 1)], 16) ^ ror32(TD[byte32(s2, 0)], 24) ^ *key++; + t2 = TD[byte32(s2, 3)] ^ ror32(TD[byte32(s1, 2)], 8) ^ ror32(TD[byte32(s0, 1)], 16) ^ ror32(TD[byte32(s3, 0)], 24) ^ *key++; + t3 = TD[byte32(s3, 3)] ^ ror32(TD[byte32(s2, 2)], 8) ^ ror32(TD[byte32(s1, 1)], 16) ^ ror32(TD[byte32(s0, 0)], 24) ^ *key++; + } + + s0 = (Td[byte32(t0, 3)] << 24) ^ (Td[byte32(t3, 2)] << 16) ^ (Td[byte32(t2, 1)] << 8) ^ Td[byte32(t1, 0)] ^ *key++; + s1 = (Td[byte32(t1, 3)] << 24) ^ (Td[byte32(t0, 2)] << 16) ^ (Td[byte32(t3, 1)] << 8) ^ Td[byte32(t2, 0)] ^ *key++; + s2 = (Td[byte32(t2, 3)] << 24) ^ (Td[byte32(t1, 2)] << 16) ^ (Td[byte32(t0, 1)] << 8) ^ Td[byte32(t3, 0)] ^ *key++; + s3 = (Td[byte32(t3, 3)] << 24) ^ (Td[byte32(t2, 2)] << 16) ^ (Td[byte32(t1, 1)] << 8) ^ Td[byte32(t0, 0)] ^ *key++; + + set32be(output + 0, s0); + set32be(output + 4, s1); + set32be(output + 8, s2); + set32be(output + 12, s3); +} + +void aes128_ecb_encrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { - aes128_ecb_encrypt_x86(context, input, output); + aes128_ecb_encrypt_x86(ctx, input, output); return; } #endif - aes128_encrypt(context, input, output); + aes128_encrypt(ctx, input, output); +} + +void aes128_ecb_decrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) +{ +#if PLATFORM_SUPPORTS_AESNI + if (aes128_supported_x86()) + { + aes128_ecb_decrypt_x86(ctx, input, output); + return; + } +#endif + aes128_decrypt(ctx, input, output); } static void ctr_add(uint8_t* counter, uint64_t n) @@ -248,3 +402,158 @@ void aes128_ctr_xor(const aes128_key* context, const uint8_t* iv, uint64_t block } } } + +// https://tools.ietf.org/rfc/rfc4493.txt + +typedef struct { + aes128_key key; + uint8_t last[16]; + uint8_t block[16]; + uint32_t size; +} aes128_cmac_ctx; + +static void aes128_cmac_process(const aes128_key* ctx, uint8_t* block, const uint8_t *buffer, uint32_t size) +{ + assert(size % 16 == 0); + +#if PLATFORM_SUPPORTS_AESNI + if (aes128_supported_x86()) + { + aes128_cmac_process_x86(ctx, block, buffer, size); + return; + } +#endif + for (uint32_t i = 0; i < size; i += 16) + { + for (size_t k = 0; k < 16; k++) + { + block[k] ^= *buffer++; + } + aes128_ecb_encrypt(ctx, block, block); + } +} + +static void aes128_cmac_init(aes128_cmac_ctx* ctx, const uint8_t* key) +{ + aes128_init(&ctx->key, key); + memset(ctx->last, 0, 16); + ctx->size = 0; +} + +static void aes128_cmac_update(aes128_cmac_ctx* ctx, const uint8_t* buffer, uint32_t size) +{ + if (ctx->size + size <= 16) + { + memcpy(ctx->block + ctx->size, buffer, size); + ctx->size += size; + return; + } + + if (ctx->size != 0) + { + uint32_t avail = 16 - ctx->size; + memcpy(ctx->block + ctx->size, buffer, avail < size ? avail : size); + buffer += avail; + size -= avail; + + aes128_cmac_process(&ctx->key, ctx->last, ctx->block, 16); + } + + if (size >= 16) + { + uint32_t full = (size - 1) & ~15; + aes128_cmac_process(&ctx->key, ctx->last, buffer, full); + buffer += full; + size -= full; + } + + memcpy(ctx->block, buffer, size); + ctx->size = size; +} + +static void cmac_gfmul(uint8_t* block) +{ + uint8_t carry = 0; + for (int i = 15; i >= 0; i--) + { + uint8_t x = block[i]; + block[i] = (block[i] << 1) | (carry >> 7); + carry = x; + } + + block[15] ^= (carry & 0x80 ? 0x87 : 0); +} + +static void aes128_cmac_done(aes128_cmac_ctx* ctx, uint8_t* mac) +{ + uint8_t zero[16] = { 0 }; + aes128_ecb_encrypt(&ctx->key, zero, mac); + + cmac_gfmul(mac); + + if (ctx->size != 16) + { + cmac_gfmul(mac); + + ctx->block[ctx->size] = 0x80; + memset(ctx->block + ctx->size + 1, 0, 16 - (ctx->size + 1)); + } + + for (size_t i = 0; i < 16; i++) + { + mac[i] ^= ctx->block[i]; + } + + aes128_cmac_process(&ctx->key, mac, ctx->last, 16); +} + +void aes128_cmac(const uint8_t* key, const uint8_t* buffer, uint32_t size, uint8_t* mac) +{ + aes128_cmac_ctx ctx; + aes128_cmac_init(&ctx, key); + aes128_cmac_update(&ctx, buffer, size); + aes128_cmac_done(&ctx, mac); +} + +void aes128_psp_decrypt(const aes128_key* ctx, const uint8_t* iv, uint32_t index, uint8_t* buffer, uint32_t size) +{ + assert(size % 16 == 0); + + uint8_t PKG_ALIGN(16) prev[16]; + uint8_t PKG_ALIGN(16) block[16]; + + if (index == 0) + { + memset(prev, 0, 16); + } + else + { + memcpy(prev, iv, 12); + set32le(prev + 12, index); + } + + memcpy(block, iv, 16); + set32le(block + 12, index); + +#if PLATFORM_SUPPORTS_AESNI + if (aes128_supported_x86()) + { + aes128_psp_decrypt_x86(ctx, prev, block, buffer, size); + return; + } +#endif + + for (uint32_t i = 0; i < size; i += 16) + { + set32le(block + 12, get32le(block + 12) + 1); + + uint8_t out[16]; + aes128_ecb_decrypt(ctx, block, out); + + for (size_t k = 0; k < 16; k++) + { + *buffer++ ^= prev[k] ^ out[k]; + } + memcpy(prev, block, 16); + } +} diff --git a/pkg2zip_aes.h b/pkg2zip_aes.h index c4acfbe..b819a2c 100644 --- a/pkg2zip_aes.h +++ b/pkg2zip_aes.h @@ -2,10 +2,18 @@ #include "pkg2zip_utils.h" -typedef struct { +typedef struct aes128_key { uint32_t PKG_ALIGN(16) key[44]; } aes128_key; -void aes128_init(aes128_key* context, const uint8_t* key); -void aes128_ecb_encrypt(const aes128_key* context, const uint8_t* input, uint8_t* output); -void aes128_ctr_xor(const aes128_key* context, const uint8_t* iv, uint64_t block, uint8_t* buffer, size_t size); +void aes128_init(aes128_key* ctx, const uint8_t* key); +void aes128_init_dec(aes128_key* ctx, const uint8_t* key); + +void aes128_ecb_encrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output); +void aes128_ecb_decrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output); + +void aes128_ctr_xor(const aes128_key* ctx, const uint8_t* iv, uint64_t block, uint8_t* buffer, size_t size); + +void aes128_cmac(const uint8_t* key, const uint8_t* buffer, uint32_t size, uint8_t* mac); + +void aes128_psp_decrypt(const aes128_key* ctx, const uint8_t* iv, uint32_t index, uint8_t* buffer, uint32_t size); diff --git a/pkg2zip_aes_x86.c b/pkg2zip_aes_x86.c index e32b7fb..a6963c1 100644 --- a/pkg2zip_aes_x86.c +++ b/pkg2zip_aes_x86.c @@ -19,46 +19,84 @@ x = _mm_xor_si128(x, a); \ } -void aes128_init_x86(aes128_key* context, const uint8_t* key) +void aes128_init_x86(aes128_key* ctx, const uint8_t* key) { - __m128i* ctx = (__m128i*)context->key; + __m128i* ekey = (__m128i*)ctx->key; __m128i x = _mm_loadu_si128((const __m128i*)key); - AES128_INIT(ctx + 0, x, 0x01); - AES128_INIT(ctx + 1, x, 0x02); - AES128_INIT(ctx + 2, x, 0x04); - AES128_INIT(ctx + 3, x, 0x08); - AES128_INIT(ctx + 4, x, 0x10); - AES128_INIT(ctx + 5, x, 0x20); - AES128_INIT(ctx + 6, x, 0x40); - AES128_INIT(ctx + 7, x, 0x80); - AES128_INIT(ctx + 8, x, 0x1b); - AES128_INIT(ctx + 9, x, 0x36); - _mm_storeu_si128(ctx + 10, x); + AES128_INIT(ekey + 0, x, 0x01); + AES128_INIT(ekey + 1, x, 0x02); + AES128_INIT(ekey + 2, x, 0x04); + AES128_INIT(ekey + 3, x, 0x08); + AES128_INIT(ekey + 4, x, 0x10); + AES128_INIT(ekey + 5, x, 0x20); + AES128_INIT(ekey + 6, x, 0x40); + AES128_INIT(ekey + 7, x, 0x80); + AES128_INIT(ekey + 8, x, 0x1b); + AES128_INIT(ekey + 9, x, 0x36); + _mm_store_si128(ekey + 10, x); +} + +void aes128_init_dec_x86(aes128_key* ctx, const uint8_t* key) +{ + aes128_key enc; + aes128_init_x86(&enc, key); + + const __m128i* ekey = (__m128i*)&enc.key; + __m128i* dkey = (__m128i*)&ctx->key; + + _mm_store_si128(dkey + 10, _mm_load_si128(ekey + 0)); + for (size_t i = 1; i < 10; i++) + { + _mm_store_si128(dkey + 10 - i, _mm_aesimc_si128(_mm_load_si128(ekey + i))); + } + _mm_store_si128(dkey + 0, _mm_load_si128(ekey + 10)); } static __m128i aes128_encrypt_x86(__m128i input, const __m128i* key) { - __m128i tmp = _mm_xor_si128(input, key[0]); - tmp = _mm_aesenc_si128(tmp, key[1]); - tmp = _mm_aesenc_si128(tmp, key[2]); - tmp = _mm_aesenc_si128(tmp, key[3]); - tmp = _mm_aesenc_si128(tmp, key[4]); - tmp = _mm_aesenc_si128(tmp, key[5]); - tmp = _mm_aesenc_si128(tmp, key[6]); - tmp = _mm_aesenc_si128(tmp, key[7]); - tmp = _mm_aesenc_si128(tmp, key[8]); - tmp = _mm_aesenc_si128(tmp, key[9]); - return _mm_aesenclast_si128(tmp, key[10]); + __m128i tmp = _mm_xor_si128(input, _mm_load_si128(key + 0)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 1)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 2)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 3)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 4)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 5)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 6)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 7)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 8)); + tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 9)); + return _mm_aesenclast_si128(tmp, _mm_load_si128(key + 10)); } -void aes128_ecb_encrypt_x86(const aes128_key* context, const uint8_t* input, uint8_t* output) +static __m128i aes128_decrypt_x86(__m128i input, const __m128i* key) { - const __m128i* key = (__m128i*)context->key; + __m128i tmp = _mm_xor_si128(input, _mm_load_si128(key + 0)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 1)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 2)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 3)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 4)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 5)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 6)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 7)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 8)); + tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 9)); + return _mm_aesdeclast_si128(tmp, _mm_load_si128(key + 10)); +} + +void aes128_ecb_encrypt_x86(const aes128_key* ctx, const uint8_t* input, uint8_t* output) +{ + const __m128i* key = (__m128i*)ctx->key; __m128i tmp = aes128_encrypt_x86(_mm_loadu_si128((const __m128i*)input), key); _mm_storeu_si128((__m128i*)output, tmp); } +void aes128_ecb_decrypt_x86(const aes128_key* ctx, const uint8_t* input, uint8_t* output) +{ + const __m128i* key = (__m128i*)ctx->key; + __m128i tmp = aes128_decrypt_x86(_mm_loadu_si128((const __m128i*)input), key); + _mm_storeu_si128((__m128i*)output, tmp); +} + static __m128i ctr_increment(__m128i counter) { __m128i swap = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); @@ -67,9 +105,9 @@ static __m128i ctr_increment(__m128i counter) return _mm_shuffle_epi8(tmp, swap); } -void aes128_ctr_xor_x86(const aes128_key* context, const uint8_t* iv, uint8_t* buffer, size_t size) +void aes128_ctr_xor_x86(const aes128_key* ctx, const uint8_t* iv, uint8_t* buffer, size_t size) { - const __m128i* key = (__m128i*)context->key; + const __m128i* key = (__m128i*)ctx->key; __m128i counter = _mm_loadu_si128((const __m128i*)iv); while (size >= 16) @@ -97,3 +135,41 @@ void aes128_ctr_xor_x86(const aes128_key* context, const uint8_t* iv, uint8_t* b memcpy(buffer, full, size); } } + +void aes128_cmac_process_x86(const aes128_key* ctx, uint8_t* block, const uint8_t* buffer, uint32_t size) +{ + const __m128i* key = (__m128i*)ctx->key; + __m128i* data = (__m128i*)buffer; + + __m128i tmp = _mm_loadu_si128((__m128i*)block); + for (uint32_t i = 0; i < size; i += 16) + { + __m128i input = _mm_loadu_si128(data++); + tmp = _mm_xor_si128(tmp, input); + tmp = aes128_encrypt_x86(tmp, key); + } + _mm_storeu_si128((__m128i*)block, tmp); +} + +void aes128_psp_decrypt_x86(const aes128_key* ctx, const uint8_t* prev, const uint8_t* block, uint8_t* buffer, uint32_t size) +{ + const __m128i* key = (__m128i*)ctx->key; + __m128i one = _mm_setr_epi32(0, 0, 0, 1); + + __m128i x = _mm_load_si128((__m128i*)prev); + __m128i y = _mm_load_si128((__m128i*)block); + + __m128i* data = (__m128i*)buffer; + + for (uint32_t i = 0; i < size; i += 16) + { + y = _mm_add_epi32(y, one); + + __m128i out = aes128_decrypt_x86(y, key); + + out = _mm_xor_si128(out, _mm_loadu_si128(data)); + out = _mm_xor_si128(out, x); + _mm_storeu_si128(data++, out); + x = y; + } +} diff --git a/pkg2zip_out.c b/pkg2zip_out.c new file mode 100644 index 0000000..aa6004e --- /dev/null +++ b/pkg2zip_out.c @@ -0,0 +1,75 @@ +#include "pkg2zip_out.h" +#include "pkg2zip_sys.h" +#include "pkg2zip_zip.h" + +static zip out_zip; +static int out_zipped; +static sys_file out_file; +static uint64_t out_file_offset; + +void out_begin(const char* name, int zipped) +{ + if (zipped) + { + zip_create(&out_zip, name); + } + out_zipped = zipped; +} + +void out_end(void) +{ + if (out_zipped) + { + zip_close(&out_zip); + } +} + +void out_add_folder(const char* path) +{ + if (out_zipped) + { + zip_add_folder(&out_zip, path); + } + else + { + sys_mkdir(path); + } +} + +void out_begin_file(const char* name) +{ + if (out_zipped) + { + zip_begin_file(&out_zip, name); + } + else + { + out_file = sys_create(name); + out_file_offset = 0; + } +} + +void out_end_file(void) +{ + if (out_zipped) + { + zip_end_file(&out_zip); + } + else + { + sys_close(out_file); + } +} + +void out_write(const void* buffer, uint32_t size) +{ + if (out_zipped) + { + zip_write_file(&out_zip, buffer, size); + } + else + { + sys_write(out_file, out_file_offset, buffer, size); + out_file_offset += size; + } +} diff --git a/pkg2zip_out.h b/pkg2zip_out.h new file mode 100644 index 0000000..34cc7ae --- /dev/null +++ b/pkg2zip_out.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +void out_begin(const char* name, int zipped); +void out_end(void); +void out_add_folder(const char* path); +void out_begin_file(const char* name); +void out_end_file(void); +void out_write(const void* buffer, uint32_t size); diff --git a/pkg2zip_psp.c b/pkg2zip_psp.c new file mode 100644 index 0000000..210707e --- /dev/null +++ b/pkg2zip_psp.c @@ -0,0 +1,416 @@ +#include "pkg2zip_psp.h" +#include "pkg2zip_out.h" +#include "pkg2zip_utils.h" + +#include +#include + +#define PSP_ISO_BLOCK_SIZE 16 +#define PSP_ISO_SECTOR_SIZE 2048 + +// https://vitadevwiki.com/vita/Keys_NonVita#PSPAESKirk4.2F7 +static const uint8_t kirk7_key38[] = { 0x12, 0x46, 0x8d, 0x7e, 0x1c, 0x42, 0x20, 0x9b, 0xba, 0x54, 0x26, 0x83, 0x5e, 0xb0, 0x33, 0x03 }; +static const uint8_t kirk7_key39[] = { 0xc4, 0x3b, 0xb6, 0xd6, 0x53, 0xee, 0x67, 0x49, 0x3e, 0xa9, 0x5f, 0xbc, 0x0c, 0xed, 0x6f, 0x8a }; +static const uint8_t kirk7_key63[] = { 0x9c, 0x9b, 0x13, 0x72, 0xf8, 0xc6, 0x40, 0xcf, 0x1c, 0x62, 0xf5, 0xd5, 0x92, 0xdd, 0xb5, 0x82 }; + +// https://vitadevwiki.com/vita/Keys_NonVita#PSPAMHashKey +static const uint8_t amctl_hashkey_3[] = { 0xe3, 0x50, 0xed, 0x1d, 0x91, 0x0a, 0x1f, 0xd0, 0x29, 0xbb, 0x1c, 0x3e, 0xf3, 0x40, 0x77, 0xfb }; +static const uint8_t amctl_hashkey_4[] = { 0x13, 0x5f, 0xa4, 0x7c, 0xab, 0x39, 0x5b, 0xa4, 0x76, 0xb8, 0xcc, 0xa9, 0x8f, 0x3a, 0x04, 0x45 }; +static const uint8_t amctl_hashkey_5[] = { 0x67, 0x8d, 0x7f, 0xa3, 0x2a, 0x9c, 0xa0, 0xd1, 0x50, 0x8a, 0xd8, 0x38, 0x5e, 0x4b, 0x01, 0x7e }; + +// lzrc decompression code from libkirk by tpu +typedef struct { + // input stream + const uint8_t* input; + uint32_t in_ptr; + uint32_t in_len; + + // output stream + uint8_t* output; + uint32_t out_ptr; + uint32_t out_len; + + // range decode + uint32_t range; + uint32_t code; + uint32_t out_code; + uint8_t lc; + + uint8_t bm_literal[8][256]; + uint8_t bm_dist_bits[8][39]; + uint8_t bm_dist[18][8]; + uint8_t bm_match[8][8]; + uint8_t bm_len[8][31]; +} lzrc_decode; + +static void rc_init(lzrc_decode* rc, void* out, int out_len, const void* in, int in_len) +{ + if (in_len < 5) + { + fatal("ERROR: internal error - lzrc input underflow! pkg may be corrupted?\n"); + } + + rc->input = in; + rc->in_len = in_len; + rc->in_ptr = 5; + + rc->output = out; + rc->out_len = out_len; + rc->out_ptr = 0; + + rc->range = 0xffffffff; + rc->lc = rc->input[0]; + rc->code = get32be(rc->input + 1); + rc->out_code = 0xffffffff; + + memset(rc->bm_literal, 0x80, sizeof(rc->bm_literal)); + memset(rc->bm_dist_bits, 0x80, sizeof(rc->bm_dist_bits)); + memset(rc->bm_dist, 0x80, sizeof(rc->bm_dist)); + memset(rc->bm_match, 0x80, sizeof(rc->bm_match)); + memset(rc->bm_len, 0x80, sizeof(rc->bm_len)); +} + +static void normalize(lzrc_decode* rc) +{ + if (rc->range < 0x01000000) + { + rc->range <<= 8; + rc->code = (rc->code << 8) + rc->input[rc->in_ptr]; + rc->in_ptr++; + } +} + +static int rc_bit(lzrc_decode* rc, uint8_t *prob) +{ + uint32_t bound; + + normalize(rc); + + bound = (rc->range >> 8) * (*prob); + *prob -= *prob >> 3; + + if (rc->code < bound) + { + rc->range = bound; + *prob += 31; + return 1; + } + else + { + rc->code -= bound; + rc->range -= bound; + return 0; + } +} + +static int rc_bittree(lzrc_decode* rc, uint8_t *probs, int limit) +{ + int number = 1; + + do + { + number = (number << 1) + rc_bit(rc, probs + number); + } + while (number < limit); + + return number; +} + +static int rc_number(lzrc_decode* rc, uint8_t *prob, uint32_t n) +{ + int number = 1; + + if (n > 3) + { + number = (number << 1) + rc_bit(rc, prob + 3); + if (n > 4) + { + number = (number << 1) + rc_bit(rc, prob + 3); + if (n > 5) + { + // direct bits + normalize(rc); + + for (uint32_t i = 0; i < n - 5; i++) + { + rc->range >>= 1; + number <<= 1; + if (rc->code < rc->range) + { + number += 1; + } + else + { + rc->code -= rc->range; + } + } + } + } + } + + if (n > 0) + { + number = (number << 1) + rc_bit(rc, prob); + if (n > 1) + { + number = (number << 1) + rc_bit(rc, prob + 1); + if (n > 2) + { + number = (number << 1) + rc_bit(rc, prob + 2); + } + } + } + + return number; +} + +static int lzrc_decompress(void* out, int out_len, const void* in, int in_len) +{ + lzrc_decode rc; + rc_init(&rc, out, out_len, in, in_len); + + if (rc.lc & 0x80) + { + // plain text + memcpy(rc.output, rc.input + 5, rc.code); + return rc.code; + } + + int rc_state = 0; + uint8_t last_byte = 0; + + for (;;) + { + uint32_t match_step = 0; + + int bit = rc_bit(&rc, &rc.bm_match[rc_state][match_step]); + if (bit == 0) // literal + { + if (rc_state > 0) + { + rc_state -= 1; + } + + int byte = rc_bittree(&rc, &rc.bm_literal[((last_byte >> rc.lc) & 0x07)][0], 0x100); + byte -= 0x100; + + if (rc.out_ptr == rc.out_len) + { + fatal("ERROR: internal error - lzrc output overflow! pkg may be corrupted?\n"); + } + rc.output[rc.out_ptr++] = (uint8_t)byte; + last_byte = (uint8_t)byte; + } + else // match + { + // find bits of match length + uint32_t len_bits = 0; + for (int i = 0; i < 7; i++) + { + match_step += 1; + bit = rc_bit(&rc, &rc.bm_match[rc_state][match_step]); + if (bit == 0) + { + break; + } + len_bits += 1; + } + + // find match length + uint32_t match_len; + if (len_bits == 0) + { + match_len = 1; + } + else + { + uint32_t len_state = ((len_bits - 1) << 2) + ((rc.out_ptr << (len_bits - 1)) & 0x03); + match_len = rc_number(&rc, &rc.bm_len[rc_state][len_state], len_bits); + if (match_len == 0xFF) + { + // end of stream + return rc.out_ptr; + } + } + + // find number of bits of match distance + uint32_t dist_state = 0; + uint32_t limit = 8; + if (match_len > 2) + { + dist_state += 7; + limit = 44; + } + int dist_bits = rc_bittree(&rc, &rc.bm_dist_bits[len_bits][dist_state], limit); + dist_bits -= limit; + + // find match distance + uint32_t match_dist; + if (dist_bits > 0) + { + match_dist = rc_number(&rc, &rc.bm_dist[dist_bits][0], dist_bits); + } + else + { + match_dist = 1; + } + + // copy match bytes + if (match_dist > rc.out_ptr) + { + fatal("ERROR: internal error - lzrc match_dist out of range! pkg may be corrupted?\n"); + } + + if (rc.out_ptr + match_len + 1 > rc.out_len) + { + fatal("ERROR: internal error - lzrc output overflow! pkg may be corrupted?\n"); + } + + const uint8_t* match_src = rc.output + rc.out_ptr - match_dist; + for (uint32_t i = 0; i <= match_len; i++) + { + rc.output[rc.out_ptr++] = *match_src++; + } + last_byte = match_src[-1]; + + rc_state = 6 + ((rc.out_ptr + 1) & 1); + } + } +} + +static void init_psp_decrypt(aes128_key* key, uint8_t* iv, const uint8_t* header) +{ + uint8_t mac[16]; + aes128_cmac(kirk7_key38, header, 0xc0, mac); + + uint8_t tmp[16]; + aes128_init_dec(key, kirk7_key63); + aes128_ecb_decrypt(key, header + 0xc0, tmp); + + aes128_key aes; + aes128_init_dec(&aes, kirk7_key38); + aes128_ecb_decrypt(&aes, tmp, tmp); + + for (size_t i = 0; i < 16; i++) + { + iv[i] = mac[i] ^ tmp[i] ^ header[0xa0 + i] ^ amctl_hashkey_3[i] ^ amctl_hashkey_5[i]; + } + + aes128_init_dec(&aes, kirk7_key39); + aes128_ecb_decrypt(&aes, iv, iv); + + for (size_t i = 0; i < 16; i++) + { + iv[i] ^= amctl_hashkey_4[i]; + } +} + +void unpack_psp_eboot(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size) +{ + if (item_size < 0x28) + { + fatal("ERROR: eboot.pbp file is to short!"); + } + + uint8_t eboot_header[0x28]; + sys_read(pkg, enc_offset + item_offset, eboot_header, sizeof(eboot_header)); + aes128_ctr_xor(pkg_key, pkg_iv, item_offset / 16, eboot_header, sizeof(eboot_header)); + + if (memcmp(eboot_header, "\x00PBP", 4) != 0) + { + fatal("ERROR: wrong eboot.pbp header signature!"); + } + + uint32_t psar_offset = get32le(eboot_header + 0x24); + if (psar_offset + 256 > item_size) + { + fatal("ERROR: eboot.pbp file is to short!"); + } + assert(psar_offset % 16 == 0); + + uint8_t psar_header[256]; + sys_read(pkg, enc_offset + item_offset + psar_offset, psar_header, sizeof(psar_header)); + aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + psar_offset) / 16, psar_header, sizeof(psar_header)); + + if (memcmp(psar_header, "NPUMDIMG", 8) != 0) + { + fatal("ERROR: wrong data.psar header signature!"); + } + + uint32_t iso_block = get32le(psar_header + 0x0c); + if (iso_block != PSP_ISO_BLOCK_SIZE) + { + fatal("ERROR: unsupported data.psar block size %u, only %u supported!", iso_block, PSP_ISO_BLOCK_SIZE); + } + + aes128_key psp_key; + uint8_t psp_iv[16]; + init_psp_decrypt(&psp_key, psp_iv, psar_header); + aes128_psp_decrypt(&psp_key, psp_iv, 0, psar_header + 0x40, 0x60); + + uint32_t iso_start = get32le(psar_header + 0x54); + uint32_t iso_end = get32le(psar_header + 0x64); + uint32_t iso_total = iso_end - iso_start - 1; + uint32_t block_count = (iso_total + PSP_ISO_BLOCK_SIZE - 1) / PSP_ISO_BLOCK_SIZE; + + uint32_t iso_table = get32le(psar_header + 0x6c); + + if (iso_table + block_count * 32 > item_size) + { + fatal("ERROR: offset table in data.psar file is too large!"); + } + + out_begin_file(path); + for (uint32_t i = 0; i < block_count; i++) + { + uint64_t table_offset = item_offset + psar_offset + iso_table + 32 * i; + + uint8_t table[32]; + sys_read(pkg, enc_offset + table_offset, table, sizeof(table)); + aes128_ctr_xor(pkg_key, pkg_iv, table_offset / 16, table, sizeof(table)); + + uint32_t t[8]; + for (size_t k = 0; k < 8; k++) + { + t[k] = get32le(table + k * 4); + } + + uint32_t block_offset = t[4] ^ t[2] ^ t[3]; + uint32_t block_size = t[5] ^ t[1] ^ t[2]; + uint32_t block_flags = t[6] ^ t[0] ^ t[3]; + + if (psar_offset + block_size > item_size) + { + fatal("ERROR: iso block size/offset is to large!"); + } + + uint8_t data[PSP_ISO_BLOCK_SIZE * PSP_ISO_SECTOR_SIZE]; + + uint64_t abs_offset = item_offset + psar_offset + block_offset; + sys_read(pkg, enc_offset + abs_offset, data, block_size); + aes128_ctr_xor(pkg_key, pkg_iv, abs_offset / 16, data, block_size); + + if ((block_flags & 4) == 0) + { + aes128_psp_decrypt(&psp_key, psp_iv, block_offset / 16, data, block_size); + } + + uint32_t out_size; + if (block_size == sizeof(data)) + { + out_write(data, (uint32_t)block_size); + } + else + { + uint8_t uncompressed[PSP_ISO_BLOCK_SIZE * PSP_ISO_SECTOR_SIZE]; + out_size = lzrc_decompress(uncompressed, sizeof(uncompressed), data, block_size); + if (out_size != sizeof(uncompressed)) + { + fatal("ERROR: internal error - lzrc decompression failed! pkg may be corrupted?"); + } + out_write(uncompressed, (uint32_t)out_size); + } + } + + out_end_file(); +} diff --git a/pkg2zip_psp.h b/pkg2zip_psp.h new file mode 100644 index 0000000..09a4a2d --- /dev/null +++ b/pkg2zip_psp.h @@ -0,0 +1,4 @@ +#include "pkg2zip_aes.h" +#include "pkg2zip_sys.h" + +void unpack_psp_eboot(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size);