122 lines
3.3 KiB
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;
|
|
}
|