cex-2-rex/kernel/src/spkg.c

122 lines
3.3 KiB
C

/* 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 <psp2kern/kernel/cpu.h>
#include <psp2kern/kernel/utils.h>
#include <stdio.h>
#include <string.h>
#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;
}