unpack PSP eboot.pbp to ISO file

This commit is contained in:
Martins Mozeiko
2017-11-05 23:10:13 -08:00
parent 4e84a279a8
commit 8cc1d686a2
8 changed files with 1000 additions and 183 deletions
+41 -122
View File
@@ -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);
+338 -29
View File
@@ -1,6 +1,9 @@
#include "pkg2zip_aes.h"
#include "pkg2zip_utils.h"
#include <assert.h>
#include <string.h>
#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);
}
}
+12 -4
View File
@@ -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);
+104 -28
View File
@@ -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;
}
}
+75
View File
@@ -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;
}
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
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);
+416
View File
@@ -0,0 +1,416 @@
#include "pkg2zip_psp.h"
#include "pkg2zip_out.h"
#include "pkg2zip_utils.h"
#include <assert.h>
#include <string.h>
#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();
}
+4
View File
@@ -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);