/* spkg.c -- spkg decryption * * Copyright (C) 2019 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ #include #include #include #include #include "spkg.h" int ksceSblDmac5AesCbcDec(void *src, void *dst, int size, void *key, int key_size, void *iv, int mask_enable); uint8_t spkg_key[0x20] = { 0x2E, 0x6F, 0x47, 0x51, 0xD1, 0x5B, 0x06, 0xC5, 0x1F, 0x57, 0x2A, 0x93, 0x06, 0xE5, 0x2D, 0xD7, 0x00, 0x7E, 0xA5, 0x6A, 0x31, 0xD4, 0x59, 0xEC, 0x6D, 0x36, 0x81, 0xAB, 0x08, 0x62,0x55, 0x01 }; uint8_t spkg_iv[0x10] = { 0xB3,0xD5,0x41,0xA5,0x68,0x75,0x1D,0xF8,0xF4,0x83,0x3B,0xAB,0x4E,0xFE,0x05,0x37 }; void xor_key(uint8_t *dst, uint8_t *src, int len) { int i; for (i = 0; i < len; i++) { dst[i] ^= src[i]; } } void key_inc(uint8_t *key, int pos) { if (key[pos] == 0xFF) { key[pos] = 0; key_inc(key, pos - 1); } else { key[pos] += 1; } } int aes_ctr_encrypt(void *data, int size, void *key, void *iv) { uint8_t ikey[16], xkey[16]; int res; SceAesContext ctx; res = ksceAesInit1(&ctx, 128, 128, key); if (res < 0) return res; memcpy(ikey, iv, 16); int i; for (i = 0; i < size; i += 16) { memcpy(xkey, ikey, 16); res = ksceAesEncrypt1(&ctx, xkey, xkey); if (res < 0) return res; xor_key(data + i, xkey, 16); key_inc(ikey, 15); } return 0; } int decrypt_spkg(void *buf, int size) { char key[0x20], iv[0x10]; int res; SceHeader *sce_header = (SceHeader *)buf; if (sce_header->magic != 0x00454353 || sce_header->version != 3 || sce_header->sce_type != 3) return SCE_SBL_ERROR_SL_EDATA; MetadataInfo *metadata_info = (MetadataInfo *)((char *)sce_header + sce_header->metadata_offset + 0x30); memcpy(key, spkg_key, 0x20); memcpy(iv, spkg_iv, 0x10); res = ksceSblDmac5AesCbcDec(metadata_info, metadata_info, sizeof(MetadataInfo), key, 256, iv, 1); if (res < 0) return res; if (metadata_info->pad0 != 0 || metadata_info->pad1 != 0 || metadata_info->pad2 != 0 || metadata_info->pad3 != 0) return SCE_SBL_ERROR_SL_EDATA; char *dec = (char *)metadata_info + sizeof(MetadataInfo); int dec_size = sce_header->header_length - sce_header->metadata_offset - 0x30 - sizeof(MetadataInfo); memcpy(key, metadata_info->key, 0x10); memcpy(iv, metadata_info->iv, 0x10); res = ksceSblDmac5AesCbcDec(dec, dec, dec_size, key, 128, iv, 1); if (res < 0) return res; MetadataHeader *metadata_header = (MetadataHeader *)dec; MetadataSection *metadata_section = (MetadataSection *)((char *)metadata_header + sizeof(MetadataHeader)); char *vault = (char *)metadata_section + metadata_header->section_count * sizeof(MetadataSection); int i; for (i = 0; i < metadata_header->section_count; i++) { if (metadata_section[i].encryption == 3) { char *vault_key = vault + metadata_section[i].key_idx * 0x10; char *vault_iv = vault + metadata_section[i].iv_idx * 0x10; memcpy(key, vault_key, 0x10); memcpy(iv, vault_iv, 0x10); res = aes_ctr_encrypt(buf + metadata_section[i].offset, metadata_section[i].size, key, iv); if (res < 0) return res; } } ksceKernelCpuDcacheAndL2WritebackRange(buf, ALIGN(size, 0x40)); return 0; }