split rpcs3 and hle libraries

merge rpcs3 utilities
This commit is contained in:
DH 2025-04-08 19:46:57 +03:00
parent b33e2662b6
commit 62ad27d1e2
1233 changed files with 7004 additions and 3819 deletions

1010
rpcs3/Crypto/aes.cpp Normal file

File diff suppressed because it is too large Load diff

179
rpcs3/Crypto/aes.h Normal file
View file

@ -0,0 +1,179 @@
#pragma once
#define POLARSSL_AES_ROM_TABLES
/**
* \file aes.h
*
* \brief AES block cipher
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#ifdef _MSC_VER
#include <basetsd.h>
typedef UINT32 uint32_t;
#else
#include <inttypes.h>
#endif
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
// Regular implementation
//
/**
* \brief AES context structure
*/
typedef struct
{
int nr; /*!< number of rounds */
uint32_t* rk; /*!< AES round keys */
uint32_t buf[68]; /*!< unaligned data */
} aes_context;
#ifdef __cplusplus
extern "C"
{
#endif
/**
* \brief AES key schedule (encryption)
*
* \param ctx AES context to be initialized
* \param key encryption key
* \param keysize must be 128, 192 or 256
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aes_setkey_enc(aes_context* ctx, const unsigned char* key, unsigned int keysize);
/**
* \brief AES key schedule (decryption)
*
* \param ctx AES context to be initialized
* \param key decryption key
* \param keysize must be 128, 192 or 256
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aes_setkey_dec(aes_context* ctx, const unsigned char* key, unsigned int keysize);
/**
* \brief AES-ECB block encryption/decryption
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 if successful
*/
int aes_crypt_ecb(aes_context* ctx,
int mode,
const unsigned char input[16],
unsigned char output[16]);
/**
* \brief AES-CBC buffer encryption/decryption
* Length should be a multiple of the block
* size (16 bytes)
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH
*/
int aes_crypt_cbc(aes_context* ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char* input,
unsigned char* output);
/**
* \brief AES-CFB128 buffer encryption/decryption.
*
* Note: Due to the nature of CFB you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT.
*
* both
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv_off offset in IV (updated after use)
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int aes_crypt_cfb128(aes_context* ctx,
int mode,
size_t length,
size_t* iv_off,
unsigned char iv[16],
const unsigned char* input,
unsigned char* output);
/**
* \brief AES-CTR buffer encryption/decryption
*
* Warning: You have to keep the maximum use of your counter in mind!
*
* Note: Due to the nature of CTR you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT.
*
* \param length The length of the data
* \param nc_off The offset in the current stream_block (for resuming
* within current cipher stream). The offset pointer to
* should be 0 at the start of a stream.
* \param nonce_counter The 128-bit nonce and counter.
* \param stream_block The saved stream-block for resuming. Is overwritten
* by the function.
* \param input The input data stream
* \param output The output data stream
*
* \return 0 if successful
*/
int aes_crypt_ctr(aes_context* ctx,
size_t length,
size_t* nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char* input,
unsigned char* output);
void aes_cmac(aes_context* ctx, size_t length, unsigned char* input, unsigned char* output);
#ifdef __cplusplus
}
#endif

686
rpcs3/Crypto/aesni.cpp Normal file
View file

@ -0,0 +1,686 @@
#if defined(__SSE2__) || defined(_M_X64)
/*
* AES-NI support functions
*
* Copyright (C) 2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set
* [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/
*/
#include "aesni.h"
#if defined(_MSC_VER) && defined(_M_X64)
#define POLARSSL_HAVE_MSVC_X64_INTRINSICS
#include <intrin.h>
#endif
/*
* AES-NI support detection routine
*/
int aesni_supports(unsigned int what)
{
static int done = 0;
static unsigned int c = 0;
if (!done)
{
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
int regs[4]; // eax, ebx, ecx, edx
__cpuid(regs, 1);
c = regs[2];
#else
asm("movl $1, %%eax \n"
"cpuid \n"
: "=c"(c)
:
: "eax", "ebx", "edx");
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
done = 1;
}
return ((c & what) != 0);
}
/*
* AES-NI AES-ECB block en(de)cryption
*/
int aesni_crypt_ecb(aes_context* ctx,
int mode,
const unsigned char input[16],
unsigned char output[16])
{
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
__m128i *rk, a;
int i;
rk = (__m128i*)ctx->rk;
a = _mm_xor_si128(_mm_loadu_si128((__m128i*)input), _mm_loadu_si128(rk++));
if (mode == AES_ENCRYPT)
{
for (i = ctx->nr - 1; i; --i)
a = _mm_aesenc_si128(a, _mm_loadu_si128(rk++));
a = _mm_aesenclast_si128(a, _mm_loadu_si128(rk));
}
else
{
for (i = ctx->nr - 1; i; --i)
a = _mm_aesdec_si128(a, _mm_loadu_si128(rk++));
a = _mm_aesdeclast_si128(a, _mm_loadu_si128(rk));
}
_mm_storeu_si128((__m128i*)output, a);
#else
asm("movdqu (%3), %%xmm0 \n" // load input
"movdqu (%1), %%xmm1 \n" // load round key 0
"pxor %%xmm1, %%xmm0 \n" // round 0
"addq $16, %1 \n" // point to next round key
"subl $1, %0 \n" // normal rounds = nr - 1
"test %2, %2 \n" // mode?
"jz 2f \n" // 0 = decrypt
"1: \n" // encryption loop
"movdqu (%1), %%xmm1 \n" // load round key
"aesenc %%xmm1, %%xmm0 \n" // do round
"addq $16, %1 \n" // point to next round key
"subl $1, %0 \n" // loop
"jnz 1b \n"
"movdqu (%1), %%xmm1 \n" // load round key
"aesenclast %%xmm1, %%xmm0 \n" // last round
"jmp 3f \n"
"2: \n" // decryption loop
"movdqu (%1), %%xmm1 \n"
"aesdec %%xmm1, %%xmm0 \n"
"addq $16, %1 \n"
"subl $1, %0 \n"
"jnz 2b \n"
"movdqu (%1), %%xmm1 \n" // load round key
"aesdeclast %%xmm1, %%xmm0 \n" // last round
"3: \n"
"movdqu %%xmm0, (%4) \n" // export output
:
: "r"(ctx->nr), "r"(ctx->rk), "r"(mode), "r"(input), "r"(output)
: "memory", "cc", "xmm0", "xmm1");
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
return (0);
}
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
static inline void clmul256(__m128i a, __m128i b, __m128i* r0, __m128i* r1)
{
__m128i c, d, e, f, ef;
c = _mm_clmulepi64_si128(a, b, 0x00);
d = _mm_clmulepi64_si128(a, b, 0x11);
e = _mm_clmulepi64_si128(a, b, 0x10);
f = _mm_clmulepi64_si128(a, b, 0x01);
// r0 = f0^e0^c1:c0 = c1:c0 ^ f0^e0:0
// r1 = d1:f1^e1^d0 = d1:d0 ^ 0:f1^e1
ef = _mm_xor_si128(e, f);
*r0 = _mm_xor_si128(c, _mm_slli_si128(ef, 8));
*r1 = _mm_xor_si128(d, _mm_srli_si128(ef, 8));
}
static inline void sll256(__m128i a0, __m128i a1, __m128i* s0, __m128i* s1)
{
__m128i l0, l1, r0, r1;
l0 = _mm_slli_epi64(a0, 1);
l1 = _mm_slli_epi64(a1, 1);
r0 = _mm_srli_epi64(a0, 63);
r1 = _mm_srli_epi64(a1, 63);
*s0 = _mm_or_si128(l0, _mm_slli_si128(r0, 8));
*s1 = _mm_or_si128(_mm_or_si128(l1, _mm_srli_si128(r0, 8)), _mm_slli_si128(r1, 8));
}
static inline __m128i reducemod128(__m128i x10, __m128i x32)
{
__m128i a, b, c, dx0, e, f, g, h;
// (1) left shift x0 by 63, 62 and 57
a = _mm_slli_epi64(x10, 63);
b = _mm_slli_epi64(x10, 62);
c = _mm_slli_epi64(x10, 57);
// (2) compute D xor'ing a, b, c and x1
// d:x0 = x1:x0 ^ [a^b^c:0]
dx0 = _mm_xor_si128(x10, _mm_slli_si128(_mm_xor_si128(_mm_xor_si128(a, b), c), 8));
// (3) right shift [d:x0] by 1, 2, 7
e = _mm_or_si128(_mm_srli_epi64(dx0, 1), _mm_srli_si128(_mm_slli_epi64(dx0, 63), 8));
f = _mm_or_si128(_mm_srli_epi64(dx0, 2), _mm_srli_si128(_mm_slli_epi64(dx0, 62), 8));
g = _mm_or_si128(_mm_srli_epi64(dx0, 7), _mm_srli_si128(_mm_slli_epi64(dx0, 57), 8));
// (4) compute h = d^e1^f1^g1 : x0^e0^f0^g0
h = _mm_xor_si128(dx0, _mm_xor_si128(e, _mm_xor_si128(f, g)));
// result is x3^h1:x2^h0
return _mm_xor_si128(x32, h);
}
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
/*
* GCM multiplication: c = a times b in GF(2^128)
* Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5.
*/
void aesni_gcm_mult(unsigned char c[16],
const unsigned char a[16],
const unsigned char b[16])
{
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
__m128i xa, xb, m0, m1, x10, x32, r;
xa.m128i_u64[1] = _byteswap_uint64(*((unsigned __int64*)a + 0));
xa.m128i_u64[0] = _byteswap_uint64(*((unsigned __int64*)a + 1));
xb.m128i_u64[1] = _byteswap_uint64(*((unsigned __int64*)b + 0));
xb.m128i_u64[0] = _byteswap_uint64(*((unsigned __int64*)b + 1));
clmul256(xa, xb, &m0, &m1);
sll256(m0, m1, &x10, &x32);
r = reducemod128(x10, x32);
*((unsigned __int64*)c + 0) = _byteswap_uint64(r.m128i_u64[1]);
*((unsigned __int64*)c + 1) = _byteswap_uint64(r.m128i_u64[0]);
#else
unsigned char aa[16], bb[16], cc[16];
size_t i;
/* The inputs are in big-endian order, so byte-reverse them */
for (i = 0; i < 16; i++)
{
aa[i] = a[15 - i];
bb[i] = b[15 - i];
}
asm("movdqu (%0), %%xmm0 \n" // a1:a0
"movdqu (%1), %%xmm1 \n" // b1:b0
/*
* Caryless multiplication xmm2:xmm1 = xmm0 * xmm1
* using [CLMUL-WP] algorithm 1 (p. 13).
*/
"movdqa %%xmm1, %%xmm2 \n" // copy of b1:b0
"movdqa %%xmm1, %%xmm3 \n" // same
"movdqa %%xmm1, %%xmm4 \n" // same
"pclmulqdq $0x00, %%xmm0, %%xmm1 \n" // a0*b0 = c1:c0
"pclmulqdq $0x11, %%xmm0, %%xmm2 \n" // a1*b1 = d1:d0
"pclmulqdq $0x10, %%xmm0, %%xmm3 \n" // a0*b1 = e1:e0
"pclmulqdq $0x01, %%xmm0, %%xmm4 \n" // a1*b0 = f1:f0
"pxor %%xmm3, %%xmm4 \n" // e1+f1:e0+f0
"movdqa %%xmm4, %%xmm3 \n" // same
"psrldq $8, %%xmm4 \n" // 0:e1+f1
"pslldq $8, %%xmm3 \n" // e0+f0:0
"pxor %%xmm4, %%xmm2 \n" // d1:d0+e1+f1
"pxor %%xmm3, %%xmm1 \n" // c1+e0+f1:c0
/*
* Now shift the result one bit to the left,
* taking advantage of [CLMUL-WP] eq 27 (p. 20)
*/
"movdqa %%xmm1, %%xmm3 \n" // r1:r0
"movdqa %%xmm2, %%xmm4 \n" // r3:r2
"psllq $1, %%xmm1 \n" // r1<<1:r0<<1
"psllq $1, %%xmm2 \n" // r3<<1:r2<<1
"psrlq $63, %%xmm3 \n" // r1>>63:r0>>63
"psrlq $63, %%xmm4 \n" // r3>>63:r2>>63
"movdqa %%xmm3, %%xmm5 \n" // r1>>63:r0>>63
"pslldq $8, %%xmm3 \n" // r0>>63:0
"pslldq $8, %%xmm4 \n" // r2>>63:0
"psrldq $8, %%xmm5 \n" // 0:r1>>63
"por %%xmm3, %%xmm1 \n" // r1<<1|r0>>63:r0<<1
"por %%xmm4, %%xmm2 \n" // r3<<1|r2>>62:r2<<1
"por %%xmm5, %%xmm2 \n" // r3<<1|r2>>62:r2<<1|r1>>63
/*
* Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1
* using [CLMUL-WP] algorithm 5 (p. 20).
* Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted).
*/
/* Step 2 (1) */
"movdqa %%xmm1, %%xmm3 \n" // x1:x0
"movdqa %%xmm1, %%xmm4 \n" // same
"movdqa %%xmm1, %%xmm5 \n" // same
"psllq $63, %%xmm3 \n" // x1<<63:x0<<63 = stuff:a
"psllq $62, %%xmm4 \n" // x1<<62:x0<<62 = stuff:b
"psllq $57, %%xmm5 \n" // x1<<57:x0<<57 = stuff:c
/* Step 2 (2) */
"pxor %%xmm4, %%xmm3 \n" // stuff:a+b
"pxor %%xmm5, %%xmm3 \n" // stuff:a+b+c
"pslldq $8, %%xmm3 \n" // a+b+c:0
"pxor %%xmm3, %%xmm1 \n" // x1+a+b+c:x0 = d:x0
/* Steps 3 and 4 */
"movdqa %%xmm1,%%xmm0 \n" // d:x0
"movdqa %%xmm1,%%xmm4 \n" // same
"movdqa %%xmm1,%%xmm5 \n" // same
"psrlq $1, %%xmm0 \n" // e1:x0>>1 = e1:e0'
"psrlq $2, %%xmm4 \n" // f1:x0>>2 = f1:f0'
"psrlq $7, %%xmm5 \n" // g1:x0>>7 = g1:g0'
"pxor %%xmm4, %%xmm0 \n" // e1+f1:e0'+f0'
"pxor %%xmm5, %%xmm0 \n" // e1+f1+g1:e0'+f0'+g0'
// e0'+f0'+g0' is almost e0+f0+g0, except for some missing
// bits carried from d. Now get those bits back in.
"movdqa %%xmm1,%%xmm3 \n" // d:x0
"movdqa %%xmm1,%%xmm4 \n" // same
"movdqa %%xmm1,%%xmm5 \n" // same
"psllq $63, %%xmm3 \n" // d<<63:stuff
"psllq $62, %%xmm4 \n" // d<<62:stuff
"psllq $57, %%xmm5 \n" // d<<57:stuff
"pxor %%xmm4, %%xmm3 \n" // d<<63+d<<62:stuff
"pxor %%xmm5, %%xmm3 \n" // missing bits of d:stuff
"psrldq $8, %%xmm3 \n" // 0:missing bits of d
"pxor %%xmm3, %%xmm0 \n" // e1+f1+g1:e0+f0+g0
"pxor %%xmm1, %%xmm0 \n" // h1:h0
"pxor %%xmm2, %%xmm0 \n" // x3+h1:x2+h0
"movdqu %%xmm0, (%2) \n" // done
:
: "r"(aa), "r"(bb), "r"(cc)
: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
/* Now byte-reverse the outputs */
for (i = 0; i < 16; i++)
c[i] = cc[15 - i];
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
return;
}
/*
* Compute decryption round keys from encryption round keys
*/
void aesni_inverse_key(unsigned char* invkey,
const unsigned char* fwdkey, int nr)
{
unsigned char* ik = invkey;
const unsigned char* fk = fwdkey + 16 * nr;
memcpy(ik, fk, 16);
for (fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16)
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
_mm_storeu_si128((__m128i*)ik, _mm_aesimc_si128(_mm_loadu_si128((__m128i*)fk)));
#else
asm("movdqu (%0), %%xmm0 \n"
"aesimc %%xmm0, %%xmm0 \n"
"movdqu %%xmm0, (%1) \n"
:
: "r"(fk), "r"(ik)
: "memory", "xmm0");
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
memcpy(ik, fk, 16);
}
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
inline static __m128i aes_key_128_assist(__m128i key, __m128i kg)
{
key = _mm_xor_si128(key, _mm_slli_si128(key, 4));
key = _mm_xor_si128(key, _mm_slli_si128(key, 4));
key = _mm_xor_si128(key, _mm_slli_si128(key, 4));
kg = _mm_shuffle_epi32(kg, _MM_SHUFFLE(3, 3, 3, 3));
return _mm_xor_si128(key, kg);
}
// [AES-WP] Part of Fig. 25 page 32
inline static void aes_key_192_assist(__m128i* temp1, __m128i* temp3, __m128i kg)
{
__m128i temp4;
kg = _mm_shuffle_epi32(kg, 0x55);
temp4 = _mm_slli_si128(*temp1, 0x4);
*temp1 = _mm_xor_si128(*temp1, temp4);
temp4 = _mm_slli_si128(temp4, 0x4);
*temp1 = _mm_xor_si128(*temp1, temp4);
temp4 = _mm_slli_si128(temp4, 0x4);
*temp1 = _mm_xor_si128(*temp1, temp4);
*temp1 = _mm_xor_si128(*temp1, kg);
kg = _mm_shuffle_epi32(*temp1, 0xff);
temp4 = _mm_slli_si128(*temp3, 0x4);
*temp3 = _mm_xor_si128(*temp3, temp4);
*temp3 = _mm_xor_si128(*temp3, kg);
}
// [AES-WP] Part of Fig. 26 page 34
inline static void aes_key_256_assist_1(__m128i* temp1, __m128i kg)
{
__m128i temp4;
kg = _mm_shuffle_epi32(kg, 0xff);
temp4 = _mm_slli_si128(*temp1, 0x4);
*temp1 = _mm_xor_si128(*temp1, temp4);
temp4 = _mm_slli_si128(temp4, 0x4);
*temp1 = _mm_xor_si128(*temp1, temp4);
temp4 = _mm_slli_si128(temp4, 0x4);
*temp1 = _mm_xor_si128(*temp1, temp4);
*temp1 = _mm_xor_si128(*temp1, kg);
}
inline static void aes_key_256_assist_2(__m128i* temp1, __m128i* temp3)
{
__m128i temp2, temp4;
temp4 = _mm_aeskeygenassist_si128(*temp1, 0x0);
temp2 = _mm_shuffle_epi32(temp4, 0xaa);
temp4 = _mm_slli_si128(*temp3, 0x4);
*temp3 = _mm_xor_si128(*temp3, temp4);
temp4 = _mm_slli_si128(temp4, 0x4);
*temp3 = _mm_xor_si128(*temp3, temp4);
temp4 = _mm_slli_si128(temp4, 0x4);
*temp3 = _mm_xor_si128(*temp3, temp4);
*temp3 = _mm_xor_si128(*temp3, temp2);
}
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
/*
* Key expansion, 128-bit case
*/
static void aesni_setkey_enc_128(unsigned char* rk,
const unsigned char* key)
{
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
__m128i *xrk, k;
xrk = (__m128i*)rk;
#define EXPAND_ROUND(k, rcon) \
_mm_storeu_si128(xrk++, k); \
k = aes_key_128_assist(k, _mm_aeskeygenassist_si128(k, rcon))
k = _mm_loadu_si128((__m128i*)key);
EXPAND_ROUND(k, 0x01);
EXPAND_ROUND(k, 0x02);
EXPAND_ROUND(k, 0x04);
EXPAND_ROUND(k, 0x08);
EXPAND_ROUND(k, 0x10);
EXPAND_ROUND(k, 0x20);
EXPAND_ROUND(k, 0x40);
EXPAND_ROUND(k, 0x80);
EXPAND_ROUND(k, 0x1b);
EXPAND_ROUND(k, 0x36);
_mm_storeu_si128(xrk, k);
#undef EXPAND_ROUND
#else
asm("movdqu (%1), %%xmm0 \n" // copy the original key
"movdqu %%xmm0, (%0) \n" // as round key 0
"jmp 2f \n" // skip auxiliary routine
/*
* Finish generating the next round key.
*
* On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff
* with X = rot( sub( r3 ) ) ^ RCON.
*
* On exit, xmm0 is r7:r6:r5:r4
* with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3
* and those are written to the round key buffer.
*/
"1: \n"
"pshufd $0xff, %%xmm1, %%xmm1 \n" // X:X:X:X
"pxor %%xmm0, %%xmm1 \n" // X+r3:X+r2:X+r1:r4
"pslldq $4, %%xmm0 \n" // r2:r1:r0:0
"pxor %%xmm0, %%xmm1 \n" // X+r3+r2:X+r2+r1:r5:r4
"pslldq $4, %%xmm0 \n" // etc
"pxor %%xmm0, %%xmm1 \n"
"pslldq $4, %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" // update xmm0 for next time!
"add $16, %0 \n" // point to next round key
"movdqu %%xmm0, (%0) \n" // write it
"ret \n"
/* Main "loop" */
"2: \n"
"aeskeygenassist $0x01, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x02, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x04, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x08, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x10, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x20, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x40, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x80, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x1B, %%xmm0, %%xmm1 \ncall 1b \n"
"aeskeygenassist $0x36, %%xmm0, %%xmm1 \ncall 1b \n"
:
: "r"(rk), "r"(key)
: "memory", "cc", "0");
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
}
/*
* Key expansion, 192-bit case
*/
static void aesni_setkey_enc_192(unsigned char* rk,
const unsigned char* key)
{
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
__m128i temp1, temp3;
__m128i* key_schedule = (__m128i*)rk;
temp1 = _mm_loadu_si128((__m128i*)key);
temp3 = _mm_loadu_si128((__m128i*)(key + 16));
key_schedule[0] = temp1;
key_schedule[1] = temp3;
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x1));
key_schedule[1] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_schedule[1]), _mm_castsi128_pd(temp1), 0));
key_schedule[2] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(temp1), _mm_castsi128_pd(temp3), 1));
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x2));
key_schedule[3] = temp1;
key_schedule[4] = temp3;
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x4));
key_schedule[4] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_schedule[4]), _mm_castsi128_pd(temp1), 0));
key_schedule[5] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(temp1), _mm_castsi128_pd(temp3), 1));
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x8));
key_schedule[6] = temp1;
key_schedule[7] = temp3;
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x10));
key_schedule[7] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_schedule[7]), _mm_castsi128_pd(temp1), 0));
key_schedule[8] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(temp1), _mm_castsi128_pd(temp3), 1));
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x20));
key_schedule[9] = temp1;
key_schedule[10] = temp3;
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x40));
key_schedule[10] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_schedule[10]), _mm_castsi128_pd(temp1), 0));
key_schedule[11] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(temp1), _mm_castsi128_pd(temp3), 1));
aes_key_192_assist(&temp1, &temp3, _mm_aeskeygenassist_si128(temp3, 0x80));
key_schedule[12] = temp1;
#else
asm("movdqu (%1), %%xmm0 \n" // copy original round key
"movdqu %%xmm0, (%0) \n"
"add $16, %0 \n"
"movq 16(%1), %%xmm1 \n"
"movq %%xmm1, (%0) \n"
"add $8, %0 \n"
"jmp 2f \n" // skip auxiliary routine
/*
* Finish generating the next 6 quarter-keys.
*
* On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4
* and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON.
*
* On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10
* and those are written to the round key buffer.
*/
"1: \n"
"pshufd $0x55, %%xmm2, %%xmm2 \n" // X:X:X:X
"pxor %%xmm0, %%xmm2 \n" // X+r3:X+r2:X+r1:r4
"pslldq $4, %%xmm0 \n" // etc
"pxor %%xmm0, %%xmm2 \n"
"pslldq $4, %%xmm0 \n"
"pxor %%xmm0, %%xmm2 \n"
"pslldq $4, %%xmm0 \n"
"pxor %%xmm2, %%xmm0 \n" // update xmm0 = r9:r8:r7:r6
"movdqu %%xmm0, (%0) \n"
"add $16, %0 \n"
"pshufd $0xff, %%xmm0, %%xmm2 \n" // r9:r9:r9:r9
"pxor %%xmm1, %%xmm2 \n" // stuff:stuff:r9+r5:r10
"pslldq $4, %%xmm1 \n" // r2:r1:r0:0
"pxor %%xmm2, %%xmm1 \n" // update xmm1 = stuff:stuff:r11:r10
"movq %%xmm1, (%0) \n"
"add $8, %0 \n"
"ret \n"
"2: \n"
"aeskeygenassist $0x01, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x02, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x04, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x08, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x10, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x20, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x40, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x80, %%xmm1, %%xmm2 \ncall 1b \n"
:
: "r"(rk), "r"(key)
: "memory", "cc", "0");
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
}
/*
* Key expansion, 256-bit case
*/
static void aesni_setkey_enc_256(unsigned char* rk,
const unsigned char* key)
{
#if defined(POLARSSL_HAVE_MSVC_X64_INTRINSICS)
__m128i temp1, temp3;
__m128i* key_schedule = (__m128i*)rk;
temp1 = _mm_loadu_si128((__m128i*)key);
temp3 = _mm_loadu_si128((__m128i*)(key + 16));
key_schedule[0] = temp1;
key_schedule[1] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x01));
key_schedule[2] = temp1;
aes_key_256_assist_2(&temp1, &temp3);
key_schedule[3] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x02));
key_schedule[4] = temp1;
aes_key_256_assist_2(&temp1, &temp3);
key_schedule[5] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x04));
key_schedule[6] = temp1;
aes_key_256_assist_2(&temp1, &temp3);
key_schedule[7] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x08));
key_schedule[8] = temp1;
aes_key_256_assist_2(&temp1, &temp3);
key_schedule[9] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x10));
key_schedule[10] = temp1;
aes_key_256_assist_2(&temp1, &temp3);
key_schedule[11] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x20));
key_schedule[12] = temp1;
aes_key_256_assist_2(&temp1, &temp3);
key_schedule[13] = temp3;
aes_key_256_assist_1(&temp1, _mm_aeskeygenassist_si128(temp3, 0x40));
key_schedule[14] = temp1;
#else
asm("movdqu (%1), %%xmm0 \n"
"movdqu %%xmm0, (%0) \n"
"add $16, %0 \n"
"movdqu 16(%1), %%xmm1 \n"
"movdqu %%xmm1, (%0) \n"
"jmp 2f \n" // skip auxiliary routine
/*
* Finish generating the next two round keys.
*
* On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and
* xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON
*
* On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12
* and those have been written to the output buffer.
*/
"1: \n"
"pshufd $0xff, %%xmm2, %%xmm2 \n"
"pxor %%xmm0, %%xmm2 \n"
"pslldq $4, %%xmm0 \n"
"pxor %%xmm0, %%xmm2 \n"
"pslldq $4, %%xmm0 \n"
"pxor %%xmm0, %%xmm2 \n"
"pslldq $4, %%xmm0 \n"
"pxor %%xmm2, %%xmm0 \n"
"add $16, %0 \n"
"movdqu %%xmm0, (%0) \n"
/* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 )
* and proceed to generate next round key from there */
"aeskeygenassist $0, %%xmm0, %%xmm2\n"
"pshufd $0xaa, %%xmm2, %%xmm2 \n"
"pxor %%xmm1, %%xmm2 \n"
"pslldq $4, %%xmm1 \n"
"pxor %%xmm1, %%xmm2 \n"
"pslldq $4, %%xmm1 \n"
"pxor %%xmm1, %%xmm2 \n"
"pslldq $4, %%xmm1 \n"
"pxor %%xmm2, %%xmm1 \n"
"add $16, %0 \n"
"movdqu %%xmm1, (%0) \n"
"ret \n"
/*
* Main "loop" - Generating one more key than necessary,
* see definition of aes_context.buf
*/
"2: \n"
"aeskeygenassist $0x01, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x02, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x04, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x08, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x10, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x20, %%xmm1, %%xmm2 \ncall 1b \n"
"aeskeygenassist $0x40, %%xmm1, %%xmm2 \ncall 1b \n"
:
: "r"(rk), "r"(key)
: "memory", "cc", "0");
#endif /* POLARSSL_HAVE_MSVC_X64_INTRINSICS */
}
/*
* Key expansion, wrapper
*/
int aesni_setkey_enc(unsigned char* rk,
const unsigned char* key,
size_t bits)
{
switch (bits)
{
case 128: aesni_setkey_enc_128(rk, key); break;
case 192: aesni_setkey_enc_192(rk, key); break;
case 256: aesni_setkey_enc_256(rk, key); break;
default: return (POLARSSL_ERR_AES_INVALID_KEY_LENGTH);
}
return (0);
}
#endif

104
rpcs3/Crypto/aesni.h Normal file
View file

@ -0,0 +1,104 @@
#pragma once
#define POLARSSL_HAVE_ASM
/**
* \file aesni.h
*
* \brief AES-NI for hardware AES acceleration on some Intel processors
*
* Copyright (C) 2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "aes.h"
#define POLARSSL_AESNI_AES 0x02000000u
#define POLARSSL_AESNI_CLMUL 0x00000002u
#ifdef __cplusplus
extern "C"
{
#endif
/**
* \brief AES-NI features detection routine
*
* \param what The feature to detect
* (POLARSSL_AESNI_AES or POLARSSL_AESNI_CLMUL)
*
* \return 1 if CPU has support for the feature, 0 otherwise
*/
int aesni_supports(unsigned int what);
/**
* \brief AES-NI AES-ECB block en(de)cryption
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 on success (cannot fail)
*/
int aesni_crypt_ecb(aes_context* ctx,
int mode,
const unsigned char input[16],
unsigned char output[16]);
/**
* \brief GCM multiplication: c = a * b in GF(2^128)
*
* \param c Result
* \param a First operand
* \param b Second operand
*
* \note Both operands and result are bit strings interpreted as
* elements of GF(2^128) as per the GCM spec.
*/
void aesni_gcm_mult(unsigned char c[16],
const unsigned char a[16],
const unsigned char b[16]);
/**
* \brief Compute decryption round keys from encryption round keys
*
* \param invkey Round keys for the equivalent inverse cipher
* \param fwdkey Original round keys (for encryption)
* \param nr Number of rounds (that is, number of round keys minus one)
*/
void aesni_inverse_key(unsigned char* invkey,
const unsigned char* fwdkey, int nr);
/**
* \brief Perform key expansion (for encryption)
*
* \param rk Destination buffer where the round keys are written
* \param key Encryption key
* \param bits Key size in bits (must be 128, 192 or 256)
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aesni_setkey_enc(unsigned char* rk,
const unsigned char* key,
size_t bits);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,185 @@
#include "stdafx.h"
#include "decrypt_binaries.h"
#include "unedat.h"
#include "unself.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "util/StrUtil.h"
#include <charconv>
#include <iostream>
LOG_CHANNEL(dec_log, "DECRYPT");
usz decrypt_binaries_t::decrypt(std::string_view klic_input)
{
if (m_index >= m_modules.size())
{
std::cout << "No paths specified" << std::endl; // For CLI
m_index = umax;
return umax;
}
if (m_klics.empty())
{
dec_log.notice("Decrypting binaries...");
std::cout << "Decrypting binaries..." << std::endl; // For CLI
// Always start with no KLIC
m_klics.emplace_back(u128{});
if (const auto keys = g_fxo->try_get<loaded_npdrm_keys>())
{
// Second klic: get it from a running game
if (const u128 klic = keys->last_key())
{
m_klics.emplace_back(klic);
}
}
// Try to use the key that has been for the current running ELF
m_klics.insert(m_klics.end(), Emu.klic.begin(), Emu.klic.end());
}
if (std::string_view text = klic_input.substr(klic_input.find_first_of('x') + 1); text.size() == 32)
{
// Allowed to fail (would simply repeat the operation if fails again)
u64 lo = 0;
u64 hi = 0;
bool success = false;
if (auto res = std::from_chars(text.data() + 0, text.data() + 16, lo, 16); res.ec == std::errc() && res.ptr == text.data() + 16)
{
if (res = std::from_chars(text.data() + 16, text.data() + 32, hi, 16); res.ec == std::errc() && res.ptr == text.data() + 32)
{
success = true;
}
}
if (success)
{
lo = std::bit_cast<be_t<u64>>(lo);
hi = std::bit_cast<be_t<u64>>(hi);
if (u128 input_key = ((u128{hi} << 64) | lo))
{
m_klics.emplace_back(input_key);
}
}
}
while (m_index < m_modules.size())
{
const std::string& _module = m_modules[m_index];
const std::string old_path = _module;
fs::file elf_file;
fs::file internal_file;
bool invalid = false;
usz key_it = 0;
u32 file_magic{};
while (true)
{
for (; key_it < m_klics.size(); key_it++)
{
internal_file.close();
if (!elf_file.open(old_path) || !elf_file.read(file_magic))
{
file_magic = 0;
}
switch (file_magic)
{
case "SCE\0"_u32:
{
// First KLIC is no KLIC
elf_file = decrypt_self(elf_file, key_it != 0 ? reinterpret_cast<u8*>(&m_klics[key_it]) : nullptr);
if (!elf_file)
{
// Try another key
continue;
}
break;
}
case "NPD\0"_u32:
{
// EDAT / SDAT
internal_file = std::move(elf_file);
elf_file = DecryptEDAT(internal_file, old_path, key_it != 0 ? 8 : 1, reinterpret_cast<u8*>(&m_klics[key_it]));
if (!elf_file)
{
// Try another key
continue;
}
break;
}
default:
{
invalid = true;
break;
}
}
if (invalid)
{
elf_file.close();
}
break;
}
if (elf_file)
{
const std::string exec_ext = fmt::to_lower(_module).ends_with(".sprx") ? ".prx" : ".elf";
const std::string new_path = file_magic == "NPD\0"_u32 ? old_path + ".unedat" :
old_path.substr(0, old_path.find_last_of('.')) + exec_ext;
if (fs::file new_file{new_path, fs::rewrite})
{
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(elf_file.size(), 1u << 24));
elf_file.seek(0);
while (usz read_size = elf_file.read(buffer.data(), buffer.size()))
{
new_file.write(buffer.data(), read_size);
}
dec_log.success("Decrypted %s -> %s", old_path, new_path);
std::cout << "Decrypted " << old_path << " -> " << new_path << std::endl; // For CLI
m_index++;
}
else
{
dec_log.error("Failed to create %s", new_path);
std::cout << "Failed to create " << new_path << std::endl; // For CLI
m_index = umax;
}
break;
}
if (!invalid)
{
// Allow the user to manually type KLIC if decryption failed
return m_index;
}
dec_log.error("Failed to decrypt \"%s\".", old_path);
std::cout << "Failed to decrypt \"" << old_path << "\"." << std::endl; // For CLI
return m_index;
}
}
dec_log.notice("Finished decrypting all binaries.");
std::cout << "Finished decrypting all binaries." << std::endl; // For CLI
return m_index;
}

View file

@ -0,0 +1,26 @@
#pragma once
class decrypt_binaries_t
{
std::vector<u128> m_klics;
std::vector<std::string> m_modules;
usz m_index = 0;
public:
decrypt_binaries_t(std::vector<std::string> modules) noexcept
: m_modules(std::move(modules))
{
}
usz decrypt(std::string_view klic_input = {});
bool done() const
{
return m_index >= m_modules.size();
}
const std::string& operator[](usz index) const
{
return ::at32(m_modules, index);
}
};

537
rpcs3/Crypto/ec.cpp Normal file
View file

@ -0,0 +1,537 @@
// Copyright 2007,2008,2010 Segher Boessenkool <segher@kernel.crashing.org>
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include "util/types.hpp"
#include <cstring>
static inline int bn_compare(const u8* a, const u8* b, u32 n)
{
for (u32 i = 0; i < n; i++)
{
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
return 0;
}
static u8 bn_add_1(u8* d, const u8* a, const u8* b, u32 n)
{
u8 c = 0;
for (u32 i = n - 1; i != umax; i--)
{
const u32 dig = a[i] + b[i] + c;
c = dig >> 8;
d[i] = dig;
}
return c;
}
static u8 bn_sub_1(u8* d, const u8* a, const u8* b, u32 n)
{
u8 c = 1;
for (u32 i = n - 1; i != umax; i--)
{
const u32 dig = a[i] + 255 - b[i] + c;
c = dig >> 8;
d[i] = dig;
}
return 1 - c;
}
static void bn_reduce(u8* d, const u8* N, u32 n)
{
if (bn_compare(d, N, n) >= 0)
bn_sub_1(d, d, N, n);
}
static void bn_add(u8* d, const u8* a, const u8* b, const u8* N, u32 n)
{
if (bn_add_1(d, a, b, n))
bn_sub_1(d, d, N, n);
bn_reduce(d, N, n);
}
static void bn_sub(u8* d, const u8* a, const u8* b, const u8* N, u32 n)
{
if (bn_sub_1(d, a, b, n))
bn_add_1(d, d, N, n);
}
static constexpr u8 inv256[0x80] = {
0x01,
0xab,
0xcd,
0xb7,
0x39,
0xa3,
0xc5,
0xef,
0xf1,
0x1b,
0x3d,
0xa7,
0x29,
0x13,
0x35,
0xdf,
0xe1,
0x8b,
0xad,
0x97,
0x19,
0x83,
0xa5,
0xcf,
0xd1,
0xfb,
0x1d,
0x87,
0x09,
0xf3,
0x15,
0xbf,
0xc1,
0x6b,
0x8d,
0x77,
0xf9,
0x63,
0x85,
0xaf,
0xb1,
0xdb,
0xfd,
0x67,
0xe9,
0xd3,
0xf5,
0x9f,
0xa1,
0x4b,
0x6d,
0x57,
0xd9,
0x43,
0x65,
0x8f,
0x91,
0xbb,
0xdd,
0x47,
0xc9,
0xb3,
0xd5,
0x7f,
0x81,
0x2b,
0x4d,
0x37,
0xb9,
0x23,
0x45,
0x6f,
0x71,
0x9b,
0xbd,
0x27,
0xa9,
0x93,
0xb5,
0x5f,
0x61,
0x0b,
0x2d,
0x17,
0x99,
0x03,
0x25,
0x4f,
0x51,
0x7b,
0x9d,
0x07,
0x89,
0x73,
0x95,
0x3f,
0x41,
0xeb,
0x0d,
0xf7,
0x79,
0xe3,
0x05,
0x2f,
0x31,
0x5b,
0x7d,
0xe7,
0x69,
0x53,
0x75,
0x1f,
0x21,
0xcb,
0xed,
0xd7,
0x59,
0xc3,
0xe5,
0x0f,
0x11,
0x3b,
0x5d,
0xc7,
0x49,
0x33,
0x55,
0xff,
};
static void bn_mon_muladd_dig(u8* d, const u8* a, u8 b, const u8* N, u32 n)
{
const u8 z = -(d[n - 1] + a[n - 1] * b) * inv256[N[n - 1] / 2];
u32 dig = d[n - 1] + a[n - 1] * b + N[n - 1] * z;
dig >>= 8;
for (u32 i = n - 2; i < n; i--)
{
dig += d[i] + a[i] * b + N[i] * z;
d[i + 1] = dig;
dig >>= 8;
}
d[0] = dig;
dig >>= 8;
if (dig)
bn_sub_1(d, d, N, n);
bn_reduce(d, N, n);
}
static void bn_mon_mul(u8* d, const u8* a, const u8* b, const u8* N, u32 n)
{
u8 t[512];
memset(t, 0, n);
for (u32 i = n - 1; i != umax; i--)
bn_mon_muladd_dig(t, a, b[i], N, n);
memcpy(d, t, n);
}
static void bn_to_mon(u8* d, const u8* N, u32 n)
{
for (u32 i = 0; i < 8 * n; i++)
bn_add(d, d, d, N, n);
}
static void bn_from_mon(u8* d, const u8* N, u32 n)
{
u8 t[512];
memset(t, 0, n);
t[n - 1] = 1;
bn_mon_mul(d, d, t, N, n);
}
static void bn_mon_exp(u8* d, const u8* a, const u8* N, u32 n, const u8* e, u32 en)
{
u8 t[512];
memset(d, 0, n);
d[n - 1] = 1;
bn_to_mon(d, N, n);
for (u32 i = 0; i < en; i++)
{
for (u8 mask = 0x80; mask != 0; mask >>= 1)
{
bn_mon_mul(t, d, d, N, n);
if ((e[i] & mask) != 0)
bn_mon_mul(d, t, a, N, n);
else
memcpy(d, t, n);
}
}
}
static void bn_mon_inv(u8* d, const u8* a, const u8* N, u32 n)
{
u8 t[512], s[512];
memset(s, 0, n);
s[n - 1] = 2;
bn_sub_1(t, N, s, n);
bn_mon_exp(d, a, N, n, t, n);
}
struct point
{
u8 x[20];
u8 y[20];
};
static thread_local u8 ec_p[20]{};
static thread_local u8 ec_a[20]{}; // mon
static thread_local u8 ec_b[20]{}; // mon
static thread_local u8 ec_N[21]{};
static thread_local point ec_G{}; // mon
static thread_local point ec_Q{}; // mon
static thread_local u8 ec_k[21]{};
static thread_local bool ec_curve_initialized{};
static thread_local bool ec_pub_initialized{};
static inline bool elt_is_zero(const u8* d)
{
for (u32 i = 0; i < 20; i++)
if (d[i] != 0)
return false;
return true;
}
static void elt_add(u8* d, const u8* a, const u8* b)
{
bn_add(d, a, b, ec_p, 20);
}
static void elt_sub(u8* d, const u8* a, const u8* b)
{
bn_sub(d, a, b, ec_p, 20);
}
static void elt_mul(u8* d, const u8* a, const u8* b)
{
bn_mon_mul(d, a, b, ec_p, 20);
}
static void elt_square(u8* d, const u8* a)
{
elt_mul(d, a, a);
}
static void elt_inv(u8* d, const u8* a)
{
u8 s[20];
memcpy(s, a, 20);
bn_mon_inv(d, s, ec_p, 20);
}
static void point_to_mon(point* p)
{
bn_to_mon(p->x, ec_p, 20);
bn_to_mon(p->y, ec_p, 20);
}
static void point_from_mon(point* p)
{
bn_from_mon(p->x, ec_p, 20);
bn_from_mon(p->y, ec_p, 20);
}
static inline void point_zero(point* p)
{
memset(p->x, 0, 20);
memset(p->y, 0, 20);
}
static inline bool point_is_zero(const point* p)
{
return elt_is_zero(p->x) && elt_is_zero(p->y);
}
static void point_double(point* r, const point* p)
{
u8 s[20], t[20];
point pp = *p;
const u8* px = pp.x;
const u8* py = pp.y;
u8* rx = r->x;
u8* ry = r->y;
if (elt_is_zero(py))
{
point_zero(r);
return;
}
elt_square(t, px); // t = px*px
elt_add(s, t, t); // s = 2*px*px
elt_add(s, s, t); // s = 3*px*px
elt_add(s, s, ec_a); // s = 3*px*px + a
elt_add(t, py, py); // t = 2*py
elt_inv(t, t); // t = 1/(2*py)
elt_mul(s, s, t); // s = (3*px*px+a)/(2*py)
elt_square(rx, s); // rx = s*s
elt_add(t, px, px); // t = 2*px
elt_sub(rx, rx, t); // rx = s*s - 2*px
elt_sub(t, px, rx); // t = -(rx-px)
elt_mul(ry, s, t); // ry = -s*(rx-px)
elt_sub(ry, ry, py); // ry = -s*(rx-px) - py
}
static void point_add(point* r, const point* p, const point* q)
{
u8 s[20], t[20], u[20];
point pp = *p;
point qq = *q;
const u8* px = pp.x;
const u8* py = pp.y;
const u8* qx = qq.x;
const u8* qy = qq.y;
u8* rx = r->x;
u8* ry = r->y;
if (point_is_zero(&pp))
{
memcpy(rx, qx, 20);
memcpy(ry, qy, 20);
return;
}
if (point_is_zero(&qq))
{
memcpy(rx, px, 20);
memcpy(ry, py, 20);
return;
}
elt_sub(u, qx, px);
if (elt_is_zero(u))
{
elt_sub(u, qy, py);
if (elt_is_zero(u))
point_double(r, &pp);
else
point_zero(r);
return;
}
elt_inv(t, u); // t = 1/(qx-px)
elt_sub(u, qy, py); // u = qy-py
elt_mul(s, t, u); // s = (qy-py)/(qx-px)
elt_square(rx, s); // rx = s*s
elt_add(t, px, qx); // t = px+qx
elt_sub(rx, rx, t); // rx = s*s - (px+qx)
elt_sub(t, px, rx); // t = -(rx-px)
elt_mul(ry, s, t); // ry = -s*(rx-px)
elt_sub(ry, ry, py); // ry = -s*(rx-px) - py
}
static void point_mul(point* d, const u8* a, const point* b) // a is bignum
{
point_zero(d);
for (u32 i = 0; i < 21; i++)
{
for (u8 mask = 0x80; mask != 0; mask >>= 1)
{
point_double(d, d);
if ((a[i] & mask) != 0)
point_add(d, d, b);
}
}
}
static bool check_ecdsa(const struct point* Q, u8* R, u8* S, const u8* hash)
{
u8 Sinv[21];
u8 e[21];
u8 w1[21], w2[21];
struct point r1, r2;
u8 rr[21];
e[0] = 0;
memcpy(e + 1, hash, 20);
bn_reduce(e, ec_N, 21);
bn_to_mon(R, ec_N, 21);
bn_to_mon(S, ec_N, 21);
bn_to_mon(e, ec_N, 21);
bn_mon_inv(Sinv, S, ec_N, 21);
bn_mon_mul(w1, e, Sinv, ec_N, 21);
bn_mon_mul(w2, R, Sinv, ec_N, 21);
bn_from_mon(w1, ec_N, 21);
bn_from_mon(w2, ec_N, 21);
point_mul(&r1, w1, &ec_G);
point_mul(&r2, w2, Q);
point_add(&r1, &r1, &r2);
point_from_mon(&r1);
rr[0] = 0;
memcpy(rr + 1, r1.x, 20);
bn_reduce(rr, ec_N, 21);
bn_from_mon(R, ec_N, 21);
bn_from_mon(S, ec_N, 21);
return (bn_compare(rr, R, 21) == 0);
}
void ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy)
{
if (ec_curve_initialized)
return;
memcpy(ec_p, p, 20);
memcpy(ec_a, a, 20);
memcpy(ec_b, b, 20);
memcpy(ec_N, N, 21);
memcpy(ec_G.x, Gx, 20);
memcpy(ec_G.y, Gy, 20);
bn_to_mon(ec_a, ec_p, 20);
bn_to_mon(ec_b, ec_p, 20);
point_to_mon(&ec_G);
ec_curve_initialized = true;
}
void ecdsa_set_pub(const u8* Q)
{
if (ec_pub_initialized)
return;
memcpy(ec_Q.x, Q, 20);
memcpy(ec_Q.y, Q + 20, 20);
point_to_mon(&ec_Q);
ec_pub_initialized = true;
}
void ecdsa_set_priv(const u8* k)
{
memcpy(ec_k, k, sizeof ec_k);
}
bool ecdsa_verify(const u8* hash, u8* R, u8* S)
{
return check_ecdsa(&ec_Q, R, S, hash);
}

12
rpcs3/Crypto/ec.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
// Licensed under the terms of the GNU GPL, version 2.0 or later versions.
// http://www.gnu.org/licenses/gpl-2.0.txt
#include "util/types.hpp"
void ecdsa_set_curve(const u8* p, const u8* a, const u8* b, const u8* N, const u8* Gx, const u8* Gy);
void ecdsa_set_pub(const u8* Q);
void ecdsa_set_priv(const u8* k);
bool ecdsa_verify(const u8* hash, u8* R, u8* S);

817
rpcs3/Crypto/key_vault.cpp Normal file
View file

@ -0,0 +1,817 @@
#include "utils.h"
#include "aes.h"
#include "key_vault.h"
#include "util/logs.hpp"
LOG_CHANNEL(key_vault_log, "KEY_VAULT");
SELF_KEY::SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct)
{
version_start = ver_start;
version_end = ver_end;
revision = rev;
self_type = type;
hex_to_bytes(erk, e.c_str(), 0);
hex_to_bytes(riv, r.c_str(), 0);
hex_to_bytes(pub, pb.c_str(), 0);
hex_to_bytes(priv, pr.c_str(), 0);
curve_type = ct;
}
KeyVault::KeyVault()
{
std::memcpy(klicensee_key, NP_KLIC_FREE, sizeof(klicensee_key));
}
void KeyVault::LoadSelfLV0Keys()
{
sk_LV0_arr.clear();
sk_LV0_arr.emplace_back(0x0000000000000000, 0x0000000000000000, 0x0000, KEY_LV0,
"CA7A24EC38BDB45B98CCD7D363EA2AF0C326E65081E0630CB9AB2D215865878A",
"F9205F46F6021697E670F13DFA726212",
"A8FD6DB24532D094EFA08CB41C9A72287D905C6B27B42BE4AB925AAF4AFFF34D41EEB54DD128700D",
"001AD976FCDE86F5B8FF3E63EF3A7F94E861975BA3",
0x33);
}
void KeyVault::LoadSelfLDRKeys()
{
sk_LDR_arr.clear();
sk_LDR_arr.emplace_back(0x0000000000000000, 0x0000000000000000, 0x0000, KEY_LDR,
"C0CEFE84C227F75BD07A7EB846509F93B238E770DACB9FF4A388F812482BE21B",
"47EE7454E4774CC9B8960C7B59F4C14D",
"C2D4AAF319355019AF99D44E2B58CA29252C89123D11D6218F40B138CAB29B7101F3AEB72A975019",
"00C5B2BFA1A413DD16F26D31C0F2ED4720DCFB0670",
0x20);
}
void KeyVault::LoadSelfLV1Keys()
{
sk_LV1_arr.clear();
sk_LV1_arr.emplace_back(0x0003000000000000, 0x0003003100000000, 0x0000, KEY_LV1,
"B9F3F9E6107CFF2680A91E118C2403CF4A6F18F3C7EFD7D13D1AC4DB760BD222",
"B43661B9A79BAD9D8E2B046469CDA1E7",
"4C870BE86DDD996A92A3F7F404F33604244A1D02AB5B78BC9DAF030B78BE8867CF586171B7D45D20",
"002CC736C7AD06D264E9AB663EB1F35F5DC159248C",
0x33);
sk_LV1_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0000, KEY_LV1,
"B880593856C8C6D2037585626A12977F50DCFCF3F132D2C89AA6E670EAFC1646",
"A79B05D4E37B8117A95E6E7C14FB640E",
"7454C7CCBFC2F66C142D78A730A3A6F973CC0FB75A46FCBB390790138910A0CAC78E5E21F4DA3375",
"00033A699FDD2DA6CDD6CCC03B2C6145F998706F74",
0x34);
sk_LV1_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0000, KEY_LV1,
"1E8EEEA9E80A729F3FA52CF523B25941EA44B4155D94E5DADC5C5A77847620C7",
"E034D31A80316960024D1B3D3164FDC3",
"7E3A196f4A5879F3A7B091A2263F7C24E1716129B580566D308D9C2254B36AEE53DEF30EC85F8398",
"005815D17125D04C33790321DE29EB6241365100B5",
0x35);
sk_LV1_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0000, KEY_LV1,
"53ABDF84BE08B0351B734F2B97D2BE1621BC6C889E4362E5C70F39D6C3ED9F23",
"44E652661AC7584DBE08ECB810FB5FC0",
"733198A7759BC07326755BC9773A8A17C8A7043C7BDAB83D88E230512E2EA3852D7DA4263A7E97F9",
"004312C65347ACBE95CC306442FEFD0AF4C2935EB3",
0x05);
sk_LV1_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0000, KEY_LV1,
"48793EBDDA1AF65D737DA2FDA2DD104447A698F8A82CAAEE992831711BA94E83",
"15DCF3C67147A45D09DE7521EECA07A1",
"85A8868C320127F10B6598964C69221C086702021D31803520E21FDE4DBE827766BE41825CB7328C",
"",
0x07);
sk_LV1_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0000, KEY_LV1,
"5FF17D836E2C4AD69476E2614F64BDD05B9115389A9A6D055B5B544B1C34E3D5",
"DF0F50EC3C4743C5B17839D7B49F24A4",
"1CDABE30833823F461CA534104115FFF60010B710631E435A7D915E82AE88EDE667264656CB7062E",
"",
0x05);
sk_LV1_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0000, KEY_LV1,
"BD0621FA19383C3C72ECBC3B008F1CD55FFD7C3BB7510BF11AD0CF0FC2B70951",
"569AF3745E1E02E3E288273CDE244CD8",
"21E26F11C2D69478609DD1BD278CDFC940D90386455BA52FCD1FA7E27AC2AFA826C79A10193B625C",
"",
0x07);
sk_LV1_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0000, KEY_LV1,
"41A6E0039041E9D8AAF4EF2F2A2971248EDBD96A3985611ED7B4CE73EE4804FE",
"C8C98D5A5CE23AF5607A352AECACB0DC",
"4389664390265F96C1A882374C0F856364E33DB09BE124A4666F9A12F0DD9C811EDD55BA21ED0667",
"",
0x12);
sk_LV1_arr.emplace_back(0x0004000000000000, 0x0004001100000000, 0x0000, KEY_LV1,
"557EDF6C063F3272B0D44EEC12F418DA774815B5415597CC5F75C21E048BAD74",
"7144D7574937818517826227EF4AC0B4",
"085D38DBF9B757329EB862107929909D32FA1DAE60641BF4AC25319D7650597EE977F8E810FEEA96",
"",
0x13);
sk_LV1_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0000, KEY_LV1,
"10CEA04973FCCC12EC19924510822D8D4C41F657FD3D7E73F415A8D687421BCD",
"ED8699562C6AC65204FA166257E7FCF4",
"9AF86FC869C159FBB62F7D9674EE257ABF12E5A96D5875B4AA73C13C2BC13E2A4079F98B9B935EE2",
"",
0x14);
}
void KeyVault::LoadSelfLV2Keys()
{
sk_LV2_arr.clear();
sk_LV2_arr.emplace_back(0x0000000300000000, 0x0003003100000000, 0x0000, KEY_LV2,
"94303F69513572AB5AE17C8C2A1839D2C24C28F65389D3BBB11894CE23E0798F",
"9769BFD187B90990AE5FEA4E110B9CF5",
"AFAF5E96AF396CBB69071082C46A8F34A030E8EDB799E0A7BE00AA264DFF3AEBF7923920D559404D",
"0070ABF9361B02291829D479F56AB248203CD3EB46",
0x20);
sk_LV2_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0000, KEY_LV2,
"575B0A6C4B4F2760A03FE4189EBAF4D947279FD982B14070349098B08FF92C10",
"411CB18F460CE50CAF2C426D8F0D93C8",
"3FEE313954CB3039C321A7E33B97FFDEC8988A8B55759161B04DBF4731284E4A8191E3F17D32B0EA",
"0073076441A08CD179E5FACE349B86DA58B5B7BA78",
0x21);
sk_LV2_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0000, KEY_LV2,
"6DBD48D787C58803A8D724DA5ACF04FF8FCE91D7545D2322F2B7ABF57014AF68",
"603A36213708520ED5D745DEC1325BA5",
"5888CB83AC3CCA9610BC173C53141C0CA58B93719E744660CA8823D5EAEE8F9BF736997054E4B7E3",
"0009EBC3DE442FA5FBF6C4F3D4F9EAB07778A142BD",
0x22);
sk_LV2_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0000, KEY_LV2,
"84015E90FA23139628A3C75CC09714E6427B527A82D18ABC3E91CD8D7DDAFF17",
"5B240444D645F2038118F97FD5A145D5",
"B266318245266B2D33641CD8A864066D077FAC60B7E27399099A70A683454B70F9888E7CC0C2BF72",
"009D4CBA2BFB1A8330D3E20E59D281D476D231C73A",
0x32);
sk_LV2_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0000, KEY_LV2,
"EAE15444048EFDE7A831BFA9F5D96F047C9FCFF50723E292CF50F5417D81E359",
"9CA9282DC7FA9F315EF3156D970B7CD4",
"0D58938CB47598A6A672874F1768068F8B80D8D17014D2ABEBAC85E5B0993D9FB6F307DDC3DDA699",
"",
0x33);
sk_LV2_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0000, KEY_LV2,
"88AD367EDEC2FEED3E2F99B1C685075C41BDEC90C84F526CAF588F89BBD1CBCC",
"8D18E8E525230E63DE10291C9DD615BF",
"86EED1D65E58890ABDA9ACA486A2BDDB9C0A529C2053FAE301F0F698EAF443DA0F60595A597A7027",
"",
0x32);
sk_LV2_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0000, KEY_LV2,
"688D5FCAC6F4EA35AC6AC79B10506007286131EE038116DB8AA2C0B0340D9FB0",
"75E0239D18B0B669EAE650972F99726B",
"008E1C820AC567D1BFB8FE3CC6AD2E1845A1D1B19ED2E18B18CA34A8D28A83EC60C63859CDB3DACA",
"",
0x33);
sk_LV2_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0000, KEY_LV2,
"E81C5B04C29FB079A4A2687A39D4EA97BFB49D80EF546CEB292979A5F77A6254",
"15058FA7F2CAD7C528B5F605F6444EB0",
"438D0E5C1E7AFB18234DB6867472FF5F52B750F30C379C7DD1EE0FD23E417B3EA819CC01BAC480ED",
"",
0x11);
sk_LV2_arr.emplace_back(0x0004001000000000, 0x0004001100000000, 0x0000, KEY_LV2,
"A1E4B86ED02BF7F1372A2C73FE02BC738907EB37CE3BA605FE783C999FAFDB97",
"BBE7799B9A37CB272E386618FDFD4AEC",
"5B31A8E2A663EBD673196E2E1022E0D64988C4E1BBFE5E474415883A3BA0D9C562A2BE9C30E9B4A8",
"",
0x07);
sk_LV2_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0000, KEY_LV2,
"0CAF212B6FA53C0DA7E2C575ADF61DBE68F34A33433B1B891ABF5C4251406A03",
"9B79374722AD888EB6A35A2DF25A8B3E",
"1034A6F98AF6625CC3E3604B59B971CA617DF337538D2179EBB22F3BDC9D0C6DA56BA7DDFD205A50",
"",
0x14);
}
void KeyVault::LoadSelfISOKeys()
{
sk_ISO_arr.clear();
sk_ISO_arr.emplace_back(0x0000006000000000, 0x0003003000000000, 0x0001, KEY_ISO,
"8860D0CFF4D0DC688D3223321B96B59A777E6914961488E07048DAECB020ECA4",
"C82D015D46CF152F1DD0C16F18B5B1E5",
"733918D7C888130509346E6B4A8B6CAA357AB557E814E8122BF102C14A314BF9475B9D70EAF9EC29",
"009BE892E122A5C943C1BB7403A67318AA9E1B286F",
0x36);
sk_ISO_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0001, KEY_ISO,
"101E27F3FA2FB53ACA924F783AD553162D56B975D05B81351A1111799F20254D",
"8D2E9C6297B8AD252998458296AC773C",
"138446EE0BDDA5638F97328C8956E6489CBBFE57C5961D40DD5C43BB4138F1C400A8B27204A5D625",
"00849DBC57D3B92F01864E6E82EB4EF0EF6311E122",
0x32);
sk_ISO_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0001, KEY_ISO,
"3F2604FA27AEADFBE1AC69EB00BB16EF196C2193CBD62900FFD8C25041680843",
"A414AC1DB7987E43777651B330B899E1",
"1F4633AFDE18614D6CEF38A2FD6C4CCAC7B6EB8109D72CD066ECEBA0193EA3F43C37AE83179A4E5F",
"0085B4B05DEBA7E6AD831653C974D95149803BB272",
0x33);
sk_ISO_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0001, KEY_ISO,
"BDB74AA6E3BA2DC10B1BD7F17198399A158DBE1FA0BEA68C90FCACBE4D04BE37",
"0207A479B1574F8E7F697528F05D5435",
"917E1F1DC48A54EB5F10B38E7569BB5383628A7C906F0DCA62FDA33805C15FAB270016940A09DB58",
"00294411363290975BA551336D3965D88AF029A17B",
0x03);
sk_ISO_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0001, KEY_ISO,
"311C015F169F2A1E0757F7064B14C7C9F3A3FFEE015BD4E3A22401A2667857CE",
"7BB8B3F5AC8E0890E3148AE5688C7350",
"3F040EFA2335FED5670BA4D5C3AB2D9D0B4BA69D154A0062EA995A7D21DBAF0DC5A0DAD333D1C1DD",
"",
0x08);
sk_ISO_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0001, KEY_ISO,
"8474ADCA3B3244931EECEB9357841442442A1C4A4BCF4E498E6738950F4E4093",
"FFF9CACCC4129125CAFB240F419E5F39",
"098E1A53E59A95316B00D5A29C05FFEBAE41D1A8A386F9DA96F98858FD25E07BB7A3BC96A5D5B556",
"",
0x03);
sk_ISO_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0001, KEY_ISO,
"E6A21C599B75696C169EC02582BDA74A776134A6E05108EA701EC0CA2AC03592",
"D292A7BD57C0BB2EABBCA1252FA9EDEF",
"2ED078A13DC4617EB550AD06E228C83C142A2D588EB5E729402D18038A14842FD65B277DCAD225A5",
"",
0x08);
sk_ISO_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0001, KEY_ISO,
"072D3A5C3BDB0D674DE209381432B20414BC9BDA0F583ECB94BD9A134176DD51",
"8516A81F02CF938740498A406C880871",
"5A778DEB5C4F12E8D48E06A2BBBBE3C90FA8C6C47DF9BDB5697FD4A8EB7941CE3F59A557E81C787D",
"",
0x21);
sk_ISO_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0100, KEY_ISO,
"786FAB8A0B89474A2CB80B3EA104CCCB9E13F66B45EC499BB31865D07C661EA8",
"94662F13D99A9F5D211C979FFDF65FE3",
"912C94C252B7799CEB45DFBB73EF7CAD9BCC0793A3331BBB79E3C47C0F5C782F698065A8D4DB0D8B",
"",
0x0E);
sk_ISO_arr.emplace_back(0x0004001000000000, 0x0004001100000000, 0x0001, KEY_ISO,
"4262657A3185D9480F82C8BD2F81766FCC2C8FD7DD5EBE8657B00B939E0C75BD",
"4F1E3EF07D893A4714B1B3D5A4E50479",
"4DBFCFA68B52F1D66E09AFA6C18EC65479EDBD027B6B8C6A5D85FE5C84D43EA40CEF1672078A0702",
"",
0x11);
sk_ISO_arr.emplace_back(0x0004001000000000, 0x0004001100000000, 0x0100, KEY_ISO,
"16AA7D7C35399E2B1BFAF68CD19D7512A7855029C08BECC4CC3F035DF7F9C70B",
"0E50DB6D937D262CB0499136852FCB80",
"AEE2795BF295662A50DFAFE70D1B0B6F0A2EBB211E1323A275FC6E2D13BE4F2F10CA34784F4CF1EC",
"",
0x0F);
sk_ISO_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0001, KEY_ISO,
"63565DBE98C3B1A52AADC907C47130FE57A10734E84F22592670F86ED2B0A086",
"953F6A99891B4739358F5363A00C08B9",
"26BE7B02E7D65C6C21BF4063CDB8C0092FE1679D62FA1A8CCC284A1D21885473A959992537A06612",
"",
0x15);
sk_ISO_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0100, KEY_ISO,
"B96EA32CB96EA32DB96EA32CB96EA32CB96EA32CB96EA32DB96EA32CB96EA32C",
"B96EA32CB96EA32DB96EA32DB96EA32C",
"2D7066E68C6AC3373B1346FD76FE7D18A207C811500E65D85DB57BC4A27AD78F59FD53F38F50E151",
"0044AA25B4276D79B494A29CB8DE104642424F8EEF",
0x02);
}
void KeyVault::LoadSelfAPPKeys()
{
sk_APP_arr.clear();
sk_APP_arr.emplace_back(0x0000009200000000, 0x0000009200000000, 0x0000, KEY_APP,
"95F50019E7A68E341FA72EFDF4D60ED376E25CF46BB48DFDD1F080259DC93F04",
"4A0955D946DB70D691A640BB7FAECC4C",
"6F8DF8EBD0A1D1DB08B30DD3A951E3F1F27E34030B42C729C55555232D61B834B8BDFFB07E54B343",
"006C3E4CCB2C69A5AD7C6F60448E50C7F9184EEAF4",
0x21);
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0001, KEY_APP,
"79481839C406A632BDB4AC093D73D99AE1587F24CE7E69192C1CD0010274A8AB",
"6F0F25E1C8C4B7AE70DF968B04521DDA",
"94D1B7378BAFF5DFED269240A7A364ED68446741622E50BC6079B6E606A2F8E0A4C56E5CFF836526",
"003DE80167D2F0E9D30F2145144A558D1174F5410C",
0x11);
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0002, KEY_APP,
"4F89BE98DDD43CAD343F5BA6B1A133B0A971566F770484AAC20B5DD1DC9FA06A",
"90C127A9B43BA9D8E89FE6529E25206F",
"8CA6905F46148D7D8D84D2AFCEAE61B41E6750FC22EA435DFA61FCE6F4F860EE4F54D9196CA5290E",
"",
0x13);
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0003, KEY_APP,
"C1E6A351FCED6A0636BFCB6801A0942DB7C28BDFC5E0A053A3F52F52FCE9754E",
"E0908163F457576440466ACAA443AE7C",
"50022D5D37C97905F898E78E7AA14A0B5CAAD5CE8190AE5629A10D6F0CF4173597B37A95A7545C92",
"",
0x0B);
sk_APP_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0004, KEY_APP,
"838F5860CF97CDAD75B399CA44F4C214CDF951AC795298D71DF3C3B7E93AAEDA",
"7FDBB2E924D182BB0D69844ADC4ECA5B",
"1F140E8EF887DAB52F079A06E6915A6460B75CD256834A43FA7AF90C23067AF412EDAFE2C1778D69",
"0074E922FDEE5DC4CDF22FC8D7986477F813400860",
0x14);
sk_APP_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0005, KEY_APP,
"C109AB56593DE5BE8BA190578E7D8109346E86A11088B42C727E2B793FD64BDC",
"15D3F191295C94B09B71EBDE088A187A",
"B6BB0A84C649A90D97EBA55B555366F52381BB38A84C8BB71DA5A5A0949043C6DB249029A43156F7",
"",
0x15);
sk_APP_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0006, KEY_APP,
"6DFD7AFB470D2B2C955AB22264B1FF3C67F180983B26C01615DE9F2ECCBE7F41",
"24BD1C19D2A8286B8ACE39E4A37801C2",
"71F46AC33FF89DF589A100A7FB64CEAC244C9A0CBBC1FDCE80FB4BF8A0D2E66293309CB8EE8CFA95",
"",
0x2C);
sk_APP_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0007, KEY_APP,
"945B99C0E69CAF0558C588B95FF41B232660ECB017741F3218C12F9DFDEEDE55",
"1D5EFBE7C5D34AD60F9FBC46A5977FCE",
"AB284CA549B2DE9AA5C903B75652F78D192F8F4A8F3CD99209415C0A84C5C9FD6BF3095C1C18FFCD",
"002CF896D35DB871D0E6A252E799876A70D043C23E",
0x15);
sk_APP_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0008, KEY_APP,
"2C9E8969EC44DFB6A8771DC7F7FDFBCCAF329EC3EC070900CABB23742A9A6E13",
"5A4CEFD5A9C3C093D0B9352376D19405",
"6E82F6B54A0E9DEBE4A8B3043EE3B24CD9BBB62B4416B0482582E419A2552E29AB4BEA0A4D7FA2D5",
"",
0x16);
sk_APP_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0009, KEY_APP,
"F69E4A2934F114D89F386CE766388366CDD210F1D8913E3B973257F1201D632B",
"F4D535069301EE888CC2A852DB654461",
"1D7B974D10E61C2ED087A0981535904677EC07E96260F89565FF7EBDA4EE035C2AA9BCBDD5893F99",
"",
0x2D);
sk_APP_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000A, KEY_APP,
"29805302E7C92F204009161CA93F776A072141A8C46A108E571C46D473A176A3",
"5D1FAB844107676ABCDFC25EAEBCB633",
"09301B6436C85B53CB1585300A3F1AF9FB14DB7C30088C4642AD66D5C148B8995BB1A698A8C71827",
"0010818ED8A666051C6198662C3D6DDE2CA4901DDC",
0x25);
sk_APP_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000B, KEY_APP,
"A4C97402CC8A71BC7748661FE9CE7DF44DCE95D0D58938A59F47B9E9DBA7BFC3",
"E4792F2B9DB30CB8D1596077A13FB3B5",
"2733C889D289550FE00EAA5A47A34CEF0C1AF187610EB07BA35D2C09BB73C80B244EB4147700D1BF",
"",
0x26);
sk_APP_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000C, KEY_APP,
"9814EFFF67B7074D1B263BF85BDC8576CE9DEC914123971B169472A1BC2387FA",
"D43B1FA8BE15714B3078C23908BB2BCA",
"7D1986C6BEE6CE1E0C5893BD2DF203881F40D5056761CC3F1F2E9D9A378617A2DE40BA5F09844CEB",
"",
0x3D);
sk_APP_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000D, KEY_APP,
"03B4C421E0C0DE708C0F0B71C24E3EE04306AE7383D8C5621394CCB99FF7A194",
"5ADB9EAFE897B54CB1060D6885BE22CF",
"71502ADB5783583AB88B2D5F23F419AF01C8B1E72FCA1E694AD49FE3266F1F9C61EFC6F29B351142",
"",
0x12);
sk_APP_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000E, KEY_APP,
"39A870173C226EB8A3EEE9CA6FB675E82039B2D0CCB22653BFCE4DB013BAEA03",
"90266C98CBAA06C1BF145FF760EA1B45",
"84DE5692809848E5ACBE25BE548F6981E3DB14735A5DDE1A0FD1F475866532B862B1AB6A004B7255",
"",
0x27);
sk_APP_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000F, KEY_APP,
"FD52DFA7C6EEF5679628D12E267AA863B9365E6DB95470949CFD235B3FCA0F3B",
"64F50296CF8CF49CD7C643572887DA0B",
"0696D6CCBD7CF585EF5E00D547503C185D7421581BAD196E081723CD0A97FA40B2C0CD2492B0B5A1",
"",
0x3A);
sk_APP_arr.emplace_back(0x0003006100000000, 0x0003006100000000, 0x0010, KEY_APP,
"A5E51AD8F32FFBDE808972ACEE46397F2D3FE6BC823C8218EF875EE3A9B0584F",
"7A203D5112F799979DF0E1B8B5B52AA4",
"50597B7F680DD89F6594D9BDC0CBEE03666AB53647D0487F7F452FE2DD02694631EA755548C9E934",
"",
0x25);
sk_APP_arr.emplace_back(0x0003006100000000, 0x0003006100000000, 0x0011, KEY_APP,
"0F8EAB8884A51D092D7250597388E3B8B75444AC138B9D36E5C7C5B8C3DF18FD",
"97AF39C383E7EF1C98FA447C597EA8FE",
"2FDA7A56AAEA65921C0284FF1942C6DE137370093D106034B59191951A5201B422D462F8726F852D",
"",
0x26);
sk_APP_arr.emplace_back(0x0003006600000000, 0x0003006600000000, 0x0013, KEY_APP,
"DBF62D76FC81C8AC92372A9D631DDC9219F152C59C4B20BFF8F96B64AB065E94",
"CB5DD4BE8CF115FFB25801BC6086E729",
"B26FE6D3E3A1E766FAE79A8E6A7F48998E7FC1E4B0AD8745FF54C018C2A6CC7A0DD7525FAFEA4917",
"",
0x12);
sk_APP_arr.emplace_back(0x0003006600000000, 0x0003006600000000, 0x0014, KEY_APP,
"491B0D72BB21ED115950379F4564CE784A4BFAABB00E8CB71294B192B7B9F88E",
"F98843588FED8B0E62D7DDCB6F0CECF4",
"04275E8838EF95BD013B223C3DF674540932F21B534C7ED2944B9104D938FEB03B824DDB866AB26E",
"",
0x27);
sk_APP_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0016, KEY_APP,
"A106692224F1E91E1C4EBAD4A25FBFF66B4B13E88D878E8CD072F23CD1C5BF7C",
"62773C70BD749269C0AFD1F12E73909E",
"566635D3E1DCEC47243AAD1628AE6B2CEB33463FC155E4635846CE33899C5E353DDFA47FEF5694AF",
"",
0x30);
sk_APP_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0017, KEY_APP,
"4E104DCE09BA878C75DA98D0B1636F0E5F058328D81419E2A3D22AB0256FDF46",
"954A86C4629E116532304A740862EF85",
"3B7B04C71CAE2B1199D57453C038BB1B541A05AD1B94167B0AB47A9B24CAECB9000CB21407009666",
"",
0x08);
sk_APP_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0018, KEY_APP,
"1F876AB252DDBCB70E74DC4A20CD8ED51E330E62490E652F862877E8D8D0F997",
"BF8D6B1887FA88E6D85C2EDB2FBEC147",
"64A04126D77BF6B4D686F6E8F87DD150A5B014BA922D2B694FFF4453E11239A6E0B58F1703C51494",
"",
0x11);
sk_APP_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x0019, KEY_APP,
"3236B9937174DF1DC12EC2DD8A318A0EA4D3ECDEA5DFB4AC1B8278447000C297",
"6153DEE781B8ADDC6A439498B816DC46",
"148DCA961E2738BAF84B2D1B6E2DA2ABD6A95F2C9571E54C6922F9ED9674F062B7F1BE5BD6FA5268",
"",
0x31);
sk_APP_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x001A, KEY_APP,
"5EFD1E9961462794E3B9EF2A4D0C1F46F642AAE053B5025504130590E66F19C9",
"1AC8FA3B3C90F8FDE639515F91B58327",
"BE4B1B513536960618BFEF12A713F6673881B02F9DC616191E823FC8337CCF99ADAA6172019C0C23",
"",
0x17);
sk_APP_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x001B, KEY_APP,
"66637570D1DEC098467DB207BAEA786861964D0964D4DBAF89E76F46955D181B",
"9F7B5713A5ED59F6B35CD8F8A165D4B8",
"4AB6FB1F6F0C3D9219923C1AC683137AB05DF667833CC6A5E8F590E4E28FE2EB180C7D5861117CFB",
"",
0x12);
sk_APP_arr.emplace_back(0x0004004600000000, 0x0004004600000000, 0x001C, KEY_APP,
"CFF025375BA0079226BE01F4A31F346D79F62CFB643CA910E16CF60BD9092752",
"FD40664E2EBBA01BF359B0DCDF543DA4",
"36C1ACE6DD5CCC0006FDF3424750FAC515FC5CFA2C93EC53C6EC2BC421708D154E91F2E7EA54A893",
"",
0x09);
sk_APP_arr.emplace_back(0x0004004600000000, 0x0004004600000000, 0x001D, KEY_APP,
"D202174EB65A62048F3674B59EF6FE72E1872962F3E1CD658DE8D7AF71DA1F3E",
"ACB9945914EBB7B9A31ECE320AE09F2D",
"430322887503CF52928FAAA410FD623C7321281C8825D95F5B47EF078EFCFC44454C3AB4F00BB879",
"",
0x1A);
}
void KeyVault::LoadSelfNPDRMKeys()
{
sk_NPDRM_arr.clear();
sk_NPDRM_arr.emplace_back(0x0001000000000000, 0x0001000000000000, 0x0001, KEY_NPDRM,
"F9EDD0301F770FABBA8863D9897F0FEA6551B09431F61312654E28F43533EA6B",
"A551CCB4A42C37A734A2B4F9657D5540",
"B05F9DA5F9121EE4031467E74C505C29A8E29D1022379EDFF0500B9AE480B5DAB4578A4C61C5D6BF",
"00040AB47509BED04BD96521AD1B365B86BF620A98",
0x11);
sk_NPDRM_arr.emplace_back(0x0001000000000000, 0x0001000000000000, 0x0002, KEY_NPDRM,
"8E737230C80E66AD0162EDDD32F1F774EE5E4E187449F19079437A508FCF9C86",
"7AAECC60AD12AED90C348D8C11D2BED5",
"05BF09CB6FD78050C78DE69CC316FF27C9F1ED66A45BFCE0A1E5A6749B19BD546BBB4602CF373440",
"",
0x0A);
sk_NPDRM_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0003, KEY_NPDRM,
"1B715B0C3E8DC4C1A5772EBA9C5D34F7CCFE5B82025D453F3167566497239664",
"E31E206FBB8AEA27FAB0D9A2FFB6B62F",
"3F51E59FC74D6618D34431FA67987FA11ABBFACC7111811473CD9988FE91C43FC74605E7B8CB732D",
"",
0x08);
sk_NPDRM_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0004, KEY_NPDRM,
"BB4DBF66B744A33934172D9F8379A7A5EA74CB0F559BB95D0E7AECE91702B706",
"ADF7B207A15AC601110E61DDFC210AF6",
"9C327471BAFF1F877AE4FE29F4501AF5AD6A2C459F8622697F583EFCA2CA30ABB5CD45D1131CAB30",
"00B61A91DF4AB6A9F142C326BA9592B5265DA88856",
0x16);
sk_NPDRM_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0006, KEY_NPDRM,
"8B4C52849765D2B5FA3D5628AFB17644D52B9FFEE235B4C0DB72A62867EAA020",
"05719DF1B1D0306C03910ADDCE4AF887",
"2A5D6C6908CA98FC4740D834C6400E6D6AD74CF0A712CF1E7DAE806E98605CC308F6A03658F2970E",
"",
0x29);
sk_NPDRM_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0007, KEY_NPDRM,
"3946DFAA141718C7BE339A0D6C26301C76B568AEBC5CD52652F2E2E0297437C3",
"E4897BE553AE025CDCBF2B15D1C9234E",
"A13AFE8B63F897DA2D3DC3987B39389DC10BAD99DFB703838C4A0BC4E8BB44659C726CFD0CE60D0E",
"009EF86907782A318D4CC3617EBACE2480E73A46F6",
0x17);
sk_NPDRM_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0009, KEY_NPDRM,
"0786F4B0CA5937F515BDCE188F569B2EF3109A4DA0780A7AA07BD89C3350810A",
"04AD3C2F122A3B35E804850CAD142C6D",
"A1FE61035DBBEA5A94D120D03C000D3B2F084B9F4AFA99A2D4A588DF92B8F36327CE9E47889A45D0",
"",
0x2A);
sk_NPDRM_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000A, KEY_NPDRM,
"03C21AD78FBB6A3D425E9AAB1298F9FD70E29FD4E6E3A3C151205DA50C413DE4",
"0A99D4D4F8301A88052D714AD2FB565E",
"3995C390C9F7FBBAB124A1C14E70F9741A5E6BDF17A605D88239652C8EA7D5FC9F24B30546C1E44B",
"009AC6B22A056BA9E0B6D1520F28A57A3135483F9F",
0x27);
sk_NPDRM_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000C, KEY_NPDRM,
"357EBBEA265FAEC271182D571C6CD2F62CFA04D325588F213DB6B2E0ED166D92",
"D26E6DD2B74CD78E866E742E5571B84F",
"00DCF5391618604AB42C8CFF3DC304DF45341EBA4551293E9E2B68FFE2DF527FFA3BE8329E015E57",
"",
0x3A);
sk_NPDRM_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000D, KEY_NPDRM,
"337A51416105B56E40D7CAF1B954CDAF4E7645F28379904F35F27E81CA7B6957",
"8405C88E042280DBD794EC7E22B74002",
"9BFF1CC7118D2393DE50D5CF44909860683411A532767BFDAC78622DB9E5456753FE422CBAFA1DA1",
"",
0x18);
sk_NPDRM_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000F, KEY_NPDRM,
"135C098CBE6A3E037EBE9F2BB9B30218DDE8D68217346F9AD33203352FBB3291",
"4070C898C2EAAD1634A288AA547A35A8",
"BBD7CCCB556C2EF0F908DC7810FAFC37F2E56B3DAA5F7FAF53A4944AA9B841F76AB091E16B231433",
"",
0x3B);
sk_NPDRM_arr.emplace_back(0x0003006100000000, 0x0003006100000000, 0x0010, KEY_NPDRM,
"4B3CD10F6A6AA7D99F9B3A660C35ADE08EF01C2C336B9E46D1BB5678B4261A61",
"C0F2AB86E6E0457552DB50D7219371C5",
"64A5C60BC2AD18B8A237E4AA690647E12BF7A081523FAD4F29BE89ACAC72F7AB43C74EC9AFFDA213",
"",
0x27);
sk_NPDRM_arr.emplace_back(0x0003006600000000, 0x0003006600000000, 0x0013, KEY_NPDRM,
"265C93CF48562EC5D18773BEB7689B8AD10C5EB6D21421455DEBC4FB128CBF46",
"8DEA5FF959682A9B98B688CEA1EF4A1D",
"9D8DB5A880608DC69717991AFC3AD5C0215A5EE413328C2ABC8F35589E04432373DB2E2339EEF7C8",
"",
0x18);
sk_NPDRM_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0016, KEY_NPDRM,
"7910340483E419E55F0D33E4EA5410EEEC3AF47814667ECA2AA9D75602B14D4B",
"4AD981431B98DFD39B6388EDAD742A8E",
"62DFE488E410B1B6B2F559E4CB932BCB78845AB623CC59FDF65168400FD76FA82ED1DC60E091D1D1",
"",
0x25);
sk_NPDRM_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x0019, KEY_NPDRM,
"FBDA75963FE690CFF35B7AA7B408CF631744EDEF5F7931A04D58FD6A921FFDB3",
"F72C1D80FFDA2E3BF085F4133E6D2805",
"637EAD34E7B85C723C627E68ABDD0419914EBED4008311731DD87FDDA2DAF71F856A70E14DA17B42",
"",
0x24);
sk_NPDRM_arr.emplace_back(0x0004004600000000, 0x0004004600000000, 0x001C, KEY_NPDRM,
"8103EA9DB790578219C4CEDF0592B43064A7D98B601B6C7BC45108C4047AA80F",
"246F4B8328BE6A2D394EDE20479247C5",
"503172C9551308A87621ECEE90362D14889BFED2CF32B0B3E32A4F9FE527A41464B735E1ADBC6762",
"",
0x30);
}
void KeyVault::LoadSelfUNK7Keys()
{
sk_UNK7_arr.clear();
sk_UNK7_arr.emplace_back(0x0000008400000000, 0x0003003100000000, 0x0000, KEY_UNK7,
"D91166973979EA8694476B011AC62C7E9F37DA26DE1E5C2EE3D66E42B8517085",
"DC01280A6E46BC674B81A7E8801EBE6E",
"A0FC44108236141BF3517A662B027AFC1AC513A05690496C754DEB7D43BDC41B80FD75C212624EE4",
"",
0x11);
sk_UNK7_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0000, KEY_UNK7,
"B73111B0B00117E48DE5E2EE5E534C0F0EFFA4890BBB8CAD01EE0F848F91583E",
"86F56F9E5DE513894874B8BA253334B1",
"B0BA1A1AB9723BB4E87CED9637BE056066BC56E16572D43D0210A06411DBF8FEB8885CD912384AE5",
"",
0x12);
sk_UNK7_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0000, KEY_UNK7,
"8E944267C02E69A4FE474B7F5FCD7974A4F936FF4355AEC4F80EFA123858D8F6",
"908A75754E521EAC2F5A4889C6D7B72D",
"91201DA7D79E8EE2563142ECBD646DA026C963AC09E760E5390FFE24DAE6864310ABE147F8204D0B",
"",
0x13);
sk_UNK7_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0000, KEY_UNK7,
"BB31DF9A6F62C0DF853075FAA65134D9CE2240306C1731D1F7DA9B5329BD699F",
"263057225873F83940A65C8C926AC3E4",
"BC3A82A4F44C43A197070CD236FDC94FCC542D69A3E803E0AFF78D1F3DA19A79D2F61FAB5B94B437",
"",
0x23);
sk_UNK7_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0000, KEY_UNK7,
"71AA75C70A255580E4AE9BDAA0B08828C53EAA713CD0713797F143B284C1589B",
"9DED878CB6BA07121C0F50E7B172A8BF",
"387FCDAEAFF1B59CFAF79CE6215A065ACEAFFAF4048A4F217E1FF5CE67C66EC3F089DB235E52F9D3",
"",
0x29);
sk_UNK7_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0000, KEY_UNK7,
"F5D1DBC182F5083CD4EA37C431C7DAC73882C07F232D2699B1DD9FDDF1BF4195",
"D3A7C3C91CBA014FCBCA6D5570DE13FF",
"97CA8A9781F45E557E98F176EF794FCDA6B151EB3DFD1ABA12151E00AE59957C3B15628FC8875D28",
"",
0x23);
sk_UNK7_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0000, KEY_UNK7,
"BF10F09590C0152F7EF749FF4B990122A4E8E5491DA49A2D931E72EEB990F860",
"22C19C5522F7A782AFC547C2640F5BDE",
"3233BA2B284189FB1687DF653002257A0925D8EB0C64EBBE8CC7DE87F548D107DE1FD3D1D285DB4F",
"",
0x29);
sk_UNK7_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0000, KEY_UNK7,
"F11DBD2C97B32AD37E55F8E743BC821D3E67630A6784D9A058DDD26313482F0F",
"FC5FA12CA3D2D336C4B8B425D679DA55",
"19E27EE90E33EDAB16B22E688B5F704E5C6EC1062070EBF43554CD03DFDAE16D684BB8B5574DBECA",
"",
0x15);
sk_UNK7_arr.emplace_back(0x0004000000000000, 0x0004001100000000, 0x0000, KEY_UNK7,
"751EE949CD3ADF50A469197494A1EC358409CCBE6E85217EBDE7A87D3FF1ABD8",
"23AE4ADA4D3F798DC5ED98000337FF77",
"1BABA87CD1AD705C462D4E7427B6DAF59A50383A348A15088F0EDFCF1ADF2B5C2B2D507B2A357D36",
"",
0x1A);
sk_UNK7_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0000, KEY_UNK7,
"46BD0891224E0CE13E2162921D4BB76193AEEE4416A729FCDD111C5536BF87C9",
"BF036387CDB613C0AC88A6D9D2CC5316",
"A14F6D5F9AD7EBB3B7A39A7C32F13E5DC3B0BA16BDC33D39FDDF88F4AEEA6CFEEB0C0796C917A952",
"",
0x0F);
}
SELF_KEY KeyVault::GetSelfLV0Key() const
{
return sk_LV0_arr[0];
}
SELF_KEY KeyVault::GetSelfLDRKey() const
{
return sk_LDR_arr[0];
}
SELF_KEY KeyVault::GetSelfLV1Key(u64 version) const
{
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
for (uint i = 0; i < sk_LV1_arr.size(); i++)
{
if (version >= sk_LV1_arr[i].version_start && version <= sk_LV1_arr[i].version_end)
{
key = sk_LV1_arr[i];
break;
}
}
return key;
}
SELF_KEY KeyVault::GetSelfLV2Key(u64 version) const
{
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
for (uint i = 0; i < sk_LV2_arr.size(); i++)
{
if (version >= sk_LV2_arr[i].version_start && version <= sk_LV2_arr[i].version_end)
{
key = sk_LV2_arr[i];
break;
}
}
return key;
}
SELF_KEY KeyVault::GetSelfISOKey(u16 revision, u64 version) const
{
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
for (uint i = 0; i < sk_ISO_arr.size(); i++)
{
if ((version >= sk_ISO_arr[i].version_start && version <= sk_ISO_arr[i].version_end) && (sk_ISO_arr[i].revision == revision))
{
key = sk_ISO_arr[i];
break;
}
}
return key;
}
SELF_KEY KeyVault::GetSelfAPPKey(u16 revision) const
{
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
for (uint i = 0; i < sk_APP_arr.size(); i++)
{
if (sk_APP_arr[i].revision == revision)
{
key = sk_APP_arr[i];
break;
}
}
return key;
}
SELF_KEY KeyVault::GetSelfUNK7Key(u64 version) const
{
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
for (uint i = 0; i < sk_UNK7_arr.size(); i++)
{
if (version >= sk_UNK7_arr[i].version_start && version <= sk_UNK7_arr[i].version_end)
{
key = sk_UNK7_arr[i];
break;
}
}
return key;
}
SELF_KEY KeyVault::GetSelfNPDRMKey(u16 revision) const
{
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
for (uint i = 0; i < sk_NPDRM_arr.size(); i++)
{
if (sk_NPDRM_arr[i].revision == revision)
{
key = sk_NPDRM_arr[i];
break;
}
}
return key;
}
SELF_KEY KeyVault::FindSelfKey(u32 type, u16 revision, u64 version)
{
// Empty key.
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
key_vault_log.trace("FindSelfKey: Type:0x%x, Revision:0x%x, Version:0x%x", type, revision, version);
// Check SELF type.
switch (type)
{
case KEY_LV0:
LoadSelfLV0Keys();
key = GetSelfLV0Key();
break;
case KEY_LV1:
LoadSelfLV1Keys();
key = GetSelfLV1Key(version);
break;
case KEY_LV2:
LoadSelfLV2Keys();
key = GetSelfLV2Key(version);
break;
case KEY_APP:
LoadSelfAPPKeys();
key = GetSelfAPPKey(revision);
break;
case KEY_ISO:
LoadSelfISOKeys();
key = GetSelfISOKey(revision, version);
break;
case KEY_LDR:
LoadSelfLDRKeys();
key = GetSelfLDRKey();
break;
case KEY_UNK7:
LoadSelfUNK7Keys();
key = GetSelfUNK7Key(version);
break;
case KEY_NPDRM:
LoadSelfNPDRMKeys();
key = GetSelfNPDRMKey(revision);
break;
default:
break;
}
return key;
}
void KeyVault::SetKlicenseeKey(const u8* key)
{
std::memcpy(klicensee_key, key, 0x10);
}
const u8* KeyVault::GetKlicenseeKey() const
{
return klicensee_key;
}
void rap_to_rif(const unsigned char* rap, unsigned char* rif)
{
int i;
int round;
aes_context aes;
unsigned char key[0x10];
unsigned char iv[0x10];
memset(key, 0, 0x10);
memset(iv, 0, 0x10);
// Initial decrypt.
aes_setkey_dec(&aes, RAP_KEY, 128);
aes_crypt_cbc(&aes, AES_DECRYPT, 0x10, iv, rap, key);
// rap2rifkey round.
for (round = 0; round < 5; ++round)
{
for (i = 0; i < 16; ++i)
{
const int p = RAP_PBOX[i];
key[p] ^= RAP_E1[p];
}
for (i = 15; i >= 1; --i)
{
const int p = RAP_PBOX[i];
const int pp = RAP_PBOX[i - 1];
key[p] ^= key[pp];
}
int o = 0;
for (i = 0; i < 16; ++i)
{
const int p = RAP_PBOX[i];
const unsigned char kc = key[p] - o;
const unsigned char ec2 = RAP_E2[p];
if (o != 1 || kc != 0xFF)
{
o = kc < ec2 ? 1 : 0;
key[p] = kc - ec2;
}
else if (kc == 0xFF)
{
key[p] = kc - ec2;
}
else
{
key[p] = kc;
}
}
}
memcpy(rif, key, 0x10);
}

315
rpcs3/Crypto/key_vault.h Normal file
View file

@ -0,0 +1,315 @@
#pragma once
#include "util/types.hpp"
#include <string>
#include <vector>
#include <memory>
enum SELF_KEY_TYPE
{
KEY_LV0 = 1,
KEY_LV1,
KEY_LV2,
KEY_APP,
KEY_ISO,
KEY_LDR,
KEY_UNK7,
KEY_NPDRM
};
struct SELF_KEY
{
u64 version_start{};
u64 version_end{};
u16 revision{};
u32 self_type{};
u8 erk[0x20]{};
u8 riv[0x10]{};
u8 pub[0x28]{};
u8 priv[0x15]{};
u32 curve_type{};
SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct);
};
constexpr u32 PASSPHRASE_KEY_LEN = 16;
constexpr u32 PASSPHRASE_OUT_LEN = 4096;
constexpr u8 SC_ISO_SERIES_KEY_1[PASSPHRASE_KEY_LEN] = {
0xD4, 0x13, 0xB8, 0x96, 0x63, 0xE1, 0xFE, 0x9F, 0x75, 0x14, 0x3D, 0x3B, 0xB4, 0x56, 0x52, 0x74 // D413B89663E1FE9F75143D3BB4565274
};
constexpr u8 SC_ISO_SERIES_KEY_2[PASSPHRASE_KEY_LEN] = {
0xFA, 0x72, 0xCE, 0xEF, 0x59, 0xB4, 0xD2, 0x98, 0x9F, 0x11, 0x19, 0x13, 0x28, 0x7F, 0x51, 0xC7 // FA72CEEF59B4D2989F111913287F51C7
};
constexpr u8 SC_KEY_FOR_MASTER_1[PASSPHRASE_KEY_LEN] = {
0xDA, 0xA4, 0xB9, 0xF2, 0xBC, 0x70, 0xB2, 0x80, 0xA7, 0xB3, 0x40, 0xFA, 0x0D, 0x04, 0xBA, 0x14 // DAA4B9F2BC70B280A7B340FA0D04BA14
};
constexpr u8 SC_KEY_FOR_MASTER_2[PASSPHRASE_KEY_LEN] = {
0x29, 0xC1, 0x94, 0xFF, 0xEC, 0x1F, 0xD1, 0x4D, 0x4A, 0xAE, 0x00, 0x6C, 0x32, 0xB3, 0x59, 0x90 // 29C194FFEC1FD14D4AAE006C32B35990
};
constexpr u8 SC_ISO_SERIES_INTERNAL_KEY_1[PASSPHRASE_KEY_LEN] = {
0x73, 0x63, 0x6B, 0x65, 0x79, 0x5F, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x6B, 0x65, 0x79, 0x00 // 73636B65795F7365726965736B657900
};
constexpr u8 SC_ISO_SERIES_INTERNAL_KEY_2[PASSPHRASE_KEY_LEN] = {
0x73, 0x63, 0x6B, 0x65, 0x79, 0x5F, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x6B, 0x65, 0x79, 0x32 // 73636B65795F7365726965736B657932
};
constexpr u8 SC_ISO_SERIES_INTERNAL_KEY_3[PASSPHRASE_KEY_LEN] = {
0x73, 0x63, 0x6B, 0x65, 0x79, 0x5F, 0x66, 0x6F, 0x72, 0x5F, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72 // 73636B65795F666F725F6D6173746572
};
constexpr u8 PKG_AES_KEY_IDU[0x10] = {
0x5d, 0xb9, 0x11, 0xe6, 0xb7, 0xe5, 0x0a, 0x7d, 0x32, 0x15, 0x38, 0xfd, 0x7c, 0x66, 0xf1, 0x7b};
constexpr u8 PKG_AES_KEY[0x10] = {
0x2e, 0x7b, 0x71, 0xd7, 0xc9, 0xc9, 0xa1, 0x4e, 0xa3, 0x22, 0x1f, 0x18, 0x88, 0x28, 0xb8, 0xf8};
constexpr u8 PKG_AES_KEY2[0x10] = {
0x07, 0xf2, 0xc6, 0x82, 0x90, 0xb5, 0x0d, 0x2c, 0x33, 0x81, 0x8d, 0x70, 0x9b, 0x60, 0xe6, 0x2b};
constexpr u8 PKG_AES_KEY_VITA_1[0x10] = {
0xE3, 0x1A, 0x70, 0xC9, 0xCE, 0x1D, 0xD7, 0x2B, 0xF3, 0xC0, 0x62, 0x29, 0x63, 0xF2, 0xEC, 0xCB};
constexpr u8 PKG_AES_KEY_VITA_2[0x10] = {
0x42, 0x3A, 0xCA, 0x3A, 0x2B, 0xD5, 0x64, 0x9F, 0x96, 0x86, 0xAB, 0xAD, 0x6F, 0xD8, 0x80, 0x1F};
constexpr u8 PKG_AES_KEY_VITA_3[0x10] = {
0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA};
constexpr u8 NP_IDPS[0x10] = {
0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
constexpr u8 NP_KLIC_FREE[0x10] = {
0x72, 0xF9, 0x90, 0x78, 0x8F, 0x9C, 0xFF, 0x74, 0x57, 0x25, 0xF0, 0x8E, 0x4C, 0x12, 0x83, 0x87};
constexpr u8 NP_OMAC_KEY_2[0x10] = {
0x6B, 0xA5, 0x29, 0x76, 0xEF, 0xDA, 0x16, 0xEF, 0x3C, 0x33, 0x9F, 0xB2, 0x97, 0x1E, 0x25, 0x6B};
constexpr u8 NP_OMAC_KEY_3[0x10] = {
0x9B, 0x51, 0x5F, 0xEA, 0xCF, 0x75, 0x06, 0x49, 0x81, 0xAA, 0x60, 0x4D, 0x91, 0xA5, 0x4E, 0x97};
constexpr u8 NP_KLIC_KEY[0x10] = {
0xF2, 0xFB, 0xCA, 0x7A, 0x75, 0xB0, 0x4E, 0xDC, 0x13, 0x90, 0x63, 0x8C, 0xCD, 0xFD, 0xD1, 0xEE};
constexpr u8 NP_RIF_KEY[0x10] = {
0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B};
// PSP Minis
constexpr u8 NP_PSP_KEY_1[0x10] = {
0x2A, 0x6A, 0xFB, 0xCF, 0x43, 0xD1, 0x57, 0x9F, 0x7D, 0x73, 0x87, 0x41, 0xA1, 0x3B, 0xD4, 0x2E};
// PSP Remasters
constexpr u8 NP_PSP_KEY_2[0x10] = {
0x0D, 0xB8, 0x57, 0x32, 0x36, 0x6C, 0xD7, 0x34, 0xFC, 0x87, 0x9E, 0x74, 0x33, 0x43, 0xBB, 0x4F};
constexpr u8 NP_PSX_KEY[0x10] = {
0x52, 0xC0, 0xB5, 0xCA, 0x76, 0xD6, 0x13, 0x4B, 0xB4, 0x5F, 0xC6, 0x6C, 0xA6, 0x37, 0xF2, 0xC1};
constexpr u8 RAP_KEY[0x10] = {
0x86, 0x9F, 0x77, 0x45, 0xC1, 0x3F, 0xD8, 0x90, 0xCC, 0xF2, 0x91, 0x88, 0xE3, 0xCC, 0x3E, 0xDF};
constexpr u8 RAP_PBOX[0x10] = {
0x0C, 0x03, 0x06, 0x04, 0x01, 0x0B, 0x0F, 0x08, 0x02, 0x07, 0x00, 0x05, 0x0A, 0x0E, 0x0D, 0x09};
constexpr u8 RAP_E1[0x10] = {
0xA9, 0x3E, 0x1F, 0xD6, 0x7C, 0x55, 0xA3, 0x29, 0xB7, 0x5F, 0xDD, 0xA6, 0x2A, 0x95, 0xC7, 0xA5};
constexpr u8 RAP_E2[0x10] = {
0x67, 0xD4, 0x5D, 0xA3, 0x29, 0x6D, 0x00, 0x6A, 0x4E, 0x7C, 0x53, 0x7B, 0xF5, 0x53, 0x8C, 0x74};
constexpr u8 SDAT_KEY[0x10] = {
0x0D, 0x65, 0x5E, 0xF8, 0xE6, 0x74, 0xA9, 0x8A, 0xB8, 0x50, 0x5C, 0xFA, 0x7D, 0x01, 0x29, 0x33};
constexpr u8 EDAT_KEY_0[0x10] = {
0xBE, 0x95, 0x9C, 0xA8, 0x30, 0x8D, 0xEF, 0xA2, 0xE5, 0xE1, 0x80, 0xC6, 0x37, 0x12, 0xA9, 0xAE};
constexpr u8 EDAT_HASH_0[0x10] = {
0xEF, 0xFE, 0x5B, 0xD1, 0x65, 0x2E, 0xEB, 0xC1, 0x19, 0x18, 0xCF, 0x7C, 0x04, 0xD4, 0xF0, 0x11};
constexpr u8 EDAT_KEY_1[0x10] = {
0x4C, 0xA9, 0xC1, 0x4B, 0x01, 0xC9, 0x53, 0x09, 0x96, 0x9B, 0xEC, 0x68, 0xAA, 0x0B, 0xC0, 0x81};
constexpr u8 EDAT_HASH_1[0x10] = {
0x3D, 0x92, 0x69, 0x9B, 0x70, 0x5B, 0x07, 0x38, 0x54, 0xD8, 0xFC, 0xC6, 0xC7, 0x67, 0x27, 0x47};
constexpr u8 EDAT_IV[0x10] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
constexpr u8 VSH_CURVE_P[0x14] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
constexpr u8 VSH_CURVE_A[0x14] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC};
constexpr u8 VSH_CURVE_B[0x14] = {
0xA6, 0x8B, 0xED, 0xC3, 0x34, 0x18, 0x02, 0x9C, 0x1D, 0x3C, 0xE3, 0x3B, 0x9A, 0x32, 0x1F, 0xCC, 0xBB, 0x9E, 0x0F, 0x0B};
constexpr u8 VSH_CURVE_N[0x15] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xB5, 0xAE, 0x3C, 0x52, 0x3E, 0x63, 0x94, 0x4F, 0x21, 0x27};
constexpr u8 VSH_CURVE_GX[0x14] = {
0x12, 0x8E, 0xC4, 0x25, 0x64, 0x87, 0xFD, 0x8F, 0xDF, 0x64, 0xE2, 0x43, 0x7B, 0xC0, 0xA1, 0xF6, 0xD5, 0xAF, 0xDE, 0x2C};
constexpr u8 VSH_CURVE_GY[0x14] = {
0x59, 0x58, 0x55, 0x7E, 0xB1, 0xDB, 0x00, 0x12, 0x60, 0x42, 0x55, 0x24, 0xDB, 0xC3, 0x79, 0xD5, 0xAC, 0x5F, 0x4A, 0xDF};
constexpr u8 VSH_PUB[0x28] = {
0x62, 0x27, 0xB0, 0x0A, 0x02, 0x85, 0x6F, 0xB0, 0x41, 0x08, 0x87, 0x67, 0x19, 0xE0, 0xA0, 0x18, 0x32, 0x91, 0xEE, 0xB9,
0x6E, 0x73, 0x6A, 0xBF, 0x81, 0xF7, 0x0E, 0xE9, 0x16, 0x1B, 0x0D, 0xDE, 0xB0, 0x26, 0x76, 0x1A, 0xFF, 0x7B, 0xC8, 0x5B};
constexpr u8 SCEPKG_RIV[0x10] = {
0x4A, 0xCE, 0xF0, 0x12, 0x24, 0xFB, 0xEE, 0xDF, 0x82, 0x45, 0xF8, 0xFF, 0x10, 0x21, 0x1E, 0x6E};
constexpr u8 SCEPKG_ERK[0x20] = {
0xA9, 0x78, 0x18, 0xBD, 0x19, 0x3A, 0x67, 0xA1, 0x6F, 0xE8, 0x3A, 0x85, 0x5E, 0x1B, 0xE9, 0xFB, 0x56, 0x40, 0x93, 0x8D,
0x4D, 0xBC, 0xB2, 0xCB, 0x52, 0xC5, 0xA2, 0xF8, 0xB0, 0x2B, 0x10, 0x31};
constexpr u8 PUP_KEY[0x40] = {
0xF4, 0x91, 0xAD, 0x94, 0xC6, 0x81, 0x10, 0x96, 0x91, 0x5F, 0xD5, 0xD2, 0x44, 0x81, 0xAE, 0xDC, 0xED, 0xED, 0xBE, 0x6B,
0xE5, 0x13, 0x72, 0x4D, 0xD8, 0xF7, 0xB6, 0x91, 0xE8, 0x8A, 0x38, 0xF4, 0xB5, 0x16, 0x2B, 0xFB, 0xEC, 0xBE, 0x3A, 0x62,
0x18, 0x5D, 0xD7, 0xC9, 0x4D, 0xA2, 0x22, 0x5A, 0xDA, 0x3F, 0xBF, 0xCE, 0x55, 0x5B, 0x9E, 0xA9, 0x64, 0x98, 0x29, 0xEB,
0x30, 0xCE, 0x83, 0x66};
// name; location; notes
constexpr s64 PAID_01 = 0x0003CD28CB47D3C1L; // spu_token_processor.self; CoreOS; Only for 2E - 083.007
constexpr s64 PAID_02 = 0x1010000001000001L; // vsh / games / utilities; /dev_flash/, cell_root/target/images; only for 2E - 080.006
constexpr s64 PAID_03 = 0x1010000001000003L; // retail games and their updates
constexpr s64 PAID_04 = 0x1010000002000003L;
constexpr s64 PAID_05 = 0x1020000401000001L; // ps2emu; /dev_flash/ps2emu; CEX DEX DECR ?
constexpr s64 PAID_06 = 0x1050000003000001L; // lv2_kernel.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_07 = 0x1070000001000002L; // onicore_child.self; /dev_flash/vsh/module; same for CEX DEX DECR
constexpr s64 PAID_08 = 0x1070000002000002L; // mcore.self; /dev_flash/vsh/module; same for CEX DEX DECR
constexpr s64 PAID_09 = 0x1070000003000002L; // mgvideo.self; /dev_flash/vsh/module; same for CEX DEX DECR
constexpr s64 PAID_10 = 0x1070000004000002L; // swagner / swreset; /dev_flash/vsh/module; DTCP-IP DRM modules
constexpr s64 PAID_11 = 0x107000000E000001L; // vtrm_server.fself; lv1
constexpr s64 PAID_12 = 0x107000000F000001L; // update_manager_server.fself; lv1
constexpr s64 PAID_13 = 0x1070000010000001L; // sc_manager_server.fself; lv1
constexpr s64 PAID_14 = 0x1070000011000001L; // secure_rtc_server.fself; lv1
constexpr s64 PAID_15 = 0x1070000012000001L; // spm_server.fself; lv1
constexpr s64 PAID_16 = 0x1070000013000001L; // sb_manager_server.fself; lv1
constexpr s64 PAID_17 = 0x1070000014000001L; // framework.fself; lv1
constexpr s64 PAID_18 = 0x1070000015000001L; // lv2_loader.fself; lv1
constexpr s64 PAID_19 = 0x1070000016000001L; // profile_loader.fself; lv1
constexpr s64 PAID_20 = 0x1070000017000001L; // ss_init.fself; lv1
constexpr s64 PAID_21 = 0x1070000018000001L; // individual_info_mgr_server.fself; lv1
constexpr s64 PAID_22 = 0x1070000019000001L; // app_info_manager_server.fself; lv1
constexpr s64 PAID_23 = 0x107000001A000001L; // ss_sc_init_pu.fself; JIG lv1 proc
constexpr s64 PAID_24 = 0x107000001C000001L; // updater_frontend.fself; lv1
constexpr s64 PAID_25 = 0x107000001D000001L; // sysmgr_ss.fself; lv1
constexpr s64 PAID_26 = 0x107000001F000001L; // sb_iso_spu_module.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_27 = 0x1070000020000001L; // sc_iso.self / sc_iso_factory.self; CoreOS / [2.43 JIG PUP]; same for CEX DEX DECR
constexpr s64 PAID_28 = 0x1070000021000001L; // spp_verifier.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_29 = 0x1070000022000001L; // spu_pkg_rvk_verifier.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_30 = 0x1070000023000001L; // spu_token_processor.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_31 = 0x1070000024000001L; // sv_iso_spu_module.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_32 = 0x1070000025000001L; // aim_spu_module.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_33 = 0x1070000026000001L; // ss_sc_init.self; [2.43 JIG PUP]
constexpr s64 PAID_34 = 0x1070000027000001L; // dispatcher.fself; lv1;
constexpr s64 PAID_35 = 0x1070000028000001L; // factory_data_mngr_server.fself; JIG lv1 proc
constexpr s64 PAID_36 = 0x1070000029000001L; // fdm_spu_module.self; [2.43 JIG PUP]
constexpr s64 PAID_37 = 0x107000002A000001L;
constexpr s64 PAID_38 = 0x1070000031000001L;
constexpr s64 PAID_39 = 0x1070000032000001L; // ss_server1.fself; lv1
constexpr s64 PAID_40 = 0x1070000033000001L; // ss_server2.fself; lv1
constexpr s64 PAID_41 = 0x1070000034000001L; // ss_server3.fself; lv1
constexpr s64 PAID_42 = 0x1070000037000001L; // mc_iso_spu_module.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_43 = 0x1070000039000001L; // bdp_bdmv.self; /dev_flash/bdplayer
constexpr s64 PAID_44 = 0x107000003A000001L; // bdj.self; /dev_flash/bdplayer
constexpr s64 PAID_45 = 0x1070000040000001L; // sys/external modules; /dev_flash/sys/external; same for CEX DEX DECR (incl. liblv2dbg_for_cex.sprx + liblv2dbg_for_dex.sprx)
constexpr s64 PAID_46 = 0x1070000041000001L; // ps1emu; /dev_flash/ps1emu; CEX DEX DECR ?
constexpr s64 PAID_47 = 0x1070000043000001L; // me_iso_spu_module.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_48 = 0x1070000044000001L; // (related to usb dongle)
constexpr s64 PAID_49 = 0x1070000045000001L; // USB Dongle Authenticator; ss_server1.fself; same for CEX DEX DECR
constexpr s64 PAID_50 = 0x1070000046000001L; // spu_mode_auth.self; [2.43 JIG PUP]
constexpr s64 PAID_51 = 0x1070000047000001L; // otheros.self; otheros.self
constexpr s64 PAID_52 = 0x1070000048000001L; // ftpd; cell_root/target/images; DECR
constexpr s64 PAID_53 = 0x107000004C000001L; // spu_utoken_processor.self; CoreOS (since FW 2.40)
constexpr s64 PAID_54 = 0x107000004E000001L; // (syscall 878)
constexpr s64 PAID_55 = 0x107000004F000001L;
constexpr s64 PAID_56 = 0x1070000050000001L;
constexpr s64 PAID_57 = 0x1070000051000001L;
constexpr s64 PAID_58 = 0x1070000052000001L; // sys/internal CEX + vsh/module modules CEX; /dev_flash/sys/internal + /dev_flash/vsh/module; Differs between CEX (this authid) and DECR
constexpr s64 PAID_59 = 0x1070000054000001L; // (syscall 21)
constexpr s64 PAID_60 = 0x1070000055000001L; // manu_info_spu_module.self; CoreOS (since FW 3.50)
constexpr s64 PAID_61 = 0x1070000058000001L; // me_iso_for_ps2emu.self; CoreOS (since FW 3.70)
constexpr s64 PAID_62 = 0x1070000059000001L; // sv_iso_for_ps2emu.self; CoreOS (since FW 3.70)
constexpr s64 PAID_63 = 0x1070000300000001L; // Lv2diag.self; BD-remarry toolkit
constexpr s64 PAID_64 = 0x10700003FC000001L; // emer_init.self; CoreOS (since FW 2.00)
constexpr s64 PAID_65 = 0x10700003FD000001L; // ps3swu; PUP root; same for CEX DEX DECR
constexpr s64 PAID_66 = 0x10700003FD000001L; // PS3ToolUpdater; cell_root/target/images; Only DECR
constexpr s64 PAID_67 = 0x10700003FD000001L; // manufacturing_updater_for_reset.self; BD-remarry toolkit
constexpr s64 PAID_68 = 0x10700003FE000001L; // sys_agent.self DECR; /dev_flash/sys/internal; DECR
constexpr s64 PAID_69 = 0x10700003FF000001L; // db_backup, mkfs, mkfs_085, mount_hdd, registry_backup, set_monitor, most sys/internal modules DECR + most vsh/module modules DECR; /dev_flash/sys/internal + /dev_flash/vsh/module + cell_root/target/images; Differs between DECR (this authid) and CEX
constexpr s64 PAID_70 = 0x1070000400000001L; // vsh / games / utilities; /dev_flash/, cell_root/target/images; only for 081.003 - 083.007
constexpr s64 PAID_71 = 0x1070000409000001L; // psp_emulator.self; /dev_flash/pspemu/psp_emulator.self; CEX DEX DECR ?
constexpr s64 PAID_72 = 0x107000040A000001L; // psp_translator.self; /dev_flash/pspemu/psp_translator.self; CEX DEX DECR ?
constexpr s64 PAID_73 = 0x107000040B000001L; // emulator_api.sprx and other .sprx; /dev_flash/pspemu/release/; CEX DEX DECR ?
constexpr s64 PAID_74 = 0x107000040C000001L; // emulator_drm.sprx; /dev_flash/pspemu/release/emulator_drm.sprx; CEX DEX DECR ?
constexpr s64 PAID_75 = 0x107000040C000001L; // libchnnlsv.sprx; /dev_flash/sys/internal/; CEX DEX DECR ?
constexpr s64 PAID_76 = 0x107000040D000001L; // ?psp related?; ?/dev_flash/pspemu/release/?; CEX DEX DECR ?
constexpr s64 PAID_77 = 0x1070000500000001L; // cellftp; cell_root/target/images/; DECR
constexpr s64 PAID_78 = 0x1070000501000001L; // hdd_copy.self; CoreOS (since FW 3.10)
constexpr s64 PAID_79 = 0x10700005FC000001L; // sys_audio; /dev_flash/sys/internal; CEX
constexpr s64 PAID_80 = 0x10700005FD000001L; // sys_init_osd; /dev_flash/sys/internal; CEX
constexpr s64 PAID_81 = 0x10700005FF000001L; // vsh.self; /dev_flash/vsh/; CEX
constexpr s64 PAID_82 = 0x1070001002000001L; // PvrRecSvr.sprx; BCJB95006\USRDIR\v320; CEX
constexpr s64 PAID_83 = 0x1070200056000001L; // cachemgr.self; WebMAF apps/USRDIR
constexpr s64 PAID_84 = 0x1070200057000001L; // EBOOT.BIN.self + .sprx files; WebMAF apps/USRDIR/prx/ps3; Demen_prx.ppu.sprx + WebMAF sprx files
constexpr s64 PAID_85 = 0x1FF0000001000001L; // lv0; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_86 = 0x1FF0000002000001L; // lv1.self; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_87 = 0x1FF0000008000001L; // lv1ldr; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_88 = 0x1FF0000009000001L; // lv2ldr; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_89 = 0x1FF000000A000001L; // isoldr; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_90 = 0x1FF000000B000001L; // rvkldr; CoreOS; same for CEX DEX DECR
constexpr s64 PAID_91 = 0x1FF000000C000001L; // appldr; CoreOS; same for CEX DEX DECR
constexpr s64 LAID_1 = 0x1070000001000001L; // (= HV processes / SCE_CELLOS_PME); flash and vflash
constexpr s64 LAID_2 = 0x1070000002000001L; // (= GameOS / PS3_LPAR); flash and vflash
constexpr s64 LAID_3 = 0x1020000003000001L; // (= PS2_LPAR / PS2_GX_LPAR / PS2_SW_LPAR / PS2_NE_LPAR); (used in ps3vflashc region inside vflash in NOR consoles, and ps3db region)... dev_flash and dev_hdd0 regions
constexpr s64 LAID_4 = 0x1080000004000001L; // (= LINUX_LPAR); (used in ps3vflashf region inside vflash in NOR consoles)... otheros bootloader region
class KeyVault
{
std::vector<SELF_KEY> sk_LV0_arr{};
std::vector<SELF_KEY> sk_LV1_arr{};
std::vector<SELF_KEY> sk_LV2_arr{};
std::vector<SELF_KEY> sk_APP_arr{};
std::vector<SELF_KEY> sk_ISO_arr{};
std::vector<SELF_KEY> sk_LDR_arr{};
std::vector<SELF_KEY> sk_UNK7_arr{};
std::vector<SELF_KEY> sk_NPDRM_arr{};
u8 klicensee_key[16]{};
public:
KeyVault();
SELF_KEY FindSelfKey(u32 type, u16 revision, u64 version);
void SetKlicenseeKey(const u8* key);
const u8* GetKlicenseeKey() const;
private:
void LoadSelfLV0Keys();
void LoadSelfLDRKeys();
void LoadSelfLV1Keys();
void LoadSelfLV2Keys();
void LoadSelfISOKeys();
void LoadSelfAPPKeys();
void LoadSelfUNK7Keys();
void LoadSelfNPDRMKeys();
SELF_KEY GetSelfLV0Key() const;
SELF_KEY GetSelfLDRKey() const;
SELF_KEY GetSelfLV1Key(u64 version) const;
SELF_KEY GetSelfLV2Key(u64 version) const;
SELF_KEY GetSelfISOKey(u16 revision, u64 version) const;
SELF_KEY GetSelfAPPKey(u16 revision) const;
SELF_KEY GetSelfUNK7Key(u64 version) const;
SELF_KEY GetSelfNPDRMKey(u16 revision) const;
};
// RAP to RIF function.
void rap_to_rif(const unsigned char* rap, unsigned char* rif);

287
rpcs3/Crypto/lz.cpp Normal file
View file

@ -0,0 +1,287 @@
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
// Licensed under the terms of the GNU GPL, version 2.0 or later versions.
// http://www.gnu.org/licenses/gpl-2.0.txt
#include <string.h>
#include <vector>
#include "lz.h"
void decode_range(unsigned int* range, unsigned int* code, unsigned char** src)
{
if (!((*range) >> 24))
{
(*range) <<= 8;
*code = ((*code) << 8) + (*src)++[5];
}
}
int decode_bit(unsigned int* range, unsigned int* code, int* index, unsigned char** src, unsigned char* c)
{
decode_range(range, code, src);
unsigned int val = ((*range) >> 8) * (*c);
*c -= ((*c) >> 3);
if (index)
(*index) <<= 1;
if (*code < val)
{
*range = val;
*c += 31;
if (index)
(*index)++;
return 1;
}
else
{
*code -= val;
*range -= val;
return 0;
}
}
int decode_number(unsigned char* ptr, int index, int* bit_flag, unsigned int* range, unsigned int* code, unsigned char** src)
{
int i = 1;
if (index >= 3)
{
decode_bit(range, code, &i, src, ptr + 0x18);
if (index >= 4)
{
decode_bit(range, code, &i, src, ptr + 0x18);
if (index >= 5)
{
decode_range(range, code, src);
for (; index >= 5; index--)
{
i <<= 1;
(*range) >>= 1;
if (*code < *range)
i++;
else
(*code) -= *range;
}
}
}
}
*bit_flag = decode_bit(range, code, &i, src, ptr);
if (index >= 1)
{
decode_bit(range, code, &i, src, ptr + 0x8);
if (index >= 2)
{
decode_bit(range, code, &i, src, ptr + 0x10);
}
}
return i;
}
int decode_word(unsigned char* ptr, int index, int* bit_flag, unsigned int* range, unsigned int* code, unsigned char** src)
{
int i = 1;
index /= 8;
if (index >= 3)
{
decode_bit(range, code, &i, src, ptr + 4);
if (index >= 4)
{
decode_bit(range, code, &i, src, ptr + 4);
if (index >= 5)
{
decode_range(range, code, src);
for (; index >= 5; index--)
{
i <<= 1;
(*range) >>= 1;
if (*code < *range)
i++;
else
(*code) -= *range;
}
}
}
}
*bit_flag = decode_bit(range, code, &i, src, ptr);
if (index >= 1)
{
decode_bit(range, code, &i, src, ptr + 1);
if (index >= 2)
{
decode_bit(range, code, &i, src, ptr + 2);
}
}
return i;
}
int decompress(unsigned char* out, unsigned char* in, unsigned int size)
{
int result;
int offset = 0;
int bit_flag = 0;
int data_length = 0;
int data_offset = 0;
unsigned char *tmp_sect1, *tmp_sect2, *tmp_sect3;
const unsigned char *buf_start, *buf_end;
unsigned char prev = 0;
unsigned char* start = out;
const unsigned char* end = (out + size);
unsigned char head = in[0];
unsigned int range = 0xFFFFFFFF;
unsigned int code = (in[1] << 24) | (in[2] << 16) | (in[3] << 8) | in[4];
if (head > 0x80) // Check if we have a valid starting byte.
{
// The dictionary header is invalid, the data is not compressed.
result = -1;
if (code <= size)
{
memcpy(out, in + 5, code);
result = static_cast<int>(start - out);
}
}
else
{
// Set up a temporary buffer (sliding window).
std::vector<unsigned char> tmp_vec(0xCC8);
unsigned char* tmp = tmp_vec.data();
memset(tmp, 0x80, 0xCA8);
while (true)
{
// Start reading at 0xB68.
tmp_sect1 = tmp + offset + 0xB68;
if (!decode_bit(&range, &code, 0, &in, tmp_sect1)) // Raw char.
{
// Adjust offset and check for stream end.
if (offset > 0)
offset--;
if (start == end)
return static_cast<int>(start - out);
// Locate first section.
int sect = ((((((static_cast<int>(start - out)) & 7) << 8) + prev) >> head) & 7) * 0xFF - 1;
tmp_sect1 = tmp + sect;
int index = 1;
// Read, decode and write back.
do
{
decode_bit(&range, &code, &index, &in, tmp_sect1 + index);
} while ((index >> 8) == 0);
// Save index.
*start++ = index;
}
else // Compressed char stream.
{
int index = -1;
// Identify the data length bit field.
do
{
tmp_sect1 += 8;
bit_flag = decode_bit(&range, &code, 0, &in, tmp_sect1);
index += bit_flag;
} while ((bit_flag != 0) && (index < 6));
// Default block size is 0x160.
int b_size = 0x160;
tmp_sect2 = tmp + index + 0x7F1;
// If the data length was found, parse it as a number.
if ((index >= 0) || (bit_flag != 0))
{
// Locate next section.
int sect = (index << 5) | ((((static_cast<int>(start - out)) << index) & 3) << 3) | (offset & 7);
tmp_sect1 = tmp + 0xBA8 + sect;
// Decode the data length (8 bit fields).
data_length = decode_number(tmp_sect1, index, &bit_flag, &range, &code, &in);
if (data_length == 0xFF)
return static_cast<int>(start - out); // End of stream.
}
else
{
// Assume one byte of advance.
data_length = 1;
}
// If we got valid parameters, seek to find data offset.
if ((data_length <= 2))
{
tmp_sect2 += 0xF8;
b_size = 0x40; // Block size is now 0x40.
}
int diff = 0;
int shift = 1;
// Identify the data offset bit field.
do
{
diff = (shift << 4) - b_size;
bit_flag = decode_bit(&range, &code, &shift, &in, tmp_sect2 + (shift << 3));
} while (diff < 0);
// If the data offset was found, parse it as a number.
if ((diff > 0) || (bit_flag != 0))
{
// Adjust diff if needed.
if (bit_flag == 0)
diff -= 8;
// Locate section.
tmp_sect3 = tmp + 0x928 + diff;
// Decode the data offset (1 bit fields).
data_offset = decode_word(tmp_sect3, diff, &bit_flag, &range, &code, &in);
}
else
{
// Assume one byte of advance.
data_offset = 1;
}
// Set buffer start/end.
buf_start = start - data_offset;
buf_end = start + data_length + 1;
// Underflow.
if (buf_start < out)
{
return -1;
}
// Overflow.
if (buf_end > end)
{
return -1;
}
// Update offset.
offset = (((static_cast<int>(buf_end - out)) + 1) & 1) + 6;
// Copy data.
do
{
*start++ = *buf_start++;
} while (start < buf_end);
}
prev = *(start - 1);
}
result = static_cast<int>(start - out);
}
return result;
}

13
rpcs3/Crypto/lz.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
// Licensed under the terms of the GNU GPL, version 2.0 or later versions.
// http://www.gnu.org/licenses/gpl-2.0.txt
// Reverse-engineered custom LempelZivMarkov based compression.
void decode_range(unsigned int* range, unsigned int* code, unsigned char** src);
int decode_bit(unsigned int* range, unsigned int* code, int* index, unsigned char** src, unsigned char* c);
int decode_number(unsigned char* ptr, int index, int* bit_flag, unsigned int* range, unsigned int* code, unsigned char** src);
int decode_word(unsigned char* ptr, int index, int* bit_flag, unsigned int* range, unsigned int* code, unsigned char** src);
int decompress(unsigned char* out, unsigned char* in, unsigned int size);

472
rpcs3/Crypto/md5.cpp Normal file
View file

@ -0,0 +1,472 @@
/*
* RFC 1321 compliant MD5 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: GPL-2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The MD5 algorithm was designed by Ron Rivest in 1991.
*
* http://www.ietf.org/rfc/rfc1321.txt
*/
#include "md5.h"
#include "utils.h"
#include <string.h>
#if !defined(MBEDTLS_MD5_ALT)
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef GET_UINT32_LE
#define GET_UINT32_LE(n, b, i) \
{ \
(n) = (static_cast<uint32_t>((b)[(i)])) | (static_cast<uint32_t>((b)[(i) + 1]) << 8) | (static_cast<uint32_t>((b)[(i) + 2]) << 16) | (static_cast<uint32_t>((b)[(i) + 3]) << 24); \
}
#endif
#ifndef PUT_UINT32_LE
#define PUT_UINT32_LE(n, b, i) \
{ \
(b)[(i)] = static_cast<unsigned char>(((n)) & 0xFF); \
(b)[(i) + 1] = static_cast<unsigned char>(((n) >> 8) & 0xFF); \
(b)[(i) + 2] = static_cast<unsigned char>(((n) >> 16) & 0xFF); \
(b)[(i) + 3] = static_cast<unsigned char>(((n) >> 24) & 0xFF); \
}
#endif
void mbedtls_md5_init(mbedtls_md5_context* ctx)
{
memset(ctx, 0, sizeof(mbedtls_md5_context));
}
void mbedtls_md5_free(mbedtls_md5_context* ctx)
{
if (ctx == NULL)
return;
mbedtls_zeroize(ctx, sizeof(mbedtls_md5_context));
}
void mbedtls_md5_clone(mbedtls_md5_context* dst,
const mbedtls_md5_context* src)
{
*dst = *src;
}
/*
* MD5 context setup
*/
int mbedtls_md5_starts_ret(mbedtls_md5_context* ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_starts(mbedtls_md5_context* ctx)
{
mbedtls_md5_starts_ret(ctx);
}
#endif
#if !defined(MBEDTLS_MD5_PROCESS_ALT)
int mbedtls_internal_md5_process(mbedtls_md5_context* ctx,
const unsigned char data[64])
{
uint32_t X[16], A, B, C, D;
GET_UINT32_LE(X[0], data, 0);
GET_UINT32_LE(X[1], data, 4);
GET_UINT32_LE(X[2], data, 8);
GET_UINT32_LE(X[3], data, 12);
GET_UINT32_LE(X[4], data, 16);
GET_UINT32_LE(X[5], data, 20);
GET_UINT32_LE(X[6], data, 24);
GET_UINT32_LE(X[7], data, 28);
GET_UINT32_LE(X[8], data, 32);
GET_UINT32_LE(X[9], data, 36);
GET_UINT32_LE(X[10], data, 40);
GET_UINT32_LE(X[11], data, 44);
GET_UINT32_LE(X[12], data, 48);
GET_UINT32_LE(X[13], data, 52);
GET_UINT32_LE(X[14], data, 56);
GET_UINT32_LE(X[15], data, 60);
#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a, b, c, d, k, s, t) \
{ \
a += F(b, c, d) + X[k] + t; \
a = S(a, s) + b; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x, y, z) (z ^ (x & (y ^ z)))
P(A, B, C, D, 0, 7, 0xD76AA478);
P(D, A, B, C, 1, 12, 0xE8C7B756);
P(C, D, A, B, 2, 17, 0x242070DB);
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
P(A, B, C, D, 4, 7, 0xF57C0FAF);
P(D, A, B, C, 5, 12, 0x4787C62A);
P(C, D, A, B, 6, 17, 0xA8304613);
P(B, C, D, A, 7, 22, 0xFD469501);
P(A, B, C, D, 8, 7, 0x698098D8);
P(D, A, B, C, 9, 12, 0x8B44F7AF);
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
P(B, C, D, A, 11, 22, 0x895CD7BE);
P(A, B, C, D, 12, 7, 0x6B901122);
P(D, A, B, C, 13, 12, 0xFD987193);
P(C, D, A, B, 14, 17, 0xA679438E);
P(B, C, D, A, 15, 22, 0x49B40821);
#undef F
#define F(x, y, z) (y ^ (z & (x ^ y)))
P(A, B, C, D, 1, 5, 0xF61E2562);
P(D, A, B, C, 6, 9, 0xC040B340);
P(C, D, A, B, 11, 14, 0x265E5A51);
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
P(A, B, C, D, 5, 5, 0xD62F105D);
P(D, A, B, C, 10, 9, 0x02441453);
P(C, D, A, B, 15, 14, 0xD8A1E681);
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
P(A, B, C, D, 9, 5, 0x21E1CDE6);
P(D, A, B, C, 14, 9, 0xC33707D6);
P(C, D, A, B, 3, 14, 0xF4D50D87);
P(B, C, D, A, 8, 20, 0x455A14ED);
P(A, B, C, D, 13, 5, 0xA9E3E905);
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
P(C, D, A, B, 7, 14, 0x676F02D9);
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
#undef F
#define F(x, y, z) (x ^ y ^ z)
P(A, B, C, D, 5, 4, 0xFFFA3942);
P(D, A, B, C, 8, 11, 0x8771F681);
P(C, D, A, B, 11, 16, 0x6D9D6122);
P(B, C, D, A, 14, 23, 0xFDE5380C);
P(A, B, C, D, 1, 4, 0xA4BEEA44);
P(D, A, B, C, 4, 11, 0x4BDECFA9);
P(C, D, A, B, 7, 16, 0xF6BB4B60);
P(B, C, D, A, 10, 23, 0xBEBFBC70);
P(A, B, C, D, 13, 4, 0x289B7EC6);
P(D, A, B, C, 0, 11, 0xEAA127FA);
P(C, D, A, B, 3, 16, 0xD4EF3085);
P(B, C, D, A, 6, 23, 0x04881D05);
P(A, B, C, D, 9, 4, 0xD9D4D039);
P(D, A, B, C, 12, 11, 0xE6DB99E5);
P(C, D, A, B, 15, 16, 0x1FA27CF8);
P(B, C, D, A, 2, 23, 0xC4AC5665);
#undef F
#define F(x, y, z) (y ^ (x | ~z))
P(A, B, C, D, 0, 6, 0xF4292244);
P(D, A, B, C, 7, 10, 0x432AFF97);
P(C, D, A, B, 14, 15, 0xAB9423A7);
P(B, C, D, A, 5, 21, 0xFC93A039);
P(A, B, C, D, 12, 6, 0x655B59C3);
P(D, A, B, C, 3, 10, 0x8F0CCC92);
P(C, D, A, B, 10, 15, 0xFFEFF47D);
P(B, C, D, A, 1, 21, 0x85845DD1);
P(A, B, C, D, 8, 6, 0x6FA87E4F);
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
P(C, D, A, B, 6, 15, 0xA3014314);
P(B, C, D, A, 13, 21, 0x4E0811A1);
P(A, B, C, D, 4, 6, 0xF7537E82);
P(D, A, B, C, 11, 10, 0xBD3AF235);
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
P(B, C, D, A, 9, 21, 0xEB86D391);
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_process(mbedtls_md5_context* ctx,
const unsigned char data[64])
{
mbedtls_internal_md5_process(ctx, data);
}
#endif
#endif /* !MBEDTLS_MD5_PROCESS_ALT */
/*
* MD5 process buffer
*/
int mbedtls_md5_update_ret(mbedtls_md5_context* ctx,
const unsigned char* input,
size_t ilen)
{
int ret;
size_t fill;
uint32_t left;
if (ilen == 0)
return (0);
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += static_cast<uint32_t>(ilen);
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < static_cast<uint32_t>(ilen))
ctx->total[1]++;
if (left && ilen >= fill)
{
memcpy(ctx->buffer + left, input, fill);
if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0)
return (ret);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64)
{
if ((ret = mbedtls_internal_md5_process(ctx, input)) != 0)
return (ret);
input += 64;
ilen -= 64;
}
if (ilen > 0)
{
memcpy(ctx->buffer + left, input, ilen);
}
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_update(mbedtls_md5_context* ctx,
const unsigned char* input,
size_t ilen)
{
mbedtls_md5_update_ret(ctx, input, ilen);
}
#endif
/*
* MD5 final digest
*/
int mbedtls_md5_finish_ret(mbedtls_md5_context* ctx,
unsigned char output[16])
{
int ret;
uint32_t used;
uint32_t high, low;
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
*/
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if (used <= 56)
{
/* Enough room for padding + length in current block */
memset(ctx->buffer + used, 0, 56 - used);
}
else
{
/* We'll need an extra block */
memset(ctx->buffer + used, 0, 64 - used);
if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0)
return (ret);
memset(ctx->buffer, 0, 56);
}
/*
* Add message length
*/
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
PUT_UINT32_LE(low, ctx->buffer, 56);
PUT_UINT32_LE(high, ctx->buffer, 60);
if ((ret = mbedtls_internal_md5_process(ctx, ctx->buffer)) != 0)
return (ret);
/*
* Output final state
*/
PUT_UINT32_LE(ctx->state[0], output, 0);
PUT_UINT32_LE(ctx->state[1], output, 4);
PUT_UINT32_LE(ctx->state[2], output, 8);
PUT_UINT32_LE(ctx->state[3], output, 12);
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5_finish(mbedtls_md5_context* ctx,
unsigned char output[16])
{
mbedtls_md5_finish_ret(ctx, output);
}
#endif
#endif /* !MBEDTLS_MD5_ALT */
/*
* output = MD5( input buffer )
*/
int mbedtls_md5_ret(const unsigned char* input,
size_t ilen,
unsigned char output[16])
{
int ret;
mbedtls_md5_context ctx;
mbedtls_md5_init(&ctx);
if ((ret = mbedtls_md5_starts_ret(&ctx)) != 0)
goto exit;
if ((ret = mbedtls_md5_update_ret(&ctx, input, ilen)) != 0)
goto exit;
if ((ret = mbedtls_md5_finish_ret(&ctx, output)) != 0)
goto exit;
exit:
mbedtls_md5_free(&ctx);
return (ret);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_md5(const unsigned char* input,
size_t ilen,
unsigned char output[16])
{
mbedtls_md5_ret(input, ilen, output);
}
#endif
#if defined(MBEDTLS_SELF_TEST)
/*
* RFC 1321 test vectors
*/
static const unsigned char md5_test_buf[7][81] =
{
{""},
{"a"},
{"abc"},
{"message digest"},
{"abcdefghijklmnopqrstuvwxyz"},
{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
{"12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890"}};
static const size_t md5_test_buflen[7] =
{
0, 1, 3, 14, 26, 62, 80};
static const unsigned char md5_test_sum[7][16] =
{
{0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E},
{0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8,
0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61},
{0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0,
0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72},
{0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D,
0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0},
{0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00,
0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B},
{0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5,
0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F},
{0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55,
0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A}};
/*
* Checkup routine
*/
int mbedtls_md5_self_test(int verbose)
{
int i, ret = 0;
unsigned char md5sum[16];
for (i = 0; i < 7; i++)
{
if (verbose != 0)
mbedtls_printf(" MD5 test #%d: ", i + 1);
ret = mbedtls_md5_ret(md5_test_buf[i], md5_test_buflen[i], md5sum);
if (ret != 0)
goto fail;
if (memcmp(md5sum, md5_test_sum[i], 16) != 0)
{
ret = 1;
goto fail;
}
if (verbose != 0)
mbedtls_printf("passed\n");
}
if (verbose != 0)
mbedtls_printf("\n");
return (0);
fail:
if (verbose != 0)
mbedtls_printf("failed\n");
return (ret);
}
#endif /* MBEDTLS_SELF_TEST */

307
rpcs3/Crypto/md5.h Normal file
View file

@ -0,0 +1,307 @@
/**
* \file md5.h
*
* \brief MD5 message digest algorithm (hash function)
*
* \warning MD5 is considered a weak message digest and its use constitutes a
* security risk. We recommend considering stronger message
* digests instead.
*/
/*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: GPL-2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_MD5_H
#define MBEDTLS_MD5_H
#include <stddef.h>
#include <stdint.h>
/* MBEDTLS_ERR_MD5_HW_ACCEL_FAILED is deprecated and should not be used. */
#define MBEDTLS_ERR_MD5_HW_ACCEL_FAILED -0x002F /**< MD5 hardware accelerator failed */
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(MBEDTLS_MD5_ALT)
// Regular implementation
//
/**
* \brief MD5 context structure
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
typedef struct mbedtls_md5_context
{
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[4]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
} mbedtls_md5_context;
#else /* MBEDTLS_MD5_ALT */
#include "md5_alt.h"
#endif /* MBEDTLS_MD5_ALT */
/**
* \brief Initialize MD5 context
*
* \param ctx MD5 context to be initialized
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void mbedtls_md5_init(mbedtls_md5_context* ctx);
/**
* \brief Clear MD5 context
*
* \param ctx MD5 context to be cleared
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void mbedtls_md5_free(mbedtls_md5_context* ctx);
/**
* \brief Clone (the state of) an MD5 context
*
* \param dst The destination context
* \param src The context to be cloned
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
void mbedtls_md5_clone(mbedtls_md5_context* dst,
const mbedtls_md5_context* src);
/**
* \brief MD5 context setup
*
* \param ctx context to be initialized
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_md5_starts_ret(mbedtls_md5_context* ctx);
/**
* \brief MD5 process buffer
*
* \param ctx MD5 context
* \param input buffer holding the data
* \param ilen length of the input data
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_md5_update_ret(mbedtls_md5_context* ctx,
const unsigned char* input,
size_t ilen);
/**
* \brief MD5 final digest
*
* \param ctx MD5 context
* \param output MD5 checksum result
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_md5_finish_ret(mbedtls_md5_context* ctx,
unsigned char output[16]);
/**
* \brief MD5 process data block (internal use only)
*
* \param ctx MD5 context
* \param data buffer holding one block of data
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_internal_md5_process(mbedtls_md5_context* ctx,
const unsigned char data[64]);
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief MD5 context setup
*
* \deprecated Superseded by mbedtls_md5_starts_ret() in 2.7.0
*
* \param ctx context to be initialized
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
MBEDTLS_DEPRECATED void mbedtls_md5_starts(mbedtls_md5_context* ctx);
/**
* \brief MD5 process buffer
*
* \deprecated Superseded by mbedtls_md5_update_ret() in 2.7.0
*
* \param ctx MD5 context
* \param input buffer holding the data
* \param ilen length of the input data
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
MBEDTLS_DEPRECATED void mbedtls_md5_update(mbedtls_md5_context* ctx,
const unsigned char* input,
size_t ilen);
/**
* \brief MD5 final digest
*
* \deprecated Superseded by mbedtls_md5_finish_ret() in 2.7.0
*
* \param ctx MD5 context
* \param output MD5 checksum result
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
MBEDTLS_DEPRECATED void mbedtls_md5_finish(mbedtls_md5_context* ctx,
unsigned char output[16]);
/**
* \brief MD5 process data block (internal use only)
*
* \deprecated Superseded by mbedtls_internal_md5_process() in 2.7.0
*
* \param ctx MD5 context
* \param data buffer holding one block of data
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
MBEDTLS_DEPRECATED void mbedtls_md5_process(mbedtls_md5_context* ctx,
const unsigned char data[64]);
#undef MBEDTLS_DEPRECATED
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
/**
* \brief Output = MD5( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output MD5 checksum result
*
* \return 0 if successful
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_md5_ret(const unsigned char* input,
size_t ilen,
unsigned char output[16]);
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief Output = MD5( input buffer )
*
* \deprecated Superseded by mbedtls_md5_ret() in 2.7.0
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output MD5 checksum result
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
MBEDTLS_DEPRECATED void mbedtls_md5(const unsigned char* input,
size_t ilen,
unsigned char output[16]);
#undef MBEDTLS_DEPRECATED
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
#if defined(MBEDTLS_SELF_TEST)
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*
* \warning MD5 is considered a weak message digest and its use
* constitutes a security risk. We recommend considering
* stronger message digests instead.
*
*/
int mbedtls_md5_self_test(int verbose);
#endif /* MBEDTLS_SELF_TEST */
#ifdef __cplusplus
}
#endif
#endif /* mbedtls_md5.h */

392
rpcs3/Crypto/sha1.cpp Normal file
View file

@ -0,0 +1,392 @@
/*
* FIPS-180-1 compliant SHA-1 implementation
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* The SHA-1 standard was published by NIST in 1993.
*
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
*/
#include "sha1.h"
#include "utils.h"
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n, b, i) \
{ \
(n) = (static_cast<uint32_t>((b)[(i)]) << 24) | (static_cast<uint32_t>((b)[(i) + 1]) << 16) | (static_cast<uint32_t>((b)[(i) + 2]) << 8) | (static_cast<uint32_t>((b)[(i) + 3])); \
}
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i)] = static_cast<unsigned char>((n) >> 24); \
(b)[(i) + 1] = static_cast<unsigned char>((n) >> 16); \
(b)[(i) + 2] = static_cast<unsigned char>((n) >> 8); \
(b)[(i) + 3] = static_cast<unsigned char>((n)); \
}
#endif
/*
* SHA-1 context setup
*/
void sha1_starts(sha1_context* ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
void sha1_process(sha1_context* ctx, const unsigned char data[64])
{
uint32_t temp, W[16], A, B, C, D, E;
GET_UINT32_BE(W[0], data, 0);
GET_UINT32_BE(W[1], data, 4);
GET_UINT32_BE(W[2], data, 8);
GET_UINT32_BE(W[3], data, 12);
GET_UINT32_BE(W[4], data, 16);
GET_UINT32_BE(W[5], data, 20);
GET_UINT32_BE(W[6], data, 24);
GET_UINT32_BE(W[7], data, 28);
GET_UINT32_BE(W[8], data, 32);
GET_UINT32_BE(W[9], data, 36);
GET_UINT32_BE(W[10], data, 40);
GET_UINT32_BE(W[11], data, 44);
GET_UINT32_BE(W[12], data, 48);
GET_UINT32_BE(W[13], data, 52);
GET_UINT32_BE(W[14], data, 56);
GET_UINT32_BE(W[15], data, 60);
#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
W[(t - 14) & 0x0F] ^ W[t & 0x0F], \
(W[t & 0x0F] = S(temp, 1)))
#define P(a, b, c, d, e, x) \
{ \
e += S(a, 5) + F(b, c, d) + K + x; \
b = S(b, 30); \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
#define F(x, y, z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
P(A, B, C, D, E, W[0]);
P(E, A, B, C, D, W[1]);
P(D, E, A, B, C, W[2]);
P(C, D, E, A, B, W[3]);
P(B, C, D, E, A, W[4]);
P(A, B, C, D, E, W[5]);
P(E, A, B, C, D, W[6]);
P(D, E, A, B, C, W[7]);
P(C, D, E, A, B, W[8]);
P(B, C, D, E, A, W[9]);
P(A, B, C, D, E, W[10]);
P(E, A, B, C, D, W[11]);
P(D, E, A, B, C, W[12]);
P(C, D, E, A, B, W[13]);
P(B, C, D, E, A, W[14]);
P(A, B, C, D, E, W[15]);
P(E, A, B, C, D, R(16));
P(D, E, A, B, C, R(17));
P(C, D, E, A, B, R(18));
P(B, C, D, E, A, R(19));
#undef K
#undef F
#define F(x, y, z) (x ^ y ^ z)
#define K 0x6ED9EBA1
P(A, B, C, D, E, R(20));
P(E, A, B, C, D, R(21));
P(D, E, A, B, C, R(22));
P(C, D, E, A, B, R(23));
P(B, C, D, E, A, R(24));
P(A, B, C, D, E, R(25));
P(E, A, B, C, D, R(26));
P(D, E, A, B, C, R(27));
P(C, D, E, A, B, R(28));
P(B, C, D, E, A, R(29));
P(A, B, C, D, E, R(30));
P(E, A, B, C, D, R(31));
P(D, E, A, B, C, R(32));
P(C, D, E, A, B, R(33));
P(B, C, D, E, A, R(34));
P(A, B, C, D, E, R(35));
P(E, A, B, C, D, R(36));
P(D, E, A, B, C, R(37));
P(C, D, E, A, B, R(38));
P(B, C, D, E, A, R(39));
#undef K
#undef F
#define F(x, y, z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
P(A, B, C, D, E, R(40));
P(E, A, B, C, D, R(41));
P(D, E, A, B, C, R(42));
P(C, D, E, A, B, R(43));
P(B, C, D, E, A, R(44));
P(A, B, C, D, E, R(45));
P(E, A, B, C, D, R(46));
P(D, E, A, B, C, R(47));
P(C, D, E, A, B, R(48));
P(B, C, D, E, A, R(49));
P(A, B, C, D, E, R(50));
P(E, A, B, C, D, R(51));
P(D, E, A, B, C, R(52));
P(C, D, E, A, B, R(53));
P(B, C, D, E, A, R(54));
P(A, B, C, D, E, R(55));
P(E, A, B, C, D, R(56));
P(D, E, A, B, C, R(57));
P(C, D, E, A, B, R(58));
P(B, C, D, E, A, R(59));
#undef K
#undef F
#define F(x, y, z) (x ^ y ^ z)
#define K 0xCA62C1D6
P(A, B, C, D, E, R(60));
P(E, A, B, C, D, R(61));
P(D, E, A, B, C, R(62));
P(C, D, E, A, B, R(63));
P(B, C, D, E, A, R(64));
P(A, B, C, D, E, R(65));
P(E, A, B, C, D, R(66));
P(D, E, A, B, C, R(67));
P(C, D, E, A, B, R(68));
P(B, C, D, E, A, R(69));
P(A, B, C, D, E, R(70));
P(E, A, B, C, D, R(71));
P(D, E, A, B, C, R(72));
P(C, D, E, A, B, R(73));
P(B, C, D, E, A, R(74));
P(A, B, C, D, E, R(75));
P(E, A, B, C, D, R(76));
P(D, E, A, B, C, R(77));
P(C, D, E, A, B, R(78));
P(B, C, D, E, A, R(79));
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}
/*
* SHA-1 process buffer
*/
void sha1_update(sha1_context* ctx, const unsigned char* input, size_t ilen)
{
size_t fill;
uint32_t left;
// TODO:: Syphurith: Orz. It is said that size_t is an unsigned type..
if (ilen <= 0)
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += static_cast<uint32_t>(ilen);
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < static_cast<uint32_t>(ilen))
ctx->total[1]++;
if (left && ilen >= fill)
{
memcpy(ctx->buffer + left, input, fill);
sha1_process(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64)
{
sha1_process(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0)
memcpy(ctx->buffer + left, input, ilen);
}
static const unsigned char sha1_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/*
* SHA-1 final digest
*/
void sha1_finish(sha1_context* ctx, unsigned char output[20])
{
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
PUT_UINT32_BE(high, msglen, 0);
PUT_UINT32_BE(low, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
sha1_update(ctx, sha1_padding, padn);
sha1_update(ctx, msglen, 8);
PUT_UINT32_BE(ctx->state[0], output, 0);
PUT_UINT32_BE(ctx->state[1], output, 4);
PUT_UINT32_BE(ctx->state[2], output, 8);
PUT_UINT32_BE(ctx->state[3], output, 12);
PUT_UINT32_BE(ctx->state[4], output, 16);
}
/*
* output = SHA-1( input buffer )
*/
void sha1(const unsigned char* input, size_t ilen, unsigned char output[20])
{
sha1_context ctx;
sha1_starts(&ctx);
sha1_update(&ctx, input, ilen);
sha1_finish(&ctx, output);
mbedtls_zeroize(&ctx, sizeof(sha1_context));
}
/*
* SHA-1 HMAC context setup
*/
void sha1_hmac_starts(sha1_context* ctx, const unsigned char* key, size_t keylen)
{
size_t i;
unsigned char sum[20];
if (keylen > 64)
{
sha1(key, keylen, sum);
keylen = 20;
key = sum;
}
memset(ctx->ipad, 0x36, 64);
memset(ctx->opad, 0x5C, 64);
for (i = 0; i < keylen; i++)
{
ctx->ipad[i] ^= key[i];
ctx->opad[i] ^= key[i];
}
sha1_starts(ctx);
sha1_update(ctx, ctx->ipad, 64);
mbedtls_zeroize(sum, sizeof(sum));
}
/*
* SHA-1 HMAC process buffer
*/
void sha1_hmac_update(sha1_context* ctx, const unsigned char* input, size_t ilen)
{
sha1_update(ctx, input, ilen);
}
/*
* SHA-1 HMAC final digest
*/
void sha1_hmac_finish(sha1_context* ctx, unsigned char output[20])
{
unsigned char tmpbuf[20];
sha1_finish(ctx, tmpbuf);
sha1_starts(ctx);
sha1_update(ctx, ctx->opad, 64);
sha1_update(ctx, tmpbuf, 20);
sha1_finish(ctx, output);
memset(tmpbuf, 0, sizeof(tmpbuf));
}
/*
* SHA1 HMAC context reset
*/
void sha1_hmac_reset(sha1_context* ctx)
{
sha1_starts(ctx);
sha1_update(ctx, ctx->ipad, 64);
}
/*
* output = HMAC-SHA-1( hmac key, input buffer )
*/
void sha1_hmac(const unsigned char* key, size_t keylen,
const unsigned char* input, size_t ilen,
unsigned char output[20])
{
sha1_context ctx;
sha1_hmac_starts(&ctx, key, keylen);
sha1_hmac_update(&ctx, input, ilen);
sha1_hmac_finish(&ctx, output);
memset(&ctx, 0, sizeof(sha1_context));
}

164
rpcs3/Crypto/sha1.h Normal file
View file

@ -0,0 +1,164 @@
#pragma once
/**
* \file sha1.h
*
* \brief SHA-1 cryptographic hash function
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#ifdef _MSC_VER
#include <basetsd.h>
typedef UINT32 uint32_t;
#else
#include <inttypes.h>
#endif
#define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */
// Regular implementation
//
/**
* \brief SHA-1 context structure
*/
typedef struct
{
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[5]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
unsigned char ipad[64]; /*!< HMAC: inner padding */
unsigned char opad[64]; /*!< HMAC: outer padding */
} sha1_context;
#ifdef __cplusplus
extern "C"
{
#endif
/**
* \brief SHA-1 context setup
*
* \param ctx context to be initialized
*/
void sha1_starts(sha1_context* ctx);
/**
* \brief SHA-1 process buffer
*
* \param ctx SHA-1 context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void sha1_update(sha1_context* ctx, const unsigned char* input, size_t ilen);
/**
* \brief SHA-1 final digest
*
* \param ctx SHA-1 context
* \param output SHA-1 checksum result
*/
void sha1_finish(sha1_context* ctx, unsigned char output[20]);
/* Internal use */
void sha1_process(sha1_context* ctx, const unsigned char data[64]);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/**
* \brief Output = SHA-1( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output SHA-1 checksum result
*/
void sha1(const unsigned char* input, size_t ilen, unsigned char output[20]);
/**
* \brief Output = SHA-1( file contents )
*
* \param path input file name
* \param output SHA-1 checksum result
*
* \return 0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR
*/
int sha1_file(const char* path, unsigned char output[20]);
/**
* \brief SHA-1 HMAC context setup
*
* \param ctx HMAC context to be initialized
* \param key HMAC secret key
* \param keylen length of the HMAC key
*/
void sha1_hmac_starts(sha1_context* ctx, const unsigned char* key, size_t keylen);
/**
* \brief SHA-1 HMAC process buffer
*
* \param ctx HMAC context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void sha1_hmac_update(sha1_context* ctx, const unsigned char* input, size_t ilen);
/**
* \brief SHA-1 HMAC final digest
*
* \param ctx HMAC context
* \param output SHA-1 HMAC checksum result
*/
void sha1_hmac_finish(sha1_context* ctx, unsigned char output[20]);
/**
* \brief SHA-1 HMAC context reset
*
* \param ctx HMAC context to be reset
*/
void sha1_hmac_reset(sha1_context* ctx);
/**
* \brief Output = HMAC-SHA-1( hmac key, input buffer )
*
* \param key HMAC secret key
* \param keylen length of the HMAC key
* \param input buffer holding the data
* \param ilen length of the input data
* \param output HMAC-SHA-1 result
*/
void sha1_hmac(const unsigned char* key, size_t keylen,
const unsigned char* input, size_t ilen,
unsigned char output[20]);
#ifdef __cplusplus
}
#endif

495
rpcs3/Crypto/sha256.cpp Normal file
View file

@ -0,0 +1,495 @@
/*
* FIPS-180-2 compliant SHA-256 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: GPL-2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#include "sha256.h"
#include "utils.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_printf printf
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#define SHA256_VALIDATE_RET(cond)
#define SHA256_VALIDATE(cond)
#if !defined(MBEDTLS_SHA256_ALT)
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n, b, i) \
do \
{ \
(n) = (static_cast<uint32_t>((b)[(i)]) << 24) | (static_cast<uint32_t>((b)[(i) + 1]) << 16) | (static_cast<uint32_t>((b)[(i) + 2]) << 8) | (static_cast<uint32_t>((b)[(i) + 3])); \
} while (0)
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n, b, i) \
do \
{ \
(b)[(i)] = static_cast<unsigned char>((n) >> 24); \
(b)[(i) + 1] = static_cast<unsigned char>((n) >> 16); \
(b)[(i) + 2] = static_cast<unsigned char>((n) >> 8); \
(b)[(i) + 3] = static_cast<unsigned char>((n)); \
} while (0)
#endif
void mbedtls_sha256_init(mbedtls_sha256_context* ctx)
{
SHA256_VALIDATE(ctx != NULL);
memset(ctx, 0, sizeof(mbedtls_sha256_context));
}
void mbedtls_sha256_free(mbedtls_sha256_context* ctx)
{
if (ctx == NULL)
return;
mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}
void mbedtls_sha256_clone(mbedtls_sha256_context* dst,
const mbedtls_sha256_context* src)
{
SHA256_VALIDATE(dst != NULL);
SHA256_VALIDATE(src != NULL);
*dst = *src;
}
/*
* SHA-256 context setup
*/
int mbedtls_sha256_starts_ret(mbedtls_sha256_context* ctx, int is224)
{
SHA256_VALIDATE_RET(ctx != NULL);
SHA256_VALIDATE_RET(is224 == 0 || is224 == 1);
ctx->total[0] = 0;
ctx->total[1] = 0;
if (is224 == 0)
{
/* SHA-256 */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
else
{
/* SHA-224 */
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
ctx->is224 = is224;
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_starts(mbedtls_sha256_context* ctx,
int is224)
{
mbedtls_sha256_starts_ret(ctx, is224);
}
#endif
#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
static const uint32_t K[] =
{
0x428A2F98,
0x71374491,
0xB5C0FBCF,
0xE9B5DBA5,
0x3956C25B,
0x59F111F1,
0x923F82A4,
0xAB1C5ED5,
0xD807AA98,
0x12835B01,
0x243185BE,
0x550C7DC3,
0x72BE5D74,
0x80DEB1FE,
0x9BDC06A7,
0xC19BF174,
0xE49B69C1,
0xEFBE4786,
0x0FC19DC6,
0x240CA1CC,
0x2DE92C6F,
0x4A7484AA,
0x5CB0A9DC,
0x76F988DA,
0x983E5152,
0xA831C66D,
0xB00327C8,
0xBF597FC7,
0xC6E00BF3,
0xD5A79147,
0x06CA6351,
0x14292967,
0x27B70A85,
0x2E1B2138,
0x4D2C6DFC,
0x53380D13,
0x650A7354,
0x766A0ABB,
0x81C2C92E,
0x92722C85,
0xA2BFE8A1,
0xA81A664B,
0xC24B8B70,
0xC76C51A3,
0xD192E819,
0xD6990624,
0xF40E3585,
0x106AA070,
0x19A4C116,
0x1E376C08,
0x2748774C,
0x34B0BCB5,
0x391C0CB3,
0x4ED8AA4A,
0x5B9CCA4F,
0x682E6FF3,
0x748F82EE,
0x78A5636F,
0x84C87814,
0x8CC70208,
0x90BEFFFA,
0xA4506CEB,
0xBEF9A3F7,
0xC67178F2,
};
#define SHR(x, n) (((x) & 0xFFFFFFFF) >> (n))
#define ROTR(x, n) (SHR(x, n) | ((x) << (32 - (n))))
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define R(t) \
( \
W[t] = S1(W[(t) - 2]) + W[(t) - 7] + \
S0(W[(t) - 15]) + W[(t) - 16])
#define P(a, b, c, d, e, f, g, h, x, K) \
do \
{ \
temp1 = (h) + S3(e) + F1((e), (f), (g)) + (K) + (x); \
temp2 = S2(a) + F0((a), (b), (c)); \
(d) += temp1; \
(h) = temp1 + temp2; \
} while (0)
int mbedtls_internal_sha256_process(mbedtls_sha256_context* ctx,
const unsigned char data[64])
{
uint32_t temp1, temp2, W[64];
uint32_t A[8];
unsigned int i;
SHA256_VALIDATE_RET(ctx != NULL);
SHA256_VALIDATE_RET((const unsigned char*)data != NULL);
for (i = 0; i < 8; i++)
A[i] = ctx->state[i];
#if defined(MBEDTLS_SHA256_SMALLER)
for (i = 0; i < 64; i++)
{
if (i < 16)
GET_UINT32_BE(W[i], data, 4 * i);
else
R(i);
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]);
temp1 = A[7];
A[7] = A[6];
A[6] = A[5];
A[5] = A[4];
A[4] = A[3];
A[3] = A[2];
A[2] = A[1];
A[1] = A[0];
A[0] = temp1;
}
#else /* MBEDTLS_SHA256_SMALLER */
for (i = 0; i < 16; i++)
GET_UINT32_BE(W[i], data, 4 * i);
for (i = 0; i < 16; i += 8)
{
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i + 0], K[i + 0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i + 1], K[i + 1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i + 2], K[i + 2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i + 3], K[i + 3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i + 4], K[i + 4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i + 5], K[i + 5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i + 6], K[i + 6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i + 7], K[i + 7]);
}
for (i = 16; i < 64; i += 8)
{
P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i + 0), K[i + 0]);
P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i + 1), K[i + 1]);
P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i + 2), K[i + 2]);
P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i + 3), K[i + 3]);
P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i + 4), K[i + 4]);
P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i + 5), K[i + 5]);
P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i + 6), K[i + 6]);
P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i + 7), K[i + 7]);
}
#endif /* MBEDTLS_SHA256_SMALLER */
for (i = 0; i < 8; i++)
ctx->state[i] += A[i];
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_process(mbedtls_sha256_context* ctx,
const unsigned char data[64])
{
mbedtls_internal_sha256_process(ctx, data);
}
#endif
#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
/*
* SHA-256 process buffer
*/
int mbedtls_sha256_update_ret(mbedtls_sha256_context* ctx,
const unsigned char* input,
size_t ilen)
{
int ret;
size_t fill;
uint32_t left;
SHA256_VALIDATE_RET(ctx != NULL);
SHA256_VALIDATE_RET(ilen == 0 || input != NULL);
if (ilen == 0)
return (0);
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += static_cast<uint32_t>(ilen);
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < static_cast<uint32_t>(ilen))
ctx->total[1]++;
if (left && ilen >= fill)
{
memcpy(ctx->buffer + left, input, fill);
if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0)
return (ret);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64)
{
if ((ret = mbedtls_internal_sha256_process(ctx, input)) != 0)
return (ret);
input += 64;
ilen -= 64;
}
if (ilen > 0)
memcpy(ctx->buffer + left, input, ilen);
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_update(mbedtls_sha256_context* ctx,
const unsigned char* input,
size_t ilen)
{
mbedtls_sha256_update_ret(ctx, input, ilen);
}
#endif
/*
* SHA-256 final digest
*/
int mbedtls_sha256_finish_ret(mbedtls_sha256_context* ctx,
unsigned char output[32])
{
int ret;
uint32_t used;
uint32_t high, low;
SHA256_VALIDATE_RET(ctx != NULL);
SHA256_VALIDATE_RET((unsigned char*)output != NULL);
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
*/
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if (used <= 56)
{
/* Enough room for padding + length in current block */
memset(ctx->buffer + used, 0, 56 - used);
}
else
{
/* We'll need an extra block */
memset(ctx->buffer + used, 0, 64 - used);
if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0)
return (ret);
memset(ctx->buffer, 0, 56);
}
/*
* Add message length
*/
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
PUT_UINT32_BE(high, ctx->buffer, 56);
PUT_UINT32_BE(low, ctx->buffer, 60);
if ((ret = mbedtls_internal_sha256_process(ctx, ctx->buffer)) != 0)
return (ret);
/*
* Output final state
*/
PUT_UINT32_BE(ctx->state[0], output, 0);
PUT_UINT32_BE(ctx->state[1], output, 4);
PUT_UINT32_BE(ctx->state[2], output, 8);
PUT_UINT32_BE(ctx->state[3], output, 12);
PUT_UINT32_BE(ctx->state[4], output, 16);
PUT_UINT32_BE(ctx->state[5], output, 20);
PUT_UINT32_BE(ctx->state[6], output, 24);
if (ctx->is224 == 0)
PUT_UINT32_BE(ctx->state[7], output, 28);
return (0);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_finish(mbedtls_sha256_context* ctx,
unsigned char output[32])
{
mbedtls_sha256_finish_ret(ctx, output);
}
#endif
#endif /* !MBEDTLS_SHA256_ALT */
/*
* output = SHA-256( input buffer )
*/
int mbedtls_sha256_ret(const unsigned char* input,
size_t ilen,
unsigned char output[32],
int is224)
{
int ret;
mbedtls_sha256_context ctx;
SHA256_VALIDATE_RET(is224 == 0 || is224 == 1);
SHA256_VALIDATE_RET(ilen == 0 || input != NULL);
SHA256_VALIDATE_RET((unsigned char*)output != NULL);
mbedtls_sha256_init(&ctx);
if ((ret = mbedtls_sha256_starts_ret(&ctx, is224)) != 0)
goto exit;
if ((ret = mbedtls_sha256_update_ret(&ctx, input, ilen)) != 0)
goto exit;
if ((ret = mbedtls_sha256_finish_ret(&ctx, output)) != 0)
goto exit;
exit:
mbedtls_sha256_free(&ctx);
return (ret);
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256(const unsigned char* input,
size_t ilen,
unsigned char output[32],
int is224)
{
mbedtls_sha256_ret(input, ilen, output, is224);
}
#endif

281
rpcs3/Crypto/sha256.h Normal file
View file

@ -0,0 +1,281 @@
/**
* \file sha256.h
*
* \brief This file contains SHA-224 and SHA-256 definitions and functions.
*
* The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic
* hash functions are defined in <em>FIPS 180-4: Secure Hash Standard (SHS)</em>.
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* SPDX-License-Identifier: GPL-2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_SHA256_H
#define MBEDTLS_SHA256_H
#include <stddef.h>
#include <stdint.h>
/* MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED is deprecated and should not be used. */
#define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED -0x0037 /**< SHA-256 hardware accelerator failed */
#define MBEDTLS_ERR_SHA256_BAD_INPUT_DATA -0x0074 /**< SHA-256 input data was malformed. */
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(MBEDTLS_SHA256_ALT)
// Regular implementation
//
/**
* \brief The SHA-256 context structure.
*
* The structure is used both for SHA-256 and for SHA-224
* checksum calculations. The choice between these two is
* made in the call to mbedtls_sha256_starts_ret().
*/
typedef struct mbedtls_sha256_context
{
uint32_t total[2]; /*!< The number of Bytes processed. */
uint32_t state[8]; /*!< The intermediate digest state. */
unsigned char buffer[64]; /*!< The data block being processed. */
int is224; /*!< Determines which function to use:
0: Use SHA-256, or 1: Use SHA-224. */
} mbedtls_sha256_context;
#else /* MBEDTLS_SHA256_ALT */
#include "sha256_alt.h"
#endif /* MBEDTLS_SHA256_ALT */
/**
* \brief This function initializes a SHA-256 context.
*
* \param ctx The SHA-256 context to initialize. This must not be \c NULL.
*/
void mbedtls_sha256_init(mbedtls_sha256_context* ctx);
/**
* \brief This function clears a SHA-256 context.
*
* \param ctx The SHA-256 context to clear. This may be \c NULL, in which
* case this function returns immediately. If it is not \c NULL,
* it must point to an initialized SHA-256 context.
*/
void mbedtls_sha256_free(mbedtls_sha256_context* ctx);
/**
* \brief This function clones the state of a SHA-256 context.
*
* \param dst The destination context. This must be initialized.
* \param src The context to clone. This must be initialized.
*/
void mbedtls_sha256_clone(mbedtls_sha256_context* dst,
const mbedtls_sha256_context* src);
/**
* \brief This function starts a SHA-224 or SHA-256 checksum
* calculation.
*
* \param ctx The context to use. This must be initialized.
* \param is224 This determines which function to use. This must be
* either \c 0 for SHA-256, or \c 1 for SHA-224.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_sha256_starts_ret(mbedtls_sha256_context* ctx, int is224);
/**
* \brief This function feeds an input buffer into an ongoing
* SHA-256 checksum calculation.
*
* \param ctx The SHA-256 context. This must be initialized
* and have a hash operation started.
* \param input The buffer holding the data. This must be a readable
* buffer of length \p ilen Bytes.
* \param ilen The length of the input data in Bytes.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_sha256_update_ret(mbedtls_sha256_context* ctx,
const unsigned char* input,
size_t ilen);
/**
* \brief This function finishes the SHA-256 operation, and writes
* the result to the output buffer.
*
* \param ctx The SHA-256 context. This must be initialized
* and have a hash operation started.
* \param output The SHA-224 or SHA-256 checksum result.
* This must be a writable buffer of length \c 32 Bytes.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_sha256_finish_ret(mbedtls_sha256_context* ctx,
unsigned char output[32]);
/**
* \brief This function processes a single data block within
* the ongoing SHA-256 computation. This function is for
* internal use only.
*
* \param ctx The SHA-256 context. This must be initialized.
* \param data The buffer holding one block of data. This must
* be a readable buffer of length \c 64 Bytes.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_internal_sha256_process(mbedtls_sha256_context* ctx,
const unsigned char data[64]);
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief This function starts a SHA-224 or SHA-256 checksum
* calculation.
*
* \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0.
*
* \param ctx The context to use. This must be initialized.
* \param is224 Determines which function to use. This must be
* either \c 0 for SHA-256, or \c 1 for SHA-224.
*/
MBEDTLS_DEPRECATED void mbedtls_sha256_starts(mbedtls_sha256_context* ctx,
int is224);
/**
* \brief This function feeds an input buffer into an ongoing
* SHA-256 checksum calculation.
*
* \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0.
*
* \param ctx The SHA-256 context to use. This must be
* initialized and have a hash operation started.
* \param input The buffer holding the data. This must be a readable
* buffer of length \p ilen Bytes.
* \param ilen The length of the input data in Bytes.
*/
MBEDTLS_DEPRECATED void mbedtls_sha256_update(mbedtls_sha256_context* ctx,
const unsigned char* input,
size_t ilen);
/**
* \brief This function finishes the SHA-256 operation, and writes
* the result to the output buffer.
*
* \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0.
*
* \param ctx The SHA-256 context. This must be initialized and
* have a hash operation started.
* \param output The SHA-224 or SHA-256 checksum result. This must be
* a writable buffer of length \c 32 Bytes.
*/
MBEDTLS_DEPRECATED void mbedtls_sha256_finish(mbedtls_sha256_context* ctx,
unsigned char output[32]);
/**
* \brief This function processes a single data block within
* the ongoing SHA-256 computation. This function is for
* internal use only.
*
* \deprecated Superseded by mbedtls_internal_sha256_process() in 2.7.0.
*
* \param ctx The SHA-256 context. This must be initialized.
* \param data The buffer holding one block of data. This must be
* a readable buffer of size \c 64 Bytes.
*/
MBEDTLS_DEPRECATED void mbedtls_sha256_process(mbedtls_sha256_context* ctx,
const unsigned char data[64]);
#undef MBEDTLS_DEPRECATED
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
/**
* \brief This function calculates the SHA-224 or SHA-256
* checksum of a buffer.
*
* The function allocates the context, performs the
* calculation, and frees the context.
*
* The SHA-256 result is calculated as
* output = SHA-256(input buffer).
*
* \param input The buffer holding the data. This must be a readable
* buffer of length \p ilen Bytes.
* \param ilen The length of the input data in Bytes.
* \param output The SHA-224 or SHA-256 checksum result. This must
* be a writable buffer of length \c 32 Bytes.
* \param is224 Determines which function to use. This must be
* either \c 0 for SHA-256, or \c 1 for SHA-224.
*/
int mbedtls_sha256_ret(const unsigned char* input,
size_t ilen,
unsigned char output[32],
int is224);
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
#if defined(MBEDTLS_DEPRECATED_WARNING)
#define MBEDTLS_DEPRECATED __attribute__((deprecated))
#else
#define MBEDTLS_DEPRECATED
#endif
/**
* \brief This function calculates the SHA-224 or SHA-256 checksum
* of a buffer.
*
* The function allocates the context, performs the
* calculation, and frees the context.
*
* The SHA-256 result is calculated as
* output = SHA-256(input buffer).
*
* \deprecated Superseded by mbedtls_sha256_ret() in 2.7.0.
*
* \param input The buffer holding the data. This must be a readable
* buffer of length \p ilen Bytes.
* \param ilen The length of the input data in Bytes.
* \param output The SHA-224 or SHA-256 checksum result. This must be
* a writable buffer of length \c 32 Bytes.
* \param is224 Determines which function to use. This must be either
* \c 0 for SHA-256, or \c 1 for SHA-224.
*/
MBEDTLS_DEPRECATED void mbedtls_sha256(const unsigned char* input,
size_t ilen,
unsigned char output[32],
int is224);
#undef MBEDTLS_DEPRECATED
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
#ifdef __cplusplus
}
#endif
#endif /* mbedtls_sha256.h */

926
rpcs3/Crypto/unedat.cpp Normal file
View file

@ -0,0 +1,926 @@
#include "stdafx.h"
#include "key_vault.h"
#include "unedat.h"
#include "sha1.h"
#include "lz.h"
#include "ec.h"
#include "utils.h"
#include "Emu/system_utils.hpp"
#include "util/asm.hpp"
#include <algorithm>
#include <span>
LOG_CHANNEL(edat_log, "EDAT");
void generate_key(int crypto_mode, int version, unsigned char* key_final, unsigned char* iv_final, unsigned char* key, unsigned char* iv)
{
int mode = crypto_mode & 0xF0000000;
uchar temp_iv[16]{};
switch (mode)
{
case 0x10000000:
// Encrypted ERK.
// Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV.
memcpy(temp_iv, EDAT_IV, 0x10);
aescbc128_decrypt(const_cast<u8*>(version ? EDAT_KEY_1 : EDAT_KEY_0), temp_iv, key, key_final, 0x10);
memcpy(iv_final, iv, 0x10);
break;
case 0x20000000:
// Default ERK.
// Use EDAT_KEY and EDAT_IV.
memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10);
memcpy(iv_final, EDAT_IV, 0x10);
break;
case 0x00000000:
// Unencrypted ERK.
// Use the original key and iv.
memcpy(key_final, key, 0x10);
memcpy(iv_final, iv, 0x10);
break;
}
}
void generate_hash(int hash_mode, int version, unsigned char* hash_final, unsigned char* hash)
{
int mode = hash_mode & 0xF0000000;
uchar temp_iv[16]{};
switch (mode)
{
case 0x10000000:
// Encrypted HASH.
// Decrypt the hash with EDAT_KEY + EDAT_IV.
memcpy(temp_iv, EDAT_IV, 0x10);
aescbc128_decrypt(const_cast<u8*>(version ? EDAT_KEY_1 : EDAT_KEY_0), temp_iv, hash, hash_final, 0x10);
break;
case 0x20000000:
// Default HASH.
// Use EDAT_HASH.
memcpy(hash_final, version ? EDAT_HASH_1 : EDAT_HASH_0, 0x10);
break;
case 0x00000000:
// Unencrypted ERK.
// Use the original hash.
memcpy(hash_final, hash, 0x10);
break;
};
}
bool decrypt(int hash_mode, int crypto_mode, int version, unsigned char* in, unsigned char* out, usz length, unsigned char* key, unsigned char* iv, unsigned char* hash, unsigned char* test_hash)
{
// Setup buffers for key, iv and hash.
unsigned char key_final[0x10] = {};
unsigned char iv_final[0x10] = {};
unsigned char hash_final_10[0x10] = {};
unsigned char hash_final_14[0x14] = {};
// Generate crypto key and hash.
generate_key(crypto_mode, version, key_final, iv_final, key, iv);
if ((hash_mode & 0xFF) == 0x01)
generate_hash(hash_mode, version, hash_final_14, hash);
else
generate_hash(hash_mode, version, hash_final_10, hash);
if ((crypto_mode & 0xFF) == 0x01) // No algorithm.
{
memcpy(out, in, length);
}
else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC
{
aescbc128_decrypt(key_final, iv_final, in, out, length);
}
else
{
edat_log.error("Unknown crypto algorithm!");
return false;
}
if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC
{
return hmac_hash_compare(hash_final_14, 0x14, in, length, test_hash, 0x14);
}
else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC
{
return cmac_hash_compare(hash_final_10, 0x10, in, length, test_hash, 0x10);
}
else if ((hash_mode & 0xFF) == 0x04) // 0x10 SHA1-HMAC
{
return hmac_hash_compare(hash_final_10, 0x10, in, length, test_hash, 0x10);
}
else
{
edat_log.error("Unknown hashing algorithm!");
return false;
}
}
// EDAT/SDAT functions.
std::tuple<u64, s32, s32> dec_section(unsigned char* metadata)
{
std::array<u8, 0x10> dec;
dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]);
dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]);
dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]);
dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]);
dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]);
dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]);
dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]);
dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]);
dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]);
dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]);
dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]);
dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]);
dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]);
dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]);
dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]);
dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]);
u64 offset = read_from_ptr<be_t<u64>>(dec, 0);
s32 length = read_from_ptr<be_t<s32>>(dec, 8);
s32 compression_end = read_from_ptr<be_t<s32>>(dec, 12);
return std::make_tuple(offset, length, compression_end);
}
u128 get_block_key(int block, NPD_HEADER* npd)
{
unsigned char empty_key[0x10] = {};
unsigned char* src_key = (npd->version <= 1) ? empty_key : npd->dev_hash;
u128 dest_key{};
std::memcpy(&dest_key, src_key, 0xC);
s32 swappedBlock = std::bit_cast<be_t<s32>>(block);
std::memcpy(reinterpret_cast<uchar*>(&dest_key) + 0xC, &swappedBlock, sizeof(swappedBlock));
return dest_key;
}
// for out data, allocate a buffer the size of 'edat->block_size'
// Also, set 'in file' to the beginning of the encrypted data, which may be offset if inside another file, but normally just reset to beginning of file
// returns number of bytes written, -1 for error
s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER* edat, NPD_HEADER* npd, u8* crypt_key, u32 block_num, u32 total_blocks, u64 size_left, bool is_out_buffer_aligned = false)
{
// Get metadata info and setup buffers.
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
const int metadata_offset = 0x100;
u8 hash[0x10] = {0};
u8 key_result[0x10] = {0};
u8 hash_result[0x14] = {0};
u64 offset = 0;
u64 metadata_sec_offset = 0;
u64 length = 0;
s32 compression_end = 0;
unsigned char empty_iv[0x10] = {};
// Decrypt the metadata.
if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0)
{
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
u8 metadata[0x20]{};
in->read_at(metadata_sec_offset, metadata, 0x20);
// If the data is compressed, decrypt the metadata.
// NOTE: For NPD version 1 the metadata is not encrypted.
if (npd->version <= 1)
{
offset = read_from_ptr<be_t<u64>>(metadata, 0x10);
length = read_from_ptr<be_t<s32>>(metadata, 0x18);
compression_end = read_from_ptr<be_t<s32>>(metadata, 0x1C);
}
else
{
std::tie(offset, length, compression_end) = dec_section(metadata);
}
std::memcpy(hash_result, metadata, 0x10);
}
else if ((edat->flags & EDAT_FLAG_0x20) != 0)
{
// If FLAG 0x20, the metadata precedes each data block.
metadata_sec_offset = metadata_offset + u64{block_num} * (metadata_section_size + edat->block_size);
u8 metadata[0x20]{};
in->read_at(metadata_sec_offset, metadata, 0x20);
std::memcpy(hash_result, metadata, 0x14);
// If FLAG 0x20 is set, apply custom xor.
for (int j = 0; j < 0x10; j++)
hash_result[j] = metadata[j] ^ metadata[j + 0x10];
offset = metadata_sec_offset + 0x20;
length = edat->block_size;
if ((block_num == (total_blocks - 1)) && (edat->file_size % edat->block_size))
length = static_cast<s32>(edat->file_size % edat->block_size);
}
else
{
metadata_sec_offset = metadata_offset + u64{block_num} * metadata_section_size;
in->read_at(metadata_sec_offset, hash_result, 0x10);
offset = metadata_offset + u64{block_num} * edat->block_size + total_blocks * metadata_section_size;
length = edat->block_size;
if ((block_num == (total_blocks - 1)) && (edat->file_size % edat->block_size))
length = static_cast<s32>(edat->file_size % edat->block_size);
}
// Locate the real data.
const usz pad_length = length;
length = utils::align<usz>(pad_length, 0x10);
// Setup buffers for decryption and read the data.
std::vector<u8> enc_data_buf(is_out_buffer_aligned || length == pad_length ? 0 : length);
std::vector<u8> dec_data_buf(length);
// Try to use out buffer for file reads if no padding is needed instead of a new buffer
u8* enc_data = enc_data_buf.empty() ? out : enc_data_buf.data();
// Variable to avoid copies when possible
u8* dec_data = dec_data_buf.data();
std::memset(hash, 0, 0x10);
std::memset(key_result, 0, 0x10);
in->read_at(offset, enc_data, length);
// Generate a key for the current block.
auto b_key = get_block_key(block_num, npd);
// Encrypt the block key with the crypto key.
aesecb128_encrypt(crypt_key, reinterpret_cast<uchar*>(&b_key), key_result);
if ((edat->flags & EDAT_FLAG_0x10) != 0)
{
aesecb128_encrypt(crypt_key, key_result, hash); // If FLAG 0x10 is set, encrypt again to get the final hash.
}
else
{
std::memcpy(hash, key_result, 0x10);
}
// Setup the crypto and hashing mode based on the extra flags.
int crypto_mode = ((edat->flags & EDAT_FLAG_0x02) == 0) ? 0x2 : 0x1;
int hash_mode;
if ((edat->flags & EDAT_FLAG_0x10) == 0)
hash_mode = 0x02;
else if ((edat->flags & EDAT_FLAG_0x20) == 0)
hash_mode = 0x04;
else
hash_mode = 0x01;
if ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) != 0)
{
crypto_mode |= 0x10000000;
hash_mode |= 0x10000000;
}
const bool should_decompress = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0) && compression_end;
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
{
// Reset the flags.
crypto_mode |= 0x01000000;
hash_mode |= 0x01000000;
// Simply copy the data without the header or the footer.
if (should_decompress)
{
std::memcpy(dec_data, enc_data, length);
}
else
{
// Optimize when decompression is not needed by avoiding 2 copies
dec_data = enc_data;
}
}
else
{
// IV is null if NPD version is 1 or 0.
u8* iv = (npd->version <= 1) ? empty_iv : npd->digest;
// Call main crypto routine on this data block.
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result))
{
edat_log.error("Block at offset 0x%llx has invalid hash!", offset);
return -1;
}
}
// Apply additional de-compression if needed and write the decrypted data.
if (should_decompress)
{
const int res = decompress(out, dec_data, edat->block_size);
size_left -= res;
if (size_left == 0)
{
if (res < 0)
{
edat_log.error("Decompression failed!");
return -1;
}
}
return res;
}
if (dec_data != out)
{
std::memcpy(out, dec_data, pad_length);
}
return pad_length;
}
// set file offset to beginning before calling
bool check_data(u8* key, EDAT_HEADER* edat, NPD_HEADER* npd, const fs::file* f, bool verbose)
{
u8 header[0xA0] = {0};
u8 empty_header[0xA0] = {0};
u8 header_hash[0x10] = {0};
u8 metadata_hash[0x10] = {0};
const u64 file_offset = f->pos();
// Check NPD version and flags.
if ((npd->version == 0) || (npd->version == 1))
{
if (edat->flags & 0x7EFFFFFE)
{
edat_log.error("Bad header flags!");
return false;
}
}
else if (npd->version == 2)
{
if (edat->flags & 0x7EFFFFE0)
{
edat_log.error("Bad header flags!");
return false;
}
}
else if ((npd->version == 3) || (npd->version == 4))
{
if (edat->flags & 0x7EFFFFC0)
{
edat_log.error("Bad header flags!");
return false;
}
}
else
{
edat_log.error("Unknown version!");
return false;
}
// Read in the file header.
f->read(header, 0xA0);
// Read in the header and metadata section hashes.
f->seek(file_offset + 0x90);
f->read(metadata_hash, 0x10);
f->read(header_hash, 0x10);
// Setup the hashing mode and the crypto mode used in the file.
const int crypto_mode = 0x1;
int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002;
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
{
hash_mode |= 0x01000000;
if (verbose)
edat_log.warning("DEBUG data detected!");
}
// Setup header key and iv buffers.
unsigned char header_key[0x10] = {0};
unsigned char header_iv[0x10] = {0};
// Test the header hash (located at offset 0xA0).
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), header, empty_header, 0xA0, header_key, header_iv, key, header_hash))
{
if (verbose)
edat_log.warning("Header hash is invalid!");
// If the header hash test fails and the data is not DEBUG, then RAP/RIF/KLIC key is invalid.
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
{
edat_log.error("RAP/RIF/KLIC key is invalid!");
return false;
}
}
// Parse the metadata info.
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0))
{
if (verbose)
edat_log.warning("COMPRESSED data detected!");
}
if (!edat->block_size)
{
return false;
}
const usz block_num = utils::aligned_div<u64>(edat->file_size, edat->block_size);
constexpr usz metadata_offset = 0x100;
const usz metadata_size = utils::mul_saturate<u64>(metadata_section_size, block_num);
u64 metadata_section_offset = metadata_offset;
if (utils::add_saturate<u64>(utils::add_saturate<u64>(file_offset, metadata_section_offset), metadata_size) > f->size())
{
return false;
}
u64 bytes_read = 0;
const auto metadata = std::make_unique<u8[]>(metadata_size);
const auto empty_metadata = std::make_unique<u8[]>(metadata_size);
while (bytes_read < metadata_size)
{
// Locate the metadata blocks.
const usz offset = file_offset + metadata_section_offset;
// Read in the metadata.
f->read_at(offset, metadata.get() + bytes_read, metadata_section_size);
// Adjust sizes.
bytes_read += metadata_section_size;
if (((edat->flags & EDAT_FLAG_0x20) != 0)) // Metadata block before each data block.
metadata_section_offset += (metadata_section_size + edat->block_size);
else
metadata_section_offset += metadata_section_size;
}
// Test the metadata section hash (located at offset 0x90).
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), metadata.get(), empty_metadata.get(), metadata_size, header_key, header_iv, key, metadata_hash))
{
if (verbose)
edat_log.warning("Metadata section hash is invalid!");
}
// Checking ECDSA signatures.
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) == 0)
{
// Setup buffers.
unsigned char metadata_signature[0x28] = {0};
unsigned char header_signature[0x28] = {0};
unsigned char signature_hash[20] = {0};
unsigned char signature_r[0x15] = {0};
unsigned char signature_s[0x15] = {0};
unsigned char zero_buf[0x15] = {0};
// Setup ECDSA curve and public key.
ecdsa_set_curve(VSH_CURVE_P, VSH_CURVE_A, VSH_CURVE_B, VSH_CURVE_N, VSH_CURVE_GX, VSH_CURVE_GY);
ecdsa_set_pub(VSH_PUB);
// Read in the metadata and header signatures.
f->seek(0xB0);
f->read(metadata_signature, 0x28);
f->read(header_signature, 0x28);
// Checking metadata signature.
// Setup signature r and s.
signature_r[0] = 0;
signature_s[0] = 0;
std::memcpy(signature_r + 1, metadata_signature, 0x14);
std::memcpy(signature_s + 1, metadata_signature + 0x14, 0x14);
if ((!std::memcmp(signature_r, zero_buf, 0x15)) || (!std::memcmp(signature_s, zero_buf, 0x15)))
{
edat_log.warning("Metadata signature is invalid!");
}
else
{
// Setup signature hash.
if ((edat->flags & EDAT_FLAG_0x20) != 0) // Sony failed again, they used buffer from 0x100 with half size of real metadata.
{
const usz metadata_buf_size = block_num * 0x10;
std::vector<u8> metadata_buf(metadata_buf_size);
f->read_at(file_offset + metadata_offset, metadata_buf.data(), metadata_buf_size);
sha1(metadata_buf.data(), metadata_buf_size, signature_hash);
}
else
sha1(metadata.get(), metadata_size, signature_hash);
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
{
edat_log.warning("Metadata signature is invalid!");
if (((edat->block_size + 0ull) * block_num) > 0x100000000)
edat_log.warning("*Due to large file size, metadata signature status may be incorrect!");
}
}
// Checking header signature.
// Setup header signature r and s.
signature_r[0] = 0;
signature_s[0] = 0;
std::memcpy(signature_r + 1, header_signature, 0x14);
std::memcpy(signature_s + 1, header_signature + 0x14, 0x14);
if ((!std::memcmp(signature_r, zero_buf, 0x15)) || (!std::memcmp(signature_s, zero_buf, 0x15)))
{
edat_log.warning("Header signature is invalid!");
}
else
{
// Setup header signature hash.
std::memset(signature_hash, 0, 20);
u8 header_buf[0xD8]{};
f->read_at(file_offset, header_buf, 0xD8);
sha1(header_buf, 0xD8, signature_hash);
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
edat_log.warning("Header signature is invalid!");
}
}
return true;
}
bool validate_dev_klic(const u8* klicensee, NPD_HEADER* npd)
{
if ((npd->license & 0x3) != 0x3)
{
return true;
}
unsigned char dev[0x60]{};
// Build the dev buffer (first 0x60 bytes of NPD header in big-endian).
std::memcpy(dev, npd, 0x60);
// Fix endianness.
s32 version = std::bit_cast<be_t<s32>>(npd->version);
s32 license = std::bit_cast<be_t<s32>>(npd->license);
s32 type = std::bit_cast<be_t<s32>>(npd->type);
std::memcpy(dev + 0x4, &version, 4);
std::memcpy(dev + 0x8, &license, 4);
std::memcpy(dev + 0xC, &type, 4);
// Check for an empty dev_hash (can't validate if devklic is NULL);
u128 klic;
std::memcpy(&klic, klicensee, sizeof(klic));
// Generate klicensee xor key.
u128 key = klic ^ std::bit_cast<u128>(NP_OMAC_KEY_2);
// Hash with generated key and compare with dev_hash.
return cmac_hash_compare(reinterpret_cast<uchar*>(&key), 0x10, dev, 0x60, npd->dev_hash, 0x10);
}
bool validate_npd_hashes(std::string_view file_name, const u8* klicensee, NPD_HEADER* npd, EDAT_HEADER* edat, bool verbose)
{
// Ignore header validation in DEBUG data.
if (edat->flags & EDAT_DEBUG_DATA_FLAG)
{
return true;
}
if (!validate_dev_klic(klicensee, npd))
{
return false;
}
if (file_name.empty())
{
return true;
}
const usz buf_len = 0x30 + file_name.size();
std::unique_ptr<u8[]> buf(new u8[buf_len]);
std::unique_ptr<u8[]> buf_lower(new u8[buf_len]);
std::unique_ptr<u8[]> buf_upper(new u8[buf_len]);
// Build the title buffer (content_id + file_name).
std::memcpy(buf.get(), npd->content_id, 0x30);
std::memcpy(buf.get() + 0x30, file_name.data(), file_name.size());
std::memcpy(buf_lower.get(), buf.get(), buf_len);
std::memcpy(buf_upper.get(), buf.get(), buf_len);
const auto buf_span = std::span(buf.get(), buf.get() + buf_len);
const auto it = std::find(buf_span.rbegin(), buf_span.rend() - 0x30, '.');
for (usz i = std::distance(it, buf_span.rend()) - 1; i < buf_len; ++i)
{
const u8 c = buf[i];
buf_upper[i] = std::toupper(c);
buf_lower[i] = std::tolower(c);
}
// Hash with NPDRM_OMAC_KEY_3 and compare with title_hash.
// Try to ignore case sensivity with file extension
const bool title_hash_result =
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_lower.get(), buf_len, npd->title_hash, 0x10) ||
cmac_hash_compare(const_cast<u8*>(NP_OMAC_KEY_3), 0x10, buf_upper.get(), buf_len, npd->title_hash, 0x10);
if (verbose)
{
if (title_hash_result)
edat_log.notice("NPD title hash is valid!");
else
edat_log.warning("NPD title hash is invalid!");
}
return title_hash_result;
}
void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT)
{
char npd_header[0x80]{};
char edat_header[0x10]{};
usz pos = input->pos();
pos += input->read_at(pos, npd_header, sizeof(npd_header));
input->read_at(pos, edat_header, sizeof(edat_header));
std::memcpy(&NPD.magic, npd_header, 4);
NPD.version = read_from_ptr<be_t<s32>>(npd_header, 4);
NPD.license = read_from_ptr<be_t<s32>>(npd_header, 8);
NPD.type = read_from_ptr<be_t<s32>>(npd_header, 12);
std::memcpy(NPD.content_id, &npd_header[16], 0x30);
std::memcpy(NPD.digest, &npd_header[64], 0x10);
std::memcpy(NPD.title_hash, &npd_header[80], 0x10);
std::memcpy(NPD.dev_hash, &npd_header[96], 0x10);
NPD.activate_time = read_from_ptr<be_t<s64>>(npd_header, 112);
NPD.expire_time = read_from_ptr<be_t<s64>>(npd_header, 120);
EDAT.flags = read_from_ptr<be_t<s32>>(edat_header, 0);
EDAT.block_size = read_from_ptr<be_t<s32>>(edat_header, 4);
EDAT.file_size = read_from_ptr<be_t<u64>>(edat_header, 8);
}
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file)
{
u128 rapkey{};
u128 rifkey{};
rap_file.read<u128>(rapkey);
rap_to_rif(reinterpret_cast<const uchar*>(&rapkey), reinterpret_cast<uchar*>(&rifkey));
return rifkey;
}
bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, NPD_HEADER* npd_out)
{
// Setup NPD and EDAT/SDAT structs.
NPD_HEADER NPD;
EDAT_HEADER EDAT;
// Read in the NPD and EDAT/SDAT headers.
read_npd_edat_header(&input, NPD, EDAT);
if (NPD.magic != "NPD\0"_u32)
{
edat_log.error("%s has invalid NPD header or already decrypted.", input_file_name);
return false;
}
if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG)
{
edat_log.error("SDATA file given to edat function");
return false;
}
// Perform header validation (EDAT only).
char real_file_name[CRYPTO_MAX_PATH]{};
extract_file_name(input_file_name.c_str(), real_file_name);
if (!validate_npd_hashes(real_file_name, custom_klic, &NPD, &EDAT, false))
{
edat_log.error("NPD hash validation failed!");
return false;
}
if (npd_out)
{
*npd_out = NPD;
}
return true;
}
// Decrypts full file
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8* custom_klic)
{
if (!input)
{
return {};
}
// Prepare the files.
input.seek(0);
// Set DEVKLIC
u128 devklic{};
// Select the EDAT key mode.
switch (mode)
{
case 0:
break;
case 1:
memcpy(&devklic, NP_KLIC_FREE, 0x10);
break;
case 2:
memcpy(&devklic, NP_OMAC_KEY_2, 0x10);
break;
case 3:
memcpy(&devklic, NP_OMAC_KEY_3, 0x10);
break;
case 4:
memcpy(&devklic, NP_KLIC_KEY, 0x10);
break;
case 5:
memcpy(&devklic, NP_PSX_KEY, 0x10);
break;
case 6:
memcpy(&devklic, NP_PSP_KEY_1, 0x10);
break;
case 7:
memcpy(&devklic, NP_PSP_KEY_2, 0x10);
break;
case 8:
{
if (custom_klic != NULL)
memcpy(&devklic, custom_klic, 0x10);
else
{
edat_log.error("Invalid custom klic!");
return fs::file{};
}
break;
}
default:
edat_log.error("Invalid mode!");
return fs::file{};
}
// Delete the bad output file if any errors arise.
auto data = std::make_unique<EDATADecrypter>(input, devklic, input_file_name, false);
if (!data->ReadHeader())
{
return fs::file{};
}
fs::file output;
output.reset(std::move(data));
return output;
}
bool EDATADecrypter::ReadHeader()
{
edata_file.seek(0);
// Read in the NPD and EDAT/SDAT headers.
read_npd_edat_header(&edata_file, npdHeader, edatHeader);
if (npdHeader.magic != "NPD\0"_u32)
{
edat_log.error("Not an NPDRM file");
return false;
}
// Check for SDAT flag.
if ((edatHeader.flags & SDAT_FLAG) == SDAT_FLAG)
{
// Generate SDAT key.
dec_key = std::bit_cast<u128>(npdHeader.dev_hash) ^ std::bit_cast<u128>(SDAT_KEY);
}
else
{
// extract key from RIF
char real_file_name[CRYPTO_MAX_PATH]{};
extract_file_name(m_file_name.c_str(), real_file_name);
if (!validate_npd_hashes(real_file_name, reinterpret_cast<const u8*>(&dec_key), &npdHeader, &edatHeader, false))
{
edat_log.error("NPD hash validation failed!");
return true;
}
// Select EDAT key.
if (m_is_key_final)
{
// Already provided
}
// Type 3: Use supplied dec_key.
else if ((npdHeader.license & 0x3) == 0x3)
{
//
}
// Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
else
{
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.content_id);
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(dec_key))
{
dec_key = GetEdatRifKeyFromRapFile(rap);
}
// Make sure we don't have an empty RIF key.
if (!dec_key)
{
edat_log.error("A valid RAP file is needed for this EDAT file! (license=%d)", npdHeader.license);
return true;
}
edat_log.trace("RIFKEY: %s", std::bit_cast<be_t<u128>>(dec_key));
}
}
edata_file.seek(0);
// k the ecdsa_verify function in this check_data function takes a ridiculous amount of time
// like it slows down load time by a factor of x20, at least, so its ignored for now
// if (!check_data(reinterpret_cast<u8*>(&dec_key), &edatHeader, &npdHeader, &edata_file, false))
//{
// edat_log.error("NPDRM check_data() failed!");
// return false;
//}
file_size = edatHeader.file_size;
total_blocks = ::narrow<u32>(utils::aligned_div(edatHeader.file_size, edatHeader.block_size));
// Try decrypting the first block instead
u8 data_sample[1];
if (file_size && !ReadData(0, data_sample, 1))
{
edat_log.error("NPDRM ReadData() failed!");
return false;
}
return true;
}
u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
{
size = std::min<u64>(size, pos > edatHeader.file_size ? 0 : edatHeader.file_size - pos);
if (!size)
{
return 0;
}
// Now we need to offset things to account for the actual 'range' requested
const u64 startOffset = pos % edatHeader.block_size;
const u64 num_blocks = utils::aligned_div(startOffset + size, edatHeader.block_size);
// Find and decrypt block range covering pos + size
const u32 starting_block = ::narrow<u32>(pos / edatHeader.block_size);
const u32 ending_block = ::narrow<u32>(std::min<u64>(starting_block + num_blocks, total_blocks));
u64 writeOffset = 0;
std::vector<u8> data_buf(edatHeader.block_size + 16);
for (u32 i = starting_block; i < ending_block; i++)
{
u64 res = decrypt_block(&edata_file, data_buf.data(), &edatHeader, &npdHeader, reinterpret_cast<uchar*>(&dec_key), i, total_blocks, edatHeader.file_size, true);
if (res == umax)
{
edat_log.error("Error Decrypting data");
return 0;
}
const usz skip_start = (i == starting_block ? startOffset : 0);
if (skip_start >= res)
{
break;
}
const usz end_pos = (i != total_blocks - 1 ? edatHeader.block_size : (edatHeader.file_size - 1) % edatHeader.block_size + 1);
const usz read_end = std::min<usz>(res, i == ending_block - 1 ? std::min<usz>(end_pos, (startOffset + size - 1) % edatHeader.block_size + 1) : end_pos);
std::memcpy(data + writeOffset, data_buf.data() + skip_start, read_end - skip_start);
std::memset(data_buf.data(), 0, read_end - skip_start);
writeOffset += read_end - skip_start;
}
return writeOffset;
}

167
rpcs3/Crypto/unedat.h Normal file
View file

@ -0,0 +1,167 @@
#pragma once
#include <array>
#include "util/File.h"
constexpr u32 SDAT_FLAG = 0x01000000;
constexpr u32 EDAT_COMPRESSED_FLAG = 0x00000001;
constexpr u32 EDAT_FLAG_0x02 = 0x00000002;
constexpr u32 EDAT_ENCRYPTED_KEY_FLAG = 0x00000008;
constexpr u32 EDAT_FLAG_0x10 = 0x00000010;
constexpr u32 EDAT_FLAG_0x20 = 0x00000020;
constexpr u32 EDAT_DEBUG_DATA_FLAG = 0x80000000;
struct loaded_npdrm_keys
{
atomic_t<u128> dec_keys[16]{};
atomic_t<u64> dec_keys_pos = 0;
u128 one_time_key{}; // For savestates
atomic_t<u32> npdrm_fds{0};
void install_decryption_key(u128 key)
{
dec_keys_pos.atomic_op([&](u64& pos)
{
dec_keys[pos++ % std::size(dec_keys)] = key;
});
}
// TODO: Check if correct for ELF files usage
u128 last_key(usz backwards = 0) const
{
backwards++;
const usz pos = dec_keys_pos;
return pos >= backwards ? dec_keys[(pos - backwards) % std::size(dec_keys)].load() : u128{};
}
SAVESTATE_INIT_POS(2);
loaded_npdrm_keys() = default;
loaded_npdrm_keys(utils::serial& ar);
void save(utils::serial& ar);
};
struct NPD_HEADER
{
u32 magic;
s32 version;
s32 license;
s32 type;
char content_id[0x30];
u8 digest[0x10];
u8 title_hash[0x10];
u8 dev_hash[0x10];
s64 activate_time;
s64 expire_time;
};
struct EDAT_HEADER
{
s32 flags;
s32 block_size;
u64 file_size;
};
// Decrypts full file, or null/empty file
extern fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8* custom_klic);
extern void read_npd_edat_header(const fs::file* input, NPD_HEADER& NPD, EDAT_HEADER& EDAT);
extern bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& input_file_name, const u8* custom_klic, NPD_HEADER* npd_out = nullptr);
u128 GetEdatRifKeyFromRapFile(const fs::file& rap_file);
struct EDATADecrypter final : fs::file_base
{
// file stream
fs::file m_edata_file;
const fs::file& edata_file;
std::string m_file_name;
bool m_is_key_final = true;
u64 file_size{0};
u32 total_blocks{0};
u64 pos{0};
NPD_HEADER npdHeader{};
EDAT_HEADER edatHeader{};
u128 dec_key{};
public:
EDATADecrypter(fs::file&& input, u128 dec_key = {}, std::string file_name = {}, bool is_key_final = true) noexcept
: m_edata_file(std::move(input)), edata_file(m_edata_file), m_file_name(std::move(file_name)), m_is_key_final(is_key_final), dec_key(dec_key)
{
}
EDATADecrypter(const fs::file& input, u128 dec_key = {}, std::string file_name = {}, bool is_key_final = true) noexcept
: m_edata_file(fs::file{}), edata_file(input), m_file_name(std::move(file_name)), m_is_key_final(is_key_final), dec_key(dec_key)
{
}
// false if invalid
bool ReadHeader();
u64 ReadData(u64 pos, u8* data, u64 size);
fs::stat_t get_stat() override
{
fs::stat_t stats = edata_file.get_stat();
stats.is_writable = false; // TODO
stats.size = file_size;
return stats;
}
bool trunc(u64) override
{
return false;
}
u64 read(void* buffer, u64 size) override
{
const u64 bytesRead = ReadData(pos, static_cast<u8*>(buffer), size);
pos += bytesRead;
return bytesRead;
}
u64 read_at(u64 offset, void* buffer, u64 size) override
{
return ReadData(offset, static_cast<u8*>(buffer), size);
}
u64 write(const void*, u64) override
{
return 0;
}
u64 seek(s64 offset, fs::seek_mode whence) override
{
const s64 new_pos =
whence == fs::seek_set ? offset :
whence == fs::seek_cur ? offset + pos :
whence == fs::seek_end ? offset + size() :
-1;
if (new_pos < 0)
{
fs::g_tls_error = fs::error::inval;
return -1;
}
pos = new_pos;
return pos;
}
u64 size() override
{
return file_size;
}
fs::file_id get_id() override
{
fs::file_id id = edata_file.get_id();
id.type.insert(0, "EDATADecrypter: "sv);
return id;
}
u128 get_key() const
{
return dec_key;
}
};

1485
rpcs3/Crypto/unpkg.cpp Normal file

File diff suppressed because it is too large Load diff

413
rpcs3/Crypto/unpkg.h Normal file
View file

@ -0,0 +1,413 @@
#pragma once
#include "Loader/PSF.h"
#include "util/endian.hpp"
#include "util/types.hpp"
#include "util/File.h"
#include <sstream>
#include <iomanip>
#include <span>
#include <deque>
// Constants
enum : u32
{
PKG_HEADER_SIZE = 0xC0, // sizeof(pkg_header) + sizeof(pkg_unk_checksum)
PKG_HEADER_SIZE2 = 0x280,
PKG_MAX_FILENAME_SIZE = 256,
};
enum : u16
{
PKG_RELEASE_TYPE_RELEASE = 0x8000,
PKG_RELEASE_TYPE_DEBUG = 0x0000,
PKG_PLATFORM_TYPE_PS3 = 0x0001,
PKG_PLATFORM_TYPE_PSP_PSVITA = 0x0002,
};
enum : u32
{
PKG_FILE_ENTRY_NPDRM = 1,
PKG_FILE_ENTRY_NPDRMEDAT = 2,
PKG_FILE_ENTRY_REGULAR = 3,
PKG_FILE_ENTRY_FOLDER = 4,
PKG_FILE_ENTRY_UNK0 = 5,
PKG_FILE_ENTRY_UNK1 = 6,
PKG_FILE_ENTRY_SDAT = 9,
PKG_FILE_ENTRY_OVERWRITE = 0x80000000,
PKG_FILE_ENTRY_PSP = 0x10000000,
PKG_FILE_ENTRY_KNOWN_BITS = 0xff | PKG_FILE_ENTRY_PSP | PKG_FILE_ENTRY_OVERWRITE,
};
enum : u32
{
PKG_CONTENT_TYPE_UNKNOWN_1 = 0x01, // ?
PKG_CONTENT_TYPE_UNKNOWN_2 = 0x02, // ?
PKG_CONTENT_TYPE_UNKNOWN_3 = 0x03, // ?
PKG_CONTENT_TYPE_GAME_DATA = 0x04, // GameData (also patches)
PKG_CONTENT_TYPE_GAME_EXEC = 0x05, // GameExec
PKG_CONTENT_TYPE_PS1_EMU = 0x06, // PS1emu
PKG_CONTENT_TYPE_PC_ENGINE = 0x07, // PSP & PCEngine
PKG_CONTENT_TYPE_UNKNOWN_4 = 0x08, // ?
PKG_CONTENT_TYPE_THEME = 0x09, // Theme
PKG_CONTENT_TYPE_WIDGET = 0x0A, // Widget
PKG_CONTENT_TYPE_LICENSE = 0x0B, // License
PKG_CONTENT_TYPE_VSH_MODULE = 0x0C, // VSHModule
PKG_CONTENT_TYPE_PSN_AVATAR = 0x0D, // PSN Avatar
PKG_CONTENT_TYPE_PSP_GO = 0x0E, // PSPgo
PKG_CONTENT_TYPE_MINIS = 0x0F, // Minis
PKG_CONTENT_TYPE_NEOGEO = 0x10, // NEOGEO
PKG_CONTENT_TYPE_VMC = 0x11, // VMC
PKG_CONTENT_TYPE_PS2_CLASSIC = 0x12, // ?PS2Classic? Seen on PS2 classic
PKG_CONTENT_TYPE_UNKNOWN_5 = 0x13, // ?
PKG_CONTENT_TYPE_PSP_REMASTERED = 0x14, // ?
PKG_CONTENT_TYPE_PSP2_GD = 0x15, // PSVita Game Data
PKG_CONTENT_TYPE_PSP2_AC = 0x16, // PSVita Additional Content
PKG_CONTENT_TYPE_PSP2_LA = 0x17, // PSVita LiveArea
PKG_CONTENT_TYPE_PSM_1 = 0x18, // PSVita PSM ?
PKG_CONTENT_TYPE_WT = 0x19, // Web TV ?
PKG_CONTENT_TYPE_UNKNOWN_6 = 0x1A, // ?
PKG_CONTENT_TYPE_UNKNOWN_7 = 0x1B, // ?
PKG_CONTENT_TYPE_UNKNOWN_8 = 0x1C, // ?
PKG_CONTENT_TYPE_PSM_2 = 0x1D, // PSVita PSM ?
PKG_CONTENT_TYPE_UNKNOWN_9 = 0x1E, // ?
PKG_CONTENT_TYPE_PSP2_THEME = 0x1F, // PSVita Theme
};
// Structs
struct PKGHeader
{
le_t<u32> pkg_magic; // Magic (0x7f504b47) (" PKG")
be_t<u16> pkg_type; // Release type (Retail:0x8000, Debug:0x0000)
be_t<u16> pkg_platform; // Platform type (PS3:0x0001, PSP:0x0002)
be_t<u32> meta_offset; // Metadata offset. Usually 0xC0 for PS3, usually 0x280 for PSP and PSVita
be_t<u32> meta_count; // Metadata item count
be_t<u32> meta_size; // Metadata size.
be_t<u32> file_count; // Number of files
be_t<u64> pkg_size; // PKG size in bytes
be_t<u64> data_offset; // Encrypted data offset
be_t<u64> data_size; // Encrypted data size in bytes
char title_id[48]; // Title ID
be_t<u64> qa_digest[2]; // This should be the hash of "files + attribs"
be_t<u128> klicensee; // Nonce
// + some stuff
};
// Extended header in PSP and PSVita packages
struct PKGExtHeader
{
le_t<u32> magic; // 0x7F657874 (" ext")
be_t<u32> unknown_1; // Maybe version. always 1
be_t<u32> ext_hdr_size; // Extended header size. ex: 0x40
be_t<u32> ext_data_size; // ex: 0x180
be_t<u32> main_and_ext_headers_hmac_offset; // ex: 0x100
be_t<u32> metadata_header_hmac_offset; // ex: 0x360, 0x390, 0x490
be_t<u64> tail_offset; // tail size seams to be always 0x1A0
be_t<u32> padding1;
be_t<u32> pkg_key_id; // Id of the AES key used for decryption. PSP = 0x1, PSVita = 0xC0000002, PSM = 0xC0000004
be_t<u32> full_header_hmac_offset; // ex: none (old pkg): 0, 0x930
u8 padding2[20];
};
struct PKGEntry
{
be_t<u32> name_offset; // File name offset
be_t<u32> name_size; // File name size
be_t<u64> file_offset; // File offset
be_t<u64> file_size; // File size
be_t<u32> type; // File type
be_t<u32> pad; // Padding (zeros)
};
// https://www.psdevwiki.com/ps3/PKG_files#PKG_Metadata
struct PKGMetaData
{
private:
static std::string to_hex_string(u8 buf[], usz size)
{
std::stringstream sstream;
for (usz i = 0; i < size; i++)
{
sstream << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(buf[i]);
}
return sstream.str();
}
static std::string to_hex_string(u8 buf[], usz size, usz dotpos)
{
std::string result = to_hex_string(buf, size);
if (result.size() > dotpos)
{
result.insert(dotpos, 1, '.');
}
return result;
}
public:
be_t<u32> drm_type{0};
be_t<u32> content_type{0};
be_t<u32> package_type{0};
be_t<u64> package_size{0};
u8 qa_digest[24]{0};
be_t<u64> unk_0x9{0};
be_t<u64> unk_0xB{0};
struct package_revision
{
struct package_revision_data
{
u8 make_package_npdrm_ver[2]{0};
u8 version[2]{0};
} data{};
std::string make_package_npdrm_ver;
std::string version;
void interpret_data()
{
make_package_npdrm_ver = to_hex_string(data.make_package_npdrm_ver, sizeof(data.make_package_npdrm_ver));
version = to_hex_string(data.version, sizeof(data.version), 2);
}
std::string to_string() const
{
return fmt::format("make package npdrm version: %s, version: %s", make_package_npdrm_ver, version);
}
} package_revision;
struct software_revision
{
struct software_revision_data
{
u8 unk[1]{0};
u8 firmware_version[3]{0};
u8 version[2]{0};
u8 app_version[2]{0};
} data{};
std::string unk; // maybe hardware id
std::string firmware_version;
std::string version;
std::string app_version;
void interpret_data()
{
unk = to_hex_string(data.unk, sizeof(data.unk));
firmware_version = to_hex_string(data.firmware_version, sizeof(data.firmware_version), 2);
version = to_hex_string(data.version, sizeof(data.version), 2);
app_version = to_hex_string(data.app_version, sizeof(data.app_version), 2);
}
std::string to_string() const
{
return fmt::format("unk: %s, firmware version: %s, version: %s, app version: %s",
unk, firmware_version, version, app_version);
}
} software_revision;
std::string title_id;
std::string install_dir;
// PSVita stuff
struct vita_item_info // size is 0x28 (40)
{
be_t<u32> offset{0};
be_t<u32> size{0};
u8 sha256[32]{0};
std::string to_string() const
{
return fmt::format("offset: 0x%x, size: 0x%x, sha256: 0x%x", offset, size, sha256);
}
} item_info;
struct vita_sfo_info // size is 0x38 (56)
{
be_t<u32> param_offset{0};
be_t<u16> param_size{0};
be_t<u32> unk_1{0}; // seen values: 0x00000001-0x00000018, 0x0000001b-0x0000001c
be_t<u32> psp2_system_ver{0}; // BCD encoded
u8 unk_2[8]{0};
u8 param_digest[32]{0}; // SHA256 of param_data. Called ParamDigest: This is sha256 digest of param.sfo.
std::string to_string() const
{
return fmt::format("param_offset: 0x%x, param_size: 0x%x, unk_1: 0x%x, psp2_system_ver: 0x%x, unk_2: 0x%x, param_digest: 0x%x",
param_offset, param_size, unk_1, psp2_system_ver, unk_2, param_digest);
}
} sfo_info;
struct vita_unknown_data_info // size is 0x48 (72)
{
be_t<u32> unknown_data_offset{0};
be_t<u16> unknown_data_size{0}; // ex: 0x320
u8 unk[32]{0};
u8 unknown_data_sha256[32]{0};
std::string to_string() const
{
return fmt::format("unknown_data_offset: 0x%x, unknown_data_size: 0x%x, unk: 0x%x, unknown_data_sha256: 0x%x",
unknown_data_offset, unknown_data_size, unk, unknown_data_sha256);
}
} unknown_data_info;
struct vita_entirety_info // size is 0x38 (56)
{
be_t<u32> entirety_data_offset{0}; // located just before SFO
be_t<u32> entirety_data_size{0}; // ex: 0xA0, C0, 0x100, 0x120, 0x160
be_t<u16> flags{0}; // ex: EE 00, FE 10, FE 78, FE F8, FF 10, FF 90, FF D0, flags indicating which digests it embeds
be_t<u16> unk_1{0}; // always 00 00
be_t<u32> unk_2{0}; // ex: 1, 0
u8 unk_3[8]{0};
u8 entirety_digest[32]{0};
std::string to_string() const
{
return fmt::format("entirety_data_offset: 0x%x, entirety_data_size: 0x%x, flags: 0x%x, unk_1: 0x%x, unk_2: 0x%x, unk_3: 0x%x, entirety_digest: 0x%x",
entirety_data_offset, entirety_data_size, flags, unk_1, unk_2, unk_3, entirety_digest);
}
} entirety_info;
struct vita_version_info // size is 0x28 (40)
{
be_t<u32> publishing_tools_version{0};
be_t<u32> psf_builder_version{0};
u8 padding[32]{0};
std::string to_string() const
{
return fmt::format("publishing_tools_version: 0x%x, psf_builder_version: 0x%x, padding: 0x%x",
publishing_tools_version, psf_builder_version, padding);
}
} version_info;
struct vita_self_info // size is 0x38 (56)
{
be_t<u32> self_info_offset{0}; // offset to the first self_info_data_element
be_t<u32> self_info_size{0}; // usually 0x10 or 0x20
u8 unk[16]{0};
u8 self_sha256[32]{0};
std::string to_string() const
{
return fmt::format("self_info_offset: 0x%x, self_info_size: 0x%x, unk: 0x%x, self_sha256: 0x%x",
self_info_offset, self_info_size, unk, self_sha256);
}
} self_info;
};
struct package_install_result
{
enum class error_type
{
no_error,
app_version,
other
} error = error_type::no_error;
struct version
{
std::string expected;
std::string found;
} version;
};
class package_reader
{
struct install_entry
{
typename std::map<std::string, install_entry*>::value_type* weak_reference{};
std::string name;
u64 file_offset{};
u64 file_size{};
u32 type{};
u32 pad{};
// Check if the entry is the same one registered in entries to install
bool is_dominating() const
{
return weak_reference->second == this;
}
};
public:
package_reader(const std::string& path, fs::file file = {});
~package_reader();
enum result
{
not_started,
started,
success,
aborted,
aborted_dirty,
error,
error_dirty
};
bool is_valid() const
{
return m_is_valid;
}
package_install_result check_target_app_version() const;
static package_install_result extract_data(std::deque<package_reader>& readers, std::deque<std::string>& bootable_paths);
const psf::registry& get_psf() const
{
return m_psf;
}
result get_result() const
{
return m_result;
};
int get_progress(int maximum = 100) const;
void abort_extract();
fs::file& file()
{
return m_file;
}
private:
bool read_header();
bool read_metadata();
bool read_param_sfo();
bool set_decryption_key();
bool read_entries(std::vector<PKGEntry>& entries);
void archive_seek(s64 new_offset, const fs::seek_mode damode = fs::seek_set);
u64 archive_read(void* data_ptr, u64 num_bytes);
bool set_install_path();
bool fill_data(std::map<std::string, install_entry*>& all_install_entries);
std::span<const char> archive_read_block(u64 offset, void* data_ptr, u64 num_bytes);
usz decrypt(u64 offset, u64 size, const uchar* key, void* local_buf);
void extract_worker();
std::deque<install_entry> m_install_entries;
std::string m_install_path;
atomic_t<bool> m_aborted = false;
atomic_t<usz> m_num_failures = 0;
atomic_t<usz> m_entry_indexer = 0;
atomic_t<usz> m_written_bytes = 0;
bool m_was_null = false;
static constexpr usz BUF_SIZE = 8192 * 1024; // 8 MB
static constexpr usz BUF_PADDING = 32;
bool m_is_valid = false;
result m_result = result::not_started;
std::string m_path{};
std::string m_install_dir{};
fs::file m_file{};
std::array<uchar, 16> m_dec_key{};
PKGHeader m_header{};
PKGMetaData m_metadata{};
psf::registry m_psf{};
// Expose bootable file installed (if installed such)
std::string m_bootable_file_path;
};

1492
rpcs3/Crypto/unself.cpp Normal file

File diff suppressed because it is too large Load diff

583
rpcs3/Crypto/unself.h Normal file
View file

@ -0,0 +1,583 @@
#pragma once
#include "key_vault.h"
#include "zlib.h"
#include "util/types.hpp"
#include "util/File.h"
#include "util/logs.hpp"
#include "unedat.h"
LOG_CHANNEL(self_log, "SELF");
// SCE-specific definitions for e_type:
enum
{
ET_SCE_EXEC = 0xFE00, // SCE Executable - PRX2
ET_SCE_RELEXEC = 0xFE04, // SCE Relocatable Executable - PRX2
ET_SCE_STUBLIB = 0xFE0C, // SCE SDK Stubs
ET_SCE_DYNEXEC = 0xFE10, // SCE EXEC_ASLR (PS4 Executable with ASLR)
ET_SCE_DYNAMIC = 0xFE18, // ?
ET_SCE_IOPRELEXEC = 0xFF80, // SCE IOP Relocatable Executable
ET_SCE_IOPRELEXEC2 = 0xFF81, // SCE IOP Relocatable Executable Version 2
ET_SCE_EERELEXEC = 0xFF90, // SCE EE Relocatable Executable
ET_SCE_EERELEXEC2 = 0xFF91, // SCE EE Relocatable Executable Version 2
ET_SCE_PSPRELEXEC = 0xFFA0, // SCE PSP Relocatable Executable
ET_SCE_PPURELEXEC = 0xFFA4, // SCE PPU Relocatable Executable
ET_SCE_ARMRELEXEC = 0xFFA5, // ?SCE ARM Relocatable Executable (PS Vita System Software earlier or equal 0.931.010)
ET_SCE_PSPOVERLAY = 0xFFA8, // ?
};
enum
{
ELFOSABI_CELL_LV2 = 102 // CELL LV2
};
enum
{
PT_SCE_RELA = 0x60000000,
PT_SCE_LICINFO_1 = 0x60000001,
PT_SCE_LICINFO_2 = 0x60000002,
PT_SCE_DYNLIBDATA = 0x61000000,
PT_SCE_PROCPARAM = 0x61000001,
PT_SCE_UNK_61000010 = 0x61000010,
PT_SCE_COMMENT = 0x6FFFFF00,
PT_SCE_LIBVERSION = 0x6FFFFF01,
PT_SCE_UNK_70000001 = 0x70000001,
PT_SCE_IOPMOD = 0x70000080,
PT_SCE_EEMOD = 0x70000090,
PT_SCE_PSPRELA = 0x700000A0,
PT_SCE_PSPRELA2 = 0x700000A1,
PT_SCE_PPURELA = 0x700000A4,
PT_SCE_SEGSYM = 0x700000A8,
};
enum
{
PF_SPU_X = 0x00100000,
PF_SPU_W = 0x00200000,
PF_SPU_R = 0x00400000,
PF_RSX_X = 0x01000000,
PF_RSX_W = 0x02000000,
PF_RSX_R = 0x04000000,
};
enum
{
SHT_SCE_RELA = 0x60000000,
SHT_SCE_NID = 0x61000001,
SHT_SCE_IOPMOD = 0x70000080,
SHT_SCE_EEMOD = 0x70000090,
SHT_SCE_PSPRELA = 0x700000A0,
SHT_SCE_PPURELA = 0x700000A4,
};
struct program_identification_header
{
u64 program_authority_id;
u32 program_vendor_id;
u32 program_type;
u64 program_sceversion;
u64 padding;
void Load(const fs::file& f);
void Show() const;
};
struct segment_ext_header
{
u64 offset; // Offset to data
u64 size; // Size of data
u32 compression; // 1 = plain, 2 = zlib
u32 unknown; // Always 0, as far as I know.
u64 encryption; // 0 = unrequested, 1 = completed, 2 = requested
void Load(const fs::file& f);
void Show() const;
};
struct version_header
{
u32 subheader_type; // 1 - sceversion
u32 present; // 0 = false, 1 = true
u32 size; // usually 0x10
u32 unknown4;
void Load(const fs::file& f);
void Show() const;
};
struct supplemental_header
{
u32 type; // 1=PS3 plaintext_capability; 2=PS3 ELF digest; 3=PS3 NPDRM, 4=PS Vita ELF digest; 5=PS Vita NPDRM; 6=PS Vita boot param; 7=PS Vita shared secret
u32 size;
u64 next; // 1 if another Supplemental Header element follows else 0
union
{
// type 1, 0x30 bytes
struct // 0x20 bytes of data
{
u32 ctrl_flag1;
u32 unknown1;
u32 unknown2;
u32 unknown3;
u32 unknown4;
u32 unknown5;
u32 unknown6;
u32 unknown7;
} PS3_plaintext_capability_header;
// type 2, 0x40 bytes
struct // 0x30 bytes of data
{
u8 constant[0x14]; // same for every PS3/PS Vita SELF, hardcoded in make_fself.exe: 627CB1808AB938E32C8C091708726A579E2586E4
u8 elf_digest[0x14]; // SHA-1. Hash F2C552BF716ED24759CBE8A0A9A6DB9965F3811C is blacklisted by appldr
u64 required_system_version; // filled on Sony authentication server, contains decimal PS3_SYSTEM_VER value from PARAM.SFO
} PS3_elf_digest_header_40;
// type 2, 0x30 bytes
struct // 0x20 bytes of data
{
u8 constant_or_elf_digest[0x14];
u8 padding[0xC];
} PS3_elf_digest_header_30;
// type 3, 0x90 bytes
struct // 0x80 bytes of data
{
NPD_HEADER npd;
} PS3_npdrm_header;
};
void Load(const fs::file& f);
void Show() const;
};
struct MetadataInfo
{
u8 key[0x10];
u8 key_pad[0x10];
u8 iv[0x10];
u8 iv_pad[0x10];
void Load(u8* in);
void Show() const;
};
struct MetadataHeader
{
u64 signature_input_length;
u32 unknown1;
u32 section_count;
u32 key_count;
u32 opt_header_size;
u32 unknown2;
u32 unknown3;
void Load(u8* in);
void Show() const;
};
struct MetadataSectionHeader
{
u64 data_offset;
u64 data_size;
u32 type;
u32 program_idx;
u32 hashed;
u32 sha1_idx;
u32 encrypted;
u32 key_idx;
u32 iv_idx;
u32 compressed;
void Load(u8* in);
void Show() const;
};
struct SectionHash
{
u8 sha1[20];
u8 padding[12];
u8 hmac_key[64];
void Load(const fs::file& f);
};
struct CapabilitiesInfo
{
u32 type;
u32 capabilities_size;
u32 next;
u32 unknown1;
u64 unknown2;
u64 unknown3;
u64 flags;
u32 unknown4;
u32 unknown5;
void Load(const fs::file& f);
};
struct Signature
{
u8 r[21];
u8 s[21];
u8 padding[6];
void Load(const fs::file& f);
};
struct SelfSection
{
u8* data;
u64 size;
u64 offset;
void Load(const fs::file& f);
};
struct Elf32_Ehdr
{
// u8 e_ident[16]; // ELF identification
u32 e_magic;
u8 e_class;
u8 e_data;
u8 e_curver;
u8 e_os_abi;
u64 e_abi_ver;
u16 e_type; // object file type
u16 e_machine; // machine type
u32 e_version; // object file version
u32 e_entry; // entry point address
u32 e_phoff; // program header offset
u32 e_shoff; // section header offset
u32 e_flags; // processor-specific flags
u16 e_ehsize; // ELF header size
u16 e_phentsize; // size of program header entry
u16 e_phnum; // number of program header entries
u16 e_shentsize; // size of section header entry
u16 e_shnum; // number of section header entries
u16 e_shstrndx; // section name string table index
void Load(const fs::file& f);
static void Show() {}
bool IsLittleEndian() const
{
return e_data == 1;
}
bool CheckMagic() const
{
return e_magic == 0x7F454C46;
}
u32 GetEntry() const
{
return e_entry;
}
};
struct Elf32_Shdr
{
u32 sh_name; // section name
u32 sh_type; // section type
u32 sh_flags; // section attributes
u32 sh_addr; // virtual address in memory
u32 sh_offset; // offset in file
u32 sh_size; // size of section
u32 sh_link; // link to other section
u32 sh_info; // miscellaneous information
u32 sh_addralign; // address alignment boundary
u32 sh_entsize; // size of entries, if section has table
void Load(const fs::file& f);
void LoadLE(const fs::file& f);
static void Show() {}
};
struct Elf32_Phdr
{
u32 p_type; // Segment type
u32 p_offset; // Segment file offset
u32 p_vaddr; // Segment virtual address
u32 p_paddr; // Segment physical address
u32 p_filesz; // Segment size in file
u32 p_memsz; // Segment size in memory
u32 p_flags; // Segment flags
u32 p_align; // Segment alignment
void Load(const fs::file& f);
void LoadLE(const fs::file& f);
static void Show() {}
};
struct Elf64_Ehdr
{
// u8 e_ident[16]; // ELF identification
u32 e_magic;
u8 e_class;
u8 e_data;
u8 e_curver;
u8 e_os_abi;
u64 e_abi_ver;
u16 e_type; // object file type
u16 e_machine; // machine type
u32 e_version; // object file version
u64 e_entry; // entry point address
u64 e_phoff; // program header offset
u64 e_shoff; // section header offset
u32 e_flags; // processor-specific flags
u16 e_ehsize; // ELF header size
u16 e_phentsize; // size of program header entry
u16 e_phnum; // number of program header entries
u16 e_shentsize; // size of section header entry
u16 e_shnum; // number of section header entries
u16 e_shstrndx; // section name string table index
void Load(const fs::file& f);
static void Show() {}
bool CheckMagic() const
{
return e_magic == 0x7F454C46;
}
u64 GetEntry() const
{
return e_entry;
}
};
struct Elf64_Shdr
{
u32 sh_name; // section name
u32 sh_type; // section type
u64 sh_flags; // section attributes
u64 sh_addr; // virtual address in memory
u64 sh_offset; // offset in file
u64 sh_size; // size of section
u32 sh_link; // link to other section
u32 sh_info; // miscellaneous information
u64 sh_addralign; // address alignment boundary
u64 sh_entsize; // size of entries, if section has table
void Load(const fs::file& f);
static void Show() {}
};
struct Elf64_Phdr
{
u32 p_type; // Segment type
u32 p_flags; // Segment flags
u64 p_offset; // Segment file offset
u64 p_vaddr; // Segment virtual address
u64 p_paddr; // Segment physical address
u64 p_filesz; // Segment size in file
u64 p_memsz; // Segment size in memory
u64 p_align; // Segment alignment
void Load(const fs::file& f);
static void Show() {}
};
struct SceHeader
{
u32 se_magic;
u32 se_hver;
u16 se_flags;
u16 se_type;
u32 se_meta;
u64 se_hsize;
u64 se_esize;
void Load(const fs::file& f);
static void Show() {}
bool CheckMagic() const
{
return se_magic == 0x53434500;
}
};
struct ext_hdr
{
u64 ext_hdr_version;
u64 program_identification_hdr_offset;
u64 ehdr_offset;
u64 phdr_offset;
u64 shdr_offset;
u64 segment_ext_hdr_offset;
u64 version_hdr_offset;
u64 supplemental_hdr_offset;
u64 supplemental_hdr_size;
u64 padding;
void Load(const fs::file& f);
static void Show() {}
};
struct SelfAdditionalInfo
{
bool valid = false;
std::vector<supplemental_header> supplemental_hdr;
program_identification_header prog_id_hdr;
};
class SCEDecrypter
{
protected:
// Main SELF file stream.
const fs::file& sce_f;
// SCE headers.
SceHeader sce_hdr{};
// Metadata structs.
MetadataInfo meta_info{};
MetadataHeader meta_hdr{};
std::vector<MetadataSectionHeader> meta_shdr{};
// Internal data buffers.
std::unique_ptr<u8[]> data_keys{};
u32 data_keys_length{};
std::unique_ptr<u8[]> data_buf{};
u32 data_buf_length{};
public:
SCEDecrypter(const fs::file& s);
std::vector<fs::file> MakeFile();
bool LoadHeaders();
bool LoadMetadata(const u8 erk[32], const u8 riv[16]);
bool DecryptData();
};
class SELFDecrypter
{
// Main SELF file stream.
const fs::file& self_f;
// SCE, SELF and APP headers.
SceHeader sce_hdr{};
ext_hdr m_ext_hdr{};
program_identification_header m_prog_id_hdr{};
// ELF64 header and program header/section header arrays.
Elf64_Ehdr elf64_hdr{};
std::vector<Elf64_Shdr> shdr64_arr{};
std::vector<Elf64_Phdr> phdr64_arr{};
// ELF32 header and program header/section header arrays.
Elf32_Ehdr elf32_hdr{};
std::vector<Elf32_Shdr> shdr32_arr{};
std::vector<Elf32_Phdr> phdr32_arr{};
// Decryption info structs.
std::vector<segment_ext_header> m_seg_ext_hdr{};
version_header m_version_hdr{};
std::vector<supplemental_header> m_supplemental_hdr_arr{};
// Metadata structs.
MetadataInfo meta_info{};
MetadataHeader meta_hdr{};
std::vector<MetadataSectionHeader> meta_shdr{};
// Internal data buffers.
std::unique_ptr<u8[]> data_keys{};
u32 data_keys_length{};
std::unique_ptr<u8[]> data_buf{};
u32 data_buf_length{};
// Main key vault instance.
KeyVault key_v{};
public:
SELFDecrypter(const fs::file& s);
fs::file MakeElf(bool isElf32);
bool LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info = nullptr);
void ShowHeaders(bool isElf32);
bool LoadMetadata(const u8* klic_key);
bool DecryptData();
bool DecryptNPDRM(u8* metadata, u32 metadata_size);
const NPD_HEADER* GetNPDHeader() const;
static bool GetKeyFromRap(const char* content_id, u8* npdrm_key);
private:
template <typename EHdr, typename SHdr, typename PHdr>
void WriteElf(fs::file& e, EHdr ehdr, SHdr shdr, PHdr phdr)
{
// Set initial offset.
u32 data_buf_offset = 0;
// Write ELF header.
WriteEhdr(e, ehdr);
// Write program headers.
for (u32 i = 0; i < ehdr.e_phnum; ++i)
{
WritePhdr(e, phdr[i]);
}
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
// PHDR type.
if (meta_shdr[i].type == 2)
{
// Decompress if necessary.
if (meta_shdr[i].compressed == 2)
{
const auto filesz = phdr[meta_shdr[i].program_idx].p_filesz;
// Create a pointer to a buffer for decompression.
std::unique_ptr<u8[]> decomp_buf(new u8[filesz]);
// Create a buffer separate from data_buf to uncompress.
std::unique_ptr<u8[]> zlib_buf(new u8[data_buf_length]);
memcpy(zlib_buf.get(), data_buf.get(), data_buf_length);
uLongf decomp_buf_length = ::narrow<uLongf>(filesz);
// Use zlib uncompress on the new buffer.
// decomp_buf_length changes inside the call to uncompress
const int rv = uncompress(decomp_buf.get(), &decomp_buf_length, zlib_buf.get() + data_buf_offset, data_buf_length);
// Check for errors (TODO: Probably safe to remove this once these changes have passed testing.)
switch (rv)
{
case Z_MEM_ERROR: self_log.error("MakeELF encountered a Z_MEM_ERROR!"); break;
case Z_BUF_ERROR: self_log.error("MakeELF encountered a Z_BUF_ERROR!"); break;
case Z_DATA_ERROR: self_log.error("MakeELF encountered a Z_DATA_ERROR!"); break;
default: break;
}
// Seek to the program header data offset and write the data.
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(decomp_buf.get(), filesz);
}
else
{
// Seek to the program header data offset and write the data.
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(data_buf.get() + data_buf_offset, meta_shdr[i].data_size);
}
// Advance the data buffer offset by data size.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
}
}
// Write section headers.
if (m_ext_hdr.shdr_offset != 0)
{
e.seek(ehdr.e_shoff);
for (u32 i = 0; i < ehdr.e_shnum; ++i)
{
WriteShdr(e, shdr[i]);
}
}
}
};
fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr);
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr, NPD_HEADER* npd_out = nullptr);
bool get_npdrm_self_header(const fs::file& self, NPD_HEADER& npd);
u128 get_default_self_klic();

170
rpcs3/Crypto/unzip.cpp Normal file
View file

@ -0,0 +1,170 @@
#include "stdafx.h"
#include "unzip.h"
#include <zlib.h>
#include "util/serialization_ext.hpp"
std::vector<u8> unzip(const void* src, usz size)
{
if (!src || !size) [[unlikely]]
{
return {};
}
std::vector<uchar> out(size * 6);
z_stream zs{};
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
int res = inflateInit2(&zs, 16 + 15);
if (res != Z_OK)
{
return {};
}
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
zs.avail_in = static_cast<uInt>(size);
zs.next_in = reinterpret_cast<const u8*>(src);
zs.avail_out = static_cast<uInt>(out.size());
zs.next_out = out.data();
while (zs.avail_in)
{
switch (inflate(&zs, Z_FINISH))
{
case Z_OK:
case Z_STREAM_END:
break;
case Z_BUF_ERROR:
if (zs.avail_in)
break;
[[fallthrough]];
default:
inflateEnd(&zs);
return out;
}
if (zs.avail_in)
{
const auto cur_size = zs.next_out - out.data();
out.resize(out.size() + 65536);
zs.avail_out = static_cast<uInt>(out.size() - cur_size);
zs.next_out = &out[cur_size];
}
}
out.resize(zs.next_out - out.data());
res = inflateEnd(&zs);
return out;
}
bool unzip(const void* src, usz size, fs::file& out)
{
if (!src || !size || !out)
{
return false;
}
bool is_valid = true;
constexpr usz BUFSIZE = 32ULL * 1024ULL;
std::vector<u8> tempbuf(BUFSIZE);
z_stream strm{};
strm.avail_in = ::narrow<uInt>(size);
strm.avail_out = static_cast<uInt>(tempbuf.size());
strm.next_in = reinterpret_cast<const u8*>(src);
strm.next_out = tempbuf.data();
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
int res = inflateInit(&strm);
if (res != Z_OK)
{
return false;
}
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
while (strm.avail_in)
{
res = inflate(&strm, Z_NO_FLUSH);
if (res == Z_STREAM_END)
break;
if (res != Z_OK)
is_valid = false;
if (strm.avail_out)
break;
if (out.write(tempbuf.data(), tempbuf.size()) != tempbuf.size())
{
is_valid = false;
}
strm.next_out = tempbuf.data();
strm.avail_out = static_cast<uInt>(tempbuf.size());
}
res = inflate(&strm, Z_FINISH);
if (res != Z_STREAM_END)
is_valid = false;
if (strm.avail_out < tempbuf.size())
{
const usz bytes_to_write = tempbuf.size() - strm.avail_out;
if (out.write(tempbuf.data(), bytes_to_write) != bytes_to_write)
{
is_valid = false;
}
}
res = inflateEnd(&strm);
return is_valid;
}
bool zip(const void* src, usz size, fs::file& out, bool multi_thread_it)
{
if (!src || !size || !out)
{
return false;
}
utils::serial compressor;
compressor.set_expect_little_data(!multi_thread_it || size < 0x40'0000);
compressor.m_file_handler = make_compressed_serialization_file_handler(out);
std::string_view buffer_view{static_cast<const char*>(src), size};
while (!buffer_view.empty())
{
if (!compressor.m_file_handler->is_valid())
{
return false;
}
const std::string_view slice = buffer_view.substr(0, 0x50'0000);
compressor(slice);
compressor.breathe();
buffer_view = buffer_view.substr(slice.size());
}
compressor.m_file_handler->finalize(compressor);
if (!compressor.m_file_handler->is_valid())
{
return false;
}
return true;
}

25
rpcs3/Crypto/unzip.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
std::vector<u8> unzip(const void* src, usz size);
template <typename T>
inline std::vector<u8> unzip(const T& src)
{
return unzip(src.data(), src.size());
}
bool unzip(const void* src, usz size, fs::file& out);
template <typename T>
inline bool unzip(const std::vector<u8>& src, fs::file& out)
{
return unzip(src.data(), src.size(), out);
}
bool zip(const void* src, usz size, fs::file& out, bool multi_thread_it = false);
template <typename T>
inline bool zip(const T& src, fs::file& out)
{
return zip(src.data(), src.size(), out);
}

242
rpcs3/Crypto/utils.cpp Normal file
View file

@ -0,0 +1,242 @@
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
// Licensed under the terms of the GNU GPL, version 2.0 or later versions.
// http://www.gnu.org/licenses/gpl-2.0.txt
#include "utils.h"
#include "aes.h"
#include "sha1.h"
#include "sha256.h"
#include "key_vault.h"
#include <cstring>
#include <stdio.h>
#include <time.h>
#include "util/StrUtil.h"
#include "util/File.h"
#include <memory>
#include <string>
#include <string_view>
#include <span>
// Auxiliary functions (endian swap, xor).
// Hex string conversion auxiliary functions.
u64 hex_to_u64(const char* hex_str)
{
auto length = std::strlen(hex_str);
u64 tmp = 0;
u64 result = 0;
char c;
while (length--)
{
c = *hex_str++;
if ((c >= '0') && (c <= '9'))
tmp = c - '0';
else if ((c >= 'a') && (c <= 'f'))
tmp = c - 'a' + 10;
else if ((c >= 'A') && (c <= 'F'))
tmp = c - 'A' + 10;
else
tmp = 0;
result |= (tmp << (length * 4));
}
return result;
}
void hex_to_bytes(unsigned char* data, const char* hex_str, unsigned int str_length)
{
const auto strn_length = (str_length > 0) ? str_length : std::strlen(hex_str);
auto data_length = strn_length / 2;
char tmp_buf[3] = {0, 0, 0};
// Don't convert if the string length is odd.
if ((strn_length % 2) == 0)
{
while (data_length--)
{
tmp_buf[0] = *hex_str++;
tmp_buf[1] = *hex_str++;
*data++ = static_cast<u8>(hex_to_u64(tmp_buf) & 0xFF);
}
}
}
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
void aescbc128_decrypt(unsigned char* key, unsigned char* iv, unsigned char* in, unsigned char* out, usz len)
{
aes_context ctx;
aes_setkey_dec(&ctx, key, 128);
aes_crypt_cbc(&ctx, AES_DECRYPT, len, iv, in, out);
// Reset the IV.
memset(iv, 0, 0x10);
}
void aescbc128_encrypt(unsigned char* key, unsigned char* iv, unsigned char* in, unsigned char* out, usz len)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
aes_crypt_cbc(&ctx, AES_ENCRYPT, len, iv, in, out);
// Reset the IV.
memset(iv, 0, 0x10);
}
void aesecb128_encrypt(unsigned char* key, unsigned char* in, unsigned char* out)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
aes_crypt_ecb(&ctx, AES_ENCRYPT, in, out);
}
bool hmac_hash_compare(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash, usz hash_len)
{
const std::unique_ptr<u8[]> out(new u8[key_len]);
sha1_hmac(key, key_len, in, in_len, out.get());
return std::memcmp(out.get(), hash, hash_len) == 0;
}
void hmac_hash_forge(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash)
{
sha1_hmac(key, key_len, in, in_len, hash);
}
bool cmac_hash_compare(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash, usz hash_len)
{
const std::unique_ptr<u8[]> out(new u8[key_len]);
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
aes_cmac(&ctx, in_len, in, out.get());
return std::memcmp(out.get(), hash, hash_len) == 0;
}
void cmac_hash_forge(unsigned char* key, int /*key_len*/, unsigned char* in, usz in_len, unsigned char* hash)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
aes_cmac(&ctx, in_len, in, hash);
}
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH])
{
std::string_view v(file_path);
if (const auto pos = v.find_last_of(fs::delim); pos != umax)
{
v.remove_prefix(pos + 1);
}
std::span r(real_file_name, CRYPTO_MAX_PATH);
strcpy_trunc(r, v);
return real_file_name;
}
std::string sha256_get_hash(const char* data, usz size, bool lower_case)
{
u8 res_hash[32];
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts_ret(&ctx, 0);
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(data), size);
mbedtls_sha256_finish_ret(&ctx, res_hash);
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
for (usz index = 0; index < 32; index++)
{
const auto pal = lower_case ? "0123456789abcdef" : "0123456789ABCDEF";
res_hash_string[index * 2] = pal[res_hash[index] >> 4];
res_hash_string[(index * 2) + 1] = pal[res_hash[index] & 15];
}
return res_hash_string;
}
void mbedtls_zeroize(void* v, size_t n)
{
static void* (*const volatile unop_memset)(void*, int, size_t) = &memset;
(void)unop_memset(v, 0, n);
}
// SC passphrase crypto
void sc_form_key(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_paid, u8* key)
{
for (u32 i = 0; i < PASSPHRASE_KEY_LEN; i++)
{
key[i] = static_cast<u8>(sc_key[i] ^ laid_paid[i]);
}
}
std::array<u8, PASSPHRASE_KEY_LEN> sc_combine_laid_paid(s64 laid, s64 paid)
{
const std::string paid_laid = fmt::format("%016llx%016llx", laid, paid);
std::array<u8, PASSPHRASE_KEY_LEN> out{};
hex_to_bytes(out.data(), paid_laid.c_str(), PASSPHRASE_KEY_LEN * 2);
return out;
}
std::array<u8, PASSPHRASE_KEY_LEN> vtrm_get_laid_paid_from_type(int type)
{
// No idea what this type stands for
switch (type)
{
case 0: return sc_combine_laid_paid(0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL);
case 1: return sc_combine_laid_paid(LAID_2, 0x1070000000000001L);
case 2: return sc_combine_laid_paid(LAID_2, 0x0000000000000000L);
case 3: return sc_combine_laid_paid(LAID_2, PAID_69);
default:
fmt::throw_exception("vtrm_get_laid_paid_from_type: Wrong type specified (type=%d)", type);
}
}
std::array<u8, PASSPHRASE_KEY_LEN> vtrm_portability_laid_paid()
{
// 107000002A000001
return sc_combine_laid_paid(0x0000000000000000L, 0x0000000000000000L);
}
int sc_decrypt(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_paid, u8* iv, u8* input, u8* output)
{
aes_context ctx;
u8 key[PASSPHRASE_KEY_LEN];
sc_form_key(sc_key, laid_paid, key);
aes_setkey_dec(&ctx, key, 128);
return aes_crypt_cbc(&ctx, AES_DECRYPT, PASSPHRASE_OUT_LEN, iv, input, output);
}
int vtrm_decrypt(int type, u8* iv, u8* input, u8* output)
{
return sc_decrypt(SC_ISO_SERIES_KEY_2, vtrm_get_laid_paid_from_type(type), iv, input, output);
}
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, u8* input, u8* output)
{
return sc_decrypt(SC_ISO_SERIES_INTERNAL_KEY_3, sc_combine_laid_paid(laid, paid), iv, input, output);
}
const u8* vtrm_portability_type_mapper(int type)
{
// No idea what this type stands for
switch (type)
{
// case 0: return key_for_type_1;
case 1: return SC_ISO_SERIES_KEY_2;
case 2: return SC_ISO_SERIES_KEY_1;
case 3: return SC_KEY_FOR_MASTER_2;
default:
fmt::throw_exception("vtrm_portability_type_mapper: Wrong type specified (type=%d)", type);
}
}
int vtrm_decrypt_with_portability(int type, u8* iv, u8* input, u8* output)
{
return sc_decrypt(vtrm_portability_type_mapper(type), vtrm_portability_laid_paid(), iv, input, output);
}

38
rpcs3/Crypto/utils.h Normal file
View file

@ -0,0 +1,38 @@
#pragma once
// Copyright (C) 2014 Hykem <hykem@hotmail.com>
// Licensed under the terms of the GNU GPL, version 2.0 or later versions.
// http://www.gnu.org/licenses/gpl-2.0.txt
#include "util/types.hpp"
#include <stdlib.h>
enum
{
CRYPTO_MAX_PATH = 4096
};
char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PATH]);
std::string sha256_get_hash(const char* data, usz size, bool lower_case);
// Hex string conversion auxiliary functions.
u64 hex_to_u64(const char* hex_str);
void hex_to_bytes(unsigned char* data, const char* hex_str, unsigned int str_length);
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
void aescbc128_decrypt(unsigned char* key, unsigned char* iv, unsigned char* in, unsigned char* out, usz len);
void aescbc128_encrypt(unsigned char* key, unsigned char* iv, unsigned char* in, unsigned char* out, usz len);
void aesecb128_encrypt(unsigned char* key, unsigned char* in, unsigned char* out);
bool hmac_hash_compare(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash, usz hash_len);
void hmac_hash_forge(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash);
bool cmac_hash_compare(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash, usz hash_len);
void cmac_hash_forge(unsigned char* key, int key_len, unsigned char* in, usz in_len, unsigned char* hash);
void mbedtls_zeroize(void* v, size_t n);
// SC passphrase crypto
int vtrm_decrypt(int type, u8* iv, u8* input, u8* output);
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, u8* input, u8* output);
int vtrm_decrypt_with_portability(int type, u8* iv, u8* input, u8* output);