290 lines
7.0 KiB
C
290 lines
7.0 KiB
C
//Project Chovy - __sce_ebootpbp generator by @dots_tb and motoharu
|
|
// With CBPS help especially: @SiliCart, @nyaaasen, @notzecoxao (and his friends?)
|
|
|
|
//Check out motoharu's project: https://github.com/motoharu-gosuto/psvcmd56/blob/master/src/CMD56Reversed/F00D/GcAuthMgrService.cpp#L1102
|
|
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <openssl/evp.h>
|
|
#include <openssl/hmac.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/obj_mac.h>
|
|
#include <openssl/ec.h>
|
|
|
|
#include "key_vault.h"
|
|
PACK(typedef struct
|
|
{
|
|
uint8_t r[0x1c];
|
|
uint8_t s[0x1c];
|
|
} ECDSA_SIG_0x1c);
|
|
|
|
PACK(typedef struct sce_ebootpbp {
|
|
uint64_t magic;
|
|
uint32_t key_type;// set to 1 (maybe keytype?)
|
|
uint32_t type;// 03 - ps1, 02 - psp
|
|
uint8_t np_title[0x30];
|
|
uint64_t aid;
|
|
uint64_t secure_tick;
|
|
uint64_t filesz;
|
|
uint64_t sw_ver;
|
|
uint8_t padding[0xf8];
|
|
ECDSA_SIG_0x1c ebootpbp_hdr_sig;
|
|
ECDSA_SIG_0x1c NPUMDIMG_sig;
|
|
ECDSA_SIG_0x1c sceebootpbp_sig;
|
|
} sce_ebootpbp);
|
|
|
|
|
|
typedef struct pbp_hdr {
|
|
uint32_t magic;
|
|
uint32_t unk;
|
|
uint32_t sfo_offset;
|
|
uint32_t icon0_offset;
|
|
uint32_t icon1_offset;
|
|
uint32_t pic0_offset;
|
|
uint32_t pic1_offset;
|
|
uint32_t snd0_offset;
|
|
uint32_t data_psp_offset;
|
|
uint32_t data_psar_offset;
|
|
} pbp_hdr;
|
|
|
|
|
|
#define PSAR_SZ 0x1C0000
|
|
#define WORK_BUF_SZ 0x7c0
|
|
|
|
|
|
//based motoharu
|
|
__declspec(dllexport) int can_be_reversed_80C17A(const uint8_t* src, int some_size, uint8_t* iv, uint8_t* src_xored_digest)
|
|
{
|
|
unsigned char src_xored[0x20];
|
|
memcpy(src_xored, iv, 0x20);
|
|
|
|
if (some_size > 0x20)
|
|
return 0x12;
|
|
|
|
for(int i = 0; i < some_size; i++)
|
|
src_xored[i] = src[i] ^ iv[i];
|
|
|
|
int r0;
|
|
|
|
SHA256_CTX sha256_ctx;
|
|
SHA256_Init(&sha256_ctx);
|
|
SHA256_Update(&sha256_ctx, src_xored, 0x20);
|
|
r0 = SHA256_Final(src_xored_digest, &sha256_ctx);
|
|
if(r0 != 1)
|
|
return 0x11;
|
|
|
|
for(int i = 0; i < 0x20; i++)
|
|
iv[i] = src_xored_digest[i] ^ iv[i];
|
|
|
|
for(int i = 0; i < 0x20; i++)
|
|
{
|
|
if(iv[i] != 0xFF)
|
|
{
|
|
iv[i] = iv[i] + 1;
|
|
break;
|
|
}
|
|
|
|
iv[i] = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
__declspec(dllexport) int f00d_KIRK0x22(const uint8_t *hash, ECDSA_SIG_0x1c *signature, int key_sel) {
|
|
|
|
|
|
uint8_t hmac_in[0x38];
|
|
uint8_t hmac_hash_iv[0x38];
|
|
memcpy(&hmac_in, hash, 0x1c);
|
|
memcpy(&hmac_in[0x1c], &keyvault_ec_privkey[key_sel], 0x1c);
|
|
|
|
HMAC_CTX *hmac_ctx = HMAC_CTX_new();
|
|
HMAC_Init_ex(hmac_ctx, &hmac_key_0x22, 0x40, EVP_sha256(), NULL);
|
|
HMAC_Update(hmac_ctx, &hmac_in, 0x1c << 1);
|
|
unsigned int len;
|
|
HMAC_Final(hmac_ctx, &hmac_hash_iv, &len);
|
|
HMAC_CTX_free(hmac_ctx);
|
|
|
|
uint8_t sha256_out[0x40];
|
|
int ret = 0;
|
|
do {
|
|
ret = can_be_reversed_80C17A(hash, 0x1c, hmac_hash_iv, &sha256_out[0]);
|
|
if(ret != 0 || (ret = can_be_reversed_80C17A(hash, 0x1c, hmac_hash_iv, &sha256_out[0x20])) != 0)
|
|
return 0;
|
|
|
|
} while(ret != 0);
|
|
|
|
//ECDSA
|
|
|
|
BIGNUM *a = BN_bin2bn(keyvault_ec_a, 0x1c, NULL),
|
|
*b = BN_bin2bn(keyvault_ec_b, 0x1c, NULL),
|
|
*p = BN_bin2bn(keyvault_ec_p, 0x1c, NULL),
|
|
*order = BN_bin2bn(keyvault_ec_N, 0x1c, NULL),
|
|
*x = BN_bin2bn(keyvault_ec_Gx, 0x1c, NULL),
|
|
*y = BN_bin2bn(keyvault_ec_Gy, 0x1c, NULL),
|
|
*priv_key = BN_bin2bn(keyvault_ec_privkey[key_sel], 0x1c, NULL),
|
|
*m = BN_bin2bn(sha256_out, 0x3c, NULL);
|
|
|
|
BN_CTX *bn_ctx = BN_CTX_new();
|
|
BN_MONT_CTX *bn_mon_ctx = BN_MONT_CTX_new();
|
|
BN_MONT_CTX_set(bn_mon_ctx, order, bn_ctx);
|
|
|
|
EC_GROUP *curve = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx);
|
|
EC_POINT *generator = EC_POINT_new(curve);
|
|
EC_POINT_set_affine_coordinates_GFp(curve, generator, x, y, bn_ctx);
|
|
EC_GROUP_set_generator(curve, generator, order, NULL);
|
|
|
|
EC_KEY *eckey=EC_KEY_new();
|
|
EC_KEY_set_group(eckey,curve);
|
|
EC_KEY_set_private_key(eckey, priv_key);
|
|
|
|
|
|
m = BN_bin2bn(sha256_out, 0x3c, NULL);
|
|
BN_mod(m, m, order, bn_ctx);
|
|
|
|
|
|
|
|
//Generate R in order to get custom "random number"
|
|
BIGNUM *sig_r = BN_new();
|
|
EC_POINT_mul(curve, generator, m, NULL, NULL, bn_ctx);
|
|
EC_POINT_get_affine_coordinates_GFp(curve, generator, sig_r, NULL, bn_ctx);
|
|
BN_nnmod(sig_r, sig_r, order, bn_ctx);
|
|
|
|
//Generate M^-1
|
|
BIGNUM *exp = BN_new();
|
|
BIGNUM *minv = BN_new();
|
|
|
|
BN_set_word(exp, (BN_ULONG)2);
|
|
BN_sub(exp, order, exp);
|
|
BN_mod_exp_mont(minv, m, exp, order, bn_ctx, bn_mon_ctx);
|
|
|
|
|
|
ECDSA_SIG *sig = ECDSA_do_sign_ex(hash, 0x1c, minv, sig_r, eckey);
|
|
|
|
|
|
if(!sig) {
|
|
ret = 0;
|
|
goto error;
|
|
|
|
}
|
|
BIGNUM *sig_s;
|
|
ECDSA_SIG_get0(sig, NULL, &sig_s);
|
|
BN_bn2bin(sig_r, &signature->r);
|
|
BN_bn2bin(sig_s, &signature->s);
|
|
ECDSA_SIG_free(sig);
|
|
//BN_free(sig_s);
|
|
ret = 1;
|
|
|
|
error:
|
|
BN_free(sig_r);
|
|
|
|
EC_POINT_free(generator);
|
|
BN_free(y);
|
|
BN_free(x);
|
|
BN_free(order);
|
|
BN_free(p);
|
|
BN_free(b);
|
|
BN_free(a);
|
|
BN_free(minv);
|
|
BN_free(exp);
|
|
BN_free(priv_key);
|
|
BN_CTX_free(bn_ctx);
|
|
BN_MONT_CTX_free(bn_mon_ctx);
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
__declspec(dllexport) int chovy_gen(char *ebootpbp, uint64_t signaid, char *outscefile)
|
|
{
|
|
|
|
int ret = 1;
|
|
FILE *fin = 0, *fout = 0;
|
|
|
|
uint8_t *work_buf = (unsigned char*) calloc (1, WORK_BUF_SZ);
|
|
sce_ebootpbp *sceebootpbp_file = (unsigned char*) calloc (1, sizeof(sce_ebootpbp));
|
|
|
|
|
|
fin = fopen(ebootpbp, "rb");
|
|
if (!fin) {
|
|
|
|
goto error;
|
|
}
|
|
memcpy(&sceebootpbp_file->magic, "NPUMDSIG", 0x8);
|
|
sceebootpbp_file->type = 2;
|
|
sceebootpbp_file->key_type = 1;
|
|
sceebootpbp_file->aid = signaid;
|
|
|
|
|
|
fseek(fin, 0, SEEK_END);
|
|
sceebootpbp_file->filesz = ftell(fin);
|
|
|
|
pbp_hdr hdr;
|
|
fseek(fin, 0, SEEK_SET);
|
|
fread(&hdr, sizeof(pbp_hdr),1,fin);
|
|
|
|
|
|
fseek(fin, 0, SEEK_SET);
|
|
fread(work_buf, hdr.icon0_offset, 1,fin);
|
|
|
|
uint8_t work_hash[0x1c];
|
|
SHA256_CTX sha256_ctx;
|
|
SHA224_Init(&sha256_ctx);
|
|
SHA224_Update(&sha256_ctx, work_buf, hdr.icon0_offset);
|
|
SHA224_Final(work_hash, &sha256_ctx);
|
|
f00d_KIRK0x22(work_hash, &sceebootpbp_file->ebootpbp_hdr_sig, sceebootpbp_file->key_type);
|
|
|
|
SHA224_Init(&sha256_ctx);
|
|
fseek(fin, hdr.data_psar_offset, SEEK_SET);
|
|
|
|
size_t size = PSAR_SZ;
|
|
int to_read = size > WORK_BUF_SZ ? WORK_BUF_SZ : size;
|
|
|
|
|
|
fread(work_buf, to_read, 1,fin);
|
|
if(memcmp(work_buf, "NPUMDIMG", 0x8) == 0)
|
|
memcpy(&sceebootpbp_file->np_title, work_buf + 0x10, sizeof(sceebootpbp_file->np_title));
|
|
else {
|
|
memcpy(&sceebootpbp_file->magic, "NPPS1SIG", sizeof(sceebootpbp_file->magic));
|
|
sceebootpbp_file->type = 3;
|
|
}
|
|
|
|
do {
|
|
size -= to_read;
|
|
SHA224_Update(&sha256_ctx, work_buf, to_read);
|
|
to_read = size > WORK_BUF_SZ ? WORK_BUF_SZ : size;
|
|
fread(work_buf, to_read, 1,fin);
|
|
} while(size > 0);
|
|
|
|
SHA224_Final(work_hash, &sha256_ctx);
|
|
|
|
f00d_KIRK0x22(work_hash, &sceebootpbp_file->NPUMDIMG_sig, sceebootpbp_file->key_type);
|
|
|
|
SHA224_Init(&sha256_ctx);
|
|
SHA224_Update(&sha256_ctx, sceebootpbp_file, 0x1C8);
|
|
SHA224_Final(work_hash, &sha256_ctx);
|
|
|
|
f00d_KIRK0x22(work_hash, &sceebootpbp_file->sceebootpbp_sig, sceebootpbp_file->key_type);
|
|
|
|
fout = fopen(outscefile, "wb");
|
|
if (!fout) {
|
|
goto error;
|
|
}
|
|
fwrite(sceebootpbp_file, 1, sizeof(sce_ebootpbp), fout);
|
|
|
|
ret = 0;
|
|
error:
|
|
if (fin)
|
|
fclose(fin);
|
|
if (fout)
|
|
fclose(fout);
|
|
free(work_buf);
|
|
free(sceebootpbp_file);
|
|
return ret;
|
|
}
|