Move to .NET Core, and use PspCrypto and LiLib, etc from chovy-sign2
This commit is contained in:
parent
47c67e61cf
commit
20115d25cb
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -2,8 +2,16 @@
|
|||
*/obj/*
|
||||
*/bin/*
|
||||
|
||||
Thumbs.Db
|
||||
|
||||
CHOVY-GEN/Debug/*
|
||||
CHOVY-GEN/Release/*
|
||||
|
||||
LiLib/bin/*
|
||||
LiLib/obj/*
|
||||
|
||||
Vita/bin/*
|
||||
Vita/lib/*
|
||||
|
||||
CHOVY-TRANSFER/obj/*
|
||||
CHOVY-TRANSFER/bin/*
|
|
@ -1,163 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="chovy-gen.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="key_vault.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{DCDBF747-DFB6-450E-A403-1C592D20EAEB}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>CHOVYGEN</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)</OutDir>
|
||||
<TargetName>CHOVY</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IgnoreImportLibrary />
|
||||
<TargetName>CHOVY</TargetName>
|
||||
<OutDir>$(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\openssl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>C:\openssl\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>ws2_32.lib;libsslMT.lib;Crypt32.lib;libcryptoMT.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>C:\openssl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>C:\openssl\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>ws2_32.lib;libsslMT.lib;Crypt32.lib;libcryptoMT.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="key_vault.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="chovy-gen.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerCommand>$(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)\CHOVY-TRANSFER.EXE</LocalDebuggerCommand>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerDebuggerType>Mixed</LocalDebuggerDebuggerType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerCommand>$(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)\CHOVY-TRANSFER.EXE</LocalDebuggerCommand>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerDebuggerType>Mixed</LocalDebuggerDebuggerType>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -1,289 +0,0 @@
|
|||
//Project Chovy - __sce_ebootpbp generator by @dots_tb and motoharu
|
||||
// With CBPS help especially: @SiliCart, @nyaaasen, @notzecoxao (and his friends?)
|
||||
|
||||
//Check out motoharu's project: https://github.com/motoharu-gosuto/psvcmd56/blob/master/src/CMD56Reversed/F00D/GcAuthMgrService.cpp#L1102
|
||||
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#include "key_vault.h"
|
||||
PACK(typedef struct
|
||||
{
|
||||
uint8_t r[0x1c];
|
||||
uint8_t s[0x1c];
|
||||
} ECDSA_SIG_0x1c);
|
||||
|
||||
PACK(typedef struct sce_ebootpbp {
|
||||
uint64_t magic;
|
||||
uint32_t key_type;// set to 1 (maybe keytype?)
|
||||
uint32_t type;// 03 - ps1, 02 - psp
|
||||
uint8_t np_title[0x30];
|
||||
uint64_t aid;
|
||||
uint64_t secure_tick;
|
||||
uint64_t filesz;
|
||||
uint64_t sw_ver;
|
||||
uint8_t padding[0xf8];
|
||||
ECDSA_SIG_0x1c ebootpbp_hdr_sig;
|
||||
ECDSA_SIG_0x1c NPUMDIMG_sig;
|
||||
ECDSA_SIG_0x1c sceebootpbp_sig;
|
||||
} sce_ebootpbp);
|
||||
|
||||
|
||||
typedef struct pbp_hdr {
|
||||
uint32_t magic;
|
||||
uint32_t unk;
|
||||
uint32_t sfo_offset;
|
||||
uint32_t icon0_offset;
|
||||
uint32_t icon1_offset;
|
||||
uint32_t pic0_offset;
|
||||
uint32_t pic1_offset;
|
||||
uint32_t snd0_offset;
|
||||
uint32_t data_psp_offset;
|
||||
uint32_t data_psar_offset;
|
||||
} pbp_hdr;
|
||||
|
||||
|
||||
#define PSAR_SZ 0x1C0000
|
||||
#define WORK_BUF_SZ 0x7c0
|
||||
|
||||
|
||||
//based motoharu
|
||||
__declspec(dllexport) int can_be_reversed_80C17A(const uint8_t* src, int some_size, uint8_t* iv, uint8_t* src_xored_digest)
|
||||
{
|
||||
unsigned char src_xored[0x20];
|
||||
memcpy(src_xored, iv, 0x20);
|
||||
|
||||
if (some_size > 0x20)
|
||||
return 0x12;
|
||||
|
||||
for(int i = 0; i < some_size; i++)
|
||||
src_xored[i] = src[i] ^ iv[i];
|
||||
|
||||
int r0;
|
||||
|
||||
SHA256_CTX sha256_ctx;
|
||||
SHA256_Init(&sha256_ctx);
|
||||
SHA256_Update(&sha256_ctx, src_xored, 0x20);
|
||||
r0 = SHA256_Final(src_xored_digest, &sha256_ctx);
|
||||
if(r0 != 1)
|
||||
return 0x11;
|
||||
|
||||
for(int i = 0; i < 0x20; i++)
|
||||
iv[i] = src_xored_digest[i] ^ iv[i];
|
||||
|
||||
for(int i = 0; i < 0x20; i++)
|
||||
{
|
||||
if(iv[i] != 0xFF)
|
||||
{
|
||||
iv[i] = iv[i] + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
iv[i] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
__declspec(dllexport) int f00d_KIRK0x22(const uint8_t *hash, ECDSA_SIG_0x1c *signature, int key_sel) {
|
||||
|
||||
|
||||
uint8_t hmac_in[0x38];
|
||||
uint8_t hmac_hash_iv[0x38];
|
||||
memcpy(&hmac_in, hash, 0x1c);
|
||||
memcpy(&hmac_in[0x1c], &keyvault_ec_privkey[key_sel], 0x1c);
|
||||
|
||||
HMAC_CTX *hmac_ctx = HMAC_CTX_new();
|
||||
HMAC_Init_ex(hmac_ctx, &hmac_key_0x22, 0x40, EVP_sha256(), NULL);
|
||||
HMAC_Update(hmac_ctx, &hmac_in, 0x1c << 1);
|
||||
unsigned int len;
|
||||
HMAC_Final(hmac_ctx, &hmac_hash_iv, &len);
|
||||
HMAC_CTX_free(hmac_ctx);
|
||||
|
||||
uint8_t sha256_out[0x40];
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = can_be_reversed_80C17A(hash, 0x1c, hmac_hash_iv, &sha256_out[0]);
|
||||
if(ret != 0 || (ret = can_be_reversed_80C17A(hash, 0x1c, hmac_hash_iv, &sha256_out[0x20])) != 0)
|
||||
return 0;
|
||||
|
||||
} while(ret != 0);
|
||||
|
||||
//ECDSA
|
||||
|
||||
BIGNUM *a = BN_bin2bn(keyvault_ec_a, 0x1c, NULL),
|
||||
*b = BN_bin2bn(keyvault_ec_b, 0x1c, NULL),
|
||||
*p = BN_bin2bn(keyvault_ec_p, 0x1c, NULL),
|
||||
*order = BN_bin2bn(keyvault_ec_N, 0x1c, NULL),
|
||||
*x = BN_bin2bn(keyvault_ec_Gx, 0x1c, NULL),
|
||||
*y = BN_bin2bn(keyvault_ec_Gy, 0x1c, NULL),
|
||||
*priv_key = BN_bin2bn(keyvault_ec_privkey[key_sel], 0x1c, NULL),
|
||||
*m = BN_bin2bn(sha256_out, 0x3c, NULL);
|
||||
|
||||
BN_CTX *bn_ctx = BN_CTX_new();
|
||||
BN_MONT_CTX *bn_mon_ctx = BN_MONT_CTX_new();
|
||||
BN_MONT_CTX_set(bn_mon_ctx, order, bn_ctx);
|
||||
|
||||
EC_GROUP *curve = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx);
|
||||
EC_POINT *generator = EC_POINT_new(curve);
|
||||
EC_POINT_set_affine_coordinates_GFp(curve, generator, x, y, bn_ctx);
|
||||
EC_GROUP_set_generator(curve, generator, order, NULL);
|
||||
|
||||
EC_KEY *eckey=EC_KEY_new();
|
||||
EC_KEY_set_group(eckey,curve);
|
||||
EC_KEY_set_private_key(eckey, priv_key);
|
||||
|
||||
|
||||
m = BN_bin2bn(sha256_out, 0x3c, NULL);
|
||||
BN_mod(m, m, order, bn_ctx);
|
||||
|
||||
|
||||
|
||||
//Generate R in order to get custom "random number"
|
||||
BIGNUM *sig_r = BN_new();
|
||||
EC_POINT_mul(curve, generator, m, NULL, NULL, bn_ctx);
|
||||
EC_POINT_get_affine_coordinates_GFp(curve, generator, sig_r, NULL, bn_ctx);
|
||||
BN_nnmod(sig_r, sig_r, order, bn_ctx);
|
||||
|
||||
//Generate M^-1
|
||||
BIGNUM *exp = BN_new();
|
||||
BIGNUM *minv = BN_new();
|
||||
|
||||
BN_set_word(exp, (BN_ULONG)2);
|
||||
BN_sub(exp, order, exp);
|
||||
BN_mod_exp_mont(minv, m, exp, order, bn_ctx, bn_mon_ctx);
|
||||
|
||||
|
||||
ECDSA_SIG *sig = ECDSA_do_sign_ex(hash, 0x1c, minv, sig_r, eckey);
|
||||
|
||||
|
||||
if(!sig) {
|
||||
ret = 0;
|
||||
goto error;
|
||||
|
||||
}
|
||||
BIGNUM *sig_s;
|
||||
ECDSA_SIG_get0(sig, NULL, &sig_s);
|
||||
BN_bn2bin(sig_r, &signature->r);
|
||||
BN_bn2bin(sig_s, &signature->s);
|
||||
ECDSA_SIG_free(sig);
|
||||
//BN_free(sig_s);
|
||||
ret = 1;
|
||||
|
||||
error:
|
||||
BN_free(sig_r);
|
||||
|
||||
EC_POINT_free(generator);
|
||||
BN_free(y);
|
||||
BN_free(x);
|
||||
BN_free(order);
|
||||
BN_free(p);
|
||||
BN_free(b);
|
||||
BN_free(a);
|
||||
BN_free(minv);
|
||||
BN_free(exp);
|
||||
BN_free(priv_key);
|
||||
BN_CTX_free(bn_ctx);
|
||||
BN_MONT_CTX_free(bn_mon_ctx);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
__declspec(dllexport) int chovy_gen(char *ebootpbp, uint64_t signaid, char *outscefile)
|
||||
{
|
||||
|
||||
int ret = 1;
|
||||
FILE *fin = 0, *fout = 0;
|
||||
|
||||
uint8_t *work_buf = (unsigned char*) calloc (1, WORK_BUF_SZ);
|
||||
sce_ebootpbp *sceebootpbp_file = (unsigned char*) calloc (1, sizeof(sce_ebootpbp));
|
||||
|
||||
|
||||
fin = fopen(ebootpbp, "rb");
|
||||
if (!fin) {
|
||||
|
||||
goto error;
|
||||
}
|
||||
memcpy(&sceebootpbp_file->magic, "NPUMDSIG", 0x8);
|
||||
sceebootpbp_file->type = 2;
|
||||
sceebootpbp_file->key_type = 1;
|
||||
sceebootpbp_file->aid = signaid;
|
||||
|
||||
|
||||
fseek(fin, 0, SEEK_END);
|
||||
sceebootpbp_file->filesz = ftell(fin);
|
||||
|
||||
pbp_hdr hdr;
|
||||
fseek(fin, 0, SEEK_SET);
|
||||
fread(&hdr, sizeof(pbp_hdr),1,fin);
|
||||
|
||||
|
||||
fseek(fin, 0, SEEK_SET);
|
||||
fread(work_buf, hdr.icon0_offset, 1,fin);
|
||||
|
||||
uint8_t work_hash[0x1c];
|
||||
SHA256_CTX sha256_ctx;
|
||||
SHA224_Init(&sha256_ctx);
|
||||
SHA224_Update(&sha256_ctx, work_buf, hdr.icon0_offset);
|
||||
SHA224_Final(work_hash, &sha256_ctx);
|
||||
f00d_KIRK0x22(work_hash, &sceebootpbp_file->ebootpbp_hdr_sig, sceebootpbp_file->key_type);
|
||||
|
||||
SHA224_Init(&sha256_ctx);
|
||||
fseek(fin, hdr.data_psar_offset, SEEK_SET);
|
||||
|
||||
size_t size = PSAR_SZ;
|
||||
int to_read = size > WORK_BUF_SZ ? WORK_BUF_SZ : size;
|
||||
|
||||
|
||||
fread(work_buf, to_read, 1,fin);
|
||||
if(memcmp(work_buf, "NPUMDIMG", 0x8) == 0)
|
||||
memcpy(&sceebootpbp_file->np_title, work_buf + 0x10, sizeof(sceebootpbp_file->np_title));
|
||||
else {
|
||||
memcpy(&sceebootpbp_file->magic, "NPPS1SIG", sizeof(sceebootpbp_file->magic));
|
||||
sceebootpbp_file->type = 3;
|
||||
}
|
||||
|
||||
do {
|
||||
size -= to_read;
|
||||
SHA224_Update(&sha256_ctx, work_buf, to_read);
|
||||
to_read = size > WORK_BUF_SZ ? WORK_BUF_SZ : size;
|
||||
fread(work_buf, to_read, 1,fin);
|
||||
} while(size > 0);
|
||||
|
||||
SHA224_Final(work_hash, &sha256_ctx);
|
||||
|
||||
f00d_KIRK0x22(work_hash, &sceebootpbp_file->NPUMDIMG_sig, sceebootpbp_file->key_type);
|
||||
|
||||
SHA224_Init(&sha256_ctx);
|
||||
SHA224_Update(&sha256_ctx, sceebootpbp_file, 0x1C8);
|
||||
SHA224_Final(work_hash, &sha256_ctx);
|
||||
|
||||
f00d_KIRK0x22(work_hash, &sceebootpbp_file->sceebootpbp_sig, sceebootpbp_file->key_type);
|
||||
|
||||
fout = fopen(outscefile, "wb");
|
||||
if (!fout) {
|
||||
goto error;
|
||||
}
|
||||
fwrite(sceebootpbp_file, 1, sizeof(sce_ebootpbp), fout);
|
||||
|
||||
ret = 0;
|
||||
error:
|
||||
if (fin)
|
||||
fclose(fin);
|
||||
if (fout)
|
||||
fclose(fout);
|
||||
free(work_buf);
|
||||
free(sceebootpbp_file);
|
||||
return ret;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
uint8_t keyvault_ec_p[0x1c] = {0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0F};
|
||||
uint8_t keyvault_ec_a[0x1c] = {0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0C};
|
||||
uint8_t keyvault_ec_b[0x1c] = {0x90, 0x65, 0x94, 0x1D, 0x29, 0x37, 0x4A, 0x8F, 0x11, 0xDD, 0x1E, 0x54, 0x01, 0x89, 0x43, 0x4E, 0x4A, 0x6E, 0xBF, 0xAF, 0x54, 0x77, 0xF6, 0xC1, 0x72, 0xF6, 0x85, 0x5E};
|
||||
uint8_t keyvault_ec_N[0x1c] = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x52, 0x26, 0x98, 0xDE, 0xEF, 0x58, 0xDB, 0x1A, 0xD9, 0xAB, 0x7F, 0x04, 0xE3, 0xAE, 0x7F};
|
||||
uint8_t keyvault_ec_Gx[0x1c] = {0x7E, 0x06, 0x09, 0x82, 0x47, 0xE6, 0xB5, 0x9F, 0x31, 0x10, 0xBC, 0xBB, 0x3A, 0xB6, 0xC2, 0x50, 0xBC, 0x5A, 0xB0, 0x6C, 0x03, 0x2D, 0xAD, 0x43, 0x68, 0x4C, 0x24, 0x8F};
|
||||
uint8_t keyvault_ec_Gy[0x1c] = {0x0B, 0xD9, 0x41, 0x8D, 0xE8, 0xE3, 0xE4, 0x5D, 0x2D, 0x70, 0x1E, 0x02, 0x37, 0xFD, 0x7F, 0x2A, 0xDE, 0x0D, 0x48, 0xB7, 0x4C, 0xEE, 0xF2, 0xF1, 0xC8, 0xAC, 0x48, 0x4E};
|
||||
uint8_t keyvault_ec_pubkey[2][0x38] = {
|
||||
{0x5F, 0x9D, 0x17, 0x1A, 0x2B, 0xDD, 0xA8, 0xD4, 0x08, 0x78, 0xBF, 0x98, 0x5A, 0xC3, 0x26, 0xED, 0x5E, 0xFF, 0x43, 0xC9, 0x37, 0x6C, 0x77, 0xEC, 0x0A, 0x00, 0xC7, 0xBB, 0xA3, 0x44, 0xE4, 0x4E, 0x6E, 0xAC, 0x25, 0x52, 0x35, 0xF9, 0x54, 0xF5, 0xB6, 0x17, 0xC7, 0xBD, 0x49, 0xF1, 0x80, 0x26, 0x24, 0x54, 0xAA, 0xE1, 0xB6, 0x2A, 0x9F, 0x2C},
|
||||
{0x67, 0x00, 0x2D, 0x9B, 0xB8, 0xE4, 0x2D, 0x2B, 0xF9, 0x61, 0x0B, 0x27, 0xFE, 0xAB, 0x9B, 0x34, 0x56, 0x15, 0x50, 0x92, 0x13, 0x12, 0xDF, 0xEE, 0x7A, 0x3A, 0x86, 0xEC, 0x6C, 0xA7, 0x14, 0x42, 0x6F, 0x6D, 0x4E, 0x96, 0x09, 0xA6, 0x38, 0xBF, 0x4A, 0xFB, 0x18, 0x2B, 0xFA, 0x50, 0xC8, 0x2F, 0xF2, 0xB4, 0xC5, 0xEC, 0x6C, 0xCD, 0x97, 0x65}
|
||||
};
|
||||
|
||||
uint8_t keyvault_ec_privkey[2][0x1c] = {
|
||||
{0x76, 0x74, 0x36, 0xA6, 0x99, 0x9D, 0x88, 0x48, 0x0E, 0xC8, 0x56, 0xF5, 0x5C, 0xEA, 0xBB, 0x43, 0x96, 0x85, 0x9E, 0x37, 0x45, 0x99, 0x40, 0x39, 0x21, 0xF5, 0x55, 0x98},
|
||||
{0x60, 0x7A, 0x2E, 0x55, 0x68, 0xB4, 0xB9, 0xA0, 0x32, 0xF4, 0x52, 0x53, 0xCF, 0xED, 0x20, 0xDB, 0x2E, 0x6E, 0x44, 0x6C, 0x37, 0x82, 0xE8, 0x2A, 0x1A, 0xB9, 0xC9, 0x23}
|
||||
};
|
||||
|
||||
uint8_t hmac_key_0x22[0x40] = {0x54, 0x88, 0xA9, 0x81, 0x1C, 0x9A, 0x2C, 0xBC, 0xCC, 0x59, 0x6B, 0x1F, 0xAD, 0x1A, 0x7E, 0x29, 0xE0, 0x75, 0x84, 0x0F, 0x47, 0x43, 0x1F, 0x37, 0xAC, 0x06, 0x02, 0x46, 0x4A, 0x27, 0x9E, 0x02, 0xDF, 0x2E, 0x71, 0x65, 0xF1, 0x13, 0x7B, 0xF6, 0x9A, 0xE6, 0xDC, 0xB9, 0xDC, 0x38, 0x8C, 0x9D, 0xCC, 0xB3, 0x64, 0xC4, 0xCA, 0x26, 0xCB, 0x8F, 0x1A, 0xF0, 0x63, 0x8A, 0x6E, 0xAD, 0xB5, 0x4D};
|
|
@ -1,11 +1,12 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.76
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33205.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CHOVY-TRANSFER", "CHOVY-TRANSFER\CHOVY-TRANSFER.csproj", "{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CHOVY-TRANSFER", "CHOVY-TRANSFER\CHOVY-TRANSFER.csproj", "{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CHOVY-GEN", "CHOVY-GEN\CHOVY-GEN.vcxproj", "{DCDBF747-DFB6-450E-A403-1C592D20EAEB}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PspCrypto", "PspCrypto\PspCrypto.csproj", "{C93D6CE7-989F-4C89-A29B-9684C9297184}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vita", "Vita\Vita.csproj", "{8463BD1A-EC79-4469-A383-26020298F512}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -29,20 +30,35 @@ Global
|
|||
{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x64.Build.0 = Debug|x64
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Debug|x86.Build.0 = Debug|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x64.ActiveCfg = Release|x64
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x64.Build.0 = Release|x64
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x86.ActiveCfg = Release|Win32
|
||||
{DCDBF747-DFB6-450E-A403-1C592D20EAEB}.Release|x86.Build.0 = Release|Win32
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C93D6CE7-989F-4C89-A29B-9684C9297184}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8463BD1A-EC79-4469-A383-26020298F512}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D2939D13-1FC7-4C9B-95D9-BA3B53E08138}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
<configuration>
|
||||
<startup>
|
||||
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup>
|
||||
</configuration>
|
||||
|
|
|
@ -1,107 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}</ProjectGuid>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>CHOVY_TRANSFER</RootNamespace>
|
||||
<AssemblyName>CHOVY-TRANS</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>chovy-trans.ico</ApplicationIcon>
|
||||
<AssemblyTitle>CHOVY-TRANSFER</AssemblyTitle>
|
||||
<Product>CHOVY-TRANSFER</Product>
|
||||
<Copyright>Copyright © 2019</Copyright>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BouncyCastle.Crypto, Version=1.8.5.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
|
||||
<HintPath>..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DotNetZip, Version=1.13.4.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DotNetZip.1.13.4\lib\net40\DotNetZip.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CHOVYTRANSFER.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="CHOVYTRANSFER.Designer.cs">
|
||||
<DependentUpon>CHOVYTRANSFER.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="cmakeys.cs" />
|
||||
<Compile Include="param.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PSVIMGBuilder.cs" />
|
||||
<Compile Include="PSVIMGStructs.cs" />
|
||||
<Compile Include="PSVMDBuilder.cs" />
|
||||
<EmbeddedResource Include="CHOVYTRANSFER.resx">
|
||||
<DependentUpon>CHOVYTRANSFER.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="chovy-trans.ico" />
|
||||
<None Include="chovytrans.gif" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PspCrypto\PspCrypto.csproj" />
|
||||
<ProjectReference Include="..\Vita\Vita.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
11
CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user
Normal file
11
CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<_LastSelectedProfileId>C:\Users\Li\Documents\git\chovy-trans\CHOVY-TRANSFER\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="CHOVYTRANSFER.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
101
CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs
generated
101
CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs
generated
|
@ -84,9 +84,10 @@
|
|||
"X:\\",
|
||||
"Y:\\",
|
||||
"Z:\\"});
|
||||
this.driveLetterSrc.Location = new System.Drawing.Point(74, 12);
|
||||
this.driveLetterSrc.Location = new System.Drawing.Point(86, 14);
|
||||
this.driveLetterSrc.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.driveLetterSrc.Name = "driveLetterSrc";
|
||||
this.driveLetterSrc.Size = new System.Drawing.Size(41, 21);
|
||||
this.driveLetterSrc.Size = new System.Drawing.Size(47, 23);
|
||||
this.driveLetterSrc.TabIndex = 1;
|
||||
this.driveLetterSrc.SelectedIndexChanged += new System.EventHandler(this.driveLetterSrc_SelectedIndexChanged);
|
||||
//
|
||||
|
@ -95,15 +96,18 @@
|
|||
this.pspFolder.BackColor = System.Drawing.Color.DimGray;
|
||||
this.pspFolder.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pspFolder.ForeColor = System.Drawing.Color.Lime;
|
||||
this.pspFolder.Location = new System.Drawing.Point(121, 13);
|
||||
this.pspFolder.Location = new System.Drawing.Point(141, 15);
|
||||
this.pspFolder.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.pspFolder.Name = "pspFolder";
|
||||
this.pspFolder.Size = new System.Drawing.Size(194, 20);
|
||||
this.pspFolder.Size = new System.Drawing.Size(226, 23);
|
||||
this.pspFolder.TabIndex = 2;
|
||||
this.pspFolder.Text = "PSP";
|
||||
this.pspFolder.TextChanged += new System.EventHandler(this.pspFolder_TextChanged);
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.groupBox1.BackColor = System.Drawing.Color.Black;
|
||||
this.groupBox1.Controls.Add(this.cmaDir);
|
||||
this.groupBox1.Controls.Add(this.driveLetterDst);
|
||||
|
@ -112,21 +116,26 @@
|
|||
this.groupBox1.Controls.Add(this.driveLetterSrc);
|
||||
this.groupBox1.Controls.Add(this.pspFolder);
|
||||
this.groupBox1.ForeColor = System.Drawing.Color.Lime;
|
||||
this.groupBox1.Location = new System.Drawing.Point(162, 12);
|
||||
this.groupBox1.Location = new System.Drawing.Point(189, 14);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(622, 41);
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.groupBox1.Size = new System.Drawing.Size(726, 47);
|
||||
this.groupBox1.TabIndex = 3;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Directories";
|
||||
//
|
||||
// cmaDir
|
||||
//
|
||||
this.cmaDir.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cmaDir.BackColor = System.Drawing.Color.DimGray;
|
||||
this.cmaDir.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.cmaDir.ForeColor = System.Drawing.Color.Lime;
|
||||
this.cmaDir.Location = new System.Drawing.Point(439, 14);
|
||||
this.cmaDir.Location = new System.Drawing.Point(512, 14);
|
||||
this.cmaDir.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.cmaDir.Name = "cmaDir";
|
||||
this.cmaDir.Size = new System.Drawing.Size(177, 20);
|
||||
this.cmaDir.Size = new System.Drawing.Size(206, 23);
|
||||
this.cmaDir.TabIndex = 6;
|
||||
this.cmaDir.Text = "Users\\XXX\\Documents\\PS Vita";
|
||||
this.cmaDir.TextChanged += new System.EventHandler(this.cmaDir_TextChanged);
|
||||
|
@ -166,59 +175,70 @@
|
|||
"X:\\",
|
||||
"Y:\\",
|
||||
"Z:\\"});
|
||||
this.driveLetterDst.Location = new System.Drawing.Point(392, 12);
|
||||
this.driveLetterDst.Location = new System.Drawing.Point(457, 13);
|
||||
this.driveLetterDst.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.driveLetterDst.Name = "driveLetterDst";
|
||||
this.driveLetterDst.Size = new System.Drawing.Size(41, 21);
|
||||
this.driveLetterDst.Size = new System.Drawing.Size(47, 23);
|
||||
this.driveLetterDst.TabIndex = 5;
|
||||
this.driveLetterDst.SelectedIndexChanged += new System.EventHandler(this.driveLetterDst_SelectedIndexChanged);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(321, 16);
|
||||
this.label2.Location = new System.Drawing.Point(376, 17);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(65, 13);
|
||||
this.label2.Size = new System.Drawing.Size(73, 15);
|
||||
this.label2.TabIndex = 4;
|
||||
this.label2.Text = "CMA Folder:";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(11, 16);
|
||||
this.label1.Location = new System.Drawing.Point(13, 18);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(63, 13);
|
||||
this.label1.Size = new System.Drawing.Size(66, 15);
|
||||
this.label1.TabIndex = 3;
|
||||
this.label1.Text = "PSP Folder:";
|
||||
//
|
||||
// pspGames
|
||||
//
|
||||
this.pspGames.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.pspGames.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.pspGames.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pspGames.ForeColor = System.Drawing.Color.Lime;
|
||||
this.pspGames.FormattingEnabled = true;
|
||||
this.pspGames.Location = new System.Drawing.Point(162, 73);
|
||||
this.pspGames.ItemHeight = 15;
|
||||
this.pspGames.Location = new System.Drawing.Point(189, 84);
|
||||
this.pspGames.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.pspGames.Name = "pspGames";
|
||||
this.pspGames.Size = new System.Drawing.Size(622, 223);
|
||||
this.pspGames.Size = new System.Drawing.Size(725, 257);
|
||||
this.pspGames.TabIndex = 4;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.ForeColor = System.Drawing.Color.Lime;
|
||||
this.label3.Location = new System.Drawing.Point(159, 56);
|
||||
this.label3.Location = new System.Drawing.Point(186, 65);
|
||||
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(82, 13);
|
||||
this.label3.Size = new System.Drawing.Size(86, 15);
|
||||
this.label3.TabIndex = 5;
|
||||
this.label3.Text = "Games on PSP:";
|
||||
//
|
||||
// transVita
|
||||
//
|
||||
this.transVita.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.transVita.BackColor = System.Drawing.Color.Black;
|
||||
this.transVita.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.transVita.ForeColor = System.Drawing.Color.Red;
|
||||
this.transVita.Location = new System.Drawing.Point(649, 302);
|
||||
this.transVita.Location = new System.Drawing.Point(757, 348);
|
||||
this.transVita.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.transVita.Name = "transVita";
|
||||
this.transVita.Size = new System.Drawing.Size(135, 23);
|
||||
this.transVita.Size = new System.Drawing.Size(158, 27);
|
||||
this.transVita.TabIndex = 6;
|
||||
this.transVita.Text = "MOV 1, PSVITA";
|
||||
this.transVita.UseVisualStyleBackColor = false;
|
||||
|
@ -227,56 +247,68 @@
|
|||
//
|
||||
// progressBar
|
||||
//
|
||||
this.progressBar.Location = new System.Drawing.Point(202, 302);
|
||||
this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBar.Location = new System.Drawing.Point(236, 348);
|
||||
this.progressBar.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.progressBar.Name = "progressBar";
|
||||
this.progressBar.Size = new System.Drawing.Size(441, 23);
|
||||
this.progressBar.Size = new System.Drawing.Size(514, 27);
|
||||
this.progressBar.TabIndex = 7;
|
||||
//
|
||||
// progressStatus
|
||||
//
|
||||
this.progressStatus.AutoSize = true;
|
||||
this.progressStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.progressStatus.ForeColor = System.Drawing.Color.Lime;
|
||||
this.progressStatus.Location = new System.Drawing.Point(159, 307);
|
||||
this.progressStatus.Location = new System.Drawing.Point(186, 354);
|
||||
this.progressStatus.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.progressStatus.Name = "progressStatus";
|
||||
this.progressStatus.Size = new System.Drawing.Size(21, 13);
|
||||
this.progressStatus.Size = new System.Drawing.Size(42, 17);
|
||||
this.progressStatus.TabIndex = 8;
|
||||
this.progressStatus.Text = "0%";
|
||||
this.progressStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.pictureBox1.BackgroundImage = global::CHOVY_TRANSFER.Properties.Resources.chovytrans;
|
||||
this.pictureBox1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
|
||||
this.pictureBox1.Location = new System.Drawing.Point(9, 8);
|
||||
this.pictureBox1.Location = new System.Drawing.Point(10, 9);
|
||||
this.pictureBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(144, 330);
|
||||
this.pictureBox1.Size = new System.Drawing.Size(168, 381);
|
||||
this.pictureBox1.TabIndex = 9;
|
||||
this.pictureBox1.TabStop = false;
|
||||
//
|
||||
// dexToggle
|
||||
//
|
||||
this.dexToggle.Location = new System.Drawing.Point(781, 0);
|
||||
this.dexToggle.Location = new System.Drawing.Point(911, 0);
|
||||
this.dexToggle.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.dexToggle.Name = "dexToggle";
|
||||
this.dexToggle.Size = new System.Drawing.Size(16, 16);
|
||||
this.dexToggle.Size = new System.Drawing.Size(19, 18);
|
||||
this.dexToggle.TabIndex = 10;
|
||||
this.dexToggle.TabStop = false;
|
||||
this.dexToggle.Click += new System.EventHandler(this.dexToggle_Click);
|
||||
//
|
||||
// currentFile
|
||||
//
|
||||
this.currentFile.AutoSize = true;
|
||||
this.currentFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.currentFile.ForeColor = System.Drawing.Color.Lime;
|
||||
this.currentFile.Location = new System.Drawing.Point(173, 328);
|
||||
this.currentFile.Location = new System.Drawing.Point(186, 378);
|
||||
this.currentFile.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.currentFile.Name = "currentFile";
|
||||
this.currentFile.Size = new System.Drawing.Size(55, 13);
|
||||
this.currentFile.Size = new System.Drawing.Size(728, 17);
|
||||
this.currentFile.TabIndex = 11;
|
||||
this.currentFile.Text = "Waiting ...";
|
||||
this.currentFile.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// CHOVYTRANSFER
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.Black;
|
||||
this.ClientSize = new System.Drawing.Size(796, 350);
|
||||
this.ClientSize = new System.Drawing.Size(929, 404);
|
||||
this.Controls.Add(this.currentFile);
|
||||
this.Controls.Add(this.dexToggle);
|
||||
this.Controls.Add(this.pictureBox1);
|
||||
|
@ -287,6 +319,7 @@
|
|||
this.Controls.Add(this.pspGames);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "CHOVYTRANSFER";
|
||||
this.Text = "Chovy-Transfer";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CHOVYTRANSFER_FormClosing);
|
||||
|
|
|
@ -2,22 +2,42 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Param_SFO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using KeyDerivation;
|
||||
using PSVIMGTOOLS;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Li.Progress;
|
||||
using Param;
|
||||
using PspCrypto;
|
||||
using Vita.ContentManager;
|
||||
using Vita.PsvImgTools;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CHOVY_TRANSFER
|
||||
{
|
||||
public partial class CHOVYTRANSFER : Form
|
||||
{
|
||||
[DllImport("CHOVY.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int chovy_gen(string ebootpbp, UInt64 AID, string outscefile);
|
||||
const int FW_VERSION = 0x3600000;
|
||||
private byte[] chovy_gen(string ebootpbp, UInt64 AID)
|
||||
{
|
||||
bool ps1 = IsPs1(ebootpbp);
|
||||
using (FileStream fs = File.OpenRead(ebootpbp))
|
||||
{
|
||||
byte[] ebootSig = new byte[0x200];
|
||||
SceNpDrm.Aid = AID;
|
||||
|
||||
if(ps1)
|
||||
SceNpDrm.KsceNpDrmEbootSigGenPs1(fs, ebootSig, FW_VERSION);
|
||||
else
|
||||
SceNpDrm.KsceNpDrmEbootSigGenPsp(fs, ebootSig, FW_VERSION);
|
||||
|
||||
return ebootSig;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDexAidSet()
|
||||
{
|
||||
|
@ -31,55 +51,6 @@ namespace CHOVY_TRANSFER
|
|||
return true;
|
||||
}
|
||||
}
|
||||
public string GetCmaDir()
|
||||
{
|
||||
string Dir = "";
|
||||
try
|
||||
{
|
||||
//try qcma
|
||||
Dir = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma").GetValue("appsPath").ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
//try sony cma
|
||||
Dir = Registry.CurrentUser.OpenSubKey(@"Software\Sony Corporation\Content Manager Assistant\Settings").GetValue("ApplicationHomePath").ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
//try devkit cma
|
||||
Dir = Registry.CurrentUser.OpenSubKey(@"Software\SCE\PSP2\Services\Content Manager Assistant for PlayStation(R)Vita DevKit\Settings").GetValue("ApplicationHomePath").ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
string DefaultDir = Path.Combine(Environment.GetEnvironmentVariable("HOMEDRIVE"), Environment.GetEnvironmentVariable("HOMEPATH"), "Documents", "PS Vita");
|
||||
if (Directory.Exists(DefaultDir))
|
||||
{
|
||||
Dir = DefaultDir;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ReadSetting("CmaDir") != "")
|
||||
{
|
||||
Dir = ReadSetting("CmaDir");
|
||||
}
|
||||
|
||||
return Dir.Replace("/","\\");
|
||||
}
|
||||
|
||||
|
||||
public string ReadSetting(string Setting)
|
||||
{
|
||||
|
@ -160,13 +131,10 @@ namespace CHOVY_TRANSFER
|
|||
string Title = GetTitleFromPbp(EbootPbp);
|
||||
string ContentId = GetContentIdFromPbp(EbootPbp);
|
||||
|
||||
string LicenseFile = Path.Combine(PspDir, "LICENSE", ContentId + ".RIF");
|
||||
|
||||
string LicenseFile = Path.Combine(PspDir, "LICENSE", ContentId);
|
||||
|
||||
if (TitleId.Length == 9 && File.Exists(LicenseFile));
|
||||
{
|
||||
if (TitleId.Length == 9 && File.Exists(LicenseFile))
|
||||
pspGames.Items.Add(TitleId + " - " + Title);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception) { };
|
||||
|
@ -194,12 +162,8 @@ namespace CHOVY_TRANSFER
|
|||
public string GetTitleFromPbp(string pbp)
|
||||
{
|
||||
byte[] SfoData = GetSfo(pbp);
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(SfoData, 0x00, SfoData.Length))
|
||||
{
|
||||
PARAM_SFO sfo = new PARAM_SFO(ms);
|
||||
return sfo.Title;
|
||||
}
|
||||
Sfo sfo = Sfo.ReadSfo(SfoData);
|
||||
return sfo["TITLE"] as String;
|
||||
}
|
||||
|
||||
public byte[] GetSfo(string pbp)
|
||||
|
@ -338,8 +302,14 @@ namespace CHOVY_TRANSFER
|
|||
pspFolder.Text = PspDir;
|
||||
}
|
||||
|
||||
string cmaDir = ReadSetting("CmaDir");
|
||||
if(cmaDir == "")
|
||||
cmaDir = SettingsReader.BackupsFolder;
|
||||
|
||||
SettingsReader.BackupsFolder = cmaDir;
|
||||
|
||||
ChangePspDir(FindPspDir());
|
||||
ChangeCmaDir(GetCmaDir());
|
||||
ChangeCmaDir(SettingsReader.BackupsFolder);
|
||||
PopulatePspGameList();
|
||||
}
|
||||
|
||||
|
@ -356,11 +326,13 @@ namespace CHOVY_TRANSFER
|
|||
|
||||
private void cmaDir_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
WriteSetting("CmaDir", Path.Combine(driveLetterDst.Text, cmaDir.Text));
|
||||
string dir = Path.Combine(driveLetterDst.Text, cmaDir.Text);
|
||||
WriteSetting("CmaDir", dir);
|
||||
SettingsReader.BackupsFolder = dir;
|
||||
}
|
||||
private void driveLetterDst_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
WriteSetting("CmaDir", Path.Combine(driveLetterDst.Text, cmaDir.Text));
|
||||
cmaDir_TextChanged(sender, e);
|
||||
}
|
||||
private void transVita_EnabledChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
@ -376,10 +348,10 @@ namespace CHOVY_TRANSFER
|
|||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
private void transVita_Click(object sender, EventArgs e)
|
||||
private async void transVita_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
if(!Directory.Exists(Path.Combine(driveLetterDst.Text, cmaDir.Text)))
|
||||
if(!Directory.Exists(SettingsReader.BackupsFolder))
|
||||
{
|
||||
MessageBox.Show("CMA Folder Doesn't Exist", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
|
@ -404,19 +376,23 @@ namespace CHOVY_TRANSFER
|
|||
cmaDir.ReadOnly = true;
|
||||
pspGames.Enabled = false;
|
||||
|
||||
bool isDlc = false;
|
||||
|
||||
string titleId = pspGames.SelectedItem.ToString().Substring(0, 9);
|
||||
string gameFolder = Path.Combine(driveLetterSrc.Text, pspFolder.Text, "GAME", titleId);
|
||||
string pspDir = Path.Combine(driveLetterSrc.Text, pspFolder.Text);
|
||||
string gameFolder = Path.Combine(pspDir, "GAME", titleId);
|
||||
string ebootFile = Path.Combine(gameFolder, "EBOOT.PBP");
|
||||
if (!File.Exists(ebootFile))
|
||||
{
|
||||
isDlc = true;
|
||||
ebootFile = Path.Combine(gameFolder, "PARAM.PBP");
|
||||
}
|
||||
|
||||
List<string> licenseFiles = new List<string>();
|
||||
string cid = GetContentIdFromPbp(ebootFile);
|
||||
licenseFiles.Add(Path.Combine(driveLetterSrc.Text, pspFolder.Text, "LICENSE", cid + ".RIF"));
|
||||
licenseFiles.Add(Path.Combine(pspDir, "LICENSE", cid + ".RIF"));
|
||||
string sigFile = Path.Combine(gameFolder, "__sce_ebootpbp");
|
||||
string backupDir = Path.Combine(driveLetterDst.Text, cmaDir.Text);
|
||||
|
||||
bool isDlc = Path.GetFileName(gameFolder) == "PARAM.PBP";
|
||||
bool isPs1 = IsPs1(ebootFile);
|
||||
|
||||
if (!File.Exists(licenseFiles.First()))
|
||||
|
@ -444,29 +420,10 @@ namespace CHOVY_TRANSFER
|
|||
File.Delete(sigFile);
|
||||
}
|
||||
|
||||
int ChovyGenRes = 100;
|
||||
Thread ChovyGen = new Thread(() =>
|
||||
{
|
||||
ChovyGenRes = chovy_gen(ebootFile, uAid, sigFile);
|
||||
});
|
||||
byte[] EbootSig = chovy_gen(ebootFile, uAid);
|
||||
Account CmaAccount = new Account(uAid);
|
||||
CmaAccount.Devkit = IsDexAidSet();
|
||||
|
||||
ChovyGen.Start();
|
||||
while (ChovyGen.IsAlive)
|
||||
{
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
if (!File.Exists(sigFile) || ChovyGenRes != 0 && !isDlc)
|
||||
{
|
||||
MessageBox.Show("CHOVY-GEN Failed! Please check CHOVY.DLL exists\nand that the Microsoft Visual C++ 2015 Redistributable Update 3 RC is installed", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
transVita.Enabled = true;
|
||||
driveLetterDst.Enabled = true;
|
||||
driveLetterSrc.Enabled = true;
|
||||
pspFolder.ReadOnly = false;
|
||||
cmaDir.ReadOnly = false;
|
||||
pspGames.Enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* BUILD PSVIMG FILE(s)
|
||||
|
@ -474,44 +431,33 @@ namespace CHOVY_TRANSFER
|
|||
|
||||
// Pacakge GAME
|
||||
|
||||
byte[] CmaKey;
|
||||
if(!IsDexAidSet())
|
||||
{
|
||||
CmaKey = CmaKeys.GenerateKey(bAid);
|
||||
}
|
||||
else
|
||||
{
|
||||
CmaKey = CmaKeys.GenerateKey(new byte[0x8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
}
|
||||
|
||||
byte[] CmaKey = CmaAccount.CmaKey;
|
||||
|
||||
string[] entrys = Directory.GetFileSystemEntries(gameFolder, "*", SearchOption.AllDirectories);
|
||||
long noEntrys = entrys.LongLength;
|
||||
string parentPath = "ux0:pspemu/temp/game/PSP/GAME/" + titleId;
|
||||
int noBlocks = 0;
|
||||
foreach (string fileName in Directory.GetFiles(gameFolder, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
noBlocks += Convert.ToInt32(new FileInfo(fileName).Length / PSVIMGConstants.PSVIMG_BLOCK_SIZE);
|
||||
}
|
||||
progressBar.Maximum = noBlocks;
|
||||
|
||||
|
||||
string pgameFolder;
|
||||
string pgameFolderl;
|
||||
string pgameFolderLicense;
|
||||
string scesys;
|
||||
if (!isPs1)
|
||||
{
|
||||
if(!IsDexAidSet())
|
||||
{
|
||||
pgameFolder = Path.Combine(backupDir, "PGAME", sAid, titleId, "game");
|
||||
pgameFolderl = Path.Combine(backupDir, "PGAME", sAid, titleId, "license");
|
||||
scesys = Path.Combine(backupDir, "PGAME", sAid, titleId, "sce_sys");
|
||||
pgameFolder = Path.Combine(SettingsReader.PspFolder, sAid, titleId, "game");
|
||||
pgameFolderLicense = Path.Combine(SettingsReader.PspFolder, sAid, titleId, "license");
|
||||
scesys = Path.Combine(SettingsReader.PspFolder, sAid, titleId, "sce_sys");
|
||||
}
|
||||
else
|
||||
{
|
||||
pgameFolder = Path.Combine(backupDir, "PGAME", "0000000000000000", titleId, "game");
|
||||
pgameFolderl = Path.Combine(backupDir, "PGAME", "0000000000000000", titleId, "license");
|
||||
scesys = Path.Combine(backupDir, "PGAME", "0000000000000000", titleId, "sce_sys");
|
||||
pgameFolder = Path.Combine(SettingsReader.PspFolder, "0000000000000000", titleId, "game");
|
||||
pgameFolderLicense = Path.Combine(SettingsReader.PspFolder, "0000000000000000", titleId, "license");
|
||||
scesys = Path.Combine(SettingsReader.PspFolder, "0000000000000000", titleId, "sce_sys");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -519,32 +465,45 @@ namespace CHOVY_TRANSFER
|
|||
{
|
||||
if(!IsDexAidSet())
|
||||
{
|
||||
pgameFolder = Path.Combine(backupDir, "PSGAME", sAid, titleId, "game");
|
||||
pgameFolderl = Path.Combine(backupDir, "PSGAME", sAid, titleId, "license");
|
||||
scesys = Path.Combine(backupDir, "PSGAME", sAid, titleId, "sce_sys");
|
||||
pgameFolder = Path.Combine(SettingsReader.Ps1Folder, sAid, titleId, "game");
|
||||
pgameFolderLicense = Path.Combine(SettingsReader.Ps1Folder, sAid, titleId, "license");
|
||||
scesys = Path.Combine(SettingsReader.Ps1Folder, sAid, titleId, "sce_sys");
|
||||
}
|
||||
else
|
||||
{
|
||||
pgameFolder = Path.Combine(backupDir, "PSGAME", "0000000000000000", titleId, "game");
|
||||
pgameFolderl = Path.Combine(backupDir, "PSGAME", "0000000000000000", titleId, "license");
|
||||
scesys = Path.Combine(backupDir, "PSGAME", "0000000000000000", titleId, "sce_sys");
|
||||
pgameFolder = Path.Combine(SettingsReader.Ps1Folder, "0000000000000000", titleId, "game");
|
||||
pgameFolderLicense = Path.Combine(SettingsReader.Ps1Folder, "0000000000000000", titleId, "license");
|
||||
scesys = Path.Combine(SettingsReader.Ps1Folder, "0000000000000000", titleId, "sce_sys");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(pgameFolder);
|
||||
Directory.CreateDirectory(pgameFolderl);
|
||||
Directory.CreateDirectory(pgameFolderLicense);
|
||||
Directory.CreateDirectory(scesys);
|
||||
|
||||
string psvimgFilepathl = Path.Combine(pgameFolderl, "license.psvimg");
|
||||
string psvimgFilepathLicense = Path.Combine(pgameFolderLicense, "license.psvimg");
|
||||
string psvimgFilepath = Path.Combine(pgameFolder, "game.psvimg");
|
||||
|
||||
string psvmdFilepathl = Path.Combine(pgameFolderl, "license.psvmd");
|
||||
string psvmdFilepathLicense = Path.Combine(pgameFolderLicense, "license.psvmd");
|
||||
string psvmdFilepath = Path.Combine(pgameFolder, "game.psvmd");
|
||||
|
||||
FileStream gamePsvimg = File.OpenWrite(psvimgFilepath);
|
||||
gamePsvimg.SetLength(0);
|
||||
await Task.Run(() =>
|
||||
{
|
||||
using (FileStream gamePsvimg = File.Open(psvimgFilepath, FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
PSVIMGBuilder builder = new PSVIMGBuilder(gamePsvimg, CmaKey);
|
||||
builder.RegisterCallback((ProgressInfo inf) =>
|
||||
{
|
||||
Invoke((Action)delegate {
|
||||
int tBlocks = builder.BlocksWritten;
|
||||
if (tBlocks > noBlocks) tBlocks = noBlocks;
|
||||
progressBar.Value = tBlocks;
|
||||
decimal progress = Math.Floor(((decimal)tBlocks / (decimal)noBlocks) * 100);
|
||||
progressStatus.Text = progress.ToString() + "%";
|
||||
currentFile.Text = inf.CurrentProcess;
|
||||
});
|
||||
});
|
||||
|
||||
foreach (string entry in entrys)
|
||||
{
|
||||
|
@ -554,7 +513,7 @@ namespace CHOVY_TRANSFER
|
|||
if (Path.GetExtension(entry).ToUpperInvariant() == ".EDAT")
|
||||
{
|
||||
string edatContentId = GetContentIdFromPspEdat(entry);
|
||||
string rifPath = Path.Combine(driveLetterSrc.Text, pspFolder.Text, "LICENSE", edatContentId + ".RIF");
|
||||
string rifPath = Path.Combine(pspDir, "LICENSE", edatContentId + ".RIF");
|
||||
if (!licenseFiles.Contains(rifPath) && File.Exists(rifPath))
|
||||
licenseFiles.Add(rifPath);
|
||||
}
|
||||
|
@ -567,45 +526,33 @@ namespace CHOVY_TRANSFER
|
|||
}
|
||||
else
|
||||
{
|
||||
builder.AddFileAsync(entry, parentPath, relativePath);
|
||||
while (!builder.HasFinished)
|
||||
{
|
||||
try
|
||||
{
|
||||
int tBlocks = builder.BlocksWritten;
|
||||
progressBar.Value = tBlocks;
|
||||
decimal progress = Math.Floor(((decimal)tBlocks / (decimal)noBlocks) * 100);
|
||||
progressStatus.Text = progress.ToString() + "%";
|
||||
currentFile.Text = "Processing: " + Path.GetFileName(entry);
|
||||
builder.AddFile(entry, parentPath, relativePath);
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
// add __sce_ebootpbp
|
||||
if(!isDlc)
|
||||
builder.AddFile(EbootSig, parentPath, "/__sce_ebootpbp");
|
||||
|
||||
long ContentSize = builder.Finish();
|
||||
gamePsvimg = File.OpenRead(psvimgFilepath);
|
||||
FileStream gamePsvmd = File.OpenWrite(psvmdFilepath);
|
||||
|
||||
using (FileStream gamePsvmd = File.Open(psvmdFilepath, FileMode.Create, FileAccess.ReadWrite))
|
||||
PSVMDBuilder.CreatePsvmd(gamePsvmd, gamePsvimg, ContentSize, "game", CmaKey);
|
||||
gamePsvmd.Close();
|
||||
gamePsvimg.Close();
|
||||
}
|
||||
|
||||
|
||||
// Package LICENSE
|
||||
FileStream licensePsvimg = File.OpenWrite(psvimgFilepathl);
|
||||
licensePsvimg.SetLength(0);
|
||||
builder = new PSVIMGBuilder(licensePsvimg, CmaKey);
|
||||
using (FileStream licensePsvimg = File.Open(psvimgFilepathLicense, FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
PSVIMGBuilder builder = new PSVIMGBuilder(licensePsvimg, CmaKey);
|
||||
foreach (string licenseFile in licenseFiles)
|
||||
builder.AddFile(licenseFile, "ux0:pspemu/temp/game/PSP/LICENSE", "/" + Path.GetFileNameWithoutExtension(licenseFile) + ".rif");
|
||||
ContentSize = builder.Finish();
|
||||
long ContentSize = builder.Finish();
|
||||
|
||||
licensePsvimg = File.OpenRead(psvimgFilepathl);
|
||||
FileStream licensePsvmd = File.OpenWrite(psvmdFilepathl);
|
||||
using (FileStream licensePsvmd = File.Open(psvmdFilepathLicense, FileMode.Create, FileAccess.ReadWrite))
|
||||
PSVMDBuilder.CreatePsvmd(licensePsvmd, licensePsvimg, ContentSize, "license", CmaKey);
|
||||
licensePsvmd.Close();
|
||||
licensePsvimg.Close();
|
||||
}
|
||||
});
|
||||
|
||||
// Write PARAM.SFO & ICON0.PNG
|
||||
|
||||
|
|
|
@ -1,64 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("CHOVY-TRANSFER")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("CHOVY-TRANSFER")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -21,16 +11,3 @@ using System.Runtime.InteropServices;
|
|||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b4cad2c0-ba54-46b6-a8d0-43a9c2390d3c")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\net6.0-windows\publish\win-x86\</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<PublishReadyToRun>true</PublishReadyToRun>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<History>True|2023-07-10T03:53:35.4493264Z;True|2023-07-10T15:48:49.3356830+12:00;True|2023-07-10T15:44:35.4847823+12:00;True|2023-07-10T15:42:39.5955955+12:00;True|2023-07-10T15:30:22.5199359+12:00;True|2023-07-10T13:56:34.8005938+12:00;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
2
CHOVY-TRANSFER/Properties/Resources.Designer.cs
generated
2
CHOVY-TRANSFER/Properties/Resources.Designer.cs
generated
|
@ -19,7 +19,7 @@ namespace CHOVY_TRANSFER.Properties {
|
|||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
|
2
CHOVY-TRANSFER/Properties/Settings.Designer.cs
generated
2
CHOVY-TRANSFER/Properties/Settings.Designer.cs
generated
|
@ -12,7 +12,7 @@ namespace CHOVY_TRANSFER.Properties {
|
|||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.0.1.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
|
257
CHOVY-TRANSFER/Sfo.cs
Normal file
257
CHOVY-TRANSFER/Sfo.cs
Normal file
|
@ -0,0 +1,257 @@
|
|||
using Li.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// A Sfo Parser Written by Li
|
||||
// Because all the others are overly-complicated for no reason!
|
||||
// MIT Licensed.
|
||||
|
||||
namespace Param
|
||||
{
|
||||
|
||||
public class Sfo
|
||||
{
|
||||
|
||||
private struct SfoEntry
|
||||
{
|
||||
internal string keyName;
|
||||
internal byte type;
|
||||
internal UInt32 valueSize;
|
||||
internal UInt32 totalSize;
|
||||
internal byte align;
|
||||
internal object value;
|
||||
}
|
||||
|
||||
const int SFO_MAGIC = 0x46535000;
|
||||
const byte PSF_TYPE_BIN = 0;
|
||||
const byte PSF_TYPE_STR = 2;
|
||||
const byte PSF_TYPE_VAL = 4;
|
||||
|
||||
private Dictionary<string, SfoEntry> sfoEntries;
|
||||
public Object this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sfoEntries.ContainsKey(index))
|
||||
return sfoEntries[index].value;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (sfoEntries.ContainsKey(index))
|
||||
{
|
||||
SfoEntry sfoEnt = sfoEntries[index];
|
||||
sfoEnt.value = value;
|
||||
|
||||
// update sz
|
||||
sfoEnt.valueSize = getObjectSz(sfoEnt.value);
|
||||
|
||||
if (sfoEnt.valueSize > sfoEnt.totalSize)
|
||||
sfoEnt.totalSize = Convert.ToUInt32(MathUtil.CalculatePaddingAmount(Convert.ToInt32(sfoEnt.valueSize), sfoEnt.align));
|
||||
|
||||
// update type
|
||||
sfoEnt.type = getPsfType(sfoEnt.value);
|
||||
|
||||
sfoEntries[index] = sfoEnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 sz = getObjectSz(value);
|
||||
int alg = MathUtil.CalculatePaddingAmount(Convert.ToInt32(sz), 4);
|
||||
|
||||
AddKey(index, value, Convert.ToUInt32(sz + alg), 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddKey(string keyName, object value, UInt32 totalSize, byte align = 4)
|
||||
{
|
||||
SfoEntry ent = new SfoEntry();
|
||||
ent.keyName = keyName;
|
||||
ent.type = getPsfType(value);
|
||||
ent.valueSize = getObjectSz(value);
|
||||
ent.totalSize = Convert.ToUInt32(totalSize + MathUtil.CalculatePaddingAmount(Convert.ToInt32(totalSize), align));
|
||||
ent.align = align;
|
||||
ent.value = value;
|
||||
sfoEntries[ent.keyName] = ent;
|
||||
}
|
||||
|
||||
public Sfo()
|
||||
{
|
||||
sfoEntries = new Dictionary<string, SfoEntry>();
|
||||
}
|
||||
|
||||
|
||||
private static UInt32 getObjectSz(Object obj)
|
||||
{
|
||||
if (obj is Int32) return 4;
|
||||
if (obj is UInt32) return 4;
|
||||
if (obj is String) return Convert.ToUInt32((obj as String).Length + 1);
|
||||
if (obj is Byte[]) return Convert.ToUInt32((obj as Byte[]).Length);
|
||||
throw new Exception("Object is of unsupported type: " + obj.GetType());
|
||||
}
|
||||
|
||||
private static byte getPsfType(Object obj)
|
||||
{
|
||||
if (obj is Int32 || obj is UInt32) return PSF_TYPE_VAL;
|
||||
if (obj is String) return PSF_TYPE_STR;
|
||||
if (obj is Byte[]) return PSF_TYPE_BIN;
|
||||
throw new Exception("Object is of unsupported type: " + obj.GetType());
|
||||
}
|
||||
|
||||
public byte[] WriteSfo(UInt32 version = 0x101, Byte align = 0x4)
|
||||
{
|
||||
using (MemoryStream sfoStream = new MemoryStream())
|
||||
{
|
||||
WriteSfo(sfoStream, version, align);
|
||||
byte[] sfoBytes = sfoStream.ToArray();
|
||||
return sfoBytes;
|
||||
}
|
||||
}
|
||||
public void WriteSfo(Stream SfoStream, UInt32 version = 0x101, Byte align = 0x4)
|
||||
{
|
||||
using (MemoryStream sfoStream = new MemoryStream())
|
||||
{
|
||||
StreamUtil sfoUtil = new StreamUtil(sfoStream);
|
||||
|
||||
sfoUtil.WriteUInt32(SFO_MAGIC);
|
||||
sfoUtil.WriteUInt32(version);
|
||||
|
||||
sfoUtil.WriteUInt32(0xFFFFFFFF); // key offset
|
||||
sfoUtil.WriteUInt32(0xFFFFFFFF); // value offset
|
||||
// (will fill these in after the file is created)
|
||||
|
||||
sfoUtil.WriteInt32(sfoEntries.Count);
|
||||
|
||||
using (MemoryStream keyTable = new MemoryStream())
|
||||
{
|
||||
StreamUtil keyUtils = new StreamUtil(keyTable);
|
||||
using (MemoryStream valueTable = new MemoryStream())
|
||||
{
|
||||
StreamUtil valueUtils = new StreamUtil(valueTable);
|
||||
foreach (SfoEntry entry in sfoEntries.Values)
|
||||
{
|
||||
// write name
|
||||
sfoUtil.WriteUInt16(Convert.ToUInt16(keyTable.Position));
|
||||
keyUtils.WriteCStr(entry.keyName);
|
||||
|
||||
|
||||
|
||||
// write entry
|
||||
|
||||
sfoUtil.WriteByte(align); // align
|
||||
sfoUtil.WriteByte(entry.type); // type
|
||||
sfoUtil.WriteUInt32(entry.valueSize); // valueSize
|
||||
sfoUtil.WriteUInt32(entry.totalSize); // totalSize
|
||||
|
||||
// write data
|
||||
sfoUtil.WriteUInt32(Convert.ToUInt32(valueTable.Position)); // dataOffset
|
||||
|
||||
switch (entry.type)
|
||||
{
|
||||
case PSF_TYPE_VAL:
|
||||
valueUtils.WriteUInt32(Convert.ToUInt32(entry.value));
|
||||
valueUtils.WritePadding(0x00, Convert.ToInt32(entry.totalSize - entry.valueSize));
|
||||
break;
|
||||
case PSF_TYPE_STR:
|
||||
valueUtils.WriteStrWithPadding(entry.value as String, 0x00, Convert.ToInt32(entry.totalSize));
|
||||
break;
|
||||
case PSF_TYPE_BIN:
|
||||
valueUtils.WriteBytesWithPadding(entry.value as Byte[], 0x00, Convert.ToInt32(entry.totalSize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
keyUtils.AlignTo(0x00, align);
|
||||
UInt32 keyOffset = Convert.ToUInt32(sfoStream.Position);
|
||||
keyTable.Seek(0x00, SeekOrigin.Begin);
|
||||
keyTable.CopyTo(sfoStream);
|
||||
|
||||
UInt32 valueOffset = Convert.ToUInt32(sfoStream.Position);
|
||||
valueTable.Seek(0x00, SeekOrigin.Begin);
|
||||
valueTable.CopyTo(sfoStream);
|
||||
|
||||
sfoStream.Seek(0x8, SeekOrigin.Begin);
|
||||
sfoUtil.WriteUInt32(keyOffset); // key offset
|
||||
sfoUtil.WriteUInt32(valueOffset); // value offset
|
||||
}
|
||||
}
|
||||
|
||||
sfoStream.Seek(0x0, SeekOrigin.Begin);
|
||||
sfoStream.CopyTo(SfoStream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Sfo ReadSfo(Stream SfoStream)
|
||||
{
|
||||
Sfo sfoFile = new Sfo();
|
||||
StreamUtil DataUtils = new StreamUtil(SfoStream);
|
||||
|
||||
// Read Sfo Header
|
||||
UInt32 magic = DataUtils.ReadUInt32();
|
||||
UInt32 version = DataUtils.ReadUInt32();
|
||||
UInt32 keyOffset = DataUtils.ReadUInt32();
|
||||
UInt32 valueOffset = DataUtils.ReadUInt32();
|
||||
UInt32 count = DataUtils.ReadUInt32();
|
||||
|
||||
if (magic == SFO_MAGIC) //\x00PSF
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
SfoEntry entry = new SfoEntry();
|
||||
|
||||
UInt16 nameOffset = DataUtils.ReadUInt16();
|
||||
entry.align = DataUtils.ReadByte();
|
||||
entry.type = DataUtils.ReadByte();
|
||||
entry.valueSize = DataUtils.ReadUInt32();
|
||||
entry.totalSize = DataUtils.ReadUInt32();
|
||||
UInt32 dataOffset = DataUtils.ReadUInt32();
|
||||
|
||||
int keyLocation = Convert.ToInt32(keyOffset + nameOffset);
|
||||
entry.keyName = DataUtils.ReadStringAt(keyLocation);
|
||||
int valueLocation = Convert.ToInt32(valueOffset + dataOffset);
|
||||
|
||||
|
||||
switch (entry.type)
|
||||
{
|
||||
case PSF_TYPE_STR:
|
||||
entry.value = DataUtils.ReadStringAt(valueLocation);
|
||||
break;
|
||||
|
||||
case PSF_TYPE_VAL:
|
||||
entry.value = DataUtils.ReadUInt32At(valueLocation);
|
||||
break;
|
||||
|
||||
case PSF_TYPE_BIN:
|
||||
entry.value = DataUtils.ReadBytesAt(valueLocation, Convert.ToInt32(entry.valueSize));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
sfoFile.sfoEntries[entry.keyName] = entry;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException("Sfo Magic is Invalid.");
|
||||
}
|
||||
|
||||
return sfoFile;
|
||||
}
|
||||
|
||||
public static Sfo ReadSfo(byte[] Sfo)
|
||||
{
|
||||
using (MemoryStream SfoStream = new MemoryStream(Sfo))
|
||||
{
|
||||
return ReadSfo(SfoStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="BouncyCastle" version="1.8.5" targetFramework="net452" />
|
||||
<package id="DotNetZip" version="1.13.4" targetFramework="net452" />
|
||||
</packages>
|
|
@ -1,569 +0,0 @@
|
|||
/* Copyright (c) 2015 - 2018 TheDarkporgramer
|
||||
*
|
||||
* This was originally done by Jappi88 (Jappi88 at Gmail dot com) https://github.com/Jappi88
|
||||
* All modifications have been TheDarkporgramer (save sfo ext ext ) https://github.com/xXxTheDarkprogramerxXx
|
||||
*
|
||||
* This(software Is provided) 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications*, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledge in the product documentation is required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* *Contact must be made to discuses permission and terms.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace Param_SFO
|
||||
{
|
||||
public class PARAM_SFO
|
||||
{
|
||||
#region << Enums >>
|
||||
public enum DataTypes : uint
|
||||
{
|
||||
PSN_Game = 18248,
|
||||
GameData = 0x4744,
|
||||
SaveData = 0x5344,
|
||||
AppPhoto = 0x4150,
|
||||
AppMusic = 0x414D,
|
||||
AppVideo = 0x4156,
|
||||
BroadCastVideo = 0x4256,
|
||||
AppleTV = 4154,
|
||||
WebTV = 5754,
|
||||
CellBE = 0x4342,
|
||||
Home = 0x484D,
|
||||
StoreFronted = 0x5346,
|
||||
HDDGame = 0x4847,
|
||||
DiscGame = 0x4447,
|
||||
AutoInstallRoot = 0x4152,
|
||||
DiscPackage = 0x4450,
|
||||
ExtraRoot = 0x5852,
|
||||
VideoRoot = 0x5652,
|
||||
ThemeRoot = 0x5452,
|
||||
DiscMovie = 0x444D,
|
||||
Game_Digital_Application = 0x4081AC0,//GD
|
||||
PS4_Game_Application_Patch = 28775,
|
||||
Additional_Content = 25441,//PSvita PS4
|
||||
GameContent = 25447,//PSVITA
|
||||
Blu_Ray_Disc = 25698,//PS4
|
||||
None
|
||||
}
|
||||
|
||||
public enum FMT : ushort
|
||||
{
|
||||
UTF_8 = 0x0004,
|
||||
ASCII = 0x0402,
|
||||
Utf8Null = 0x0204,
|
||||
UINT32 = 0x0404,
|
||||
}
|
||||
|
||||
#endregion << Enums >>
|
||||
|
||||
#region << Vars>>
|
||||
public List<Table> Tables { get; set; }
|
||||
|
||||
#endregion << Vars>>
|
||||
|
||||
#region << Example Of Calling Functions >>
|
||||
//ypu can use this as SFO.Atribute
|
||||
public string Attribute
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
{
|
||||
if (t.Name == "ATTRIBUTE")
|
||||
return t.Value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public DataTypes DataType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return DataTypes.None;
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == "CATEGORY")
|
||||
return ((DataTypes)BitConverter.ToUInt16(Encoding.UTF8.GetBytes(t.Value), 0));
|
||||
return DataTypes.None;
|
||||
}
|
||||
}
|
||||
|
||||
public string APP_VER
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
{
|
||||
if (t.Name == "APP_VER")
|
||||
return t.Value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string Detail
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == "DETAIL")
|
||||
return t.Value;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string ContentID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == "CONTENT_ID")
|
||||
return t.Value;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string GetValue(string tagName)
|
||||
{
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == tagName)
|
||||
return t.Value;
|
||||
return "";
|
||||
}
|
||||
public string TITLEID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == "TITLE_ID")
|
||||
return t.Value;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string TitleID
|
||||
{
|
||||
get
|
||||
{
|
||||
string name = TITLEID;
|
||||
if (name == "")
|
||||
return "";
|
||||
return name.Split('-')[0];
|
||||
}
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == "TITLE")
|
||||
return t.Value;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return "";
|
||||
foreach (Table t in Tables)
|
||||
if (t.Name == "CATEGORY")
|
||||
return t.Value;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public enum Playstation
|
||||
{
|
||||
ps3 = 0,
|
||||
psvita = 1,
|
||||
ps4 = 2,
|
||||
psp = 3,
|
||||
unknown = 4,//there will be a time i no longer support the scene this will be for ps5+ most probabbly
|
||||
}
|
||||
|
||||
public Playstation PlaystationVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tables == null)
|
||||
return Playstation.unknown;
|
||||
foreach (Table t in Tables)
|
||||
{
|
||||
if (t.Name == "PS3_SYSTEM_VER")
|
||||
return Playstation.ps3;//this is the unique offset for ps3
|
||||
if (t.Name == "PSP2_SYSTEM_VER")
|
||||
{
|
||||
return Playstation.psvita;//this is the only flag that tells us its a psvita
|
||||
}
|
||||
if (t.Name == "PSP_SYSTEM_VER")
|
||||
{
|
||||
return Playstation.psp;//this is how we know its a psp
|
||||
}
|
||||
if (t.Name == "SYSTEM_VER")//i believe this to be only ps4
|
||||
{
|
||||
return Playstation.ps4;
|
||||
}
|
||||
}
|
||||
return Playstation.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion << Example Of Calling Functions >>
|
||||
|
||||
#region Param.SFO Struct
|
||||
|
||||
public struct Header
|
||||
{
|
||||
public static byte[] Magic = { 0, 0x50, 0x53, 0x46 };
|
||||
public static byte[] version = { 01, 01, 0, 0 };
|
||||
public static uint KeyTableStart = 0;
|
||||
public static uint DataTableStart = 0;
|
||||
public static uint IndexTableEntries = 0;
|
||||
|
||||
private static byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
var header = new byte[20];
|
||||
Array.Copy(Magic, 0, header, 0, 4);
|
||||
Array.Copy(version, 0, header, 4, 4);
|
||||
Array.Copy(BitConverter.GetBytes(KeyTableStart), 0, header, 8, 4);
|
||||
Array.Copy(BitConverter.GetBytes(DataTableStart), 0, header, 12, 4);
|
||||
Array.Copy(BitConverter.GetBytes(IndexTableEntries), 0, header, 16, 4);
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Read(BinaryReader input)
|
||||
{
|
||||
input.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
input.Read(Magic, 0, 4);
|
||||
input.Read(version, 0, 4);
|
||||
KeyTableStart = input.ReadUInt32();
|
||||
DataTableStart = input.ReadUInt32();
|
||||
IndexTableEntries = input.ReadUInt32();
|
||||
}
|
||||
|
||||
}
|
||||
[Serializable]
|
||||
public struct Table : IComparable
|
||||
{
|
||||
public index_table Indextable;
|
||||
public string Name;
|
||||
public string Value;
|
||||
public int index;
|
||||
|
||||
public byte[] NameBuffer
|
||||
{
|
||||
get
|
||||
{
|
||||
var buffer = new byte[Name.Length + 1];
|
||||
Array.Copy(Encoding.UTF8.GetBytes(Name), 0, buffer, 0, Encoding.UTF8.GetBytes(Name).Length);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ValueBuffer
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] buffer;
|
||||
switch (Indextable.param_data_fmt)
|
||||
{
|
||||
case FMT.ASCII:
|
||||
buffer = new byte[Indextable.param_data_max_len];
|
||||
Array.Copy(Encoding.ASCII.GetBytes(Value), 0, buffer, 0, Encoding.UTF8.GetBytes(Value).Length);
|
||||
return buffer;
|
||||
case FMT.UINT32:
|
||||
return BitConverter.GetBytes(uint.Parse(Value));
|
||||
case FMT.UTF_8:
|
||||
buffer = new byte[Indextable.param_data_max_len];
|
||||
Array.Copy(Encoding.UTF8.GetBytes(Value), 0, buffer, 0, Encoding.UTF8.GetBytes(Value).Length);
|
||||
return buffer;
|
||||
case FMT.Utf8Null:
|
||||
buffer = new byte[Indextable.param_data_max_len];
|
||||
Array.Copy(Encoding.UTF8.GetBytes(Value), 0, buffer, 0, Encoding.UTF8.GetBytes(Value).Length);/*write the length of the array*/
|
||||
return buffer;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
[Serializable]
|
||||
public struct index_table
|
||||
{
|
||||
public FMT param_data_fmt; /* param_data data type */
|
||||
public uint param_data_len; /* param_data used bytes */
|
||||
public uint param_data_max_len; /* param_data total reserved bytes */
|
||||
public uint param_data_offset; /* param_data offset (relative to start offset of data_table) */
|
||||
public ushort param_key_offset; /* param_key offset (relative to start offset of key_table) */
|
||||
|
||||
|
||||
private byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = new byte[16];
|
||||
Array.Copy(BitConverter.GetBytes(param_key_offset), 0, data, 0, 2);
|
||||
Array.Copy(BitConverter.GetBytes(((ushort)param_data_fmt)), 0, data, 2, 2);
|
||||
Array.Copy(BitConverter.GetBytes(param_data_len), 0, data, 4, 4);
|
||||
Array.Copy(BitConverter.GetBytes(param_data_max_len), 0, data, 8, 4);
|
||||
Array.Copy(BitConverter.GetBytes(param_data_offset), 0, data, 12, 4);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader input)
|
||||
{
|
||||
param_key_offset = input.ReadUInt16();
|
||||
param_data_fmt = (FMT)input.ReadUInt16();
|
||||
param_data_len = input.ReadUInt32();
|
||||
param_data_max_len = input.ReadUInt32();
|
||||
param_data_offset = input.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private enum DATA_TYPE : byte
|
||||
{
|
||||
BinaryData = 0,
|
||||
Utf8Text = 2,
|
||||
Si32Integer = 4
|
||||
}
|
||||
|
||||
#endregion Param.SFO Struct
|
||||
|
||||
#region << Methods >>
|
||||
|
||||
|
||||
public PARAM_SFO()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PARAM_SFO(string filepath)
|
||||
{
|
||||
Init(new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read));
|
||||
}
|
||||
|
||||
public PARAM_SFO(byte[] inputdata)
|
||||
{
|
||||
Init(new MemoryStream(inputdata));
|
||||
}
|
||||
|
||||
public PARAM_SFO(Stream input)
|
||||
{
|
||||
Init(input);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is the SaveSFO Function for PS3/PS4/PSVita/And PSP no longer needed for Sony's CMD
|
||||
/// </summary>
|
||||
/// <param name="psfo">SFO That has been opened</param>
|
||||
/// <param name="filename">Save Location</param>
|
||||
public void SaveSFO(PARAM_SFO psfo, string filename)
|
||||
{
|
||||
//we start by opening the stream to the file
|
||||
using (var stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
if (!stream.CanSeek)
|
||||
throw new ArgumentException("Stream must be seekable");//throw this error we cant seek the stream
|
||||
|
||||
var utf8 = new UTF8Encoding(false);//encoding
|
||||
using (var writer = new BinaryWriter(stream, utf8))//start binary reader
|
||||
{
|
||||
|
||||
#region << Header Info (DevWiki) >>
|
||||
/*
|
||||
Header
|
||||
* 0x00 0x04 magic PSF
|
||||
0x04 0x04 version 01 01 00 00 1.01
|
||||
0x08 0x04 key_table_start 24 00 00 00 Absolute start offset of key_table = 0x24
|
||||
0x0C 0x04 data_table_start 30 00 00 00 Absolute start offset of data_table = 0x30
|
||||
0x10 0x04 tables_entries 01 00 00 00 Number of entries in index_table, key_table, and data_table = 1
|
||||
*/
|
||||
|
||||
#endregion <<Header Info >>
|
||||
|
||||
//so lets start writing the info
|
||||
writer.Write(Header.Magic);//write magic "\0PSF"
|
||||
writer.Write(Header.version);//write version info this is mayjor and minor (01 01 00 00 1.01)
|
||||
Header.KeyTableStart = 0x14 + Header.IndexTableEntries * 0x10;/*we can write all this lovely info from the tables back*/
|
||||
writer.Write(Header.KeyTableStart);
|
||||
|
||||
Header.DataTableStart = Convert.ToUInt32(Header.KeyTableStart + Tables.Sum(i => i.Name.Length + 1));//needs to be Uint
|
||||
if (Header.DataTableStart % 4 != 0)
|
||||
Header.DataTableStart = (Header.DataTableStart / 4 + 1) * 4;
|
||||
writer.Write(Header.DataTableStart);
|
||||
Header.IndexTableEntries = Convert.ToUInt32(Tables.Count);
|
||||
writer.Write(Header.IndexTableEntries);
|
||||
|
||||
int lastKeyOffset = Convert.ToInt32(Header.KeyTableStart);
|
||||
int lastValueOffset = Convert.ToInt32(Header.DataTableStart);
|
||||
for (var i = 0; i < Tables.Count; i++)
|
||||
{
|
||||
var entry = Tables[i];
|
||||
|
||||
writer.BaseStream.Seek(0x14 + i * 0x10, SeekOrigin.Begin);
|
||||
writer.Write((ushort)(lastKeyOffset - Header.KeyTableStart));
|
||||
|
||||
|
||||
writer.Write((ushort)entry.Indextable.param_data_fmt);
|
||||
|
||||
writer.Write(entry.Indextable.param_data_len);
|
||||
writer.Write(entry.Indextable.param_data_max_len);
|
||||
writer.Write(lastValueOffset - Header.DataTableStart);
|
||||
|
||||
writer.BaseStream.Seek(lastKeyOffset, SeekOrigin.Begin);
|
||||
writer.Write(utf8.GetBytes(entry.Name));
|
||||
writer.Write((byte)0);
|
||||
lastKeyOffset = (int)writer.BaseStream.Position;
|
||||
|
||||
writer.BaseStream.Seek(lastValueOffset, SeekOrigin.Begin);
|
||||
writer.Write(entry.ValueBuffer);
|
||||
lastValueOffset = (int)writer.BaseStream.Position;
|
||||
}
|
||||
|
||||
//I'm doing this to just rewrite the first item (Some Cleanup will be needed)
|
||||
//Or maybe not as when I checked this gives a 1 - 1 match with how the Sony tool works
|
||||
//we need to rewrite that first item (PS4/PS3/PSV should be APP-VER)
|
||||
lastKeyOffset = Convert.ToInt32(Header.KeyTableStart);
|
||||
lastValueOffset = Convert.ToInt32(Header.DataTableStart);
|
||||
|
||||
var tableentry = Tables[0];
|
||||
|
||||
writer.BaseStream.Seek(lastKeyOffset, SeekOrigin.Begin);
|
||||
writer.Write(utf8.GetBytes(tableentry.Name));
|
||||
writer.Write((byte)0);
|
||||
lastKeyOffset = (int)writer.BaseStream.Position;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string ReadValue(BinaryReader br, index_table table)
|
||||
{
|
||||
br.BaseStream.Position = ((Header.DataTableStart) + table.param_data_offset);
|
||||
switch (table.param_data_fmt)
|
||||
{
|
||||
case FMT.ASCII:
|
||||
//return Encoding.GetEncoding(1252).GetString(br.ReadBytes((int) table.param_data_max_len)).Replace("\0", "");
|
||||
return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", "");
|
||||
case FMT.UINT32:
|
||||
return br.ReadUInt32().ToString();
|
||||
case FMT.UTF_8:
|
||||
return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", "");
|
||||
case FMT.Utf8Null:
|
||||
return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", "");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadValueSpecialChars(BinaryReader br, index_table table)
|
||||
{
|
||||
br.BaseStream.Position = ((Header.DataTableStart) + table.param_data_offset);
|
||||
switch (table.param_data_fmt)
|
||||
{
|
||||
case FMT.ASCII:
|
||||
return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", "");
|
||||
case FMT.UINT32:
|
||||
return br.ReadUInt32().ToString();
|
||||
case FMT.UTF_8:
|
||||
return Encoding.UTF8.GetString(br.ReadBytes((int)table.param_data_max_len)).Replace("\0", "");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadName(BinaryReader br, index_table table)
|
||||
{
|
||||
br.BaseStream.Position = (Header.KeyTableStart + table.param_key_offset);
|
||||
string name = "";
|
||||
while (((byte)br.PeekChar()) != 0)
|
||||
name += br.ReadChar();
|
||||
br.BaseStream.Position++;
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start Reading the Parameter file
|
||||
/// </summary>
|
||||
/// <param name="input">Input Stream</param>
|
||||
private void Init(Stream input)
|
||||
{
|
||||
using (var br = new BinaryReader(input))
|
||||
{
|
||||
Header.Read(br);
|
||||
var tables = new List<index_table>();
|
||||
for (int i = 0; i < Header.IndexTableEntries; i++)
|
||||
{
|
||||
var t = new index_table();
|
||||
t.Read(br);
|
||||
tables.Add(t);
|
||||
}
|
||||
var xtables = new List<Table>();
|
||||
int count = 0;
|
||||
foreach (index_table t in tables)
|
||||
{
|
||||
var x = new Table();
|
||||
x.index = count;
|
||||
x.Indextable = t;
|
||||
x.Name = ReadName(br, t);
|
||||
x.Value = ReadValue(br, t);
|
||||
count++;
|
||||
xtables.Add(x);
|
||||
}
|
||||
Tables = xtables;
|
||||
br.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion << Methods >>
|
||||
|
||||
}
|
||||
}
|
9
LiLib/LiLib.csproj
Normal file
9
LiLib/LiLib.csproj
Normal file
|
@ -0,0 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
32
LiLib/MathUtil.cs
Normal file
32
LiLib/MathUtil.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Li.Utilities
|
||||
{
|
||||
public static class MathUtil
|
||||
{
|
||||
public static int CalculateDifference(int val1, int val2)
|
||||
{
|
||||
int smaller = Convert.ToInt32(Math.Min(val1, val2));
|
||||
int larger = Convert.ToInt32(Math.Max(val1, val2));
|
||||
|
||||
return larger - smaller;
|
||||
}
|
||||
|
||||
public static byte[] StringToByteArray(string hex)
|
||||
{
|
||||
return Enumerable.Range(0, hex.Length).Where(x => x % 2 == 0).Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
|
||||
}
|
||||
|
||||
public static int CalculatePaddingAmount(int total, int alignTo)
|
||||
{
|
||||
int remainder = total % alignTo;
|
||||
int padAmt = alignTo - (remainder);
|
||||
if ((remainder) == 0) return 0;
|
||||
return padAmt;
|
||||
}
|
||||
}
|
||||
}
|
62
LiLib/Progress/ProgressInfo.cs
Normal file
62
LiLib/Progress/ProgressInfo.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Li.Progress
|
||||
{
|
||||
public class ProgressInfo
|
||||
{
|
||||
private int totalDone;
|
||||
private int totalRemain;
|
||||
private string currentlyDoing;
|
||||
|
||||
public int Done
|
||||
{
|
||||
get
|
||||
{
|
||||
return totalDone;
|
||||
}
|
||||
}
|
||||
|
||||
public int Remain
|
||||
{
|
||||
get
|
||||
{
|
||||
return totalRemain;
|
||||
}
|
||||
}
|
||||
|
||||
public string CurrentProcess
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentlyDoing;
|
||||
}
|
||||
}
|
||||
|
||||
public double Progress
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.ToDouble(totalDone) / Convert.ToDouble(totalRemain) * 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
public int ProgressInt
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.ToInt32(Math.Floor(Progress));
|
||||
}
|
||||
}
|
||||
|
||||
internal ProgressInfo(int done, int remain, string currentProcess)
|
||||
{
|
||||
totalDone = done;
|
||||
totalRemain = remain;
|
||||
currentlyDoing = currentProcess;
|
||||
}
|
||||
}
|
||||
}
|
38
LiLib/Progress/ProgressTracker.cs
Normal file
38
LiLib/Progress/ProgressTracker.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Li.Progress
|
||||
{
|
||||
public class ProgressTracker
|
||||
{
|
||||
private List<Action<ProgressInfo>> progressCallbacks = new List<Action<ProgressInfo>>();
|
||||
|
||||
public void RegisterCallback(Action<ProgressInfo> cb)
|
||||
{
|
||||
progressCallbacks.Add(cb);
|
||||
}
|
||||
|
||||
protected void copyToProgress(Stream src, Stream dst, string msg)
|
||||
{
|
||||
src.Seek(0, SeekOrigin.Begin);
|
||||
byte[] readBuffer = new byte[0x30000];
|
||||
while (src.Position < src.Length)
|
||||
{
|
||||
int readAmt = src.Read(readBuffer, 0x00, readBuffer.Length);
|
||||
dst.Write(readBuffer, 0x00, readAmt);
|
||||
|
||||
updateProgress(Convert.ToInt32(src.Position), Convert.ToInt32(src.Length), msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateProgress(int done, int remain, string what)
|
||||
{
|
||||
ProgressInfo inf = new ProgressInfo(done, remain, what);
|
||||
foreach (Action<ProgressInfo> cb in progressCallbacks)
|
||||
cb(inf);
|
||||
}
|
||||
}
|
||||
}
|
204
LiLib/StreamUtil.cs
Normal file
204
LiLib/StreamUtil.cs
Normal file
|
@ -0,0 +1,204 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Li.Utilities
|
||||
{
|
||||
public class StreamUtil
|
||||
{
|
||||
private Stream s;
|
||||
public StreamUtil(Stream s)
|
||||
{
|
||||
this.s = s;
|
||||
}
|
||||
public string ReadStrLen(int len)
|
||||
{
|
||||
return Encoding.UTF8.GetString(ReadBytes(len));
|
||||
}
|
||||
public string ReadCDStr(int len)
|
||||
{
|
||||
return ReadStrLen(len).Trim(' ');
|
||||
}
|
||||
public string ReadCStr()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
byte c = (byte)s.ReadByte();
|
||||
if (c == 0)
|
||||
break;
|
||||
ms.WriteByte(c);
|
||||
}
|
||||
return Encoding.UTF8.GetString(ms.ToArray());
|
||||
}
|
||||
}
|
||||
public UInt32 ReadUInt32At(int location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
UInt32 outp = ReadUInt32();
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return outp;
|
||||
}
|
||||
|
||||
public Int32 ReadInt32At(int location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
Int32 outp = ReadInt32();
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return outp;
|
||||
}
|
||||
|
||||
public byte[] ReadBytesAt(int location, int length)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
byte[] work_buf = ReadBytes(length);
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return work_buf;
|
||||
}
|
||||
|
||||
public string ReadStringAt(int location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
string outp = ReadCStr();
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
return outp;
|
||||
}
|
||||
public byte ReadByte()
|
||||
{
|
||||
return (byte)s.ReadByte();
|
||||
}
|
||||
public byte[] ReadBytes(int len)
|
||||
{
|
||||
byte[] data = new byte[len];
|
||||
s.Read(data, 0x00, len);
|
||||
return data;
|
||||
}
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
byte[] vbytes = ReadBytes(0x2);
|
||||
return BitConverter.ToUInt16(vbytes);
|
||||
}
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
byte[] vbytes = ReadBytes(0x2);
|
||||
return BitConverter.ToInt16(vbytes);
|
||||
}
|
||||
public UInt32 ReadUInt32()
|
||||
{
|
||||
byte[] vbytes = ReadBytes(0x4);
|
||||
return BitConverter.ToUInt32(vbytes);
|
||||
}
|
||||
public Int32 ReadInt32()
|
||||
{
|
||||
byte[] vbytes = ReadBytes(0x4);
|
||||
return BitConverter.ToInt32(vbytes);
|
||||
}
|
||||
public void WriteBytesWithPadding(byte[] data, byte b, int len)
|
||||
{
|
||||
if (len < data.Length)
|
||||
{
|
||||
s.Write(data, 0, len);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBytes(data);
|
||||
WritePadding(b, (len - data.Length));
|
||||
}
|
||||
}
|
||||
public void WriteStrWithPadding(string str, byte b, int len)
|
||||
{
|
||||
WriteBytesWithPadding(Encoding.UTF8.GetBytes(str), b, len);
|
||||
}
|
||||
public void WriteUInt64(UInt64 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
public void WriteInt64(Int64 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
public void WriteUInt16(UInt16 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
public void WriteInt16(Int16 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
|
||||
public void WriteUInt32(UInt32 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
public void WriteInt32BE(Int32 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v).Reverse().ToArray());
|
||||
}
|
||||
public void WriteInt32At(Int32 v, long location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
WriteInt32(v);
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
}
|
||||
public void WriteUInt32At(UInt32 v, long location)
|
||||
{
|
||||
long oldPos = s.Position;
|
||||
s.Seek(location, SeekOrigin.Begin);
|
||||
WriteUInt32(v);
|
||||
s.Seek(oldPos, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
public void WriteInt32(Int32 v)
|
||||
{
|
||||
WriteBytes(BitConverter.GetBytes(v));
|
||||
}
|
||||
public void WriteCStr(string str)
|
||||
{
|
||||
WriteStr(str);
|
||||
WriteByte(0x00);
|
||||
}
|
||||
public void WriteStr(string str)
|
||||
{
|
||||
WriteBytes(Encoding.UTF8.GetBytes(str));
|
||||
}
|
||||
|
||||
public void WritePadding(byte b, int len)
|
||||
{
|
||||
if (len < 0) return;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
WriteByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignTo(byte padByte, int align)
|
||||
{
|
||||
int padAmt = MathUtil.CalculatePaddingAmount(Convert.ToInt32(s.Position), align);
|
||||
|
||||
this.WritePadding(padByte, padAmt);
|
||||
}
|
||||
public void PadUntil(byte b, int len)
|
||||
{
|
||||
int remain = Convert.ToInt32(len - s.Length);
|
||||
WritePadding(b, remain);
|
||||
}
|
||||
public void WriteBytes(byte[] bytes)
|
||||
{
|
||||
s.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
s.WriteByte(b);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
710
PspCrypto/AMCTRL.cs
Normal file
710
PspCrypto/AMCTRL.cs
Normal file
|
@ -0,0 +1,710 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public class AMCTRL
|
||||
{
|
||||
static readonly Memory<byte> kirk_buf = new byte[0x0814];
|
||||
static readonly Memory<byte> kirk_buf2 = new byte[0x8014];
|
||||
|
||||
// AMCTRL keys.
|
||||
static readonly byte[] amctrl_key1 = { 0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB };
|
||||
static readonly byte[] amctrl_key2 = { 0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45 };
|
||||
static readonly byte[] amctrl_key3 = { 0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E };
|
||||
|
||||
public unsafe struct MAC_KEY
|
||||
{
|
||||
public int type;
|
||||
private fixed byte _key[16];
|
||||
|
||||
public Span<byte> key
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _key)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _pad[16];
|
||||
|
||||
public Span<byte> pad
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _pad)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
public int pad_size;
|
||||
}
|
||||
|
||||
public unsafe struct CIPHER_KEY
|
||||
{
|
||||
public int type;
|
||||
public int seed;
|
||||
fixed byte _key[16];
|
||||
|
||||
public Span<byte> key
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _key)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* KIRK wrapper functions.
|
||||
*/
|
||||
static int Kirk4(Span<byte> buf, int size, int type)
|
||||
{
|
||||
int retv;
|
||||
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
|
||||
hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
|
||||
hdr.keyseed = type;
|
||||
hdr.data_size = size;
|
||||
|
||||
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_ENCRYPT_IV_0);
|
||||
|
||||
if (retv != 0)
|
||||
return -2142174447; // 0x80510311;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Kirk5(Span<byte> buf, int size)
|
||||
{
|
||||
int retv;
|
||||
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
|
||||
hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
|
||||
hdr.keyseed = 0x0100;
|
||||
hdr.data_size = size;
|
||||
|
||||
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_ENCRYPT_IV_FUSE);
|
||||
|
||||
if (retv != 0)
|
||||
return -2142174446; // 0x80510312;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Kirk7(Span<byte> buf, int size, int type)
|
||||
{
|
||||
int retv;
|
||||
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
|
||||
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
|
||||
hdr.keyseed = type;
|
||||
hdr.data_size = size;
|
||||
|
||||
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_0);
|
||||
|
||||
if (retv != 0)
|
||||
return -2142174447; // 0x80510311;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Kirk8(Span<byte> buf, int size)
|
||||
{
|
||||
int retv;
|
||||
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
|
||||
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
|
||||
hdr.keyseed = 0x0100;
|
||||
hdr.data_size = size;
|
||||
|
||||
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_FUSE);
|
||||
|
||||
if (retv != 0)
|
||||
return -2142174446; // 0x80510312;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Kirk14(Span<byte> buf)
|
||||
{
|
||||
int retv;
|
||||
|
||||
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, 0x14, null, 0, KIRKEngine.KIRK_CMD_PRNG);
|
||||
|
||||
if (retv != 0)
|
||||
return -2142174443; // 0x80510315;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encrypt_buf(Span<byte> buf, int size, Span<byte> key, int key_type)
|
||||
{
|
||||
int i, retv;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
buf[0x14 + i] ^= key[i];
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = buf)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
retv = Kirk4(buf, size, key_type);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
buf.Slice(size + 4, 16).CopyTo(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decrypt_buf(Span<byte> buf, int size, Span<byte> key, int key_type)
|
||||
{
|
||||
int i, retv;
|
||||
Span<byte> tmp = stackalloc byte[16];
|
||||
|
||||
buf.Slice(size + 0x14 - 16, 16).CopyTo(tmp);
|
||||
|
||||
retv = Kirk7(buf, size, key_type);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
buf[i] ^= key[i];
|
||||
}
|
||||
|
||||
tmp.CopyTo(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cipher_buf(Span<byte> kbuf, Span<byte> dbuf, int size, ref CIPHER_KEY ckey)
|
||||
{
|
||||
int i, retv;
|
||||
Span<byte> tmp1 = stackalloc byte[16], tmp2 = stackalloc byte[16];
|
||||
|
||||
ckey.key.CopyTo(kbuf[0x14..]);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
kbuf[0x14 + i] ^= amctrl_key3[i];
|
||||
}
|
||||
|
||||
if (ckey.type == 2)
|
||||
retv = Kirk8(kbuf, 16);
|
||||
else
|
||||
retv = Kirk7(kbuf, 16, 0x39);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
kbuf[i] ^= amctrl_key2[i];
|
||||
}
|
||||
|
||||
kbuf.Slice(0, 0x10).CopyTo(tmp2);
|
||||
|
||||
if (ckey.seed == 1)
|
||||
{
|
||||
tmp1.Fill(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp2.CopyTo(tmp1);
|
||||
var tmp = ckey.seed - 1;
|
||||
MemoryMarshal.Write(tmp1[0x0c..], ref tmp);
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += 16)
|
||||
{
|
||||
tmp2[..12].CopyTo(kbuf[(0x14 + i)..]);
|
||||
MemoryMarshal.Write(kbuf[(0x14 + i + 12)..], ref ckey.seed);
|
||||
ckey.seed += 1;
|
||||
}
|
||||
|
||||
retv = decrypt_buf(kbuf, size, tmp1, 0x63);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
dbuf[i] ^= kbuf[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int sceDrmBBMacInit(Span<byte> mkey, int type)
|
||||
{
|
||||
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
|
||||
macKey.type = type;
|
||||
macKey.key.Clear();
|
||||
macKey.pad.Clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int sceDrmBBMacUpdate(Span<byte> mkey, ReadOnlySpan<byte> buf, int size)
|
||||
{
|
||||
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
|
||||
|
||||
int retv = 0, ksize, p, type;
|
||||
int kbuf;
|
||||
|
||||
if (macKey.pad_size > 16)
|
||||
{
|
||||
retv = -2142174462; // 0x80510302
|
||||
return retv;
|
||||
}
|
||||
|
||||
if (macKey.pad_size + size <= 16)
|
||||
{
|
||||
buf[..size].CopyTo(macKey.pad[macKey.pad_size..]);
|
||||
macKey.pad_size += size;
|
||||
retv = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
kbuf = 0x14;
|
||||
macKey.pad[..macKey.pad_size].CopyTo(kirk_buf[0x14..].Span);
|
||||
|
||||
p = macKey.pad_size;
|
||||
|
||||
macKey.pad_size += size;
|
||||
macKey.pad_size &= 0x0f;
|
||||
if (macKey.pad_size == 0)
|
||||
macKey.pad_size = 16;
|
||||
|
||||
size -= macKey.pad_size;
|
||||
buf.Slice(size, macKey.pad_size).CopyTo(macKey.pad);
|
||||
|
||||
type = (macKey.type == 2) ? 0x3A : 0x38;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
ksize = (size + p >= 0x0800) ? 0x0800 : size + p;
|
||||
buf.Slice(offset, ksize - p).CopyTo(kirk_buf[(kbuf + p)..].Span);
|
||||
retv = encrypt_buf(kirk_buf.Span, ksize, macKey.key, type);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
size -= (ksize - p);
|
||||
offset += ksize - p;
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
public static int sceDrmBBMacUpdate2(Span<byte> mkey, Span<byte> buf, int size)
|
||||
{
|
||||
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
|
||||
|
||||
int retv = 0, ksize, p, type;
|
||||
int kbuf;
|
||||
|
||||
if (macKey.pad_size > 16)
|
||||
{
|
||||
retv = -2142174462; // 0x80510302
|
||||
return retv;
|
||||
}
|
||||
|
||||
if (macKey.pad_size + size <= 16)
|
||||
{
|
||||
buf.Slice(0, size).CopyTo(macKey.pad.Slice(macKey.pad_size));
|
||||
macKey.pad_size += size;
|
||||
retv = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
kbuf = 0x14;
|
||||
macKey.pad.Slice(0, macKey.pad_size).CopyTo(kirk_buf.Slice(0x14).Span);
|
||||
|
||||
p = macKey.pad_size;
|
||||
|
||||
macKey.pad_size += (size & 0x0f);
|
||||
//mkey.pad_size &= 0x0f;
|
||||
if (macKey.pad_size == 0)
|
||||
macKey.pad_size = 16;
|
||||
|
||||
size -= macKey.pad_size;
|
||||
buf.Slice(size, macKey.pad_size).CopyTo(macKey.pad);
|
||||
|
||||
type = (macKey.type == 2) ? 0x3A : 0x38;
|
||||
|
||||
int idx = 0;
|
||||
|
||||
ksize = size + p;
|
||||
int offset = 0;
|
||||
if (size + p >= 0x8001)
|
||||
{
|
||||
;
|
||||
buf.Slice(offset, 0x8000 - p).CopyTo(kirk_buf2.Slice(kbuf + p).Span);
|
||||
retv = encrypt_buf(kirk_buf2.Span, 0x8000, macKey.key, type);
|
||||
idx = 0x8000 - p;
|
||||
var fix = -p;
|
||||
while (retv == 0)
|
||||
{
|
||||
if (size <= 0x10000 - fix)
|
||||
{
|
||||
p = 0;
|
||||
ksize = size;
|
||||
break;
|
||||
}
|
||||
buf.Slice(offset + idx, 0x8000).CopyTo(kirk_buf2.Slice(kbuf).Span);
|
||||
retv = encrypt_buf(kirk_buf2.Span, 0x8000, macKey.key, type);
|
||||
fix = idx;
|
||||
idx += 0x8000;
|
||||
}
|
||||
|
||||
if (retv != 0)
|
||||
{
|
||||
return retv;
|
||||
}
|
||||
}
|
||||
buf.Slice(offset + idx, size - idx).CopyTo(kirk_buf2.Slice(kbuf + p).Span);
|
||||
retv = encrypt_buf(kirk_buf2.Span, ksize - idx, macKey.key, type);
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
public static int sceDrmBBMacFinal(Span<byte> mkey, Span<byte> buf, ReadOnlySpan<byte> vkey)
|
||||
{
|
||||
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
|
||||
int i, retv, code;
|
||||
Span<byte> tmp = stackalloc byte[16], tmp1 = stackalloc byte[16];
|
||||
int kbuf;
|
||||
uint t0, v0, v1;
|
||||
|
||||
if (macKey.pad_size > 16)
|
||||
return -2142174462; //0x80510302;
|
||||
|
||||
code = (macKey.type == 2) ? 0x3A : 0x38;
|
||||
kbuf = 0x14;
|
||||
|
||||
kirk_buf.Slice(kbuf, 16).Span.Fill(0);
|
||||
retv = Kirk4(kirk_buf.Span, 16, code);
|
||||
if (retv != 0)
|
||||
{
|
||||
return retv;
|
||||
}
|
||||
|
||||
kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp);
|
||||
|
||||
t0 = ((tmp[0] & 0x80) > 0) ? 0x87u : 0;
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
v1 = tmp[i + 0];
|
||||
v0 = tmp[i + 1];
|
||||
v1 <<= 1;
|
||||
v0 >>= 7;
|
||||
v0 |= v1;
|
||||
tmp[i + 0] = (byte)v0;
|
||||
}
|
||||
v0 = tmp[15];
|
||||
v0 <<= 1;
|
||||
v0 ^= t0;
|
||||
tmp[15] = (byte)v0;
|
||||
|
||||
if (macKey.pad_size < 16)
|
||||
{
|
||||
t0 = ((tmp[0] & 0x80) > 0) ? 0x87u : 0;
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
v1 = tmp[i + 0];
|
||||
v0 = tmp[i + 1];
|
||||
v1 <<= 1;
|
||||
v0 >>= 7;
|
||||
v0 |= v1;
|
||||
tmp[i + 0] = (byte)v0;
|
||||
}
|
||||
v0 = tmp[15];
|
||||
v0 <<= 1;
|
||||
v0 ^= t0;
|
||||
tmp[15] = (byte)v0;
|
||||
|
||||
macKey.pad[macKey.pad_size] = 0x80;
|
||||
if (macKey.pad_size + 1 < 16)
|
||||
{
|
||||
macKey.pad.Slice(macKey.pad_size + 1, 16 - macKey.pad_size - 1).Fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
macKey.pad[i] ^= tmp[i];
|
||||
}
|
||||
|
||||
macKey.pad.CopyTo(kirk_buf.Slice(kbuf).Span);
|
||||
macKey.key.CopyTo(tmp1);
|
||||
|
||||
retv = encrypt_buf(kirk_buf.Span, 0x10, tmp1, code);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
for (i = 0; i < 0x10; i++)
|
||||
{
|
||||
tmp1[i] ^= amctrl_key1[i];
|
||||
}
|
||||
|
||||
if (macKey.type == 2)
|
||||
{
|
||||
tmp1.CopyTo(kirk_buf.Slice(kbuf).Span);
|
||||
|
||||
retv = Kirk5(kirk_buf.Span, 0x10);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
retv = Kirk4(kirk_buf.Span, 0x10, code);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp1);
|
||||
}
|
||||
|
||||
if (vkey != null)
|
||||
{
|
||||
for (i = 0; i < 0x10; i++)
|
||||
{
|
||||
tmp1[i] ^= vkey[i];
|
||||
}
|
||||
tmp1.CopyTo(kirk_buf.Slice(kbuf).Span);
|
||||
|
||||
retv = Kirk4(kirk_buf.Span, 0x10, code);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
kirk_buf.Slice(kbuf, 16).Span.CopyTo(tmp1);
|
||||
}
|
||||
|
||||
tmp1.CopyTo(buf);
|
||||
|
||||
macKey.key.Fill(0);
|
||||
macKey.pad.Fill(0);
|
||||
|
||||
macKey.pad_size = 0;
|
||||
macKey.type = 0;
|
||||
retv = 0;
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static int bbmac_getkey(Span<byte> mkey, ReadOnlySpan<byte> bbmac, Span<byte> vkey)
|
||||
{
|
||||
int i, retv, type, code;
|
||||
Span<byte> tmp = stackalloc byte[16], tmp1 = stackalloc byte[16];
|
||||
int kbuf;
|
||||
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
|
||||
|
||||
type = macKey.type;
|
||||
retv = sceDrmBBMacFinal(mkey, tmp, null);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
kbuf = 0x14;
|
||||
|
||||
if (type == 3)
|
||||
{
|
||||
bbmac[..0x10].CopyTo(kirk_buf[kbuf..].Span);
|
||||
Kirk7(kirk_buf.Span, 0x10, 0x63);
|
||||
}
|
||||
else
|
||||
{
|
||||
bbmac[..0x10].CopyTo(kirk_buf.Span);
|
||||
}
|
||||
|
||||
kirk_buf[..16].Span.CopyTo(tmp1);
|
||||
tmp1.CopyTo(kirk_buf[kbuf..].Span);
|
||||
|
||||
code = (type == 2) ? 0x3A : 0x38;
|
||||
Kirk7(kirk_buf.Span, 0x10, code);
|
||||
|
||||
for (i = 0; i < 0x10; i++)
|
||||
{
|
||||
vkey[i] = (byte)(tmp[i] ^ kirk_buf.Span[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int sceDrmBBMacFinal2(Span<byte> mkey, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> vkey)
|
||||
{
|
||||
int retv, type;
|
||||
byte[] tmp = new byte[16];
|
||||
int kbuf;
|
||||
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);
|
||||
|
||||
type = macKey.type;
|
||||
retv = sceDrmBBMacFinal(mkey, tmp, vkey);
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
kbuf = 0x14;
|
||||
|
||||
if (type == 3)
|
||||
{
|
||||
hash[..0x10].CopyTo(kirk_buf[kbuf..].Span);
|
||||
Kirk7(kirk_buf.Span, 0x10, 0x63);
|
||||
}
|
||||
else
|
||||
{
|
||||
hash[..0x10].CopyTo(kirk_buf.Span);
|
||||
}
|
||||
|
||||
retv = 0;
|
||||
if (!kirk_buf.Span[..0x10].SequenceEqual(tmp))
|
||||
{
|
||||
retv = -2142174464; //0x80510300;
|
||||
}
|
||||
//for (i = 0; i < 0x10; i++)
|
||||
//{
|
||||
// if (kirk_buf.Span[i] != tmp[i])
|
||||
// {
|
||||
// retv = -2142174464; //0x80510300;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
BBCipher functions.
|
||||
*/
|
||||
public static int sceDrmBBCipherInit(out CIPHER_KEY ckey, int type, int mode, ReadOnlySpan<byte> header_key, ReadOnlySpan<byte> version_key, int seed)
|
||||
{
|
||||
int i, retv;
|
||||
int kbuf;
|
||||
|
||||
kbuf = 0x14;
|
||||
ckey = new CIPHER_KEY { type = type };
|
||||
if (mode == 2)
|
||||
{
|
||||
ckey.seed = seed + 1;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
ckey.key[i] = header_key[i];
|
||||
}
|
||||
if (version_key != null)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
ckey.key[i] ^= version_key[i];
|
||||
}
|
||||
}
|
||||
retv = 0;
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
ckey.seed = 1;
|
||||
retv = Kirk14(kirk_buf.Span);
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
kirk_buf.Slice(0, 0x10).CopyTo(kirk_buf.Slice(kbuf));
|
||||
kirk_buf.Slice(kbuf + 0xC, 4).Span.Fill(0);
|
||||
|
||||
if (ckey.type == 2)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
kirk_buf.Span[i + kbuf] ^= amctrl_key2[i];
|
||||
}
|
||||
retv = Kirk5(kirk_buf.Span, 0x10);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
kirk_buf.Span[i + kbuf] ^= amctrl_key3[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
kirk_buf.Span[i + kbuf] ^= amctrl_key2[i];
|
||||
}
|
||||
retv = Kirk4(kirk_buf.Span, 0x10, 0x39);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
kirk_buf.Span[i + kbuf] ^= amctrl_key3[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (retv != 0)
|
||||
return retv;
|
||||
|
||||
kirk_buf.Slice(kbuf, 0x10).Span.CopyTo(ckey.key);
|
||||
// kirk_buf.Slice(kbuf, 0x10).Span.CopyTo(header_key);
|
||||
|
||||
if (version_key != null)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
ckey.key[i] ^= version_key[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retv = 0;
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
public static int sceDrmBBCipherUpdate(ref CIPHER_KEY ckey, Span<byte> data, int size)
|
||||
{
|
||||
int p, retv, dsize;
|
||||
|
||||
retv = 0;
|
||||
p = 0;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
dsize = (size >= 0x0800) ? 0x0800 : size;
|
||||
retv = cipher_buf(kirk_buf.Span, data.Slice(p), dsize, ref ckey);
|
||||
|
||||
if (retv != 0)
|
||||
break;
|
||||
|
||||
size -= dsize;
|
||||
p += dsize;
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
public static int sceDrmBBCipherFinal(ref CIPHER_KEY ckey)
|
||||
{
|
||||
ckey.key.Fill(0);
|
||||
ckey.type = 0;
|
||||
ckey.seed = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
251
PspCrypto/AesHelper.cs
Normal file
251
PspCrypto/AesHelper.cs
Normal file
|
@ -0,0 +1,251 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public static class AesHelper
|
||||
{
|
||||
private static readonly byte[] padding = { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 };
|
||||
|
||||
static readonly byte[] IV0 = new byte[16];
|
||||
static readonly byte[] Z = new byte[16];
|
||||
|
||||
public static Aes CreateAes()
|
||||
{
|
||||
var aes = Aes.Create();
|
||||
aes.KeySize = 128;
|
||||
if (aes == null)
|
||||
{
|
||||
throw new Exception("Create Aes Failed");
|
||||
}
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.None;
|
||||
aes.IV = IV0;
|
||||
return aes;
|
||||
}
|
||||
|
||||
public static Aes CreateKirkAes()
|
||||
{
|
||||
var aes = CreateAes();
|
||||
aes.Key = KeyVault.kirk1_key;
|
||||
return aes;
|
||||
}
|
||||
|
||||
#if false
|
||||
public static byte[] Cmac(Aes aes, byte[] orgdata, int offset = 0, int len = -1)
|
||||
{
|
||||
if (len == -1)
|
||||
{
|
||||
len = orgdata.Length;
|
||||
}
|
||||
|
||||
byte[] data;
|
||||
if (offset == 0 && len == orgdata.Length)
|
||||
{
|
||||
data = orgdata;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new byte[len];
|
||||
Buffer.BlockCopy(orgdata, offset, data, 0, len);
|
||||
}
|
||||
// SubKey generation
|
||||
// step 1, AES-128 with key K is applied to an all-zero input block.
|
||||
byte[] L = AesEncrypt(aes, Z);
|
||||
|
||||
// step 2, K1 is derived through the following operation:
|
||||
byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
|
||||
if ((L[0] & 0x80) == 0x80)
|
||||
FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of c
|
||||
|
||||
// step 3, K2 is derived through the following operation:
|
||||
byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
|
||||
if ((FirstSubkey[0] & 0x80) == 0x80)
|
||||
SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
|
||||
|
||||
// MAC computing
|
||||
if (((data.Length != 0) && (data.Length % 16 == 0)))
|
||||
{
|
||||
// If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits),
|
||||
// the last block shall be exclusive-OR'ed with K1 before processing
|
||||
for (int j = 0; j < FirstSubkey.Length; j++)
|
||||
data[data.Length - 16 + j] ^= FirstSubkey[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, the last block shall be padded with 10^i
|
||||
byte[] padding = new byte[16 - data.Length % 16];
|
||||
padding[0] = 0x80;
|
||||
|
||||
data = data.Concat(padding).ToArray();
|
||||
|
||||
// and exclusive-OR'ed with K2
|
||||
for (int j = 0; j < SecondSubkey.Length; j++)
|
||||
data[data.Length - 16 + j] ^= SecondSubkey[j];
|
||||
}
|
||||
|
||||
// The result of the previous process will be the input of the last encryption.
|
||||
byte[] encResult = AesEncrypt(aes, data);
|
||||
|
||||
byte[] HashValue = new byte[16];
|
||||
//Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
|
||||
Buffer.BlockCopy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
|
||||
|
||||
return HashValue;
|
||||
}
|
||||
|
||||
#endif
|
||||
public static void Cmac(Aes aes, Span<byte> dst, ReadOnlySpan<byte> src)
|
||||
{
|
||||
byte[] data = src.ToArray();
|
||||
// SubKey generation
|
||||
// step 1, AES-128 with key K is applied to an all-zero input block.
|
||||
byte[] L = AesEncrypt(aes, Z);
|
||||
|
||||
// step 2, K1 is derived through the following operation:
|
||||
byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
|
||||
if ((L[0] & 0x80) == 0x80)
|
||||
FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of c
|
||||
|
||||
// step 3, K2 is derived through the following operation:
|
||||
byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
|
||||
if ((FirstSubkey[0] & 0x80) == 0x80)
|
||||
SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
|
||||
|
||||
// MAC computing
|
||||
if (((data.Length != 0) && (data.Length % 16 == 0)))
|
||||
{
|
||||
// If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits),
|
||||
// the last block shall be exclusive-OR'ed with K1 before processing
|
||||
for (int j = 0; j < FirstSubkey.Length; j++)
|
||||
data[data.Length - 16 + j] ^= FirstSubkey[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, the last block shall be padded with 10^i
|
||||
byte[] padding = new byte[16 - data.Length % 16];
|
||||
padding[0] = 0x80;
|
||||
|
||||
data = data.Concat(padding).ToArray();
|
||||
|
||||
// and exclusive-OR'ed with K2
|
||||
for (int j = 0; j < SecondSubkey.Length; j++)
|
||||
data[data.Length - 16 + j] ^= SecondSubkey[j];
|
||||
}
|
||||
|
||||
// The result of the previous process will be the input of the last encryption.
|
||||
byte[] encResult = AesEncrypt(aes, data);
|
||||
|
||||
encResult.AsSpan(encResult.Length - 16,16).CopyTo(dst);
|
||||
|
||||
//byte[] HashValue = new byte[16];
|
||||
//Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
|
||||
//Buffer.BlockCopy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
|
||||
|
||||
//return HashValue;
|
||||
}
|
||||
|
||||
private static byte[] Rol(byte[] b)
|
||||
{
|
||||
byte[] r = new byte[b.Length];
|
||||
byte carry = 0;
|
||||
|
||||
for (int i = b.Length - 1; i >= 0; i--)
|
||||
{
|
||||
ushort u = (ushort)(b[i] << 1);
|
||||
r[i] = (byte)((u & 0xff) + carry);
|
||||
carry = (byte)((u & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private static byte[] AesEncrypt(Aes aes, byte[] data)
|
||||
{
|
||||
using var encryptor = aes.CreateEncryptor();
|
||||
return encryptor.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
#if false
|
||||
|
||||
public static byte[] AesEncrypt(Aes aes, byte[] data, int offset, int length)
|
||||
{
|
||||
using var encryptor = aes.CreateEncryptor();
|
||||
return encryptor.TransformFinalBlock(data, offset, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void AesEncrypt(Aes aes, Span<byte> oubput, ReadOnlySpan<byte> input, int size = 0)
|
||||
{
|
||||
byte[] buffer;
|
||||
if (size == 0)
|
||||
{
|
||||
size = input.Length;
|
||||
}
|
||||
if (size % 16 != 0)
|
||||
{
|
||||
buffer = new byte[(size + 15) / 16 * 16];
|
||||
var bufferSpan = new Span<byte>(buffer);
|
||||
input.CopyTo(bufferSpan);
|
||||
padding.AsSpan(0, buffer.Length - size).CopyTo(bufferSpan[size..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = input[..size].ToArray();
|
||||
}
|
||||
using var encryptor = aes.CreateEncryptor();
|
||||
var encData = encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
|
||||
encData.AsSpan().CopyTo(oubput);
|
||||
}
|
||||
|
||||
#if false
|
||||
public static byte[] AesDecrypt(Aes aes, byte[] data, int offset, int length)
|
||||
{
|
||||
aes.Padding = PaddingMode.None;
|
||||
using var encryptor = aes.CreateDecryptor();
|
||||
int fixLength = length;
|
||||
if (length % 16 != 0)
|
||||
{
|
||||
fixLength = (length / 16 + 1) * 16;
|
||||
}
|
||||
|
||||
byte[] ret = encryptor.TransformFinalBlock(data, offset, fixLength);
|
||||
return ret.Take(length).ToArray();
|
||||
}
|
||||
|
||||
public static void AesDecrypt(Aes aes, byte[] src, byte[] dst, int size)
|
||||
{
|
||||
var tmp = AesDecrypt(aes, src, 0, size);
|
||||
Buffer.BlockCopy(tmp, 0, dst, 0, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void AesDecrypt(Aes aes, Span<byte> dst, ReadOnlySpan<byte> src, int length)
|
||||
{
|
||||
|
||||
int fixLength = length;
|
||||
if (length % 16 != 0)
|
||||
{
|
||||
fixLength = (length + 15) / 16 * 16;
|
||||
}
|
||||
var buffer = src[..fixLength].ToArray();
|
||||
using var encryptor = aes.CreateDecryptor();
|
||||
var decData = encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
|
||||
decData.AsSpan(0, length).CopyTo(dst);
|
||||
}
|
||||
|
||||
public static int AesDecrypt(ReadOnlySpan<byte> src, Span<byte> dst, ReadOnlySpan<byte> key)
|
||||
{
|
||||
Aes aes = Aes.Create();
|
||||
aes.Key = key[..16].ToArray();
|
||||
return aes.DecryptEcb(src[..16], dst, PaddingMode.None);
|
||||
}
|
||||
|
||||
public static int AesEncrypt(ReadOnlySpan<byte> src, Span<byte> dst, ReadOnlySpan<byte> key)
|
||||
{
|
||||
Aes aes = Aes.Create();
|
||||
aes.Key = key[..16].ToArray();
|
||||
return aes.EncryptEcb(src[..16], dst, PaddingMode.None);
|
||||
}
|
||||
}
|
||||
}
|
126
PspCrypto/AtracCrypto.cs
Normal file
126
PspCrypto/AtracCrypto.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public class AtracCrypto
|
||||
{
|
||||
|
||||
const int NBYTES = 0x180;
|
||||
private static uint ROTR32(uint v, int n)
|
||||
{
|
||||
n &= 32 - 1;
|
||||
return (v >> n) | (v << (32 - n));
|
||||
}
|
||||
|
||||
public static int UnscrambleAtracData(byte[] data, uint key)
|
||||
{
|
||||
int blocks = (data.Length / NBYTES) / 0x10;
|
||||
int chunks_rest = (data.Length / NBYTES) % 0x10;
|
||||
Span<uint> ptr = MemoryMarshal.Cast<byte, uint>(data);
|
||||
uint tmp2 = key;
|
||||
uint tmp;
|
||||
uint value;
|
||||
// for each block
|
||||
while (blocks > 0)
|
||||
{
|
||||
// for each chunk of block
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
tmp = tmp2;
|
||||
|
||||
// for each value of chunk
|
||||
for (int k = 0; k < (NBYTES / 4); k++)
|
||||
{
|
||||
value = ptr[k];
|
||||
ptr[k] = tmp ^ value;
|
||||
tmp = tmp2 + (value * 123456789);
|
||||
}
|
||||
|
||||
tmp2 = ROTR32(tmp2, 1);
|
||||
ptr = ptr[(NBYTES / 4)..]; // pointer on next chunk
|
||||
}
|
||||
|
||||
blocks--;
|
||||
}
|
||||
|
||||
// do rest chunks
|
||||
for (int i = 0; i < chunks_rest; i++)
|
||||
{
|
||||
tmp = tmp2;
|
||||
|
||||
// for each value of chunk
|
||||
for (int k = 0; k < (NBYTES / 4); k++)
|
||||
{
|
||||
value = ptr[k];
|
||||
ptr[k] = tmp ^ value;
|
||||
tmp = tmp2 + (value * 123456789);
|
||||
}
|
||||
|
||||
tmp2 = ROTR32(tmp2, 1);
|
||||
ptr = ptr[(NBYTES / 4)..]; // next chunk
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void ScrambleAtracData(Stream input, Stream output, uint key)
|
||||
{
|
||||
int blocks = (Convert.ToInt32(input.Length) / NBYTES) / 0x10;
|
||||
int chunks_rest = (Convert.ToInt32(input.Length) / NBYTES) % 0x10;
|
||||
Span<byte> block = stackalloc byte[NBYTES];
|
||||
uint tmp2 = key;
|
||||
uint tmp;
|
||||
// for each block
|
||||
while (blocks > 0)
|
||||
{
|
||||
// for each chunk of block
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
tmp = tmp2;
|
||||
|
||||
input.Read(block);
|
||||
Span<uint> ptr = MemoryMarshal.Cast<byte, uint>(block);
|
||||
|
||||
// for each value of chunk
|
||||
for (int k = 0; k < (NBYTES / 4); k++)
|
||||
{
|
||||
ptr[k] ^= tmp;
|
||||
tmp = tmp2 + (ptr[k] * 123456789);
|
||||
}
|
||||
output.Write(block);
|
||||
|
||||
tmp2 = ROTR32(tmp2, 1);
|
||||
ptr = ptr[(NBYTES / 4)..]; // pointer on next chunk
|
||||
}
|
||||
|
||||
blocks--;
|
||||
}
|
||||
|
||||
// do rest chunks
|
||||
for (int i = 0; i < chunks_rest; i++)
|
||||
{
|
||||
tmp = tmp2;
|
||||
|
||||
input.Read(block);
|
||||
Span<uint> ptr = MemoryMarshal.Cast<byte, uint>(block);
|
||||
|
||||
// for each value of chunk
|
||||
for (int k = 0; k < (NBYTES / 4); k++)
|
||||
{
|
||||
ptr[k] ^= tmp;
|
||||
tmp = tmp2 + (ptr[k] * 123456789);
|
||||
}
|
||||
output.Write(block);
|
||||
|
||||
tmp2 = ROTR32(tmp2, 1);
|
||||
ptr = ptr[(NBYTES / 4)..]; // next chunk
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
172
PspCrypto/DNASHelper.cs
Normal file
172
PspCrypto/DNASHelper.cs
Normal file
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
using PgdHeader = DNASStream.PgdHeader;
|
||||
using PgdDesc = DNASStream.PgdDesc;
|
||||
|
||||
public static class DNASHelper
|
||||
{
|
||||
public static int CalculateSize(int dataSize, int blockSize)
|
||||
{
|
||||
int alignSize = (dataSize + 15) & ~15;
|
||||
int tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16);
|
||||
int pgdSize = 0x90 + alignSize + tableSize;
|
||||
return pgdSize;
|
||||
}
|
||||
|
||||
public static int Encrypt(Span<byte> pgdData, ReadOnlySpan<byte> data, ReadOnlySpan<byte> key, int dataSize, int keyIndex, int drmType, int flag = 2, int blockSize = 0x400)
|
||||
{
|
||||
// Additional size variables.
|
||||
var dataOffset = 0x90;
|
||||
var alignSize = (dataSize + 15) & ~15;
|
||||
var tableOffset = dataOffset + alignSize;
|
||||
var tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16);
|
||||
var pgdSize = 0x90 + alignSize + tableSize;
|
||||
|
||||
if (pgdData.Length < pgdSize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
data[..dataSize].CopyTo(pgdData[dataOffset..]);
|
||||
|
||||
ref var pgdHdr = ref MemoryMarshal.AsRef<PgdHeader>(pgdData);
|
||||
pgdHdr.Magic = 0x44475000;
|
||||
pgdHdr.KeyIndex = keyIndex;
|
||||
pgdHdr.DrmType = drmType;
|
||||
|
||||
// Select the hashing, crypto and open modes.
|
||||
int macType;
|
||||
int cipherType;
|
||||
var openFlag = flag;
|
||||
if (drmType == 1)
|
||||
{
|
||||
macType = 1;
|
||||
cipherType = 1;
|
||||
openFlag |= 4;
|
||||
if (keyIndex > 1)
|
||||
{
|
||||
macType = 3;
|
||||
openFlag |= 0xc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
macType = 2;
|
||||
cipherType = 2;
|
||||
}
|
||||
|
||||
// Select the fixed DNAS key.
|
||||
|
||||
|
||||
byte[] dnasKey = null;
|
||||
|
||||
if ((openFlag & 2) != 0)
|
||||
{
|
||||
dnasKey = DNASStream.DnasKey1;
|
||||
}
|
||||
else if ((openFlag & 1) != 0)
|
||||
{
|
||||
dnasKey = DNASStream.DnasKey2;
|
||||
}
|
||||
|
||||
if (dnasKey == null)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
// Set the decryption parameters in the decrypted header.
|
||||
ref var pgdDesc = ref MemoryMarshal.AsRef<PgdDesc>(pgdHdr.PgdDesc);
|
||||
pgdDesc.DataSize = dataSize;
|
||||
pgdDesc.BlockSize = blockSize;
|
||||
pgdDesc.DataOffset = dataOffset;
|
||||
|
||||
// Generate random header and data keys.
|
||||
RandomNumberGenerator.Fill(pgdData.Slice(0x10, 0x30));
|
||||
|
||||
// Encrypt the data.
|
||||
DNASStream.DoBBCipher(pgdData[dataOffset..], alignSize, 0, key, pgdDesc.Key, cipherType);
|
||||
|
||||
// Build data MAC hash.
|
||||
var tableNum = tableSize / 16;
|
||||
for (int i = 0; i < tableNum; i++)
|
||||
{
|
||||
int rsize = alignSize - i * blockSize;
|
||||
if (rsize > blockSize)
|
||||
rsize = blockSize;
|
||||
if (keyIndex < 3)
|
||||
{
|
||||
BuildBBMac(pgdData[(dataOffset + i * blockSize)..], rsize, key,
|
||||
pgdData[(tableOffset + i * 16)..],
|
||||
macType);
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildBBMac(pgdData[(dataOffset + i * blockSize)..], rsize, key,
|
||||
pgdData[(tableOffset + i * 16)..],
|
||||
macType);
|
||||
}
|
||||
}
|
||||
|
||||
// Build table MAC hash.
|
||||
BuildBBMac(pgdData.Slice(tableOffset), tableSize, key, pgdHdr.MacTableHash, macType);
|
||||
|
||||
// Encrypt the PGD header block (0x30 bytes).
|
||||
DNASStream.DoBBCipher(pgdHdr.PgdDesc, 0x30, 0, key, pgdHdr.DescKey, cipherType);
|
||||
|
||||
// Build MAC hash at 0x70 (key hash).
|
||||
BuildBBMac(pgdData, 0x70, key, pgdHdr.Hash70, macType);
|
||||
|
||||
// Build MAC hash at 0x80 (DNAS hash).
|
||||
BuildBBMac(pgdData, 0x80, dnasKey, pgdHdr.Hash80, macType);
|
||||
|
||||
return pgdSize;
|
||||
}
|
||||
|
||||
static int BuildBBMac(ReadOnlySpan<byte> data, int size, ReadOnlySpan<byte> key, Span<byte> hash, int macType, int seed = 0)
|
||||
{
|
||||
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<AMCTRL.MAC_KEY>()];
|
||||
Span<byte> tmpKey = stackalloc byte[0x10];
|
||||
int ret = unchecked((int)0x80510201);
|
||||
if (hash != null)
|
||||
{
|
||||
ret = AMCTRL.sceDrmBBMacInit(mkey, macType);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
key.CopyTo(tmpKey);
|
||||
if (seed != 0)
|
||||
{
|
||||
var tmpXor = MemoryMarshal.Cast<byte, int>(tmpKey);
|
||||
tmpXor[0] ^= seed;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBMacFinal(mkey, hash, tmpKey);
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = unchecked((int)0x80510207);
|
||||
}
|
||||
|
||||
if (macType == 3)
|
||||
{
|
||||
Utils.BuildDrmBBMacFinal2(hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
636
PspCrypto/DNASStream.cs
Normal file
636
PspCrypto/DNASStream.cs
Normal file
|
@ -0,0 +1,636 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public class DNASStream : Stream
|
||||
{
|
||||
internal static readonly byte[] DnasKeyBase =
|
||||
{
|
||||
0x2A, 0x05, 0x54, 0x40, 0x62, 0xD9, 0x1F, 0xE3, 0xF2, 0xD0, 0x2B, 0xC6, 0x21, 0xFF, 0x20, 0x0E,
|
||||
0xB1, 0x44, 0x28, 0xDF, 0x0A, 0xCD, 0x14, 0x5B, 0xC8, 0x19, 0x36, 0x90, 0xD1, 0x42, 0x99, 0x2F
|
||||
};
|
||||
|
||||
internal static readonly byte[] DnasKey1 =
|
||||
{
|
||||
0xED, 0xE2, 0x5D, 0x2D, 0xBB, 0xF8, 0x12, 0xE5, 0x3C, 0x5C, 0x59, 0x32, 0xFA, 0xE3, 0xE2, 0x43
|
||||
};
|
||||
|
||||
internal static readonly byte[] DnasKey2 =
|
||||
{
|
||||
0x27, 0x74, 0xFB, 0xEB, 0xA4, 0xA0, 0x01, 0xD7, 0x02, 0x56, 0x9E, 0x33, 0x8C, 0x19, 0x57, 0x83
|
||||
};
|
||||
|
||||
private static Memory<byte> _gMemory = new byte[0x640];
|
||||
private static Memory<byte> _gCipherMemory = new byte[0x200];
|
||||
|
||||
private Stream _baseStream;
|
||||
private byte[] _versionKey;
|
||||
|
||||
private long _position;
|
||||
private long _pgdOffset;
|
||||
private int _keyIndex;
|
||||
private int _openFlag;
|
||||
private long _dataOffset;
|
||||
private long _tableOffset;
|
||||
|
||||
public int KeyIndex => _keyIndex;
|
||||
|
||||
private PgdDesc _desc;
|
||||
|
||||
internal unsafe struct PgdHeader
|
||||
{
|
||||
public uint Magic;
|
||||
public int KeyIndex;
|
||||
public int DrmType;
|
||||
public int Unk12;
|
||||
private fixed byte _descKey[0x10];
|
||||
public Span<byte> DescKey
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _descKey)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _keyHash[0x10];
|
||||
public Span<byte> KeyHash
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _keyHash)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _pgdDesc[0x30];
|
||||
public Span<byte> PgdDesc
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _pgdDesc)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x30);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _macTableHash[0x10];
|
||||
public Span<byte> MacTableHash
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _macTableHash)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _hash70[0x10];
|
||||
public Span<byte> Hash70
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _hash70)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _hash80[0x10];
|
||||
public Span<byte> Hash80
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _hash80)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe struct PgdDesc
|
||||
{
|
||||
private fixed byte _key[0x10];
|
||||
|
||||
public Span<byte> Key
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _key)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
public int Version;
|
||||
public int DataSize;
|
||||
public int BlockSize;
|
||||
public int DataOffset;
|
||||
private fixed byte _unk20[0x10];
|
||||
|
||||
public Span<byte> Unk20
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _unk20)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int BlockSize => _desc.BlockSize;
|
||||
|
||||
public DNASStream(Stream stream, long pgdOffset, ReadOnlySpan<byte> versionKey, int flag = 2)
|
||||
: this(stream, pgdOffset, versionKey.ToArray(), flag)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DNASStream(Stream stream, long pgdOffset, byte[] versionKey = null, int flag = 2)
|
||||
{
|
||||
_baseStream = stream;
|
||||
_pgdOffset = pgdOffset;
|
||||
var offset = stream.Seek(pgdOffset, SeekOrigin.Begin);
|
||||
if (offset != _pgdOffset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
Span<byte> hdr = _gMemory[..0x90].Span;
|
||||
var size = stream.Read(hdr);
|
||||
if (size != 0x90)
|
||||
{
|
||||
throw new ArgumentException("stream too small", nameof(stream));
|
||||
}
|
||||
var header = MemoryMarshal.AsRef<PgdHeader>(hdr);
|
||||
_keyIndex = header.KeyIndex;
|
||||
if (_keyIndex == 1)
|
||||
{
|
||||
_versionKey = versionKey ?? new byte[16];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (versionKey == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(versionKey));
|
||||
}
|
||||
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<AMCTRL.MAC_KEY>()];
|
||||
AMCTRL.sceDrmBBMacInit(mkey, 1);
|
||||
AMCTRL.sceDrmBBMacUpdate(mkey, DnasKeyBase, (_keyIndex - 1) * 0x10);
|
||||
AMCTRL.sceDrmBBMacFinal(mkey, _versionKey, versionKey);
|
||||
return;
|
||||
}
|
||||
|
||||
int macType;
|
||||
int cipherType;
|
||||
|
||||
if (header.DrmType == 1)
|
||||
{
|
||||
flag |= 4;
|
||||
macType = 1;
|
||||
cipherType = 1;
|
||||
if (header.KeyIndex > 1)
|
||||
{
|
||||
flag |= 0xc;
|
||||
macType = 3;
|
||||
}
|
||||
}
|
||||
else if (header.DrmType == 0 && (flag & 4) == 0)
|
||||
{
|
||||
macType = 2;
|
||||
cipherType = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
byte[] dnasKey = null;
|
||||
|
||||
if ((flag & 2) != 0)
|
||||
{
|
||||
dnasKey = DnasKey1;
|
||||
}
|
||||
else if ((flag & 1) != 0)
|
||||
{
|
||||
dnasKey = DnasKey2;
|
||||
}
|
||||
|
||||
if (dnasKey == null)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
var ret = CheckBBMac(hdr, 0x80, dnasKey, header.Hash80, macType);
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new IOException("Wrong MAC 0x80");
|
||||
}
|
||||
|
||||
if (!Utils.IsEmpty(_versionKey, 0x10))
|
||||
{
|
||||
ret = CheckBBMac(hdr, 0x70, _versionKey, header.Hash70, macType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = GetMacKey(hdr, 0x70, _versionKey, header.Hash70, macType);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new IOException("Wrong MAC 0x70");
|
||||
}
|
||||
|
||||
ret = DoBBCipher(header.PgdDesc, 0x30, 0, _versionKey, header.DescKey, cipherType);
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new IOException($"Error 0x{ret:X8}");
|
||||
}
|
||||
var desc = MemoryMarshal.AsRef<PgdDesc>(header.PgdDesc);
|
||||
if (desc.Version != 0)
|
||||
{
|
||||
throw new IOException($"Error 0x{8051020:X8}");
|
||||
}
|
||||
|
||||
if (desc.BlockSize != 0x400)
|
||||
{
|
||||
throw new IOException($"Error 0x{80510204:X8}");
|
||||
}
|
||||
|
||||
_openFlag = flag | 0x10;
|
||||
_desc = desc;
|
||||
_dataOffset = _desc.DataOffset + pgdOffset;
|
||||
var blockSize = desc.BlockSize;
|
||||
var alignSize = (desc.DataSize + 15) & ~15;
|
||||
var tableSize = ((alignSize + blockSize - 1) & ~(blockSize - 1)) / (blockSize / 16);
|
||||
_tableOffset = pgdOffset + 0x90 + alignSize;
|
||||
if (header.KeyIndex < 3 && 0x7ffff < tableSize)
|
||||
{
|
||||
|
||||
}
|
||||
{
|
||||
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<AMCTRL.MAC_KEY>()];
|
||||
ret = AMCTRL.sceDrmBBMacInit(mkey, macType);
|
||||
stream.Seek(_tableOffset, SeekOrigin.Begin);
|
||||
int read = 0;
|
||||
if (tableSize != 0)
|
||||
{
|
||||
Span<byte> dataBuf = new byte[0x400];
|
||||
do
|
||||
{
|
||||
var tmpSize = tableSize - read;
|
||||
if (tmpSize > 0x400)
|
||||
{
|
||||
tmpSize = 0x400;
|
||||
}
|
||||
|
||||
var data = dataBuf.Slice(0, tmpSize);
|
||||
var readSize = stream.Read(data);
|
||||
if (readSize != tmpSize)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, tmpSize);
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
read += 0x400;
|
||||
} while (read < tableSize);
|
||||
}
|
||||
ret = AMCTRL.sceDrmBBMacFinal2(mkey, header.MacTableHash, _versionKey);
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new IOException($"Error 0x{80510204:X8}");
|
||||
}
|
||||
}
|
||||
|
||||
_position = 0;
|
||||
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int ret;
|
||||
Span<byte> bufferSpan = buffer;
|
||||
if ((_openFlag & 0x10) == 0)
|
||||
{
|
||||
throw new IOException($"Error 0x{80510207:X8}");
|
||||
}
|
||||
|
||||
var dataSize = _desc.DataSize;
|
||||
var seekOffset = _position;
|
||||
if (seekOffset < dataSize)
|
||||
{
|
||||
var macType = 2;
|
||||
var cipherType = 2;
|
||||
if ((_openFlag & 4) != 0)
|
||||
{
|
||||
macType = 1;
|
||||
if ((_openFlag & 8) != 0)
|
||||
{
|
||||
macType = 3;
|
||||
}
|
||||
|
||||
cipherType = 1;
|
||||
}
|
||||
|
||||
var endOffset = dataSize;
|
||||
if (seekOffset + count <= dataSize)
|
||||
{
|
||||
endOffset = (int)(seekOffset + count);
|
||||
}
|
||||
|
||||
var blockSize = _desc.BlockSize;
|
||||
var alignOffset = (int)seekOffset;
|
||||
var totalReadSize = 0;
|
||||
while (true)
|
||||
{
|
||||
if (endOffset <= alignOffset)
|
||||
{
|
||||
return totalReadSize;
|
||||
}
|
||||
|
||||
if ((_openFlag & 0x10) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var align = alignOffset & blockSize - 1;
|
||||
|
||||
alignOffset -= align;
|
||||
var alignBlockSize = endOffset - alignOffset;
|
||||
int readBytes;
|
||||
int uVar6;
|
||||
Span<byte> readBuffer;
|
||||
if (align == 0 && blockSize <= alignBlockSize)
|
||||
{
|
||||
readBytes = alignBlockSize & ~(blockSize - 1);
|
||||
readBuffer = bufferSpan;
|
||||
uVar6 = readBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
readBytes = blockSize;
|
||||
readBuffer = _gMemory.Span;
|
||||
if (dataSize < alignOffset + blockSize)
|
||||
{
|
||||
readBytes = (dataSize - alignOffset + 15) & ~15;
|
||||
}
|
||||
|
||||
uVar6 = blockSize;
|
||||
if (endOffset < alignOffset + blockSize)
|
||||
{
|
||||
uVar6 = alignBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
_baseStream.Seek(_dataOffset + alignOffset, SeekOrigin.Begin);
|
||||
var realReadBytes = _baseStream.Read(readBuffer.Slice(0, readBytes));
|
||||
if (realReadBytes < readBytes)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
var tableOffset = (alignOffset / blockSize) * 0x10;
|
||||
_baseStream.Seek(_tableOffset + tableOffset, SeekOrigin.Begin);
|
||||
var blockNr = 0;
|
||||
if (readBytes != 0)
|
||||
{
|
||||
var tableReadOffset = 0;
|
||||
var cipherSpan = _gCipherMemory.Span;
|
||||
do
|
||||
{
|
||||
alignBlockSize = readBytes - tableReadOffset;
|
||||
if (blockSize < readBytes - tableReadOffset)
|
||||
{
|
||||
alignBlockSize = blockSize;
|
||||
}
|
||||
|
||||
if ((blockNr & 0x1f) == 0)
|
||||
{
|
||||
if (blockSize == 0)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
var tableBlock = readBytes / blockSize - blockNr;
|
||||
if (tableBlock == 0)
|
||||
{
|
||||
tableBlock = 1;
|
||||
}
|
||||
|
||||
if (0x20 < tableBlock)
|
||||
{
|
||||
tableBlock = 0x20;
|
||||
}
|
||||
cipherSpan.Fill(0);
|
||||
realReadBytes = _baseStream.Read(cipherSpan[..(tableBlock * 16)]);
|
||||
if (realReadBytes < tableBlock * 16)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
if (_keyIndex < 3)
|
||||
{
|
||||
ret = CheckBBMac(readBuffer[tableReadOffset..], alignBlockSize, _versionKey,
|
||||
cipherSpan.Slice((blockNr & 0x1f) * 16), macType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = CheckBBMac(readBuffer[tableReadOffset..], alignBlockSize, _versionKey,
|
||||
cipherSpan[((blockNr & 0x1f) * 16)..], macType, alignOffset);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
tableReadOffset += blockSize;
|
||||
blockNr++;
|
||||
} while (tableReadOffset < readBytes);
|
||||
}
|
||||
ret = DoBBCipher(readBuffer, readBytes, alignOffset + align >> 4, _versionKey, _desc.Key, cipherType);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
var iVar2 = uVar6 - align;
|
||||
seekOffset += iVar2;
|
||||
_position = seekOffset;
|
||||
if (readBuffer != bufferSpan)
|
||||
{
|
||||
readBuffer.Slice(align, iVar2).CopyTo(bufferSpan);
|
||||
}
|
||||
bufferSpan = bufferSpan[iVar2..];
|
||||
totalReadSize += iVar2;
|
||||
alignOffset += uVar6;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if ((_openFlag & 0x10) == 0)
|
||||
{
|
||||
throw new IOException($"Error 0x{80510206:X8}");
|
||||
}
|
||||
|
||||
var dataSize = _desc.DataSize;
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin:
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
offset += -_position;
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
offset += dataSize;
|
||||
break;
|
||||
}
|
||||
if (offset > 0xffffffff)
|
||||
{
|
||||
offset = 0xffffffff;
|
||||
}
|
||||
|
||||
if (offset > dataSize)
|
||||
{
|
||||
offset = dataSize;
|
||||
}
|
||||
|
||||
_position = offset;
|
||||
|
||||
return _position;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
internal static int CheckBBMac(ReadOnlySpan<byte> data, int size, ReadOnlySpan<byte> key, ReadOnlySpan<byte> hash, int macType, int seed = 0)
|
||||
{
|
||||
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<AMCTRL.MAC_KEY>()];
|
||||
Span<byte> tmpKey = stackalloc byte[0x10];
|
||||
int ret = unchecked((int)0x80510201);
|
||||
if (hash != null)
|
||||
{
|
||||
ret = AMCTRL.sceDrmBBMacInit(mkey, macType);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
key.CopyTo(tmpKey);
|
||||
if (seed != 0)
|
||||
{
|
||||
var tmpXor = MemoryMarshal.Cast<byte, int>(tmpKey);
|
||||
tmpXor[0] ^= seed;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBMacFinal2(mkey, hash, tmpKey);
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = unchecked((int)0x80510207);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal static int GetMacKey(ReadOnlySpan<byte> data, int size, Span<byte> key, ReadOnlySpan<byte> hash, int macType, int seed = 0)
|
||||
{
|
||||
Span<byte> mkey = stackalloc byte[Marshal.SizeOf<AMCTRL.MAC_KEY>()];
|
||||
Span<byte> tmpKey = stackalloc byte[0x10];
|
||||
int ret = unchecked((int)0x80510201);
|
||||
if (hash != null)
|
||||
{
|
||||
ret = AMCTRL.sceDrmBBMacInit(mkey, macType);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBMacUpdate(mkey, data, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = AMCTRL.bbmac_getkey(mkey, hash, tmpKey);
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = unchecked((int)0x80510207);
|
||||
}
|
||||
if (seed != 0)
|
||||
{
|
||||
var tmpXor = MemoryMarshal.Cast<byte, int>(tmpKey);
|
||||
tmpXor[0] ^= seed;
|
||||
}
|
||||
tmpKey.CopyTo(key);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal static int DoBBCipher(Span<byte> data, int size, int seed, ReadOnlySpan<byte> versionKey,
|
||||
ReadOnlySpan<byte> headerKey, int cipherType)
|
||||
{
|
||||
int ret = AMCTRL.sceDrmBBCipherInit(out var ckey, cipherType, 2, headerKey, versionKey, seed);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBCipherUpdate(ref ckey, data, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = AMCTRL.sceDrmBBCipherFinal(ref ckey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public byte[] VersionKey => _versionKey;
|
||||
|
||||
public override bool CanRead => _baseStream.CanRead;
|
||||
public override bool CanSeek => _baseStream.CanSeek;
|
||||
public override bool CanWrite => false;
|
||||
public override long Length => _desc.DataSize;
|
||||
public override long Position
|
||||
{
|
||||
get => _position;
|
||||
set => _position = value;
|
||||
}
|
||||
}
|
||||
}
|
113
PspCrypto/ECDsaHelper.cs
Normal file
113
PspCrypto/ECDsaHelper.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using PspCrypto.Security.Cryptography;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public static class ECDsaHelper
|
||||
{
|
||||
public static ECCurve SetCurve(byte[] p, byte[] a, byte[] b, byte[] n, byte[] gx, byte[] gy)
|
||||
{
|
||||
return new ECCurve
|
||||
{
|
||||
A = a,
|
||||
B = b,
|
||||
Prime = p,
|
||||
Order = n,
|
||||
CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
|
||||
Cofactor = new byte[] { 0x01 },
|
||||
G = new ECPoint { X = gx, Y = gy }
|
||||
};
|
||||
}
|
||||
|
||||
public static (byte[], ECPoint) GenerateKey(byte[] p, byte[] a, byte[] b, byte[] n, byte[] gx, byte[] gy)
|
||||
{
|
||||
var curve = new ECCurve
|
||||
{
|
||||
A = a,
|
||||
B = b,
|
||||
Prime = p,
|
||||
Order = n,
|
||||
CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
|
||||
Cofactor = new byte[] { 0x01 },
|
||||
G = { X = gx, Y = gy }
|
||||
};
|
||||
var ecdsa = new ECDsaManaged();
|
||||
ecdsa.GenerateKey(curve);
|
||||
var parameter = ecdsa.ExportExplicitParameters(true);
|
||||
return (parameter.D, parameter.Q);
|
||||
}
|
||||
|
||||
public static ECDsa Create(ECCurve curve, byte[] privateKey)
|
||||
{
|
||||
return Create(curve, privateKey, new byte[privateKey.Length], new byte[privateKey.Length]);
|
||||
}
|
||||
|
||||
|
||||
public static ECDsa Create(ECCurve curve, byte[] pubx, byte[] puby)
|
||||
{
|
||||
return Create(curve, null, pubx, puby);
|
||||
}
|
||||
|
||||
public static ECDsa Create(ECCurve curve, Span<byte> pubx, Span<byte> puby)
|
||||
{
|
||||
return Create(curve, null, pubx.ToArray(), puby.ToArray());
|
||||
}
|
||||
|
||||
public static ECDsa Create(ECCurve curve, byte[] privateKey, byte[] pubx, byte[] puby, bool ebootPbp = false, int type = 1)
|
||||
{
|
||||
var par = new ECParameters
|
||||
{
|
||||
Curve = curve,
|
||||
D = privateKey,
|
||||
Q = { X = pubx, Y = puby }
|
||||
};
|
||||
return new ECDsaManaged(par, ebootPbp, type);
|
||||
}
|
||||
|
||||
public static void SignNpImageHeader(Span<byte> npHdr)
|
||||
{
|
||||
var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2,
|
||||
KeyVault.Gy2);
|
||||
using var ecdsa = Create(curve, KeyVault.ec_Priv2, KeyVault.Px2, KeyVault.Py2);
|
||||
var hash = ecdsa.SignData(npHdr[..0xD8].ToArray(), HashAlgorithmName.SHA1);
|
||||
hash.CopyTo(npHdr[0xD8..]);
|
||||
}
|
||||
|
||||
public static bool VerifyEdat(Span<byte> edat)
|
||||
{
|
||||
var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2,
|
||||
KeyVault.Gy2);
|
||||
using var ecdsa = Create(curve, KeyVault.EdatPx, KeyVault.EdatPy);
|
||||
return ecdsa.VerifyData(edat[..0x58], edat.Slice(0x58, 0x28), HashAlgorithmName.SHA1);
|
||||
}
|
||||
|
||||
public static void SignEdat(Span<byte> edat)
|
||||
{
|
||||
var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2,
|
||||
KeyVault.Gy2);
|
||||
using var ecdsa = Create(curve, KeyVault.EdatPirv, KeyVault.EdatPx, KeyVault.EdatPy);
|
||||
var sig = ecdsa.SignData(edat[..0x58].ToArray(), HashAlgorithmName.SHA1);
|
||||
sig.CopyTo(edat[0x58..]);
|
||||
}
|
||||
|
||||
public static void SignParamSfo(ReadOnlySpan<byte> param, Span<byte> sig)
|
||||
{
|
||||
var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2,
|
||||
KeyVault.Gy2);
|
||||
using var ecdsa = Create(curve, KeyVault.ec_Priv2, KeyVault.Px2, KeyVault.Py2);
|
||||
var sigTmp = ecdsa.SignData(param.ToArray(), HashAlgorithmName.SHA1);
|
||||
sigTmp.CopyTo(sig);
|
||||
}
|
||||
|
||||
public static bool VerifyEbootPbp(Span<byte> data, Span<byte> sig)
|
||||
{
|
||||
var sha224 = SHA224.Create();
|
||||
var hash = sha224.ComputeHash(data.ToArray());
|
||||
var curve = SetCurve(KeyVault.Eboot_p, KeyVault.Eboot_a, KeyVault.Eboot_b, KeyVault.Eboot_N, KeyVault.Eboot_Gx,
|
||||
KeyVault.Eboot_Gy);
|
||||
using var ecdsa = Create(curve, KeyVault.Eboot_priv2, KeyVault.Eboot_pub2x, KeyVault.Eboot_pub2y, true);
|
||||
return ecdsa.VerifyHash(hash, sig);
|
||||
}
|
||||
}
|
||||
}
|
1113
PspCrypto/KIRKEngine.cs
Normal file
1113
PspCrypto/KIRKEngine.cs
Normal file
File diff suppressed because it is too large
Load Diff
231
PspCrypto/KeyVault.cs
Normal file
231
PspCrypto/KeyVault.cs
Normal file
|
@ -0,0 +1,231 @@
|
|||
using System;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
|
||||
public static class KeyVault
|
||||
{
|
||||
// KIRK AES keys
|
||||
public static readonly byte[][] kirkKeys =
|
||||
{
|
||||
new byte[] {0x2C, 0x92, 0xE5, 0x90, 0x2B, 0x86, 0xC1, 0x06, 0xB7, 0x2E, 0xEA, 0x6C, 0xD4, 0xEC, 0x72, 0x48},
|
||||
new byte[] {0x05, 0x8D, 0xC8, 0x0B, 0x33, 0xA5, 0xBF, 0x9D, 0x56, 0x98, 0xFA, 0xE0, 0xD3, 0x71, 0x5E, 0x1F},
|
||||
new byte[] {0xB8, 0x13, 0xC3, 0x5E, 0xC6, 0x44, 0x41, 0xE3, 0xDC, 0x3C, 0x16, 0xF5, 0xB4, 0x5E, 0x64, 0x84},
|
||||
new byte[] {0x98, 0x02, 0xC4, 0xE6, 0xEC, 0x9E, 0x9E, 0x2F, 0xFC, 0x63, 0x4C, 0xE4, 0x2F, 0xBB, 0x46, 0x68},
|
||||
new byte[] {0x99, 0x24, 0x4C, 0xD2, 0x58, 0xF5, 0x1B, 0xCB, 0xB0, 0x61, 0x9C, 0xA7, 0x38, 0x30, 0x07, 0x5F},
|
||||
new byte[] {0x02, 0x25, 0xD7, 0xBA, 0x63, 0xEC, 0xB9, 0x4A, 0x9D, 0x23, 0x76, 0x01, 0xB3, 0xF6, 0xAC, 0x17},
|
||||
new byte[] {0x60, 0x99, 0xF2, 0x81, 0x70, 0x56, 0x0E, 0x5F, 0x74, 0x7C, 0xB5, 0x20, 0xC0, 0xCD, 0xC2, 0x3C},
|
||||
new byte[] {0x76, 0x36, 0x8B, 0x43, 0x8F, 0x77, 0xD8, 0x7E, 0xFE, 0x5F, 0xB6, 0x11, 0x59, 0x39, 0x88, 0x5C},
|
||||
new byte[] {0x14, 0xA1, 0x15, 0xEB, 0x43, 0x4A, 0x1B, 0xA4, 0x90, 0x5E, 0x03, 0xB6, 0x17, 0xA1, 0x5C, 0x04},
|
||||
new byte[] {0xE6, 0x58, 0x03, 0xD9, 0xA7, 0x1A, 0xA8, 0x7F, 0x05, 0x9D, 0x22, 0x9D, 0xAF, 0x54, 0x53, 0xD0},
|
||||
new byte[] {0xBA, 0x34, 0x80, 0xB4, 0x28, 0xA7, 0xCA, 0x5F, 0x21, 0x64, 0x12, 0xF7, 0x0F, 0xBB, 0x73, 0x23},
|
||||
new byte[] {0x72, 0xAD, 0x35, 0xAC, 0x9A, 0xC3, 0x13, 0x0A, 0x77, 0x8C, 0xB1, 0x9D, 0x88, 0x55, 0x0B, 0x0C},
|
||||
new byte[] {0x84, 0x85, 0xC8, 0x48, 0x75, 0x08, 0x43, 0xBC, 0x9B, 0x9A, 0xEC, 0xA7, 0x9C, 0x7F, 0x60, 0x18},
|
||||
new byte[] {0xB5, 0xB1, 0x6E, 0xDE, 0x23, 0xA9, 0x7B, 0x0E, 0xA1, 0x7C, 0xDB, 0xA2, 0xDC, 0xDE, 0xC4, 0x6E},
|
||||
new byte[] {0xC8, 0x71, 0xFD, 0xB3, 0xBC, 0xC5, 0xD2, 0xF2, 0xE2, 0xD7, 0x72, 0x9D, 0xDF, 0x82, 0x68, 0x82},
|
||||
new byte[] {0x0A, 0xBB, 0x33, 0x6C, 0x96, 0xD4, 0xCD, 0xD8, 0xCB, 0x5F, 0x4B, 0xE0, 0xBA, 0xDB, 0x9E, 0x03},
|
||||
new byte[] {0x32, 0x29, 0x5B, 0xD5, 0xEA, 0xF7, 0xA3, 0x42, 0x16, 0xC8, 0x8E, 0x48, 0xFF, 0x50, 0xD3, 0x71},
|
||||
new byte[] {0x46, 0xF2, 0x5E, 0x8E, 0x4D, 0x2A, 0xA5, 0x40, 0x73, 0x0B, 0xC4, 0x6E, 0x47, 0xEE, 0x6F, 0x0A},
|
||||
new byte[] {0x5D, 0xC7, 0x11, 0x39, 0xD0, 0x19, 0x38, 0xBC, 0x02, 0x7F, 0xDD, 0xDC, 0xB0, 0x83, 0x7D, 0x9D},
|
||||
new byte[] {0x51, 0xDD, 0x65, 0xF0, 0x71, 0xA4, 0xE5, 0xEA, 0x6A, 0xAF, 0x12, 0x19, 0x41, 0x29, 0xB8, 0xF4},
|
||||
new byte[] {0x03, 0x76, 0x3C, 0x68, 0x65, 0xC6, 0x9B, 0x0F, 0xFE, 0x8F, 0xD8, 0xEE, 0xA4, 0x36, 0x16, 0xA0},
|
||||
new byte[] {0x7D, 0x50, 0xB8, 0x5C, 0xAF, 0x67, 0x69, 0xF0, 0xE5, 0x4A, 0xA8, 0x09, 0x8B, 0x0E, 0xBE, 0x1C},
|
||||
new byte[] {0x72, 0x68, 0x4B, 0x32, 0xAC, 0x3B, 0x33, 0x2F, 0x2A, 0x7A, 0xFC, 0x9E, 0x14, 0xD5, 0x6F, 0x6B},
|
||||
new byte[] {0x20, 0x1D, 0x31, 0x96, 0x4A, 0xD9, 0x9F, 0xBF, 0x32, 0xD5, 0xD6, 0x1C, 0x49, 0x1B, 0xD9, 0xFC},
|
||||
new byte[] {0xF8, 0xD8, 0x44, 0x63, 0xD6, 0x10, 0xD1, 0x2A, 0x44, 0x8E, 0x96, 0x90, 0xA6, 0xBB, 0x0B, 0xAD},
|
||||
new byte[] {0x5C, 0xD4, 0x05, 0x7F, 0xA1, 0x30, 0x60, 0x44, 0x0A, 0xD9, 0xB6, 0x74, 0x5F, 0x24, 0x4F, 0x4E},
|
||||
new byte[] {0xF4, 0x8A, 0xD6, 0x78, 0x59, 0x9C, 0x22, 0xC1, 0xD4, 0x11, 0x93, 0x3D, 0xF8, 0x45, 0xB8, 0x93},
|
||||
new byte[] {0xCA, 0xE7, 0xD2, 0x87, 0xA2, 0xEC, 0xC1, 0xCD, 0x94, 0x54, 0x2B, 0x5E, 0x1D, 0x94, 0x88, 0xB2},
|
||||
new byte[] {0xDE, 0x26, 0xD3, 0x7A, 0x39, 0x95, 0x6C, 0x2A, 0xD8, 0xC3, 0xA6, 0xAF, 0x21, 0xEB, 0xB3, 0x01},
|
||||
new byte[] {0x7C, 0xB6, 0x8B, 0x4D, 0xA3, 0x8D, 0x1D, 0xD9, 0x32, 0x67, 0x9C, 0xA9, 0x9F, 0xFB, 0x28, 0x52},
|
||||
new byte[] {0xA0, 0xB5, 0x56, 0xB4, 0x69, 0xAB, 0x36, 0x8F, 0x36, 0xDE, 0xC9, 0x09, 0x2E, 0xCB, 0x41, 0xB1},
|
||||
new byte[] {0x93, 0x9D, 0xE1, 0x9B, 0x72, 0x5F, 0xEE, 0xE2, 0x45, 0x2A, 0xBC, 0x17, 0x06, 0xD1, 0x47, 0x69},
|
||||
new byte[] {0xA4, 0xA4, 0xE6, 0x21, 0x38, 0x2E, 0xF1, 0xAF, 0x7B, 0x17, 0x7A, 0xE8, 0x42, 0xAD, 0x00, 0x31},
|
||||
new byte[] {0xC3, 0x7F, 0x13, 0xE8, 0xCF, 0x84, 0xDB, 0x34, 0x74, 0x7B, 0xC3, 0xA0, 0xF1, 0x9D, 0x3A, 0x73},
|
||||
new byte[] {0x2B, 0xF7, 0x83, 0x8A, 0xD8, 0x98, 0xE9, 0x5F, 0xA5, 0xF9, 0x01, 0xDA, 0x61, 0xFE, 0x35, 0xBB},
|
||||
new byte[] {0xC7, 0x04, 0x62, 0x1E, 0x71, 0x4A, 0x66, 0xEA, 0x62, 0xE0, 0x4B, 0x20, 0x3D, 0xB8, 0xC2, 0xE5},
|
||||
new byte[] {0xC9, 0x33, 0x85, 0x9A, 0xAB, 0x00, 0xCD, 0xCE, 0x4D, 0x8B, 0x8E, 0x9F, 0x3D, 0xE6, 0xC0, 0x0F},
|
||||
new byte[] {0x18, 0x42, 0x56, 0x1F, 0x2B, 0x5F, 0x34, 0xE3, 0x51, 0x3E, 0xB7, 0x89, 0x77, 0x43, 0x1A, 0x65},
|
||||
new byte[] {0xDC, 0xB0, 0xA0, 0x06, 0x5A, 0x50, 0xA1, 0x4E, 0x59, 0xAC, 0x97, 0x3F, 0x17, 0x58, 0xA3, 0xA3},
|
||||
new byte[] {0xC4, 0xDB, 0xAE, 0x83, 0xE2, 0x9C, 0xF2, 0x54, 0xA3, 0xDD, 0x37, 0x4E, 0x80, 0x7B, 0xF4, 0x25},
|
||||
new byte[] {0xBF, 0xAE, 0xEB, 0x49, 0x82, 0x65, 0xC5, 0x7C, 0x64, 0xB8, 0xC1, 0x7E, 0x19, 0x06, 0x44, 0x09},
|
||||
new byte[] {0x79, 0x7C, 0xEC, 0xC3, 0xB3, 0xEE, 0x0A, 0xC0, 0x3B, 0xD8, 0xE6, 0xC1, 0xE0, 0xA8, 0xB1, 0xA4},
|
||||
new byte[] {0x75, 0x34, 0xFE, 0x0B, 0xD6, 0xD0, 0xC2, 0x8D, 0x68, 0xD4, 0xE0, 0x2A, 0xE7, 0xD5, 0xD1, 0x55},
|
||||
new byte[] {0xFA, 0xB3, 0x53, 0x26, 0x97, 0x4F, 0x4E, 0xDF, 0xE4, 0xC3, 0xA8, 0x14, 0xC3, 0x2F, 0x0F, 0x88},
|
||||
new byte[] {0xEC, 0x97, 0xB3, 0x86, 0xB4, 0x33, 0xC6, 0xBF, 0x4E, 0x53, 0x9D, 0x95, 0xEB, 0xB9, 0x79, 0xE4},
|
||||
new byte[] {0xB3, 0x20, 0xA2, 0x04, 0xCF, 0x48, 0x06, 0x29, 0xB5, 0xDD, 0x8E, 0xFC, 0x98, 0xD4, 0x17, 0x7B},
|
||||
new byte[] {0x5D, 0xFC, 0x0D, 0x4F, 0x2C, 0x39, 0xDA, 0x68, 0x4A, 0x33, 0x74, 0xED, 0x49, 0x58, 0xA7, 0x3A},
|
||||
new byte[] {0xD7, 0x5A, 0x54, 0x22, 0xCE, 0xD9, 0xA3, 0xD6, 0x2B, 0x55, 0x7D, 0x8D, 0xE8, 0xBE, 0xC7, 0xEC},
|
||||
new byte[] {0x6B, 0x4A, 0xEE, 0x43, 0x45, 0xAE, 0x70, 0x07, 0xCF, 0x8D, 0xCF, 0x4E, 0x4A, 0xE9, 0x3C, 0xFA},
|
||||
new byte[] {0x2B, 0x52, 0x2F, 0x66, 0x4C, 0x2D, 0x11, 0x4C, 0xFE, 0x61, 0x31, 0x8C, 0x56, 0x78, 0x4E, 0xA6},
|
||||
new byte[] {0x3A, 0xA3, 0x4E, 0x44, 0xC6, 0x6F, 0xAF, 0x7B, 0xFA, 0xE5, 0x53, 0x27, 0xEF, 0xCF, 0xCC, 0x24},
|
||||
new byte[] {0x2B, 0x5C, 0x78, 0xBF, 0xC3, 0x8E, 0x49, 0x9D, 0x41, 0xC3, 0x3C, 0x5C, 0x7B, 0x27, 0x96, 0xCE},
|
||||
new byte[] {0xF3, 0x7E, 0xEA, 0xD2, 0xC0, 0xC8, 0x23, 0x1D, 0xA9, 0x9B, 0xFA, 0x49, 0x5D, 0xB7, 0x08, 0x1B},
|
||||
new byte[] {0x70, 0x8D, 0x4E, 0x6F, 0xD1, 0xF6, 0x6F, 0x1D, 0x1E, 0x1F, 0xCB, 0x02, 0xF9, 0xB3, 0x99, 0x26},
|
||||
new byte[] {0x0F, 0x67, 0x16, 0xE1, 0x80, 0x69, 0x9C, 0x51, 0xFC, 0xC7, 0xAD, 0x6E, 0x4F, 0xB8, 0x46, 0xC9},
|
||||
new byte[] {0x56, 0x0A, 0x49, 0x4A, 0x84, 0x4C, 0x8E, 0xD9, 0x82, 0xEE, 0x0B, 0x6D, 0xC5, 0x7D, 0x20, 0x8D},
|
||||
new byte[] {0x12, 0x46, 0x8D, 0x7E, 0x1C, 0x42, 0x20, 0x9B, 0xBA, 0x54, 0x26, 0x83, 0x5E, 0xB0, 0x33, 0x03},
|
||||
new byte[] {0xC4, 0x3B, 0xB6, 0xD6, 0x53, 0xEE, 0x67, 0x49, 0x3E, 0xA9, 0x5F, 0xBC, 0x0C, 0xED, 0x6F, 0x8A},
|
||||
new byte[] {0x2C, 0xC3, 0xCF, 0x8C, 0x28, 0x78, 0xA5, 0xA6, 0x63, 0xE2, 0xAF, 0x2D, 0x71, 0x5E, 0x86, 0xBA},
|
||||
new byte[] {0x83, 0x3D, 0xA7, 0x0C, 0xED, 0x6A, 0x20, 0x12, 0xD1, 0x96, 0xE6, 0xFE, 0x5C, 0x4D, 0x37, 0xC5},
|
||||
new byte[] {0xC7, 0x43, 0xD0, 0x67, 0x42, 0xEE, 0x90, 0xB8, 0xCA, 0x75, 0x50, 0x35, 0x20, 0xAD, 0xBC, 0xCE},
|
||||
new byte[] {0x8A, 0xE3, 0x66, 0x3F, 0x8D, 0x9E, 0x82, 0xA1, 0xED, 0xE6, 0x8C, 0x9C, 0xE8, 0x25, 0x6D, 0xAA},
|
||||
new byte[] {0x7F, 0xC9, 0x6F, 0x0B, 0xB1, 0x48, 0x5C, 0xA5, 0x5D, 0xD3, 0x64, 0xB7, 0x7A, 0xF5, 0xE4, 0xEA},
|
||||
new byte[] {0x91, 0xB7, 0x65, 0x78, 0x8B, 0xCB, 0x8B, 0xD4, 0x02, 0xED, 0x55, 0x3A, 0x66, 0x62, 0xD0, 0xAD},
|
||||
new byte[] {0x28, 0x24, 0xF9, 0x10, 0x1B, 0x8D, 0x0F, 0x7B, 0x6E, 0xB2, 0x63, 0xB5, 0xB5, 0x5B, 0x2E, 0xBB},
|
||||
new byte[] {0x30, 0xE2, 0x57, 0x5D, 0xE0, 0xA2, 0x49, 0xCE, 0xE8, 0xCF, 0x2B, 0x5E, 0x4D, 0x9F, 0x52, 0xC7},
|
||||
new byte[] {0x5E, 0xE5, 0x04, 0x39, 0x62, 0x32, 0x02, 0xFA, 0x85, 0x39, 0x3F, 0x72, 0xBB, 0x77, 0xFD, 0x1A},
|
||||
new byte[] {0xF8, 0x81, 0x74, 0xB1, 0xBD, 0xE9, 0xBF, 0xDD, 0x45, 0xE2, 0xF5, 0x55, 0x89, 0xCF, 0x46, 0xAB},
|
||||
new byte[] {0x7D, 0xF4, 0x92, 0x65, 0xE3, 0xFA, 0xD6, 0x78, 0xD6, 0xFE, 0x78, 0xAD, 0xBB, 0x3D, 0xFB, 0x63},
|
||||
new byte[] {0x74, 0x7F, 0xD6, 0x2D, 0xC7, 0xA1, 0xCA, 0x96, 0xE2, 0x7A, 0xCE, 0xFF, 0xAA, 0x72, 0x3F, 0xF7},
|
||||
new byte[] {0x1E, 0x58, 0xEB, 0xD0, 0x65, 0xBB, 0xF1, 0x68, 0xC5, 0xBD, 0xF7, 0x46, 0xBA, 0x7B, 0xE1, 0x00},
|
||||
new byte[] {0x24, 0x34, 0x7D, 0xAF, 0x5E, 0x4B, 0x35, 0x72, 0x7A, 0x52, 0x27, 0x6B, 0xA0, 0x54, 0x74, 0xDB},
|
||||
new byte[] {0x09, 0xB1, 0xC7, 0x05, 0xC3, 0x5F, 0x53, 0x66, 0x77, 0xC0, 0xEB, 0x36, 0x77, 0xDF, 0x83, 0x07},
|
||||
new byte[] {0xCC, 0xBE, 0x61, 0x5C, 0x05, 0xA2, 0x00, 0x33, 0x37, 0x8E, 0x59, 0x64, 0xA7, 0xDD, 0x70, 0x3D},
|
||||
new byte[] {0x0D, 0x47, 0x50, 0xBB, 0xFC, 0xB0, 0x02, 0x81, 0x30, 0xE1, 0x84, 0xDE, 0xA8, 0xD4, 0x84, 0x13},
|
||||
new byte[] {0x0C, 0xFD, 0x67, 0x9A, 0xF9, 0xB4, 0x72, 0x4F, 0xD7, 0x8D, 0xD6, 0xE9, 0x96, 0x42, 0x28, 0x8B},
|
||||
new byte[] {0x7A, 0xD3, 0x1A, 0x8B, 0x4B, 0xEF, 0xC2, 0xC2, 0xB3, 0x99, 0x01, 0xA9, 0xFE, 0x76, 0xB9, 0x87},
|
||||
new byte[] {0xBE, 0x78, 0x78, 0x17, 0xC7, 0xF1, 0x6F, 0x1A, 0xE0, 0xEF, 0x3B, 0xDE, 0x4C, 0xC2, 0xD7, 0x86},
|
||||
new byte[] {0x7C, 0xD8, 0xB8, 0x91, 0x91, 0x0A, 0x43, 0x14, 0xD0, 0x53, 0x3D, 0xD8, 0x4C, 0x45, 0xBE, 0x16},
|
||||
new byte[] {0x32, 0x72, 0x2C, 0x88, 0x07, 0xCF, 0x35, 0x7D, 0x4A, 0x2F, 0x51, 0x19, 0x44, 0xAE, 0x68, 0xDA},
|
||||
new byte[] {0x7E, 0x6B, 0xBF, 0xF6, 0xF6, 0x87, 0xB8, 0x98, 0xEE, 0xB5, 0x1B, 0x32, 0x16, 0xE4, 0x6E, 0x5D},
|
||||
new byte[] {0x08, 0xEA, 0x5A, 0x83, 0x49, 0xB5, 0x9D, 0xB5, 0x3E, 0x07, 0x79, 0xB1, 0x9A, 0x59, 0xA3, 0x54},
|
||||
new byte[] {0xF3, 0x12, 0x81, 0xBF, 0xE6, 0x9F, 0x51, 0xD1, 0x64, 0x08, 0x25, 0x21, 0xFF, 0xBB, 0x22, 0x61},
|
||||
new byte[] {0xAF, 0xFE, 0x8E, 0xB1, 0x3D, 0xD1, 0x7E, 0xD8, 0x0A, 0x61, 0x24, 0x1C, 0x95, 0x92, 0x56, 0xB6},
|
||||
new byte[] {0x92, 0xCD, 0xB4, 0xC2, 0x5B, 0xF2, 0x35, 0x5A, 0x23, 0x09, 0xE8, 0x19, 0xC9, 0x14, 0x42, 0x35},
|
||||
new byte[] {0xE1, 0xC6, 0x5B, 0x22, 0x6B, 0xE1, 0xDA, 0x02, 0xBA, 0x18, 0xFA, 0x21, 0x34, 0x9E, 0xF9, 0x6D},
|
||||
new byte[] {0x14, 0xEC, 0x76, 0xCE, 0x97, 0xF3, 0x8A, 0x0A, 0x34, 0x50, 0x6C, 0x53, 0x9A, 0x5C, 0x9A, 0xB4},
|
||||
new byte[] {0x1C, 0x9B, 0xC4, 0x90, 0xE3, 0x06, 0x64, 0x81, 0xFA, 0x59, 0xFD, 0xB6, 0x00, 0xBB, 0x28, 0x70},
|
||||
new byte[] {0x43, 0xA5, 0xCA, 0xCC, 0x0D, 0x6C, 0x2D, 0x3F, 0x2B, 0xD9, 0x89, 0x67, 0x6B, 0x3F, 0x7F, 0x57},
|
||||
new byte[] {0x00, 0xEF, 0xFD, 0x18, 0x08, 0xA4, 0x05, 0x89, 0x3C, 0x38, 0xFB, 0x25, 0x72, 0x70, 0x61, 0x06},
|
||||
new byte[] {0xEE, 0xAF, 0x49, 0xE0, 0x09, 0x87, 0x9B, 0xEF, 0xAA, 0xD6, 0x32, 0x6A, 0x32, 0x13, 0xC4, 0x29},
|
||||
new byte[] {0x8D, 0x26, 0xB9, 0x0F, 0x43, 0x1D, 0xBB, 0x08, 0xDB, 0x1D, 0xDA, 0xC5, 0xB5, 0x2C, 0x92, 0xED},
|
||||
new byte[] {0x57, 0x7C, 0x30, 0x60, 0xAE, 0x6E, 0xBE, 0xAE, 0x3A, 0xAB, 0x18, 0x19, 0xC5, 0x71, 0x68, 0x0B},
|
||||
new byte[] {0x11, 0x5A, 0x5D, 0x20, 0xD5, 0x3A, 0x8D, 0xD3, 0x9C, 0xC5, 0xAF, 0x41, 0x0F, 0x0F, 0x18, 0x6F},
|
||||
new byte[] {0x0D, 0x4D, 0x51, 0xAB, 0x23, 0x79, 0xBF, 0x80, 0x3A, 0xBF, 0xB9, 0x0E, 0x75, 0xFC, 0x14, 0xBF},
|
||||
new byte[] {0x99, 0x93, 0xDA, 0x3E, 0x7D, 0x2E, 0x5B, 0x15, 0xF2, 0x52, 0xA4, 0xE6, 0x6B, 0xB8, 0x5A, 0x98},
|
||||
new byte[] {0xF4, 0x28, 0x30, 0xA5, 0xFB, 0x0D, 0x8D, 0x76, 0x0E, 0xA6, 0x71, 0xC2, 0x2B, 0xDE, 0x66, 0x9D},
|
||||
new byte[] {0xFB, 0x5F, 0xEB, 0x7F, 0xC7, 0xDC, 0xDD, 0x69, 0x37, 0x01, 0x97, 0x9B, 0x29, 0x03, 0x5C, 0x47},
|
||||
new byte[] {0x02, 0x32, 0x6A, 0xE7, 0xD3, 0x96, 0xCE, 0x7F, 0x1C, 0x41, 0x9D, 0xD6, 0x52, 0x07, 0xED, 0x09},
|
||||
new byte[] {0x9C, 0x9B, 0x13, 0x72, 0xF8, 0xC6, 0x40, 0xCF, 0x1C, 0x62, 0xF5, 0xD5, 0x92, 0xDD, 0xB5, 0x82},
|
||||
new byte[] {0x03, 0xB3, 0x02, 0xE8, 0x5F, 0xF3, 0x81, 0xB1, 0x3B, 0x8D, 0xAA, 0x2A, 0x90, 0xFF, 0x5E, 0x61},
|
||||
new byte[] {0xBC, 0xD7, 0xF9, 0xD3, 0x2F, 0xAC, 0xF8, 0x47, 0xC0, 0xFB, 0x4D, 0x2F, 0x30, 0x9A, 0xBD, 0xA6},
|
||||
new byte[] {0xF5, 0x55, 0x96, 0xE9, 0x7F, 0xAF, 0x86, 0x7F, 0xAC, 0xB3, 0x3A, 0xE6, 0x9C, 0x8B, 0x6F, 0x93},
|
||||
new byte[] {0xEE, 0x29, 0x70, 0x93, 0xF9, 0x4E, 0x44, 0x59, 0x44, 0x17, 0x1F, 0x8E, 0x86, 0xE1, 0x70, 0xFC},
|
||||
new byte[] {0xE4, 0x34, 0x52, 0x0C, 0xF0, 0x88, 0xCF, 0xC8, 0xCD, 0x78, 0x1B, 0x6C, 0xCF, 0x8C, 0x48, 0xC4},
|
||||
new byte[] {0xC1, 0xBF, 0x66, 0x81, 0x8E, 0xF9, 0x53, 0xF2, 0xE1, 0x26, 0x6B, 0x6F, 0x55, 0x0C, 0xC9, 0xCD},
|
||||
new byte[] {0x56, 0x0F, 0xFF, 0x8F, 0x3C, 0x96, 0x49, 0x14, 0x45, 0x16, 0xF1, 0xBC, 0xBF, 0xCE, 0xA3, 0x0C},
|
||||
new byte[] {0x24, 0x08, 0xDC, 0x75, 0x37, 0x60, 0xA2, 0x9F, 0x05, 0x54, 0xB5, 0xF2, 0x43, 0x85, 0x73, 0x99},
|
||||
new byte[] {0xDD, 0xD5, 0xB5, 0x6A, 0x59, 0xC5, 0x5A, 0xE8, 0x3B, 0x96, 0x67, 0xC7, 0x5C, 0x2A, 0xE2, 0xDC},
|
||||
new byte[] {0xAA, 0x68, 0x67, 0x72, 0xE0, 0x2D, 0x44, 0xD5, 0xCD, 0xBB, 0x65, 0x04, 0xBC, 0xD5, 0xBF, 0x4E},
|
||||
new byte[] {0x1F, 0x17, 0xF0, 0x14, 0xE7, 0x77, 0xA2, 0xFE, 0x4B, 0x13, 0x6B, 0x56, 0xCD, 0x7E, 0xF7, 0xE9},
|
||||
new byte[] {0xC9, 0x35, 0x48, 0xCF, 0x55, 0x8D, 0x75, 0x03, 0x89, 0x6B, 0x2E, 0xEB, 0x61, 0x8C, 0xA9, 0x02},
|
||||
new byte[] {0xDE, 0x34, 0xC5, 0x41, 0xE7, 0xCA, 0x86, 0xE8, 0xBE, 0xA7, 0xC3, 0x1C, 0xEC, 0xE4, 0x36, 0x0F},
|
||||
new byte[] {0xDD, 0xE5, 0xFF, 0x55, 0x1B, 0x74, 0xF6, 0xF4, 0xE0, 0x16, 0xD7, 0xAB, 0x22, 0x31, 0x1B, 0x6A},
|
||||
new byte[] {0xB0, 0xE9, 0x35, 0x21, 0x33, 0x3F, 0xD7, 0xBA, 0xB4, 0x76, 0x2C, 0xCB, 0x4D, 0x80, 0x08, 0xD8},
|
||||
new byte[] {0x38, 0x14, 0x69, 0xC4, 0xC3, 0xF9, 0x1B, 0x96, 0x33, 0x63, 0x8E, 0x4D, 0x5F, 0x3D, 0xF0, 0x29},
|
||||
new byte[] {0xFA, 0x48, 0x6A, 0xD9, 0x8E, 0x67, 0x16, 0xEF, 0x6A, 0xB0, 0x87, 0xF5, 0x89, 0x45, 0x7F, 0x2A},
|
||||
new byte[] {0x32, 0x1A, 0x09, 0x12, 0x50, 0x14, 0x8A, 0x3E, 0x96, 0x3D, 0xEA, 0x02, 0x59, 0x32, 0xE1, 0x8F},
|
||||
new byte[] {0x4B, 0x00, 0xBE, 0x29, 0xBC, 0xB0, 0x28, 0x64, 0xCE, 0xFD, 0x43, 0xA9, 0x6F, 0xD9, 0x5C, 0xED},
|
||||
new byte[] {0x57, 0x7D, 0xC4, 0xFF, 0x02, 0x44, 0xE2, 0x80, 0x91, 0xF4, 0xCA, 0x0A, 0x75, 0x69, 0xFD, 0xA8},
|
||||
new byte[] {0x83, 0x53, 0x36, 0xC6, 0x18, 0x03, 0xE4, 0x3E, 0x4E, 0xB3, 0x0F, 0x6B, 0x6E, 0x79, 0x9B, 0x7A},
|
||||
new byte[] {0x5C, 0x92, 0x65, 0xFD, 0x7B, 0x59, 0x6A, 0xA3, 0x7A, 0x2F, 0x50, 0x9D, 0x85, 0xE9, 0x27, 0xF8},
|
||||
new byte[] {0x9A, 0x39, 0xFB, 0x89, 0xDF, 0x55, 0xB2, 0x60, 0x14, 0x24, 0xCE, 0xA6, 0xD9, 0x65, 0x0A, 0x9D},
|
||||
new byte[] {0x8B, 0x75, 0xBE, 0x91, 0xA8, 0xC7, 0x5A, 0xD2, 0xD7, 0xA5, 0x94, 0xA0, 0x1C, 0xBB, 0x95, 0x91},
|
||||
new byte[] {0x95, 0xC2, 0x1B, 0x8D, 0x05, 0xAC, 0xF5, 0xEC, 0x5A, 0xEE, 0x77, 0x81, 0x23, 0x95, 0xC4, 0xD7},
|
||||
new byte[] {0xB9, 0xA4, 0x61, 0x64, 0x36, 0x33, 0xFA, 0x5D, 0x94, 0x88, 0xE2, 0xD3, 0x28, 0x1E, 0x01, 0xA2},
|
||||
new byte[] {0xB8, 0xB0, 0x84, 0xFB, 0x9F, 0x4C, 0xFA, 0xF7, 0x30, 0xFE, 0x73, 0x25, 0xA2, 0xAB, 0x89, 0x7D},
|
||||
new byte[] {0x5F, 0x8C, 0x17, 0x9F, 0xC1, 0xB2, 0x1D, 0xF1, 0xF6, 0x36, 0x7A, 0x9C, 0xF7, 0xD3, 0xD4, 0x7C},
|
||||
};
|
||||
|
||||
public static readonly byte[] kirk1_key = { 0x98, 0xC9, 0x40, 0x97, 0x5C, 0x1D, 0x10, 0xE8, 0x7F, 0xE6, 0x0E, 0xA3, 0xFD, 0x03, 0xA8, 0xBA };
|
||||
public static readonly byte[] kirk16_key = { 0x47, 0x5E, 0x09, 0xF4, 0xA2, 0x37, 0xDA, 0x9B, 0xEF, 0xFF, 0x3B, 0xC0, 0x77, 0x14, 0x3D, 0x8A };
|
||||
|
||||
/* ECC Curves for Kirk 1 and Kirk 0x11 */
|
||||
// Common Curve paramters p and a
|
||||
public static readonly byte[] ec_p = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
public static readonly byte[] ec_a = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC }; // mon
|
||||
|
||||
// Kirk 0xC,0xD,0x10,0x11,(likely 0x12)- Unique curve parameters for b, N, and base point G for Kirk 0xC,0xD,0x10,0x11,(likely 0x12) service
|
||||
// Since public key is variable, it is not specified here
|
||||
public static readonly byte[] ec_b2 = { 0xA6, 0x8B, 0xED, 0xC3, 0x34, 0x18, 0x02, 0x9C, 0x1D, 0x3C, 0xE3, 0x3B, 0x9A, 0x32, 0x1F, 0xCC, 0xBB, 0x9E, 0x0F, 0x0B };// mon
|
||||
public static readonly byte[] ec_N2 = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xB5, 0xAE, 0x3C, 0x52, 0x3E, 0x63, 0x94, 0x4F, 0x21, 0x27 };
|
||||
public static readonly byte[] Gx2 = { 0x12, 0x8E, 0xC4, 0x25, 0x64, 0x87, 0xFD, 0x8F, 0xDF, 0x64, 0xE2, 0x43, 0x7B, 0xC0, 0xA1, 0xF6, 0xD5, 0xAF, 0xDE, 0x2C };
|
||||
public static readonly byte[] Gy2 = { 0x59, 0x58, 0x55, 0x7E, 0xB1, 0xDB, 0x00, 0x12, 0x60, 0x42, 0x55, 0x24, 0xDB, 0xC3, 0x79, 0xD5, 0xAC, 0x5F, 0x4A, 0xDF };
|
||||
|
||||
// KIRK 1 - Unique curve parameters for b, N, and base point G
|
||||
// Since public key is hard coded, it is also included
|
||||
public static readonly byte[] ec_b1 = { 0x65, 0xD1, 0x48, 0x8C, 0x03, 0x59, 0xE2, 0x34, 0xAD, 0xC9, 0x5B, 0xD3, 0x90, 0x80, 0x14, 0xBD, 0x91, 0xA5, 0x25, 0xF9 };
|
||||
public static readonly byte[] ec_N1 = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xB5, 0xC6, 0x17, 0xF2, 0x90, 0xEA, 0xE1, 0xDB, 0xAD, 0x8F };
|
||||
public static readonly byte[] Gx1 = { 0x22, 0x59, 0xAC, 0xEE, 0x15, 0x48, 0x9C, 0xB0, 0x96, 0xA8, 0x82, 0xF0, 0xAE, 0x1C, 0xF9, 0xFD, 0x8E, 0xE5, 0xF8, 0xFA };
|
||||
public static readonly byte[] Gy1 = { 0x60, 0x43, 0x58, 0x45, 0x6D, 0x0A, 0x1C, 0xB2, 0x90, 0x8D, 0xE9, 0x0F, 0x27, 0xD7, 0x5C, 0x82, 0xBE, 0xC1, 0x08, 0xC0 };
|
||||
|
||||
public static readonly byte[] Px1 = { 0xED, 0x9C, 0xE5, 0x82, 0x34, 0xE6, 0x1A, 0x53, 0xC6, 0x85, 0xD6, 0x4D, 0x51, 0xD0, 0x23, 0x6B, 0xC3, 0xB5, 0xD4, 0xB9 };
|
||||
public static readonly byte[] Py1 = { 0x04, 0x9D, 0xF1, 0xA0, 0x75, 0xC0, 0xE0, 0x4F, 0xB3, 0x44, 0x85, 0x8B, 0x61, 0xB7, 0x9B, 0x69, 0xA6, 0x3D, 0x2C, 0x39 };
|
||||
public static readonly byte[] ec_Priv1 = { 0xF3, 0x92, 0xE2, 0x64, 0x90, 0xB8, 0x0F, 0xD8, 0x89, 0xF2, 0xD9, 0x72, 0x2C, 0x1F, 0x34, 0xD7, 0x27, 0x4F, 0x98, 0x3D };
|
||||
|
||||
public static readonly byte[] Px2 = { 0x01, 0x21, 0xEA, 0x6E, 0xCD, 0xB2, 0x3A, 0x3E, 0x23, 0x75, 0x67, 0x1C, 0x53, 0x62, 0xE8, 0xE2, 0x8B, 0x1E, 0x78, 0x3B };
|
||||
public static readonly byte[] Py2 = { 0x1A, 0x27, 0x32, 0x15, 0x8B, 0x8C, 0xED, 0x98, 0x46, 0x6C, 0x18, 0xA3, 0xAC, 0x3B, 0x11, 0x06, 0xAF, 0xB4, 0xEC, 0x3B };
|
||||
public static readonly byte[] ec_Priv2 = { 0x14, 0xB0, 0x22, 0xE8, 0x92, 0xCF, 0x86, 0x14, 0xA4, 0x45, 0x57, 0xDB, 0x09, 0x5C, 0x92, 0x8D, 0xE9, 0xB8, 0x99, 0x70 };
|
||||
|
||||
public static readonly byte[] EdatPx = { 0x1F, 0x07, 0x2B, 0xCC, 0xC1, 0x62, 0xF2, 0xCF, 0xAE, 0xA0, 0xE7, 0xF4, 0xCD, 0xFD, 0x9C, 0xAE, 0xC6, 0xC4, 0x55, 0x21 };
|
||||
public static readonly byte[] EdatPy = { 0x53, 0x01, 0xF4, 0xE3, 0x70, 0xC3, 0xED, 0xE2, 0xD4, 0xF5, 0xDB, 0xC3, 0xA7, 0xDE, 0x8C, 0xAA, 0xE8, 0xAD, 0x5B, 0x7D };
|
||||
public static readonly byte[] EdatPirv = { 0xe5, 0xc4, 0xd0, 0xa8, 0x24, 0x9a, 0x6f, 0x27, 0xe5, 0xe0, 0xc9, 0xd5, 0x34, 0xf4, 0xda, 0x15, 0x22, 0x3f, 0x42, 0xad };
|
||||
|
||||
public static readonly byte[] Eboot_p = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0F };
|
||||
public static readonly byte[] Eboot_a = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x53, 0x73, 0xD3, 0x79, 0xF6, 0x9D, 0xA2, 0x8D, 0x09, 0x99, 0x9F, 0xED, 0x57, 0xA9, 0x0C };
|
||||
public static readonly byte[] Eboot_b = { 0x90, 0x65, 0x94, 0x1D, 0x29, 0x37, 0x4A, 0x8F, 0x11, 0xDD, 0x1E, 0x54, 0x01, 0x89, 0x43, 0x4E, 0x4A, 0x6E, 0xBF, 0xAF, 0x54, 0x77, 0xF6, 0xC1, 0x72, 0xF6, 0x85, 0x5E };
|
||||
public static readonly byte[] Eboot_N = { 0xA5, 0x3E, 0x11, 0x3E, 0x46, 0xD8, 0xC9, 0xC1, 0xF0, 0x9D, 0x9B, 0xCB, 0x2A, 0x52, 0x26, 0x98, 0xDE, 0xEF, 0x58, 0xDB, 0x1A, 0xD9, 0xAB, 0x7F, 0x04, 0xE3, 0xAE, 0x7F };
|
||||
public static readonly byte[] Eboot_Gx = { 0x7E, 0x06, 0x09, 0x82, 0x47, 0xE6, 0xB5, 0x9F, 0x31, 0x10, 0xBC, 0xBB, 0x3A, 0xB6, 0xC2, 0x50, 0xBC, 0x5A, 0xB0, 0x6C, 0x03, 0x2D, 0xAD, 0x43, 0x68, 0x4C, 0x24, 0x8F };
|
||||
public static readonly byte[] Eboot_Gy = { 0x0B, 0xD9, 0x41, 0x8D, 0xE8, 0xE3, 0xE4, 0x5D, 0x2D, 0x70, 0x1E, 0x02, 0x37, 0xFD, 0x7F, 0x2A, 0xDE, 0x0D, 0x48, 0xB7, 0x4C, 0xEE, 0xF2, 0xF1, 0xC8, 0xAC, 0x48, 0x4E };
|
||||
public static readonly byte[] Eboot_pub1x = { 0x5F, 0x9D, 0x17, 0x1A, 0x2B, 0xDD, 0xA8, 0xD4, 0x08, 0x78, 0xBF, 0x98, 0x5A, 0xC3, 0x26, 0xED, 0x5E, 0xFF, 0x43, 0xC9, 0x37, 0x6C, 0x77, 0xEC, 0x0A, 0x00, 0xC7, 0xBB };
|
||||
public static readonly byte[] Eboot_pub1y = { 0xA3, 0x44, 0xE4, 0x4E, 0x6E, 0xAC, 0x25, 0x52, 0x35, 0xF9, 0x54, 0xF5, 0xB6, 0x17, 0xC7, 0xBD, 0x49, 0xF1, 0x80, 0x26, 0x24, 0x54, 0xAA, 0xE1, 0xB6, 0x2A, 0x9F, 0x2C };
|
||||
public static readonly byte[] Eboot_priv1 = { 0x76, 0x74, 0x36, 0xA6, 0x99, 0x9D, 0x88, 0x48, 0x0E, 0xC8, 0x56, 0xF5, 0x5C, 0xEA, 0xBB, 0x43, 0x96, 0x85, 0x9E, 0x37, 0x45, 0x99, 0x40, 0x39, 0x21, 0xF5, 0x55, 0x98 };
|
||||
public static readonly byte[] Eboot_pub2x = { 0x67, 0x00, 0x2D, 0x9B, 0xB8, 0xE4, 0x2D, 0x2B, 0xF9, 0x61, 0x0B, 0x27, 0xFE, 0xAB, 0x9B, 0x34, 0x56, 0x15, 0x50, 0x92, 0x13, 0x12, 0xDF, 0xEE, 0x7A, 0x3A, 0x86, 0xEC };
|
||||
public static readonly byte[] Eboot_pub2y = { 0x6C, 0xA7, 0x14, 0x42, 0x6F, 0x6D, 0x4E, 0x96, 0x09, 0xA6, 0x38, 0xBF, 0x4A, 0xFB, 0x18, 0x2B, 0xFA, 0x50, 0xC8, 0x2F, 0xF2, 0xB4, 0xC5, 0xEC, 0x6C, 0xCD, 0x97, 0x65 };
|
||||
public static readonly byte[] Eboot_priv2 = { 0x60, 0x7A, 0x2E, 0x55, 0x68, 0xB4, 0xB9, 0xA0, 0x32, 0xF4, 0x52, 0x53, 0xCF, 0xED, 0x20, 0xDB, 0x2E, 0x6E, 0x44, 0x6C, 0x37, 0x82, 0xE8, 0x2A, 0x1A, 0xB9, 0xC9, 0x23 };
|
||||
public static readonly byte[][] Eboot_priv = { Eboot_priv1, Eboot_priv2 };
|
||||
public static readonly byte[][] Eboot_pubx = { Eboot_pub1x, Eboot_pub2x };
|
||||
public static readonly byte[][] Eboot_puby = { Eboot_pub1y, Eboot_pub2y };
|
||||
|
||||
public static readonly byte[] Eboot_hmacKey = { 0x54, 0x88, 0xA9, 0x81, 0x1C, 0x9A, 0x2C, 0xBC, 0xCC, 0x59, 0x6B, 0x1F, 0xAD, 0x1A, 0x7E, 0x29, 0xE0, 0x75, 0x84, 0x0F, 0x47, 0x43, 0x1F, 0x37, 0xAC, 0x06, 0x02, 0x46, 0x4A, 0x27, 0x9E, 0x02, 0xDF, 0x2E, 0x71, 0x65, 0xF1, 0x13, 0x7B, 0xF6, 0x9A, 0xE6, 0xDC, 0xB9, 0xDC, 0x38, 0x8C, 0x9D, 0xCC, 0xB3, 0x64, 0xC4, 0xCA, 0x26, 0xCB, 0x8F, 0x1A, 0xF0, 0x63, 0x8A, 0x6E, 0xAD, 0xB5, 0x4D };
|
||||
|
||||
|
||||
public static readonly byte[] VitaKirk18PubKey0x = { 0x5F, 0x9D, 0x17, 0x1A, 0x2B, 0xDD, 0xA8, 0xD4, 0x08, 0x78, 0xBF, 0x98, 0x5A, 0xC3, 0x26, 0xED, 0x5E, 0xFF, 0x43, 0xC9, 0x37, 0x6C, 0x77, 0xEC, 0x0A, 0x00, 0xC7, 0xBB };
|
||||
public static readonly byte[] VitaKirk18PubKey0y = { 0xA3, 0x44, 0xE4, 0x4E, 0x6E, 0xAC, 0x25, 0x52, 0x35, 0xF9, 0x54, 0xF5, 0xB6, 0x17, 0xC7, 0xBD, 0x49, 0xF1, 0x80, 0x26, 0x24, 0x54, 0xAA, 0xE1, 0xB6, 0x2A, 0x9F, 0x2C };
|
||||
|
||||
public static readonly byte[] VitaKirk18PubKey1x = { 0x67, 0x00, 0x2D, 0x9B, 0xB8, 0xE4, 0x2D, 0x2B, 0xF9, 0x61, 0x0B, 0x27, 0xFE, 0xAB, 0x9B, 0x34, 0x56, 0x15, 0x50, 0x92, 0x13, 0x12, 0xDF, 0xEE, 0x7A, 0x3A, 0x86, 0xEC };
|
||||
public static readonly byte[] VitaKirk18PubKey1y = { 0x6C, 0xA7, 0x14, 0x42, 0x6F, 0x6D, 0x4E, 0x96, 0x09, 0xA6, 0x38, 0xBF, 0x4A, 0xFB, 0x18, 0x2B, 0xFA, 0x50, 0xC8, 0x2F, 0xF2, 0xB4, 0xC5, 0xEC, 0x6C, 0xCD, 0x97, 0x65 };
|
||||
|
||||
public static readonly byte[] VitaKirk18PubKey1000x = { 0x64, 0xDD, 0xD3, 0x1E, 0x46, 0x7A, 0x90, 0x8F, 0x99, 0x0D, 0x63, 0xF4, 0x59, 0x32, 0x3C, 0x1C, 0xA3, 0xCE, 0xCF, 0x00, 0xA8, 0x1C, 0x57, 0x40, 0xA9, 0x6D, 0x2E, 0x1C };
|
||||
public static readonly byte[] VitaKirk18PubKey1000y = { 0x38, 0x61, 0xA1, 0x9D, 0x0A, 0xBD, 0xC5, 0xED, 0xDB, 0xD6, 0x04, 0xFA, 0x67, 0xC6, 0xDA, 0xB4, 0x28, 0x3C, 0x29, 0x67, 0x86, 0xD9, 0xA8, 0x07, 0xE0, 0xC1, 0x3B, 0xA8 };
|
||||
|
||||
public static readonly byte[] drmActRifSig =
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
public static readonly byte[] drmRifKey = { 0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B };
|
||||
|
||||
public static readonly byte[] drmActdatKey = { 0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
|
||||
|
||||
public static readonly byte[] drmVersionKeyKey =
|
||||
{
|
||||
0xF0, 0x79, 0xD5, 0x19, 0x8F, 0x23, 0xEF, 0xCE,
|
||||
0xB5, 0x4B, 0x9E, 0xCD, 0xCD, 0xFD, 0xD3, 0xD7,
|
||||
0x07, 0x3D, 0x9E, 0x9D, 0xA8, 0xFD, 0x3B, 0x2F,
|
||||
0x63, 0x18, 0x93, 0x2E, 0xF8, 0x57, 0xA6, 0x64,
|
||||
0x37, 0x49, 0xB7, 0x01, 0xCA, 0xE2, 0xE0, 0xC5,
|
||||
0x44, 0x2E, 0x06, 0xB6, 0x1E, 0xFF, 0x84, 0xF2,
|
||||
0x9D, 0x31, 0xB8, 0x5A, 0xC8, 0xFA, 0x16, 0x80,
|
||||
0x73, 0x60, 0x18, 0x82, 0x18, 0x77, 0x91, 0x9D,
|
||||
|
||||
};
|
||||
|
||||
public static readonly byte[] DrmFixedKey = { 0x38, 0x20, 0xD0, 0x11, 0x07, 0xA3, 0xFF, 0x3E, 0x0A, 0x4C, 0x20, 0x85, 0x39, 0x10, 0xB5, 0x54 };
|
||||
}
|
||||
}
|
8
PspCrypto/Libraries.cs
Normal file
8
PspCrypto/Libraries.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
internal static class Libraries
|
||||
{
|
||||
internal const string CryptoNative = "PspCryptoHelper";
|
||||
}
|
41
PspCrypto/Lz.cs
Normal file
41
PspCrypto/Lz.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public class Lz
|
||||
{
|
||||
public static byte[] compress(byte[] in_buf, bool np9660=false)
|
||||
{
|
||||
//Decoder decoder = new Decoder();
|
||||
//using var inStream = new MemoryStream(@in);
|
||||
//using var outStream = new MemoryStream(@out);
|
||||
//byte[] properties = new byte[5];
|
||||
//inStream.Read(properties, 0, 5);
|
||||
//decoder.SetDecoderProperties(properties);
|
||||
//decoder.Code(inStream, outStream, insize, size, null);
|
||||
//return 0;
|
||||
var lzrc = new Lzrc(np9660);
|
||||
|
||||
// compress data, and get the compressed data length
|
||||
return lzrc.lzrc_compress(in_buf, in_buf.Length);
|
||||
}
|
||||
public static int decompress(byte[] @out, byte[] @in, int size, int insize, bool np9660=false)
|
||||
{
|
||||
//Decoder decoder = new Decoder();
|
||||
//using var inStream = new MemoryStream(@in);
|
||||
//using var outStream = new MemoryStream(@out);
|
||||
//byte[] properties = new byte[5];
|
||||
//inStream.Read(properties, 0, 5);
|
||||
//decoder.SetDecoderProperties(properties);
|
||||
//decoder.Code(inStream, outStream, insize, size, null);
|
||||
//return 0;
|
||||
var lzrc = new Lzrc(np9660);
|
||||
lzrc.lzrc_decompress(@out, size, @in, insize);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
908
PspCrypto/Lzrc.cs
Normal file
908
PspCrypto/Lzrc.cs
Normal file
|
@ -0,0 +1,908 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public class Lzrc
|
||||
{
|
||||
private bool np9660;
|
||||
|
||||
private byte[] input;
|
||||
private int in_ptr;
|
||||
private int in_len;
|
||||
|
||||
private byte[] output;
|
||||
private int out_ptr;
|
||||
private int out_len;
|
||||
|
||||
private uint range;
|
||||
private uint code;
|
||||
private uint out_code;
|
||||
private byte lc;
|
||||
private byte[][] bm_literal;
|
||||
private byte[][] bm_dist_bits;
|
||||
private byte[][] bm_dist;
|
||||
private byte[][] bm_match;
|
||||
private byte[][] bm_len;
|
||||
|
||||
const int MAX_WIN_SZ = 16384;
|
||||
const int MAX_TBL_SZ = 65280;
|
||||
const int TBL_SZ = 65536;
|
||||
|
||||
private byte[] text_buf = new byte[TBL_SZ];
|
||||
private int t_start, t_end, t_fill, sp_fill;
|
||||
private int t_len, t_pos;
|
||||
|
||||
private int[] prev = new int[TBL_SZ], next = new int[TBL_SZ];
|
||||
private int[] root = new int[TBL_SZ];
|
||||
|
||||
public Lzrc(bool np9660 = false)
|
||||
{
|
||||
this.np9660 = np9660;
|
||||
|
||||
if (np9660)
|
||||
{
|
||||
this.bm_literal = new byte[8][];
|
||||
this.bm_dist_bits = new byte[8][];
|
||||
this.bm_dist = new byte[18][];
|
||||
this.bm_match = new byte[8][];
|
||||
this.bm_len = new byte[8][];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bm_literal = new byte[8][];
|
||||
this.bm_dist_bits = new byte[8][];
|
||||
this.bm_dist = new byte[16][];
|
||||
this.bm_match = new byte[8][];
|
||||
this.bm_len = new byte[8][];
|
||||
}
|
||||
}
|
||||
|
||||
static void Init(byte[][] arr, byte value, int length)
|
||||
{
|
||||
for (int i = 0; i < arr.Length; i++)
|
||||
{
|
||||
arr[i] = new byte[length];
|
||||
for (int j = 0; j < length; j++)
|
||||
{
|
||||
arr[i][j] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte rc_getbyte()
|
||||
{
|
||||
if (in_ptr == in_len)
|
||||
{
|
||||
throw new Exception("End of input!");
|
||||
}
|
||||
|
||||
return input[in_ptr++];
|
||||
}
|
||||
|
||||
void rc_putbyte(byte b)
|
||||
{
|
||||
if (out_ptr == out_len)
|
||||
{
|
||||
throw new Exception("Output overflow!");
|
||||
}
|
||||
|
||||
output[out_ptr++] = b;
|
||||
}
|
||||
|
||||
void re_init(ref byte[] in_buf, int in_len)
|
||||
{
|
||||
input = in_buf;
|
||||
this.in_len = in_len;
|
||||
in_ptr = 0;
|
||||
|
||||
this.output = new byte[in_len];
|
||||
this.out_len = in_len;
|
||||
out_ptr = 0;
|
||||
|
||||
range = 0xffffffff;
|
||||
code = 0x00000000;
|
||||
lc = 5;
|
||||
out_code = 0xffffffff;
|
||||
|
||||
re_putbyte(lc);
|
||||
|
||||
|
||||
if (this.np9660)
|
||||
{
|
||||
Init(bm_literal, 0x80, 256);
|
||||
Init(bm_dist_bits, 0x80, 39);
|
||||
Init(bm_dist, 0x80, 8);
|
||||
Init(bm_match, 0x80, 8);
|
||||
Init(bm_len, 0x80, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
Init(bm_literal, 0x80, 256); // 2048 2680 2656
|
||||
Init(bm_dist_bits, 0x80, 23); // 184
|
||||
Init(bm_dist, 0x80, 8); // 128
|
||||
Init(bm_match, 0x80, 8); // 64
|
||||
Init(bm_len, 0x80, 32); // 256
|
||||
|
||||
}
|
||||
//memset(re->bm_literal, 0x80, 2048);
|
||||
//memset(re->bm_dist_bits, 0x80, 312);
|
||||
//memset(re->bm_dist, 0x80, 144);
|
||||
//memset(re->bm_match, 0x80, 64);
|
||||
//memset(re->bm_len, 0x80, 248);
|
||||
}
|
||||
|
||||
void rc_init(byte[] out_buf, int out_len, byte[] in_buf, int in_len)
|
||||
{
|
||||
input = in_buf;
|
||||
this.in_len = in_len;
|
||||
in_ptr = 0;
|
||||
|
||||
output = out_buf;
|
||||
this.out_len = out_len;
|
||||
out_ptr = 0;
|
||||
|
||||
range = 0xffffffff;
|
||||
lc = rc_getbyte();
|
||||
code = (uint)((rc_getbyte() << 24) |
|
||||
(rc_getbyte() << 16) |
|
||||
(rc_getbyte() << 8) |
|
||||
rc_getbyte());
|
||||
out_code = 0xffffffff;
|
||||
|
||||
if (this.np9660)
|
||||
{
|
||||
Init(bm_literal, 0x80, 256);
|
||||
Init(bm_dist_bits, 0x80, 39);
|
||||
Init(bm_dist, 0x80, 8);
|
||||
Init(bm_match, 0x80, 8);
|
||||
Init(bm_len, 0x80, 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
Init(bm_literal, 0x80, 256); // 2048 2680 2656
|
||||
Init(bm_dist_bits, 0x80, 23); // 184
|
||||
Init(bm_dist, 0x80, 8); // 128
|
||||
Init(bm_match, 0x80, 8); // 64
|
||||
Init(bm_len, 0x80, 32); // 256
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
if (range < 0x01000000)
|
||||
{
|
||||
range <<= 8;
|
||||
code = (code << 8) + input[in_ptr];
|
||||
in_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
int rc_bit(byte[] probs, int index)
|
||||
{
|
||||
uint bound;
|
||||
|
||||
normalize();
|
||||
|
||||
bound = (range >> 8) * probs[index];
|
||||
probs[index] -= (byte)(probs[index] >> 3);
|
||||
|
||||
if (code < bound)
|
||||
{
|
||||
range = bound;
|
||||
probs[index] += 31;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
code -= bound;
|
||||
range -= bound;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int rc_bittree(byte[] probs, int index, int limit)
|
||||
{
|
||||
int number = 1;
|
||||
do
|
||||
{
|
||||
number = (number << 1) + rc_bit(probs, index + number);
|
||||
} while (number < limit);
|
||||
|
||||
number -= limit;
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
int rc_number(byte[] prob, int index, int n)
|
||||
{
|
||||
int i, number = 1;
|
||||
|
||||
if (n > 3)
|
||||
{
|
||||
number = (number << 1) + rc_bit(prob, index + 3);
|
||||
if (n > 4)
|
||||
{
|
||||
number = (number << 1) + rc_bit(prob, index + 3);
|
||||
}
|
||||
|
||||
if (n > 5)
|
||||
{
|
||||
normalize();
|
||||
for (i = 0; i < n - 5; i++)
|
||||
{
|
||||
range >>= 1;
|
||||
number <<= 1;
|
||||
if (code < range)
|
||||
{
|
||||
number += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
code -= range;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
number = (number << 1) + rc_bit(prob, index + 0);
|
||||
if (n > 1)
|
||||
{
|
||||
number = (number << 1) + rc_bit(prob, index + 1);
|
||||
if (n > 2)
|
||||
{
|
||||
number = (number << 1) + rc_bit(prob, index + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
public void init_tree()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TBL_SZ; i++)
|
||||
{
|
||||
root[i] = -1;
|
||||
prev[i] = -1;
|
||||
next[i] = -1;
|
||||
}
|
||||
|
||||
t_start = 0;
|
||||
t_end = 0;
|
||||
t_fill = 0;
|
||||
sp_fill = 0;
|
||||
}
|
||||
|
||||
void fill_buffer()
|
||||
{
|
||||
//void *memcpy(void *dest, const void * src, size_t n)
|
||||
|
||||
int content_size, back_size, front_size;
|
||||
|
||||
if (sp_fill == in_len)
|
||||
return;
|
||||
|
||||
content_size = (t_fill < t_end) ? (MAX_TBL_SZ + t_fill - t_end) : (t_fill - t_end);
|
||||
if (content_size >= 509)
|
||||
return;
|
||||
|
||||
if (t_fill < t_start)
|
||||
{
|
||||
back_size = t_start - t_fill - 1;
|
||||
if (sp_fill + back_size > in_len)
|
||||
back_size = in_len - sp_fill;
|
||||
|
||||
Array.ConstrainedCopy(input, sp_fill, text_buf, t_fill, back_size);
|
||||
// memcpy(text_buf + t_fill, re->input + sp_fill, back_size);
|
||||
|
||||
sp_fill += back_size;
|
||||
t_fill += back_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
back_size = MAX_TBL_SZ - t_fill;
|
||||
if (t_start == 0)
|
||||
back_size -= 1;
|
||||
if (sp_fill + back_size > in_len)
|
||||
back_size = in_len - sp_fill;
|
||||
|
||||
Array.ConstrainedCopy(input, sp_fill, text_buf, t_fill, back_size);
|
||||
//memcpy(text_buf + t_fill, re->input + sp_fill, back_size);
|
||||
|
||||
sp_fill += back_size;
|
||||
t_fill += back_size;
|
||||
|
||||
front_size = t_start;
|
||||
if (t_start != 0)
|
||||
front_size -= 1;
|
||||
if (sp_fill + front_size > in_len)
|
||||
front_size = in_len - sp_fill;
|
||||
|
||||
Array.ConstrainedCopy(input, sp_fill, text_buf, 0, front_size);
|
||||
//memcpy(text_buf, re->input + sp_fill, front_size);
|
||||
|
||||
sp_fill += front_size;
|
||||
|
||||
Array.ConstrainedCopy(text_buf, 255, text_buf, MAX_TBL_SZ, front_size);
|
||||
//memcpy(text_buf + max_tbl_sz, text_buf, 255);
|
||||
|
||||
t_fill += front_size;
|
||||
if (t_fill >= MAX_TBL_SZ)
|
||||
t_fill -= MAX_TBL_SZ;
|
||||
}
|
||||
}
|
||||
void remove_node(int p)
|
||||
{
|
||||
int t, q;
|
||||
|
||||
if (prev[p] == -1)
|
||||
return;
|
||||
|
||||
t = text_buf[p + 0];
|
||||
t = (t << 8) | text_buf[p + 1];
|
||||
|
||||
q = next[p];
|
||||
if (q != -1)
|
||||
prev[q] = prev[p];
|
||||
|
||||
if (prev[p] == -2)
|
||||
root[t] = q;
|
||||
else
|
||||
next[prev[p]] = q;
|
||||
|
||||
prev[p] = -1;
|
||||
next[p] = -1;
|
||||
}
|
||||
|
||||
int insert_node(int pos, out int match_len, out int match_dist, int do_cmp)
|
||||
{
|
||||
//Span<byte> src, win;
|
||||
int i, t, p;
|
||||
int content_size;
|
||||
|
||||
//src = text_buf[pos..];
|
||||
//win = text_buf[t_start..];
|
||||
content_size = (t_fill < pos) ? (MAX_TBL_SZ + t_fill - pos) : (t_fill - pos);
|
||||
t_len = 1;
|
||||
t_pos = 0;
|
||||
match_len = t_len;
|
||||
match_dist = t_pos;
|
||||
|
||||
if (in_ptr >= in_len)
|
||||
{
|
||||
match_len = 256;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_ptr >= (in_len - 1))
|
||||
return 0;
|
||||
|
||||
t = text_buf[pos];
|
||||
t = (t << 8) | text_buf[pos+1];
|
||||
if (root[t] == -1)
|
||||
{
|
||||
root[t] = pos;
|
||||
prev[pos] = -2;
|
||||
next[pos] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = root[t];
|
||||
root[t] = pos;
|
||||
prev[pos] = -2;
|
||||
next[pos] = p;
|
||||
|
||||
if (p != -1)
|
||||
prev[p] = pos;
|
||||
|
||||
while (do_cmp == 1 && p != -1)
|
||||
{
|
||||
for (i = 0; (i < 255 && i < content_size); i++)
|
||||
{
|
||||
if (text_buf[pos+i] != text_buf[p + i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > t_len)
|
||||
{
|
||||
t_len = i;
|
||||
t_pos = pos - p;
|
||||
}
|
||||
else if (i == t_len)
|
||||
{
|
||||
int mp = pos - p;
|
||||
if (mp < 0)
|
||||
mp += MAX_TBL_SZ;
|
||||
if (mp < t_pos)
|
||||
{
|
||||
t_len = i;
|
||||
t_pos = pos - p;
|
||||
}
|
||||
}
|
||||
if (i == 255)
|
||||
{
|
||||
remove_node(p);
|
||||
break;
|
||||
}
|
||||
|
||||
p = next[p];
|
||||
}
|
||||
|
||||
if (this.np9660)
|
||||
{
|
||||
// have we calculated match_dist of 256 when its not the end?
|
||||
if (t_len == 256 && in_ptr < in_len)
|
||||
return 1;
|
||||
}
|
||||
if (t_pos < 0) throw new Exception("t_pos was < 0 :?"); // TODO: figure out why this happens on np9660.
|
||||
|
||||
match_len = t_len;
|
||||
match_dist = t_pos;
|
||||
|
||||
return 1;
|
||||
}
|
||||
void update_tree(int length)
|
||||
{
|
||||
int i, win_size;
|
||||
int tmp_len, tmp_pos;
|
||||
|
||||
win_size = (t_end >= t_start) ? (t_end - t_start) : (MAX_TBL_SZ + t_end - t_start);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (win_size == MAX_WIN_SZ)
|
||||
{
|
||||
remove_node(t_start);
|
||||
t_start += 1;
|
||||
if (t_start == MAX_TBL_SZ)
|
||||
t_start = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
win_size += 1;
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
insert_node(t_end, out tmp_len, out tmp_pos, 0);
|
||||
}
|
||||
t_end += 1;
|
||||
if (t_end >= MAX_TBL_SZ)
|
||||
t_end -= MAX_TBL_SZ;
|
||||
}
|
||||
}
|
||||
void re_bittree(ref byte[] probs,int index, int limit, int number)
|
||||
{
|
||||
int n, tmp, bit;
|
||||
|
||||
number += limit;
|
||||
|
||||
// Get total bits used by number
|
||||
tmp = number;
|
||||
n = 0;
|
||||
while (tmp > 1)
|
||||
{
|
||||
tmp >>= 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
tmp = number >> n;
|
||||
bit = (number >> (n - 1)) & 1;
|
||||
re_bit(ref probs, index + tmp, bit);
|
||||
n -= 1;
|
||||
} while (n > 0);
|
||||
}
|
||||
|
||||
void re_bit(ref byte[] prob, int index, int bit)
|
||||
{
|
||||
uint bound;
|
||||
uint old_r, old_c;
|
||||
byte old_p;
|
||||
|
||||
re_normalize();
|
||||
|
||||
old_r = range;
|
||||
old_c = code;
|
||||
old_p = prob[index];
|
||||
|
||||
var pProb = prob[index];
|
||||
|
||||
bound = (range >> 8) * (pProb);
|
||||
pProb -= (byte)(pProb >> 3);
|
||||
|
||||
if (bit != 0)
|
||||
{
|
||||
range = bound;
|
||||
pProb += 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
code += bound;
|
||||
if (code < old_c)
|
||||
out_code += 1;
|
||||
range -= bound;
|
||||
}
|
||||
|
||||
prob[index] = pProb;
|
||||
}
|
||||
|
||||
void re_normalize()
|
||||
{
|
||||
if (range < 0x01000000)
|
||||
{
|
||||
if (out_code != 0xffffffff)
|
||||
{
|
||||
if (out_code > 255)
|
||||
{
|
||||
int p, old_c;
|
||||
p = out_ptr - 1;
|
||||
do
|
||||
{
|
||||
old_c = output[p];
|
||||
output[p] += 1;
|
||||
p -= 1;
|
||||
} while (old_c == 0xff);
|
||||
}
|
||||
|
||||
re_putbyte((byte)(out_code & 0xff));
|
||||
}
|
||||
out_code = (code >> 24) & 0xff;
|
||||
range <<= 8;
|
||||
code <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void re_putbyte(byte out_byte)
|
||||
{
|
||||
if (out_ptr == out_len)
|
||||
{
|
||||
out_len += 0x1000;
|
||||
Array.Resize(ref output, out_len);
|
||||
}
|
||||
|
||||
output[out_ptr++] = out_byte;
|
||||
}
|
||||
byte re_getbyte()
|
||||
{
|
||||
if (in_ptr == in_len)
|
||||
{
|
||||
throw new Exception("End of input!");
|
||||
}
|
||||
|
||||
return input[in_ptr++];
|
||||
}
|
||||
|
||||
void re_number(ref byte[] prob, int index, int n, int number)
|
||||
{
|
||||
int i;
|
||||
UInt32 old_c;
|
||||
|
||||
i = 1;
|
||||
|
||||
if (n > 3)
|
||||
{
|
||||
re_bit(ref prob, index + 3,(number >> (n - i)) & 1);
|
||||
i += 1;
|
||||
if (n > 4)
|
||||
{
|
||||
re_bit(ref prob, index + 3, (number >> (n - i)) & 1);
|
||||
i += 1;
|
||||
if (n > 5)
|
||||
{
|
||||
re_normalize();
|
||||
for (i = 3; i < n - 2; i++)
|
||||
{
|
||||
range >>= 1;
|
||||
if (((number >> (n - i)) & 1) == 0)
|
||||
{
|
||||
old_c = code;
|
||||
code += range;
|
||||
if (code < old_c)
|
||||
out_code += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
re_bit(ref prob, index + 0, (number >> (n - i - 0)) & 1);
|
||||
if (n > 1)
|
||||
{
|
||||
re_bit(ref prob, index + 1, (number >> (n - i - 1)) & 1);
|
||||
if (n > 2)
|
||||
{
|
||||
re_bit(ref prob, index + 2, (number >> (n - i - 2)) & 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void re_flush()
|
||||
{
|
||||
re_putbyte((byte)((out_code) & 0xff));
|
||||
re_putbyte((byte)((code >> 24) & 0xff));
|
||||
re_putbyte((byte)((code >> 16) & 0xff));
|
||||
re_putbyte((byte)((code >> 8) & 0xff));
|
||||
re_putbyte((byte)((code >> 0) & 0xff));
|
||||
}
|
||||
|
||||
private byte[] re_trunc()
|
||||
{
|
||||
Array.Resize(ref output, out_ptr);
|
||||
return output;
|
||||
}
|
||||
|
||||
public byte[] lzrc_compress(byte[] in_buf, int in_len)
|
||||
{
|
||||
int match_step, re_state, len_state, dist_state;
|
||||
int i, cur_byte, last_byte;
|
||||
int match_len, len_bits;
|
||||
int match_dist, dist_bits, limit;
|
||||
int round = -1;
|
||||
|
||||
// initalize buffers to all 0x80
|
||||
re_init(ref in_buf, in_len);
|
||||
|
||||
// initalize the tree
|
||||
init_tree();
|
||||
|
||||
// initalize variable to 0 ...
|
||||
re_state = 0;
|
||||
last_byte = 0;
|
||||
match_len = 0;
|
||||
match_dist = 0;
|
||||
|
||||
bool flg = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
round += 1;
|
||||
match_step = 0;
|
||||
|
||||
fill_buffer();
|
||||
insert_node(t_end, out match_len, out match_dist, 1);
|
||||
|
||||
if (match_len < 256)
|
||||
{
|
||||
// condition is different if np9660 vs pops
|
||||
if (this.np9660)
|
||||
flg = (match_len < 4 && match_dist > 255);
|
||||
else
|
||||
flg = (match_len <= 4 && match_dist > 255);
|
||||
|
||||
if(flg) // if (condition)
|
||||
match_len = 1;
|
||||
update_tree(match_len);
|
||||
}
|
||||
|
||||
// condition is different if np9660 vs pops
|
||||
if (this.np9660)
|
||||
flg = (match_len == 1 || (match_len < 4 && match_dist > 255));
|
||||
else
|
||||
flg = (match_len == 1 || (match_len <= 4 && match_dist > 255));
|
||||
|
||||
if (flg)
|
||||
{
|
||||
re_bit(ref bm_match[re_state], match_step, 0);
|
||||
|
||||
if (re_state > 0)
|
||||
re_state -= 1;
|
||||
|
||||
cur_byte = re_getbyte();
|
||||
re_bittree(ref bm_literal[((last_byte >> lc) & 0x07)], 0, 0x100, cur_byte);
|
||||
|
||||
if (!this.np9660 && in_ptr >= in_len)
|
||||
{
|
||||
re_normalize();
|
||||
re_flush();
|
||||
return re_trunc();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
re_bit(ref bm_match[re_state], match_step, 1);
|
||||
|
||||
// write bitstream length (8 bits, where 0 marks the end of it)
|
||||
len_bits = 0;
|
||||
for (i = 1; i < 8; i++)
|
||||
{
|
||||
match_step += 1;
|
||||
if ((match_len - 1) < (1 << i))
|
||||
break;
|
||||
re_bit(ref bm_match[re_state], match_step, 1);
|
||||
len_bits += 1;
|
||||
}
|
||||
if (i != 8)
|
||||
re_bit(ref bm_match[re_state], match_step, 0);
|
||||
|
||||
if (len_bits > 0)
|
||||
{
|
||||
len_state = ((len_bits - 1) << 2) + ((in_ptr << (len_bits - 1)) & 0x03);
|
||||
re_number(ref bm_len[re_state], len_state, len_bits, (match_len - 1));
|
||||
|
||||
if (this.np9660)
|
||||
flg = (match_len == 256);
|
||||
else
|
||||
flg = (in_ptr >= in_len);
|
||||
|
||||
if (flg)
|
||||
{
|
||||
re_normalize();
|
||||
re_flush();
|
||||
return re_trunc();
|
||||
}
|
||||
}
|
||||
|
||||
// determine limit ...
|
||||
dist_state = 0;
|
||||
limit = 8;
|
||||
|
||||
// condition is different if np9660 vs pops
|
||||
if (this.np9660)
|
||||
flg = (match_len > 3);
|
||||
else
|
||||
flg = (match_len > 4);
|
||||
|
||||
|
||||
if (flg) // if (condition)
|
||||
{
|
||||
dist_state += 7;
|
||||
|
||||
if (this.np9660)
|
||||
{
|
||||
limit = 44;
|
||||
}
|
||||
else
|
||||
{
|
||||
limit = 16;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// find total 1s in the match_dist
|
||||
dist_bits = 0;
|
||||
if(match_dist > 0) {
|
||||
while ((match_dist >> dist_bits) != 1)
|
||||
{
|
||||
dist_bits += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Match dist is 0.. uhh cant match with yourself..");
|
||||
}
|
||||
|
||||
re_bittree(ref bm_dist_bits[len_bits], dist_state, limit, dist_bits);
|
||||
|
||||
if (dist_bits > 0)
|
||||
re_number(ref bm_dist[dist_bits], 0, dist_bits, match_dist);
|
||||
|
||||
|
||||
in_ptr += match_len;
|
||||
re_state = 6 + ((in_ptr + 1) & 1);
|
||||
}
|
||||
last_byte = input[in_ptr - 1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int lzrc_decompress(byte[] out_buf, int out_len, byte[] in_buf, int in_len)
|
||||
{
|
||||
int match_step, rc_state, len_state, dist_state = 0;
|
||||
int i, bit, cur_byte, last_byte;
|
||||
int match_len, len_bits;
|
||||
int match_dist, dist_bits, limit;
|
||||
int match_src;
|
||||
int round = -1;
|
||||
|
||||
bool flg = false;
|
||||
len_state = 0;
|
||||
|
||||
rc_init(out_buf, out_len, in_buf, in_len);
|
||||
|
||||
/*if ((lc & 0x80) != 0)
|
||||
{
|
||||
Buffer.BlockCopy(in_buf, 5, out_buf, 0, (int)code);
|
||||
return (int)code;
|
||||
}*/
|
||||
|
||||
rc_state = 0;
|
||||
last_byte = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
round += 1;
|
||||
match_step = 0;
|
||||
bit = rc_bit(bm_match[rc_state], match_step);
|
||||
// if bit is 0, just copy from the bit tree into the output ?
|
||||
if (bit == 0)
|
||||
{
|
||||
if (rc_state > 0)
|
||||
rc_state -= 1;
|
||||
|
||||
cur_byte = rc_bittree(bm_literal[(((out_ptr & 7) << 8) + last_byte >> lc) & 0x07], 0, 0x100);
|
||||
|
||||
rc_putbyte((byte)cur_byte);
|
||||
if (out_ptr == out_len) return out_ptr;
|
||||
}
|
||||
else // This essentially goes; "hey the bytes that go here, are the same ones that were already *here*
|
||||
{
|
||||
// Determine bit length?
|
||||
len_bits = 0;
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
match_step += 1;
|
||||
bit = rc_bit(bm_match[rc_state], match_step);
|
||||
if (bit == 0)
|
||||
break;
|
||||
len_bits += 1;
|
||||
}
|
||||
|
||||
// Get the match length ..
|
||||
if (len_bits == 0)
|
||||
{
|
||||
match_len = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len_state = ((len_bits - 1) << 2) + ((out_ptr << (len_bits - 1)) & 0x03);
|
||||
match_len = rc_number(bm_len[rc_state], len_state, len_bits);
|
||||
if (this.np9660 && match_len == 0xFF)
|
||||
return out_ptr;
|
||||
}
|
||||
|
||||
dist_state = 0;
|
||||
limit = 8;
|
||||
if (this.np9660)
|
||||
flg = (match_len > 2);
|
||||
else
|
||||
flg = (match_len > 3);
|
||||
|
||||
if (flg)
|
||||
{
|
||||
dist_state += 7;
|
||||
if (this.np9660)
|
||||
limit = 44;
|
||||
else
|
||||
limit = 16;
|
||||
}
|
||||
dist_bits = rc_bittree(bm_dist_bits[len_bits], dist_state, limit);
|
||||
|
||||
if (dist_bits > 0)
|
||||
match_dist = rc_number(bm_dist[dist_bits], 0, dist_bits);
|
||||
else
|
||||
match_dist = 1;
|
||||
|
||||
match_src = out_ptr - match_dist;
|
||||
if (match_dist > out_ptr || match_dist < 0)
|
||||
{
|
||||
//Console.WriteLine($"match_dist out of range! 0x{match_dist:x8}");
|
||||
//return -1; // test
|
||||
throw new Exception($"match_dist out of range! 0x{match_dist:x8}");
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < match_len + 1; i++)
|
||||
{
|
||||
rc_putbyte(output[match_src++]);
|
||||
}
|
||||
rc_state = 6 + ((out_ptr + 1) & 1);
|
||||
if (out_ptr == out_len) return out_ptr;
|
||||
}
|
||||
last_byte = output[out_ptr - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
PspCrypto/PspCrypto.csproj
Normal file
29
PspCrypto/PspCrypto.csproj
Normal file
|
@ -0,0 +1,29 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resource.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
12
PspCrypto/PspParameter.cs
Normal file
12
PspCrypto/PspParameter.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ECDsaTest
|
||||
{
|
||||
internal class PspParameter
|
||||
{
|
||||
public byte[] Kinv { get; set; }
|
||||
public byte[] Rp { get; set; }
|
||||
}
|
||||
}
|
73
PspCrypto/Resource.Designer.cs
generated
Normal file
73
PspCrypto/Resource.Designer.cs
generated
Normal file
|
@ -0,0 +1,73 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PspCrypto {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resource {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resource() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PspCrypto.Resource", typeof(Resource).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] @__sce_discinfo {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("__sce_discinfo", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
PspCrypto/Resource.resx
Normal file
124
PspCrypto/Resource.resx
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="__sce_discinfo" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>__sce_discinfo;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
28
PspCrypto/SceDdrdb.cs
Normal file
28
PspCrypto/SceDdrdb.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public static class SceDdrdb
|
||||
{
|
||||
public static int sceDdrdbHash(ReadOnlySpan<byte> src, int size, Span<byte> digest)
|
||||
{
|
||||
SHA1.HashData(src[..size], digest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int sceDdrdbSigvry(ReadOnlySpan<byte> pubKey, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> sig)
|
||||
{
|
||||
Span<byte> buff = stackalloc byte[Marshal.SizeOf<KIRKEngine.KIRK_CMD17_BUFFER>()];
|
||||
ref KIRKEngine.KIRK_CMD17_BUFFER buffer = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_CMD17_BUFFER>(buff);
|
||||
pubKey[..0x28].CopyTo(buffer.public_key.point);
|
||||
hash[..20].CopyTo(buffer.message_hash);
|
||||
sig[..0x28].CopyTo(buffer.signature.sig);
|
||||
return KIRKEngine.sceUtilsBufferCopyWithRange(null, 0, buff, 100, KIRKEngine.KIRK_CMD_ECDSA_VERIFY);
|
||||
}
|
||||
}
|
||||
}
|
513
PspCrypto/SceMemlmd.cs
Normal file
513
PspCrypto/SceMemlmd.cs
Normal file
|
@ -0,0 +1,513 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public static class SceMemlmd
|
||||
{
|
||||
private static readonly Memory<byte> MemlmdKirkMemory = new byte[0x150]; // DAT_00002604
|
||||
private static readonly Memory<byte> MemlmdMem_BFC00000 = new byte[0x3000];
|
||||
private static readonly Memory<byte> MemlmdMem_BFC00280 = MemlmdMem_BFC00000.Slice(0x280, 0xC0);
|
||||
private static readonly Memory<byte> MemlmdMem_BFC00340 = MemlmdMem_BFC00000.Slice(0x340, 0x300);
|
||||
private static readonly Memory<byte> MemlmdMem_BFC00A00 = MemlmdMem_BFC00000.Slice(0xA00, 0x200);
|
||||
private static readonly Memory<byte> MemlmdMem_2780 = new byte[0x200];
|
||||
|
||||
private static readonly byte[] key7A90 =
|
||||
{
|
||||
0x77, 0x3F, 0x4B, 0xE1, 0x4C, 0x0A, 0xB4, 0x52, 0x67, 0x2B, 0x67, 0x56, 0x82, 0x4C, 0xCF, 0x42,
|
||||
0xAA, 0x37, 0xFF, 0xC0, 0x89, 0x41, 0xE5, 0x63, 0x5E, 0x84, 0xE9, 0xFB, 0x53, 0xDA, 0x94, 0x9E,
|
||||
0x9B, 0xB7, 0xC2, 0xA4, 0x22, 0x9F, 0xDF, 0x1F
|
||||
};
|
||||
internal static readonly byte[] key_4C940AF0 = { 0xA8, 0xB1, 0x47, 0x77, 0xDC, 0x49, 0x6A, 0x6F, 0x38, 0x4C, 0x4D, 0x96, 0xBD, 0x49, 0xEC, 0x9B };
|
||||
internal static readonly byte[] key_4C940BF0 = { 0x3B, 0x9B, 0x1A, 0x56, 0x21, 0x80, 0x14, 0xED, 0x8E, 0x8B, 0x08, 0x42, 0xFA, 0x2C, 0xDC, 0x3A };
|
||||
internal static readonly byte[] key_4C9410F0 = { 0x31, 0x1F, 0x98, 0xD5, 0x7B, 0x58, 0x95, 0x45, 0x32, 0xAB, 0x3A, 0xE3, 0x89, 0x32, 0x4B, 0x34 };
|
||||
internal static readonly byte[] key_4C9412F0 = { 0x26, 0x38, 0x0A, 0xAC, 0xA5, 0xD8, 0x74, 0xD1, 0x32, 0xB7, 0x2A, 0xBF, 0x79, 0x9E, 0x6D, 0xDB };
|
||||
internal static readonly byte[] key_4C9413F0 = { 0x53, 0xE7, 0xAB, 0xB9, 0xC6, 0x4A, 0x4B, 0x77, 0x92, 0x17, 0xB5, 0x74, 0x0A, 0xDA, 0xA9, 0xEA };
|
||||
internal static readonly byte[] key_4C9414F0 = { 0x45, 0xEF, 0x5C, 0x5D, 0xED, 0x81, 0x99, 0x84, 0x12, 0x94, 0x8F, 0xAB, 0xE8, 0x05, 0x6D, 0x7D };
|
||||
internal static readonly byte[] key_4C9415F0 = { 0x70, 0x1B, 0x08, 0x25, 0x22, 0xA1, 0x4D, 0x3B, 0x69, 0x21, 0xF9, 0x71, 0x0A, 0xA8, 0x41, 0xA9 };
|
||||
internal static readonly byte[] key_4C949AF0 = { 0x48, 0x58, 0xAA, 0x38, 0x78, 0x9A, 0x6C, 0x0D, 0x42, 0xEA, 0xC8, 0x19, 0x23, 0x34, 0x4D, 0xF0 };
|
||||
internal static readonly byte[] key_4C949BF0 = { 0x20, 0x00, 0x5B, 0x67, 0x48, 0x77, 0x02, 0x60, 0xCF, 0x0C, 0xAB, 0x7E, 0xAE, 0x0C, 0x55, 0xA1 };
|
||||
internal static readonly byte[] key_4C949CF0 = { 0x3F, 0x67, 0x09, 0xA1, 0x47, 0x71, 0xD6, 0x9E, 0x27, 0x7C, 0x7B, 0x32, 0x67, 0x0E, 0x65, 0x8A };
|
||||
internal static readonly byte[] key_4C949DF0 = { 0x9B, 0x92, 0x99, 0x91, 0xA2, 0xE8, 0xAA, 0x4A, 0x87, 0x10, 0xA0, 0x9A, 0xBF, 0x88, 0xC0, 0xAC };
|
||||
internal static readonly byte[] key_4C949EF0 = { 0x90, 0x22, 0x66, 0xE9, 0x59, 0x11, 0x9B, 0x99, 0x67, 0x39, 0x49, 0x81, 0xAB, 0x98, 0x08, 0xA6 };
|
||||
internal static readonly byte[] key_4C949FF0 = { 0xA0, 0xA5, 0x55, 0x0A, 0xFA, 0xB2, 0x16, 0x62, 0x05, 0xDC, 0x4B, 0x8E, 0xDA, 0xD5, 0xA5, 0xCA };
|
||||
internal static readonly byte[] key_4C94A0F0 = { 0x78, 0x96, 0xAE, 0x9C, 0xE7, 0x89, 0x2D, 0xF5, 0x34, 0x9C, 0x29, 0x36, 0xD1, 0xF9, 0xE8, 0x3C };
|
||||
internal static readonly byte[] key_4C94A1F0 = { 0x71, 0x44, 0x53, 0xB6, 0xE6, 0x75, 0x3F, 0xF0, 0x8D, 0x5E, 0xB4, 0xB2, 0xEA, 0x06, 0x23, 0x6A };
|
||||
internal static readonly byte[] key_4C9491F0 = { 0x85, 0x93, 0x1F, 0xED, 0x2C, 0x4D, 0xA4, 0x53, 0x59, 0x9C, 0x3F, 0x16, 0xF3, 0x50, 0xDE, 0x46 };
|
||||
internal static readonly byte[] key_4C9494F0 = { 0x76, 0xF2, 0x6C, 0x0A, 0xCA, 0x3A, 0xBA, 0x4E, 0xAC, 0x76, 0xD2, 0x40, 0xF5, 0xC3, 0xBF, 0xF9 };
|
||||
internal static readonly byte[] key_4C9490F0 = { 0xFA, 0x79, 0x09, 0x36, 0xE6, 0x19, 0xE8, 0xA4, 0xA9, 0x41, 0x37, 0x18, 0x81, 0x02, 0xE9, 0xB3 };
|
||||
|
||||
internal static readonly byte[] key_00000000 =
|
||||
{
|
||||
0x6A, 0x19, 0x71, 0xF3, 0x18, 0xDE, 0xD3, 0xA2, 0x6D, 0x3B, 0xDE, 0xC7, 0xBE, 0x98, 0xE2, 0x4C,
|
||||
0xE3, 0xDC, 0xDF, 0x42, 0x7B, 0x5B, 0x12, 0x28, 0x7D, 0xC0, 0x7A, 0x59, 0x86, 0xF0, 0xF5, 0xB5,
|
||||
0x58, 0xD8, 0x64, 0x18, 0x84, 0x24, 0x7F, 0xE9, 0x57, 0xAB, 0x4F, 0xC6, 0x92, 0x6D, 0x70, 0x29,
|
||||
0xD3, 0x61, 0x87, 0x87, 0xD0, 0xAE, 0x2C, 0xE7, 0x37, 0x77, 0xC7, 0x3C, 0x96, 0x7E, 0x21, 0x1F,
|
||||
0x65, 0x95, 0xC0, 0x61, 0x57, 0xAC, 0x64, 0xD8, 0x5A, 0x6D, 0x14, 0xD2, 0x9C, 0x54, 0xC6, 0x68,
|
||||
0x5D, 0xF5, 0xC3, 0xF0, 0x50, 0xDA, 0xEA, 0x19, 0x43, 0xA7, 0xAD, 0xC3, 0x2A, 0x14, 0xCA, 0xC8,
|
||||
0x4C, 0x83, 0x86, 0x18, 0xAE, 0x86, 0x49, 0xFB, 0x4F, 0x45, 0x75, 0xD2, 0xC3, 0xD6, 0xE1, 0x13,
|
||||
0x69, 0x37, 0xC6, 0x90, 0xCF, 0xF9, 0x79, 0xA1, 0x77, 0x3A, 0x3E, 0xBB, 0xBB, 0xD5, 0x3B, 0x84,
|
||||
0x1B, 0x9A, 0xB8, 0x79, 0xF0, 0xD3, 0x5F, 0x6F, 0x4C, 0xC0, 0x28, 0x87, 0xBC, 0xAE, 0xDA, 0x00
|
||||
};
|
||||
|
||||
internal static readonly byte[] key_01000000 =
|
||||
{
|
||||
0x50, 0xCC, 0x03, 0xAC, 0x3F, 0x53, 0x1A, 0xFA, 0x0A, 0xA4, 0x34, 0x23, 0x86, 0x61, 0x7F, 0x97,
|
||||
0x84, 0x1C, 0x1A, 0x1D, 0x08, 0xD4, 0x50, 0xB6, 0xD9, 0x73, 0x27, 0x80, 0xD1, 0xDE, 0xEE, 0xCA,
|
||||
0x49, 0x8B, 0x84, 0x37, 0xDB, 0xF0, 0x70, 0xA2, 0xA6, 0x2B, 0x09, 0x4D, 0x3B, 0x29, 0xDE, 0x0B,
|
||||
0xE1, 0x6F, 0x04, 0x7A, 0xC4, 0x18, 0x7A, 0x69, 0x73, 0xBF, 0x02, 0xD8, 0xA1, 0xD0, 0x58, 0x7E,
|
||||
0x69, 0xCE, 0xAC, 0x5E, 0x1B, 0x0A, 0xF8, 0x19, 0xE6, 0x9A, 0xC0, 0xDE, 0xA0, 0xB2, 0xCE, 0x04,
|
||||
0x43, 0xC0, 0x9D, 0x50, 0x5D, 0x0A, 0xD7, 0xFD, 0xC6, 0x53, 0xAA, 0x13, 0xDD, 0x2C, 0x3B, 0x2B,
|
||||
0xBF, 0xAB, 0x7C, 0xF5, 0xA0, 0x4A, 0x79, 0xE3, 0xF1, 0x7B, 0x2E, 0xB2, 0xA3, 0xAC, 0x8E, 0x0A,
|
||||
0x38, 0x9B, 0x9E, 0xAA, 0xEC, 0x2B, 0xA3, 0x75, 0x13, 0x75, 0x77, 0x98, 0x6A, 0x66, 0x92, 0x65,
|
||||
0xBC, 0x97, 0x80, 0x0E, 0x32, 0x88, 0x9F, 0x64, 0xBA, 0x99, 0x8A, 0x72, 0x96, 0x9F, 0xE1, 0xE0
|
||||
};
|
||||
|
||||
internal static readonly byte[] key_16D59E03 = { 0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E, 0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1 };
|
||||
|
||||
internal static readonly byte[] key_4467415D =
|
||||
{
|
||||
0x66, 0x0F, 0xCB, 0x3B, 0x30, 0x75, 0xE3, 0x10, 0x0A, 0x95, 0x65, 0xC7, 0x3C, 0x93, 0x87, 0x22,
|
||||
0xF3, 0xA4, 0xB1, 0xE8, 0x9A, 0xFB, 0x53, 0x52, 0x8F, 0x64, 0xB2, 0xDA, 0xB7, 0x76, 0xB9, 0x56,
|
||||
0x96, 0xB6, 0x4C, 0x02, 0xE6, 0x9B, 0xAE, 0xED, 0x86, 0x48, 0xBA, 0xA6, 0x4F, 0x23, 0x15, 0x03,
|
||||
0x1F, 0xC4, 0xF7, 0x3A, 0x05, 0xC3, 0x3C, 0xE2, 0x2F, 0x36, 0xC4, 0x26, 0xF2, 0x42, 0x40, 0x1F,
|
||||
0x97, 0xEE, 0x9C, 0xC6, 0xD9, 0x68, 0xE0, 0xE7, 0xE3, 0x9F, 0xCE, 0x05, 0xE8, 0xD1, 0x8B, 0x1B,
|
||||
0x57, 0x34, 0x3D, 0x0D, 0xDF, 0xA8, 0x64, 0xBF, 0x8F, 0x4C, 0x37, 0x3F, 0x93, 0xD5, 0x45, 0x9E,
|
||||
0x2B, 0x25, 0x2C, 0x62, 0x74, 0xDE, 0xC1, 0x53, 0xAB, 0x6D, 0xDF, 0x2C, 0xCE, 0x5A, 0x6B, 0x1F,
|
||||
0x5E, 0x24, 0x4A, 0xFB, 0x7D, 0xFF, 0xE8, 0xF5, 0x19, 0x77, 0xEF, 0xCC, 0x74, 0xFE, 0x8B, 0x63,
|
||||
0x31, 0xAE, 0x99, 0x05, 0x7F, 0x51, 0xF2, 0x72, 0x6A, 0x20, 0x8D, 0x1C, 0xAC, 0x4C, 0xF6, 0x50
|
||||
};
|
||||
|
||||
internal static readonly byte[] key_CFEF05F0 = { 0xCA, 0xFB, 0xBF, 0xC7, 0x50, 0xEA, 0xB4, 0x40, 0x8E, 0x44, 0x5C, 0x63, 0x53, 0xCE, 0x80, 0xB1 };
|
||||
internal static readonly byte[] key_CFEF06F0 = { 0x9F, 0x67, 0x1A, 0x7A, 0x22, 0xF3, 0x59, 0x0B, 0xAA, 0x6D, 0xA4, 0xC6, 0x8B, 0xD0, 0x03, 0x77 };
|
||||
internal static readonly byte[] key_CFEF08F0 = { 0x2E, 0x00, 0xF6, 0xF7, 0x52, 0xCF, 0x95, 0x5A, 0xA1, 0x26, 0xB4, 0x84, 0x9B, 0x58, 0x76, 0x2F };
|
||||
|
||||
public static int memlmd_EF73E85B(Span<byte> modData, int size, out int newSize) => KernelModuleDecrypt(modData, size, out newSize, 0);
|
||||
|
||||
public static int memlmd_CF03556B(Span<byte> modData, int size, out int newSize) => KernelModuleDecrypt(modData, size, out newSize, 1);
|
||||
|
||||
static int KernelModuleDecrypt(Span<byte> modData, int size, out int newSize, int use_polling)
|
||||
{
|
||||
int ret;
|
||||
newSize = 0;
|
||||
Span<byte> local_80 = stackalloc byte[48];
|
||||
Span<byte> local_50 = stackalloc byte[32];
|
||||
if (modData.IsEmpty)
|
||||
{
|
||||
return -0xc9;
|
||||
}
|
||||
if (size < 0x160)
|
||||
{
|
||||
return -0xca;
|
||||
}
|
||||
//if ((modData[0] & 0x3f) != 0)
|
||||
//{
|
||||
// return -0xcb;
|
||||
//}
|
||||
|
||||
//if ((0x220202 >> (MemoryMarshal.Read<int>(modData) >> 0x1b)) == 0)
|
||||
//{
|
||||
// return -0xcc;
|
||||
//}
|
||||
modData[..0x150].CopyTo(MemlmdKirkMemory.Span);
|
||||
var hdr = MemoryMarshal.Read<PSPHeader2>(MemlmdKirkMemory.Span);
|
||||
int? keySeed = null;
|
||||
bool? keyFlag = null;
|
||||
Span<byte> key = null;
|
||||
if (hdr.tag == 0x4C94A1F0)
|
||||
{
|
||||
keySeed = 0x43;
|
||||
keyFlag = true;
|
||||
key = key_4C94A1F0;
|
||||
}
|
||||
else if (hdr.tag == 0x4C949BF0)
|
||||
{
|
||||
keySeed = 0x43;
|
||||
keyFlag = true;
|
||||
key = key_4C949BF0;
|
||||
}
|
||||
else if (hdr.tag == 0xB1B9C434)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hdr.tag == 0x4C9491F0)
|
||||
{
|
||||
key = key_4C9491F0;
|
||||
}
|
||||
else if (hdr.tag == 0x4C9494F0)
|
||||
{
|
||||
key = key_4C9494F0;
|
||||
}
|
||||
else if (hdr.tag == 0x4C9490F0)
|
||||
{
|
||||
key = key_4C9490F0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hdr.tag == 0x00000000)
|
||||
{
|
||||
key = key_00000000;
|
||||
keySeed = 0x42;
|
||||
}
|
||||
else if (hdr.tag == 0x01000000)
|
||||
{
|
||||
key = key_01000000;
|
||||
keySeed = 0x43;
|
||||
}
|
||||
keyFlag = false;
|
||||
goto keytagout;
|
||||
}
|
||||
keySeed = 0x43;
|
||||
keyFlag = true;
|
||||
}
|
||||
keytagout:
|
||||
//if (keyFlag == true && size < 0x160)
|
||||
//{
|
||||
// return -0xca;
|
||||
//}
|
||||
if (keyFlag == true)
|
||||
{
|
||||
for (var i = 0; i < 0x30; i++)
|
||||
{
|
||||
if (hdr.sCheck[i] != 0)
|
||||
{
|
||||
ret = -0x12e;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keyFlag == false)
|
||||
{
|
||||
// TODO blacklistCheck
|
||||
}
|
||||
newSize = MemoryMarshal.Read<int>(hdr.sizeInfo);
|
||||
if (size - 0x150 < newSize)
|
||||
{
|
||||
ret = -0xce;
|
||||
goto errout;
|
||||
}
|
||||
if (keyFlag == true)
|
||||
{
|
||||
for (byte i = 0; i < 9; i++)
|
||||
{
|
||||
key.CopyTo(MemlmdMem_BFC00A00.Span[(i * 0x10 + 0x14)..]);
|
||||
MemlmdMem_BFC00A00.Span[i * 0x10 + 0x14] = i;
|
||||
}
|
||||
ref var refHdr = ref MemoryMarshal.AsRef<PSPHeader2>(modData);
|
||||
refHdr.sCheck.Slice(0x30, 0x28).CopyTo(MemlmdMem_2780.Span);
|
||||
refHdr.sCheck.Slice(0x30, 0x28).Fill(0);
|
||||
MemlmdMem_2780.Span.Slice(0, 0x28).CopyTo(local_80);
|
||||
var tmp = size - 4;
|
||||
MemoryMarshal.Write(modData, ref tmp);
|
||||
if (use_polling == 0)
|
||||
{
|
||||
ret = KIRKEngine.sceUtilsBufferCopyWithRange(modData, size, modData, size, KIRKEngine.KIRK_CMD_SHA1_HASH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
modData.Slice(0, 0x14).CopyTo(local_50);
|
||||
MemlmdKirkMemory.Span.Slice(0, 0x20).CopyTo(modData);
|
||||
key7A90.CopyTo(MemlmdMem_BFC00340);
|
||||
local_50.Slice(0, 0x14).CopyTo(MemlmdMem_BFC00340.Span[0x28..]);
|
||||
local_80.Slice(0, 0x28).CopyTo(MemlmdMem_BFC00340.Span[0x3C..]);
|
||||
if (use_polling == 0)
|
||||
{
|
||||
ret = KIRKEngine.sceUtilsBufferCopyWithRange(null, 0, MemlmdMem_BFC00340.Span, 100, KIRKEngine.KIRK_CMD_ECDSA_VERIFY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
// clear key_4C9494F0 psp 660
|
||||
// clear key_4C9495F0 psp 660
|
||||
// clear key_4C94A1F0 psv
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -0x132;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -0x66;
|
||||
}
|
||||
else if (ret == 0xc)
|
||||
{
|
||||
ret = -0x6b;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -0x69;
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key[..0x90].CopyTo(MemlmdMem_BFC00A00.Span[0x14..]);
|
||||
}
|
||||
ret = Kirk7(MemlmdMem_BFC00A00.Span, 0x90, keySeed.Value, use_polling);
|
||||
if (ret == 0)
|
||||
{
|
||||
MemlmdMem_BFC00A00[..0x90].CopyTo(MemlmdMem_BFC00280);
|
||||
if (keyFlag == true)
|
||||
{
|
||||
hdr.CheckData[..0x5C].CopyTo(MemlmdMem_BFC00A00.Span);
|
||||
hdr.keyData4.CopyTo(MemlmdMem_BFC00A00[0x5C..].Span);
|
||||
hdr.sha1Hash.CopyTo(MemlmdMem_BFC00A00[0x6C..].Span);
|
||||
hdr.keyData.CopyTo(MemlmdMem_BFC00A00[0x80..].Span);
|
||||
hdr.cmacDataHash.CopyTo(MemlmdMem_BFC00A00[0xB0..].Span);
|
||||
hdr.sizeInfo.CopyTo(MemlmdMem_BFC00A00[0xC0..].Span);
|
||||
hdr.RawHdr.CopyTo(MemlmdMem_BFC00A00[0xD0..].Span);
|
||||
MemlmdMem_BFC00A00.Slice(0x34, 0x28).Span.Fill(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hdr.CheckData.CopyTo(MemlmdMem_BFC00A00.Span);
|
||||
hdr.keyData50.CopyTo(MemlmdMem_BFC00A00[0x80..].Span);
|
||||
hdr.RawHdr.CopyTo(MemlmdMem_BFC00A00[0xD0..].Span);
|
||||
}
|
||||
if (keyFlag == true)
|
||||
{
|
||||
MemlmdMem_BFC00A00.Slice(0x5C, 0x60).CopyTo(MemlmdMem_BFC00340[0x14..]);
|
||||
ret = Kirk7(MemlmdMem_BFC00340.Span, 0x60, keySeed.Value, use_polling);
|
||||
if (ret == 0)
|
||||
{
|
||||
MemlmdMem_BFC00340.Slice(0, 0x60).CopyTo(MemlmdMem_BFC00A00[0x5C..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto kirkerr;
|
||||
}
|
||||
}
|
||||
if (keyFlag == true)
|
||||
{
|
||||
MemlmdMem_BFC00A00.Slice(0x6C, 0x14).CopyTo(MemlmdMem_BFC00340);
|
||||
MemlmdMem_BFC00A00.Slice(0x5C, 0x10).CopyTo(MemlmdMem_BFC00A00[0x70..]);
|
||||
MemlmdMem_BFC00A00.Slice(0x18, 0x58).Span.Fill(0);
|
||||
MemlmdMem_BFC00A00[..4].CopyTo(MemlmdMem_BFC00A00[4..]);
|
||||
var tmp = 0x14c;
|
||||
MemoryMarshal.Write(MemlmdMem_BFC00A00.Span, ref tmp);
|
||||
MemlmdMem_BFC00280[..0x10].CopyTo(MemlmdMem_BFC00A00[8..]);
|
||||
MemlmdMem_BFC00280[..0x10].Span.Fill(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemlmdMem_BFC00A00.Slice(4, 0x14).CopyTo(MemlmdMem_BFC00340);
|
||||
var tmp = 0x14c;
|
||||
MemoryMarshal.Write(MemlmdMem_BFC00A00.Span, ref tmp);
|
||||
MemlmdMem_BFC00280[..0x14].CopyTo(MemlmdMem_BFC00A00[4..]);
|
||||
}
|
||||
if (use_polling == 0)
|
||||
{
|
||||
ret = KIRKEngine.sceUtilsBufferCopyWithRange(MemlmdMem_BFC00A00.Span, 0x150, MemlmdMem_BFC00A00.Span, 0x150, KIRKEngine.KIRK_CMD_SHA1_HASH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
if (!MemlmdMem_BFC00A00[..0x14].Span.SequenceEqual(MemlmdMem_BFC00340.Span[..0x14]))
|
||||
{
|
||||
ret = -0x12e;
|
||||
goto errout;
|
||||
}
|
||||
if (keyFlag == true)
|
||||
{
|
||||
for (var i = 0; i < 0x40; i++)
|
||||
{
|
||||
MemlmdMem_BFC00A00[0x80..].Span[i] ^= MemlmdMem_BFC00280[0x10..].Span[i];
|
||||
}
|
||||
MemlmdMem_BFC00280.Slice(0x10, 0x40).Span.Fill(0);
|
||||
ret = Kirk7(MemlmdMem_BFC00A00[0x6C..].Span, 0x40, keySeed.Value, use_polling);
|
||||
if (ret != 0)
|
||||
{
|
||||
goto kirkerr;
|
||||
}
|
||||
for (var i = 0; i < 0x40; i++)
|
||||
{
|
||||
modData[0x40..][i] = (byte)(MemlmdMem_BFC00A00[0x6C..].Span[i] ^ MemlmdMem_BFC00280[0x50..].Span[i]);
|
||||
}
|
||||
MemlmdMem_BFC00280.Slice(0x50, 0x40).Span.Fill(0);
|
||||
modData.Slice(0x80, 0x30).Fill(0);
|
||||
|
||||
ref var cmd1Hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_CMD1_HEADER>(modData[0x40..]);
|
||||
cmd1Hdr.mode = 1;
|
||||
MemlmdMem_BFC00A00.Slice(0xc0, 0x10).Span.CopyTo(cmd1Hdr.off70); // DAT_00009e80
|
||||
modData.Slice(0xc0, 0x10).Fill(0);
|
||||
MemlmdMem_BFC00A00.Slice(0xd0, 0x80).Span.CopyTo(modData[0xd0..]); // psp hdr size 0x80
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < 0x70; i++)
|
||||
{
|
||||
MemlmdMem_BFC00A00[0x40..].Span[i] ^= MemlmdMem_BFC00280[0x14..].Span[i];
|
||||
}
|
||||
ret = Kirk7(MemlmdMem_BFC00A00[0x2C..].Span, 0x70, keySeed.Value, use_polling);
|
||||
if (ret == 0)
|
||||
{
|
||||
for (var i = 0; i < 0x70; i++)
|
||||
{
|
||||
modData[0x40..][i] = (byte)(MemlmdMem_BFC00A00[0x2C..].Span[i] ^ MemlmdMem_BFC00280[0x20..].Span[i]);
|
||||
}
|
||||
MemlmdMem_BFC00A00.Slice(0xB0, 0xA0).Span.CopyTo(modData[0xB0..]);
|
||||
ref var cmd1ecdsaHdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_CMD1_ECDSA_HEADER>(modData[0x40..]);
|
||||
if (cmd1ecdsaHdr.ecdsa_hash != 1)
|
||||
{
|
||||
ret = -0x12f;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// goto kirk err;
|
||||
goto kirkerr;
|
||||
}
|
||||
}
|
||||
if (use_polling == 0)
|
||||
{
|
||||
// File.WriteAllBytes("wrongdata", modData.ToArray());
|
||||
ret = KIRKEngine.sceUtilsBufferCopyWithRange(modData, size, modData[0x40..], size - 0x40, KIRKEngine.KIRK_CMD_DECRYPT_PRIVATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
goto rout;
|
||||
}
|
||||
}
|
||||
}
|
||||
errout:
|
||||
|
||||
MemlmdKirkMemory.Span.Fill(0);
|
||||
newSize = 0;
|
||||
rout:
|
||||
MemlmdMem_BFC00A00.Span.Fill(0);
|
||||
|
||||
return ret;
|
||||
kirkerr:
|
||||
ret ^= 0xC;
|
||||
ret = -0x6a;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
static int Kirk7(Span<byte> data, int size, int seed, int use_polling)
|
||||
{
|
||||
KIRKEngine.KIRK_AES128CBC_HEADER hdr = new KIRKEngine.KIRK_AES128CBC_HEADER
|
||||
{
|
||||
mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC,
|
||||
keyseed = seed,
|
||||
data_size = size
|
||||
};
|
||||
MemoryMarshal.Write(data, ref hdr);
|
||||
//using (var ms = new MemoryStream(data))
|
||||
//{
|
||||
// ms.Seek(offset, SeekOrigin.Begin);
|
||||
// using var bw = new BinaryWriter(ms);
|
||||
// bw.Write(KIRKEngine.KIRK_MODE_DECRYPT_CBC);
|
||||
// bw.Write(0);
|
||||
// bw.Write(0);
|
||||
// bw.Write(seed);
|
||||
// bw.Write(size);
|
||||
//}
|
||||
if (use_polling == 0)
|
||||
{
|
||||
KIRKEngine.sceUtilsBufferCopyWithRange(data, size + 20, data, size + 20,
|
||||
KIRKEngine.KIRK_CMD_DECRYPT_IV_0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int Kirk8(Span<byte> buf, int size, int use_polling)
|
||||
{
|
||||
int retv;
|
||||
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
|
||||
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
|
||||
hdr.keyseed = 0x0100;
|
||||
hdr.data_size = size;
|
||||
|
||||
retv = KIRKEngine.sceUtilsBufferCopyWithRange(buf, size + 0x14, buf, size, KIRKEngine.KIRK_CMD_DECRYPT_IV_FUSE);
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
private static readonly byte[] key_XOR_2304 =
|
||||
{
|
||||
0x71, 0xF6, 0xA8, 0x31, 0x1E, 0xE0, 0xFF, 0x1E, 0x50, 0xBA, 0x6C, 0xD2, 0x98, 0x2D, 0xD6, 0x2D
|
||||
};
|
||||
|
||||
private static readonly byte[] key_XOR_2314 =
|
||||
{
|
||||
0xAA, 0x85, 0x4D, 0xB0, 0xFF, 0xCA, 0x47, 0xEB, 0x38, 0x7F, 0xD7, 0xE4, 0x3D, 0x62, 0xB0, 0x10
|
||||
};
|
||||
|
||||
static int memlmd_6192F715(Span<byte> modData, int size) => KernelModuleSignCheck(modData, size, 0);
|
||||
|
||||
static int memlmd_EA94592C(Span<byte> modData, int size) => KernelModuleSignCheck(modData, size, 1);
|
||||
|
||||
static int KernelModuleSignCheck(Span<byte> modData, int size, int use_polling)
|
||||
{
|
||||
int ret = -0xc9;
|
||||
if (modData.IsEmpty)
|
||||
{
|
||||
goto errorout;
|
||||
}
|
||||
if (size < 0x15F)
|
||||
{
|
||||
ret = -0xca;
|
||||
goto errorout;
|
||||
}
|
||||
modData.Slice(0x80, 0xD0).CopyTo(MemlmdMem_BFC00A00.Span.Slice(0x14));
|
||||
|
||||
for (var i = 0; i < 0xD0; i++)
|
||||
{
|
||||
MemlmdMem_BFC00A00[0x14..].Span[i] ^= key_XOR_2314[i & 0xF];
|
||||
}
|
||||
ret = Kirk8(MemlmdMem_BFC00A00.Span, 0xD0, use_polling);
|
||||
if (ret == 0)
|
||||
{
|
||||
for (var i = 0; i < 0xD0; i++)
|
||||
{
|
||||
MemlmdMem_BFC00A00.Span[i] ^= key_XOR_2304[i & 0xF];
|
||||
}
|
||||
MemlmdMem_BFC00A00.Slice(0x40, 0x90).Span.CopyTo(modData[0x80..]);
|
||||
MemlmdMem_BFC00A00.Slice(0, 0x40).Span.CopyTo(modData[0x110..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -0x67;
|
||||
}
|
||||
else if (ret != 0xc)
|
||||
{
|
||||
ret = -0x6a;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -0x67;
|
||||
}
|
||||
}
|
||||
errorout:
|
||||
MemlmdMem_BFC00A00.Slice(0, 0x164).Span.Fill(0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
2662
PspCrypto/SceMesgLed.cs
Normal file
2662
PspCrypto/SceMesgLed.cs
Normal file
File diff suppressed because it is too large
Load Diff
1338
PspCrypto/SceNpDrm.cs
Normal file
1338
PspCrypto/SceNpDrm.cs
Normal file
File diff suppressed because it is too large
Load Diff
28
PspCrypto/SceRtc.cs
Normal file
28
PspCrypto/SceRtc.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public class SceRtc
|
||||
{
|
||||
public static ulong ksceRtcGetCurrentTick()
|
||||
{
|
||||
return ksceRtcGetCurrentSecureTick();
|
||||
}
|
||||
|
||||
public static ulong ksceRtcGetCurrentNetworkTick()
|
||||
{
|
||||
return ksceRtcGetCurrentSecureTick();
|
||||
}
|
||||
public static ulong ksceRtcGetCurrentSecureTick()
|
||||
{
|
||||
DateTime epoch = new DateTime(1, 1, 1, 0, 0, 0);
|
||||
DateTime now = DateTime.UtcNow;
|
||||
TimeSpan ts = now.Subtract(epoch);
|
||||
return Convert.ToUInt64(Math.Floor(ts.TotalMilliseconds)) * 1000;
|
||||
}
|
||||
}
|
||||
}
|
170
PspCrypto/Security/Cryptography/ECDsaManaged.cs
Normal file
170
PspCrypto/Security/Cryptography/ECDsaManaged.cs
Normal file
|
@ -0,0 +1,170 @@
|
|||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Crypto.Signers;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using System;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
internal class ECDsaManaged : System.Security.Cryptography.ECDsa
|
||||
{
|
||||
private ECKeyParameters _ecKeyParameters;
|
||||
private readonly bool _ebootPbp;
|
||||
private readonly int _type;
|
||||
|
||||
public ECDsaManaged()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ECDsaManaged(System.Security.Cryptography.ECParameters parameters, bool ebootPbp, int type)
|
||||
{
|
||||
_ebootPbp = ebootPbp;
|
||||
_type = type;
|
||||
var gx = new BigInteger(1, parameters.Curve.G.X);
|
||||
var gy = new BigInteger(1, parameters.Curve.G.Y);
|
||||
var curve = ConvertECCurve(parameters.Curve);
|
||||
var g = curve.CreatePoint(gx, gy);
|
||||
var domainParameters = new ECDomainParameters(curve, g, curve.Order);
|
||||
if (parameters.D != null)
|
||||
{
|
||||
var privateKey = new BigInteger(1, parameters.D);
|
||||
_ecKeyParameters = new ECPrivateKeyParameters(privateKey, domainParameters);
|
||||
}
|
||||
else if (parameters.Q.X != null && parameters.Q.Y != null)
|
||||
{
|
||||
var publicKey = curve.CreatePoint(new BigInteger(1, parameters.Q.X), new BigInteger(1, parameters.Q.Y));
|
||||
_ecKeyParameters = new ECPublicKeyParameters(publicKey, domainParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters", nameof(parameters));
|
||||
}
|
||||
}
|
||||
|
||||
public override byte[] SignHash(byte[] hash)
|
||||
{
|
||||
if (_ecKeyParameters is not ECPrivateKeyParameters)
|
||||
{
|
||||
throw new ArgumentException("key is not private Key");
|
||||
}
|
||||
var signer = CreateSigner();
|
||||
signer.Init(true, _ecKeyParameters);
|
||||
signer.BlockUpdate(hash);
|
||||
return signer.GenerateSignature();
|
||||
}
|
||||
|
||||
public override bool VerifyHash(byte[] hash, byte[] signature)
|
||||
{
|
||||
var signer = CreateSigner();
|
||||
if (_ecKeyParameters is ECPrivateKeyParameters ecPrivateKeyParameters)
|
||||
{
|
||||
var publicKey = new ECPublicKeyParameters(
|
||||
ecPrivateKeyParameters.Parameters.G.Multiply(ecPrivateKeyParameters.D),
|
||||
ecPrivateKeyParameters.Parameters);
|
||||
signer.Init(false, publicKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
signer.Init(false, _ecKeyParameters);
|
||||
}
|
||||
signer.BlockUpdate(hash);
|
||||
return signer.VerifySignature(signature);
|
||||
}
|
||||
|
||||
protected override byte[] HashData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm)
|
||||
{
|
||||
var dataSpan = new ReadOnlySpan<byte>(data, offset, count);
|
||||
if (hashAlgorithm == System.Security.Cryptography.HashAlgorithmName.SHA256)
|
||||
{
|
||||
return System.Security.Cryptography.SHA256.HashData(dataSpan);
|
||||
}
|
||||
else if (hashAlgorithm == System.Security.Cryptography.HashAlgorithmName.SHA1)
|
||||
{
|
||||
return System.Security.Cryptography.SHA1.HashData(dataSpan);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"{hashAlgorithm} not supported");
|
||||
}
|
||||
}
|
||||
|
||||
private ISigner CreateSigner()
|
||||
{
|
||||
IDigest digest = DigestUtilities.GetDigest("NONE");
|
||||
IDsa dsa = _ebootPbp ? new ECDsaSigner(new EbootPbpKCalculator(_type)) : new ECDsaSigner();
|
||||
var signer = new DsaDigestSigner(dsa, digest, PlainDsaEncoding.Instance);
|
||||
return signer;
|
||||
}
|
||||
|
||||
private FpCurve _fpCurve;
|
||||
|
||||
public override void GenerateKey(System.Security.Cryptography.ECCurve curve)
|
||||
{
|
||||
_fpCurve = ConvertECCurve(curve);
|
||||
var gx = new BigInteger(1, curve.G.X);
|
||||
var gy = new BigInteger(1, curve.G.Y);
|
||||
var g = _fpCurve.CreatePoint(gx, gy);
|
||||
var domainParameters = new ECDomainParameters(_fpCurve, g, _fpCurve.Order);
|
||||
var gen = new ECKeyPairGenerator();
|
||||
gen.Init(new ECKeyGenerationParameters(domainParameters, new SecureRandom()));
|
||||
var keyPair = gen.GenerateKeyPair();
|
||||
_ecKeyParameters = (ECKeyParameters)keyPair.Private;
|
||||
}
|
||||
|
||||
public override System.Security.Cryptography.ECParameters ExportExplicitParameters(bool includePrivateParameters)
|
||||
{
|
||||
var normalG = _ecKeyParameters.Parameters.G;
|
||||
var curve = new System.Security.Cryptography.ECCurve
|
||||
{
|
||||
A = _fpCurve.A.ToBigInteger().ToByteArrayUnsigned(),
|
||||
B = _fpCurve.B.ToBigInteger().ToByteArrayUnsigned(),
|
||||
Prime = _fpCurve.Q.ToByteArrayUnsigned(),
|
||||
Order = _fpCurve.Order.ToByteArrayUnsigned(),
|
||||
Cofactor = _fpCurve.Cofactor.ToByteArrayUnsigned(),
|
||||
G = new System.Security.Cryptography.ECPoint
|
||||
{
|
||||
X = normalG.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(),
|
||||
Y = normalG.AffineYCoord.ToBigInteger().ToByteArrayUnsigned()
|
||||
}
|
||||
};
|
||||
var parameters = new System.Security.Cryptography.ECParameters
|
||||
{
|
||||
Curve = curve
|
||||
};
|
||||
if (includePrivateParameters && _ecKeyParameters is ECPrivateKeyParameters privateKeyParameters)
|
||||
{
|
||||
parameters.D = privateKeyParameters.D.ToByteArrayUnsigned();
|
||||
var publicKey = _ecKeyParameters.Parameters.G.Multiply(privateKeyParameters.D).Normalize();
|
||||
parameters.Q = new System.Security.Cryptography.ECPoint
|
||||
{
|
||||
X = publicKey.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(),
|
||||
Y = publicKey.AffineYCoord.ToBigInteger().ToByteArrayUnsigned()
|
||||
};
|
||||
}
|
||||
else if (_ecKeyParameters is ECPublicKeyParameters publicKeyParameters)
|
||||
{
|
||||
var publicKey = publicKeyParameters.Q.Normalize();
|
||||
parameters.Q = new System.Security.Cryptography.ECPoint
|
||||
{
|
||||
X = publicKey.AffineXCoord.ToBigInteger().ToByteArrayUnsigned(),
|
||||
Y = publicKey.AffineYCoord.ToBigInteger().ToByteArrayUnsigned()
|
||||
};
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static FpCurve ConvertECCurve(System.Security.Cryptography.ECCurve curve)
|
||||
{
|
||||
var p = new BigInteger(1, curve.Prime);
|
||||
var a = new BigInteger(1, curve.A);
|
||||
var b = new BigInteger(1, curve.B);
|
||||
var n = new BigInteger(1, curve.Order);
|
||||
var fpCurve = new FpCurve(p, a, b, n, BigInteger.One);
|
||||
return fpCurve;
|
||||
}
|
||||
}
|
||||
}
|
103
PspCrypto/Security/Cryptography/EbootPbpKCalculator.cs
Normal file
103
PspCrypto/Security/Cryptography/EbootPbpKCalculator.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Org.BouncyCastle.Crypto.Macs;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Crypto.Signers;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using System;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
internal class EbootPbpKCalculator : IDsaKCalculator
|
||||
{
|
||||
private int _type;
|
||||
|
||||
private BigInteger _n;
|
||||
|
||||
public EbootPbpKCalculator(int type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public bool IsDeterministic => true;
|
||||
|
||||
private readonly Memory<byte> _hash = new byte[0x40];
|
||||
|
||||
public void Init(BigInteger n, SecureRandom random)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public void Init(BigInteger n, BigInteger d, byte[] message)
|
||||
{
|
||||
_n = n;
|
||||
Span<byte> hmacIn = stackalloc byte[0x38];
|
||||
message[..0x1C].CopyTo(hmacIn);
|
||||
KeyVault.Eboot_priv[_type].CopyTo(hmacIn[0x1C..]);
|
||||
|
||||
var hmac = new HMac(new Sha256Digest());
|
||||
hmac.Init(new KeyParameter(KeyVault.Eboot_hmacKey));
|
||||
hmac.BlockUpdate(hmacIn);
|
||||
var hmac_hash_iv = new byte[hmac.GetMacSize()];
|
||||
hmac.DoFinal(hmac_hash_iv);
|
||||
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = can_be_reversed_80C17A(message, 0x1c, hmac_hash_iv, _hash.Span);
|
||||
if (ret != 0 || (ret = can_be_reversed_80C17A(message, 0x1c, hmac_hash_iv, _hash.Span[0x20..])) != 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
} while (ret != 0);
|
||||
}
|
||||
|
||||
public BigInteger NextK()
|
||||
{
|
||||
var bn = new BigInteger(1, _hash.Span[..0x3c]);
|
||||
var ret = bn.Mod(_n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private static int can_be_reversed_80C17A(Span<byte> src, int some_size, Span<byte> iv,
|
||||
Span<byte> src_xored_digest)
|
||||
{
|
||||
Span<byte> src_xored = stackalloc byte[0x20];
|
||||
iv.CopyTo(src_xored);
|
||||
|
||||
if (some_size > 0x20)
|
||||
{
|
||||
return 0x12;
|
||||
}
|
||||
|
||||
for (int i = 0; i < some_size; i++)
|
||||
{
|
||||
src_xored[i] ^= src[i];
|
||||
}
|
||||
|
||||
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
var hash = sha256.ComputeHash(src_xored.ToArray());
|
||||
hash.CopyTo(src_xored_digest);
|
||||
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
{
|
||||
iv[i] ^= src_xored_digest[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
{
|
||||
if (iv[i] != 0xFF)
|
||||
{
|
||||
iv[i] += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
iv[i] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
116
PspCrypto/Security/Cryptography/HMACCommon.cs
Normal file
116
PspCrypto/Security/Cryptography/HMACCommon.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
//
|
||||
// This class provides the common functionality for HMACSHA1, HMACSHA256, HMACMD5, etc.
|
||||
// Ideally, this would be encapsulated in a common base class but the preexisting contract
|
||||
// locks these public classes into deriving directly from HMAC so we have to use encapsulation
|
||||
// and delegation to HMACCommon instead.
|
||||
//
|
||||
// This wrapper adds the ability to change the Key on the fly for compat with the desktop.
|
||||
//
|
||||
internal sealed class HMACCommon
|
||||
{
|
||||
public HMACCommon(string hashAlgorithmId, byte[] key, int blockSize) :
|
||||
this(hashAlgorithmId, (ReadOnlySpan<byte>)key, blockSize)
|
||||
{
|
||||
// If the key is smaller than the block size, the delegated ctor won't have initialized ActualKey,
|
||||
// so set it here as would ChangeKey.
|
||||
ActualKey ??= key;
|
||||
}
|
||||
|
||||
internal HMACCommon(string hashAlgorithmId, ReadOnlySpan<byte> key, int blockSize)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(hashAlgorithmId));
|
||||
Debug.Assert(blockSize > 0 || blockSize == -1);
|
||||
|
||||
_hashAlgorithmId = hashAlgorithmId;
|
||||
_blockSize = blockSize;
|
||||
|
||||
// note: will not set ActualKey if key size is smaller or equal than blockSize
|
||||
// this is to avoid extra allocation. ActualKey can still be used if key is generated.
|
||||
// Otherwise the ReadOnlySpan overload would actually be slower than byte array overload.
|
||||
ActualKey = ChangeKeyImpl(key);
|
||||
}
|
||||
|
||||
public int HashSizeInBits => _hMacProvider.HashSizeInBytes * 8;
|
||||
public int HashSizeInBytes => _hMacProvider.HashSizeInBytes;
|
||||
|
||||
public void ChangeKey(byte[] key)
|
||||
{
|
||||
ActualKey = ChangeKeyImpl(key) ?? key;
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_hMacProvider))]
|
||||
private byte[] ChangeKeyImpl(ReadOnlySpan<byte> key)
|
||||
{
|
||||
byte[] modifiedKey = null;
|
||||
|
||||
// If _blockSize is -1 the key isn't going to be extractable by the object holder,
|
||||
// so there's no point in recalculating it in managed code.
|
||||
if (key.Length > _blockSize && _blockSize > 0)
|
||||
{
|
||||
// Perform RFC 2104, section 2 key adjustment.
|
||||
modifiedKey = _hashAlgorithmId switch
|
||||
{
|
||||
"SHA224" => SHA224.HashData(key),
|
||||
_ => throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", _hashAlgorithmId)),
|
||||
};
|
||||
}
|
||||
|
||||
HashProvider oldHashProvider = _hMacProvider;
|
||||
_hMacProvider = null!;
|
||||
oldHashProvider?.Dispose(true);
|
||||
_hMacProvider = HashProviderDispenser.CreateMacProvider(_hashAlgorithmId, key);
|
||||
|
||||
return modifiedKey;
|
||||
}
|
||||
|
||||
// The actual key used for hashing. This will not be the same as the original key passed to ChangeKey() if the original key exceeded the
|
||||
// hash algorithm's block size. (See RFC 2104, section 2)
|
||||
public byte[] ActualKey { get; private set; }
|
||||
|
||||
// Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources.
|
||||
public void AppendHashData(byte[] data, int offset, int count) =>
|
||||
_hMacProvider.AppendHashData(data, offset, count);
|
||||
|
||||
public void AppendHashData(ReadOnlySpan<byte> source) =>
|
||||
_hMacProvider.AppendHashData(source);
|
||||
|
||||
// Compute the hash based on the appended data and resets the HashProvider for more hashing.
|
||||
public byte[] FinalizeHashAndReset() =>
|
||||
_hMacProvider.FinalizeHashAndReset();
|
||||
|
||||
public int FinalizeHashAndReset(Span<byte> destination) =>
|
||||
_hMacProvider.FinalizeHashAndReset(destination);
|
||||
|
||||
public bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten) =>
|
||||
_hMacProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
|
||||
|
||||
public int GetCurrentHash(Span<byte> destination) =>
|
||||
_hMacProvider.GetCurrentHash(destination);
|
||||
|
||||
public void Reset() => _hMacProvider.Reset();
|
||||
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_hMacProvider?.Dispose(true);
|
||||
_hMacProvider = null!;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly string _hashAlgorithmId;
|
||||
private HashProvider _hMacProvider;
|
||||
private readonly int _blockSize;
|
||||
}
|
||||
}
|
125
PspCrypto/Security/Cryptography/HMACManagedHashProvider.cs
Normal file
125
PspCrypto/Security/Cryptography/HMACManagedHashProvider.cs
Normal file
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
internal sealed class HMACManagedHashProvider : HashProvider
|
||||
{
|
||||
private bool _hashing;
|
||||
private readonly int _blockSizeValue;
|
||||
private readonly int _hashSizeValue;
|
||||
|
||||
private readonly byte[] _key;
|
||||
private readonly HashProvider _hash1;
|
||||
private readonly HashProvider _hash2;
|
||||
|
||||
public HMACManagedHashProvider(string hashAlgorithmId, ReadOnlySpan<byte> key)
|
||||
{
|
||||
_hash1 = HashProviderDispenser.CreateHashProvider(hashAlgorithmId);
|
||||
_hash2 = HashProviderDispenser.CreateHashProvider(hashAlgorithmId);
|
||||
|
||||
_blockSizeValue = 64;
|
||||
_hashSizeValue = 224 / 8;
|
||||
|
||||
_key = InitializeKey(key);
|
||||
}
|
||||
|
||||
private byte[] InitializeKey(ReadOnlySpan<byte> key)
|
||||
{
|
||||
if (key.Length > _blockSizeValue)
|
||||
{
|
||||
byte[] result = new byte[_hashSizeValue];
|
||||
_hash1.AppendHashData(key);
|
||||
int written = _hash1.FinalizeHashAndReset(result);
|
||||
Debug.Assert(written == result.Length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return key.ToArray();
|
||||
}
|
||||
|
||||
public override void AppendHashData(ReadOnlySpan<byte> data)
|
||||
{
|
||||
if (!_hashing)
|
||||
{
|
||||
AppendInnerBuffer();
|
||||
_hashing = true;
|
||||
}
|
||||
|
||||
_hash1.AppendHashData(data);
|
||||
}
|
||||
|
||||
public override int FinalizeHashAndReset(Span<byte> destination)
|
||||
{
|
||||
int written = GetCurrentHash(destination);
|
||||
Reset();
|
||||
return written;
|
||||
}
|
||||
|
||||
public override int GetCurrentHash(Span<byte> destination)
|
||||
{
|
||||
if (!_hashing)
|
||||
{
|
||||
AppendInnerBuffer();
|
||||
_hashing = true;
|
||||
}
|
||||
|
||||
// finalize the original hash
|
||||
Span<byte> hashValue1 = stackalloc byte[_hashSizeValue];
|
||||
int hash1Written = _hash1.GetCurrentHash(hashValue1);
|
||||
Debug.Assert(hash1Written == hashValue1.Length);
|
||||
|
||||
// write the outer array
|
||||
AppendOuterBuffer();
|
||||
// write the inner hash and finalize the hash
|
||||
_hash2.AppendHashData(hashValue1);
|
||||
return _hash2.FinalizeHashAndReset(destination);
|
||||
}
|
||||
|
||||
private void AppendInnerBuffer() => AppendPaddingBuffer(0x36, _hash1);
|
||||
private void AppendOuterBuffer() => AppendPaddingBuffer(0x5C, _hash2);
|
||||
|
||||
private void AppendPaddingBuffer(byte paddingConstant, HashProvider hash)
|
||||
{
|
||||
Span<byte> paddingBuffer = stackalloc byte[_blockSizeValue];
|
||||
paddingBuffer.Fill(paddingConstant);
|
||||
|
||||
for (int i = 0; i < _key.Length; i++)
|
||||
{
|
||||
paddingBuffer[i] ^= _key[i];
|
||||
}
|
||||
|
||||
hash.AppendHashData(paddingBuffer);
|
||||
CryptographicOperations.ZeroMemory(paddingBuffer);
|
||||
}
|
||||
|
||||
public override int HashSizeInBytes => _hashSizeValue;
|
||||
|
||||
public override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_hash1.Dispose();
|
||||
_hash2.Dispose();
|
||||
|
||||
CryptographicOperations.ZeroMemory(_key);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
if (_hashing)
|
||||
{
|
||||
_hash1.Reset();
|
||||
_hash2.Reset();
|
||||
_hashing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
156
PspCrypto/Security/Cryptography/HMACSHA224.cs
Normal file
156
PspCrypto/Security/Cryptography/HMACSHA224.cs
Normal file
|
@ -0,0 +1,156 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
public class HMACSHA224 : HMAC
|
||||
{
|
||||
/// <summary>
|
||||
/// The hash size produced by the HMAC SHA224 algorithm, in bits.
|
||||
/// </summary>
|
||||
public const int HashSizeInBits = 224;
|
||||
|
||||
/// <summary>
|
||||
/// The hash size produced by the HMAC SHA24 algorithm, in bytes.
|
||||
/// </summary>
|
||||
public const int HashSizeInBytes = HashSizeInBits / 8;
|
||||
|
||||
public HMACSHA224()
|
||||
: this(RandomNumberGenerator.GetBytes(BlockSize))
|
||||
{ }
|
||||
|
||||
public HMACSHA224(byte[] key)
|
||||
{
|
||||
if (key is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
HashName = HashAlgorithmNames.SHA224;
|
||||
_hMacCommon = new HMACCommon(HashAlgorithmNames.SHA224, key, BlockSize);
|
||||
base.Key = _hMacCommon.ActualKey!;
|
||||
// this not really needed as it'll initialize BlockSizeValue with same value it has which is 64.
|
||||
// we just want to be explicit in all HMAC extended classes
|
||||
BlockSizeValue = BlockSize;
|
||||
HashSizeValue = _hMacCommon.HashSizeInBits;
|
||||
Debug.Assert(HashSizeValue == HashSizeInBits);
|
||||
}
|
||||
|
||||
public override byte[] Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Key;
|
||||
}
|
||||
set
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
_hMacCommon.ChangeKey(value);
|
||||
base.Key = _hMacCommon.ActualKey!;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HashCore(byte[] rgb, int ib, int cb) =>
|
||||
_hMacCommon.AppendHashData(rgb, ib, cb);
|
||||
|
||||
protected override void HashCore(ReadOnlySpan<byte> source) =>
|
||||
_hMacCommon.AppendHashData(source);
|
||||
|
||||
protected override byte[] HashFinal() =>
|
||||
_hMacCommon.FinalizeHashAndReset();
|
||||
|
||||
protected override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
|
||||
_hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
|
||||
|
||||
public override void Initialize() => _hMacCommon.Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Computes the HMAC of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="key">The HMAC key.</param>
|
||||
/// <param name="source">The data to HMAC.</param>
|
||||
/// <returns>The HMAC of the data.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="key" /> or <paramref name="source" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static byte[] HashData(byte[] key, byte[] source)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
|
||||
return HashData(new ReadOnlySpan<byte>(key), new ReadOnlySpan<byte>(source));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the HMAC of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="key">The HMAC key.</param>
|
||||
/// <param name="source">The data to HMAC.</param>
|
||||
/// <returns>The HMAC of the data.</returns>
|
||||
public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source)
|
||||
{
|
||||
byte[] buffer = new byte[HashSizeInBytes];
|
||||
|
||||
int written = HashData(key, source, buffer.AsSpan());
|
||||
Debug.Assert(written == buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the HMAC of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="key">The HMAC key.</param>
|
||||
/// <param name="source">The data to HMAC.</param>
|
||||
/// <param name="destination">The buffer to receive the HMAC value.</param>
|
||||
/// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
|
||||
/// size. The SHA224 algorithm always produces a 224-bit HMAC, or 28 bytes.
|
||||
/// </exception>
|
||||
public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
|
||||
{
|
||||
if (!TryHashData(key, source, destination, out int bytesWritten))
|
||||
{
|
||||
throw new ArgumentException("Destination is too short.", nameof(destination));
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to compute the HMAC of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="key">The HMAC key.</param>
|
||||
/// <param name="source">The data to HMAC.</param>
|
||||
/// <param name="destination">The buffer to receive the HMAC value.</param>
|
||||
/// <param name="bytesWritten">
|
||||
/// When this method returns, the total number of bytes written into <paramref name="destination"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
|
||||
/// calculated hash, <see langword="true"/> otherwise.
|
||||
/// </returns>
|
||||
public static bool TryHashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
|
||||
{
|
||||
if (destination.Length < HashSizeInBytes)
|
||||
{
|
||||
bytesWritten = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA224, key, source, destination);
|
||||
Debug.Assert(bytesWritten == HashSizeInBytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private HMACCommon _hMacCommon;
|
||||
private const int BlockSize = 64;
|
||||
}
|
||||
}
|
13
PspCrypto/Security/Cryptography/HashAlgorithmNames.cs
Normal file
13
PspCrypto/Security/Cryptography/HashAlgorithmNames.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
internal static class HashAlgorithmNames
|
||||
{
|
||||
public const string SHA224 = "SHA224";
|
||||
}
|
||||
}
|
79
PspCrypto/Security/Cryptography/HashProvider.cs
Normal file
79
PspCrypto/Security/Cryptography/HashProvider.cs
Normal file
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
//
|
||||
// This abstract class represents a reusable hash object and can wrap a CNG or WinRT hash object.
|
||||
//
|
||||
internal abstract class HashProvider : IDisposable
|
||||
{
|
||||
// Adds new data to be hashed. This can be called repeatedly in order to hash data from noncontiguous sources.
|
||||
public void AppendHashData(byte[] data, int offset, int count)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(data);
|
||||
|
||||
// AppendHashData can be called via exposed APIs (e.g. a type that derives from
|
||||
// HMACSHA1 and calls HashCore) and could be passed bad data from there. It could
|
||||
// also receive a bad count from HashAlgorithm reading from a Stream that returns
|
||||
// an invalid number of bytes read. Since our implementations of AppendHashDataCore
|
||||
// end up using unsafe code, we want to be sure the arguments are valid.
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(offset), "Non-negative number required.");
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(count), "Non-negative number required.");
|
||||
if (data.Length - offset < count)
|
||||
throw new ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");
|
||||
|
||||
AppendHashData(new ReadOnlySpan<byte>(data, offset, count));
|
||||
}
|
||||
|
||||
public abstract void AppendHashData(ReadOnlySpan<byte> data);
|
||||
|
||||
// Compute the hash based on the appended data and resets the HashProvider for more hashing.
|
||||
public abstract int FinalizeHashAndReset(Span<byte> destination);
|
||||
|
||||
public abstract int GetCurrentHash(Span<byte> destination);
|
||||
|
||||
public byte[] FinalizeHashAndReset()
|
||||
{
|
||||
byte[] ret = new byte[HashSizeInBytes];
|
||||
|
||||
int written = FinalizeHashAndReset(ret);
|
||||
Debug.Assert(written == HashSizeInBytes);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public bool TryFinalizeHashAndReset(Span<byte> destination, out int bytesWritten)
|
||||
{
|
||||
if (destination.Length < HashSizeInBytes)
|
||||
{
|
||||
bytesWritten = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten = FinalizeHashAndReset(destination);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the length of the byte array returned by FinalizeHashAndReset.
|
||||
public abstract int HashSizeInBytes { get; }
|
||||
|
||||
// Releases any native resources and keys used by the HashProvider.
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Releases any native resources and keys used by the HashProvider.
|
||||
public abstract void Dispose(bool disposing);
|
||||
|
||||
public abstract void Reset();
|
||||
}
|
||||
}
|
53
PspCrypto/Security/Cryptography/HashProviderDispenser.cs
Normal file
53
PspCrypto/Security/Cryptography/HashProviderDispenser.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
internal class HashProviderDispenser
|
||||
{
|
||||
public static HashProvider CreateHashProvider(string hashAlgorithmId)
|
||||
{
|
||||
switch (hashAlgorithmId)
|
||||
{
|
||||
case HashAlgorithmNames.SHA224:
|
||||
return new SHAManagedHashProvider(hashAlgorithmId);
|
||||
}
|
||||
throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", hashAlgorithmId));
|
||||
}
|
||||
|
||||
public static class OneShotHashProvider
|
||||
{
|
||||
public static unsafe int MacData(
|
||||
string hashAlgorithmId,
|
||||
ReadOnlySpan<byte> key,
|
||||
ReadOnlySpan<byte> source,
|
||||
Span<byte> destination)
|
||||
{
|
||||
using HashProvider provider = CreateMacProvider(hashAlgorithmId, key);
|
||||
provider.AppendHashData(source);
|
||||
return provider.FinalizeHashAndReset(destination);
|
||||
}
|
||||
|
||||
public static int HashData(string hashAlgorithmId, ReadOnlySpan<byte> source, Span<byte> destination)
|
||||
{
|
||||
HashProvider provider = CreateHashProvider(hashAlgorithmId);
|
||||
provider.AppendHashData(source);
|
||||
return provider.FinalizeHashAndReset(destination);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpan<byte> key)
|
||||
{
|
||||
switch (hashAlgorithmId)
|
||||
{
|
||||
case HashAlgorithmNames.SHA224:
|
||||
return new HMACManagedHashProvider(hashAlgorithmId, key);
|
||||
}
|
||||
throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", hashAlgorithmId));
|
||||
}
|
||||
}
|
||||
}
|
146
PspCrypto/Security/Cryptography/SHA224.cs
Normal file
146
PspCrypto/Security/Cryptography/SHA224.cs
Normal file
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
public abstract class SHA224 : HashAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// The hash size produced by the SHA224 algorithm, in bits.
|
||||
/// </summary>
|
||||
public const int HashSizeInBits = 224;
|
||||
|
||||
/// <summary>
|
||||
/// The hash size produced by the SHA224 algorithm, in bytes.
|
||||
/// </summary>
|
||||
public const int HashSizeInBytes = HashSizeInBits / 8;
|
||||
|
||||
public SHA224()
|
||||
{
|
||||
// SHA-224 hash length are 224 bits long
|
||||
HashSizeValue = HashSizeInBits;
|
||||
}
|
||||
|
||||
public static new SHA224 Create() => new Implementation();
|
||||
|
||||
public new static SHA224 Create(string hashName)
|
||||
{
|
||||
var o = (SHA224)CryptoConfig.CreateFromName(hashName);
|
||||
// in case machine.config isn't configured to use any SHA224 implementation
|
||||
if (o == null)
|
||||
{
|
||||
o = new Implementation();
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the hash of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to hash.</param>
|
||||
/// <returns>The hash of the data.</returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="source" /> is <see langword="null" />.
|
||||
/// </exception>
|
||||
public static byte[] HashData(byte[] source)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
|
||||
return HashData(new ReadOnlySpan<byte>(source));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the hash of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to hash.</param>
|
||||
/// <returns>The hash of the data.</returns>
|
||||
public static byte[] HashData(ReadOnlySpan<byte> source)
|
||||
{
|
||||
byte[] buffer = GC.AllocateUninitializedArray<byte>(HashSizeInBytes);
|
||||
|
||||
int written = HashData(source, buffer.AsSpan());
|
||||
Debug.Assert(written == buffer.Length);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the hash of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to hash.</param>
|
||||
/// <param name="destination">The buffer to receive the hash value.</param>
|
||||
/// <returns>The total number of bytes written to <paramref name="destination" />.</returns>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The buffer in <paramref name="destination"/> is too small to hold the calculated hash
|
||||
/// size. The SHA224 algorithm always produces a 224-bit hash, or 28 bytes.
|
||||
/// </exception>
|
||||
public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination)
|
||||
{
|
||||
if (!TryHashData(source, destination, out int bytesWritten))
|
||||
throw new ArgumentException("Destination is too short.", nameof(destination));
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to compute the hash of data using the SHA224 algorithm.
|
||||
/// </summary>
|
||||
/// <param name="source">The data to hash.</param>
|
||||
/// <param name="destination">The buffer to receive the hash value.</param>
|
||||
/// <param name="bytesWritten">
|
||||
/// When this method returns, the total number of bytes written into <paramref name="destination"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="false"/> if <paramref name="destination"/> is too small to hold the
|
||||
/// calculated hash, <see langword="true"/> otherwise.
|
||||
/// </returns>
|
||||
public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
|
||||
{
|
||||
if (destination.Length < HashSizeInBytes)
|
||||
{
|
||||
bytesWritten = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesWritten = HashProviderDispenser.OneShotHashProvider.HashData(HashAlgorithmNames.SHA224, source, destination);
|
||||
Debug.Assert(bytesWritten == HashSizeInBytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private sealed class Implementation : SHA224
|
||||
{
|
||||
private readonly HashProvider _hashProvider;
|
||||
|
||||
public Implementation()
|
||||
{
|
||||
_hashProvider = HashProviderDispenser.CreateHashProvider(HashAlgorithmNames.SHA224);
|
||||
HashSizeValue = _hashProvider.HashSizeInBytes * 8;
|
||||
}
|
||||
|
||||
protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
|
||||
_hashProvider.AppendHashData(array, ibStart, cbSize);
|
||||
|
||||
protected sealed override void HashCore(ReadOnlySpan<byte> source) =>
|
||||
_hashProvider.AppendHashData(source);
|
||||
|
||||
protected sealed override byte[] HashFinal() =>
|
||||
_hashProvider.FinalizeHashAndReset();
|
||||
|
||||
protected sealed override bool TryHashFinal(Span<byte> destination, out int bytesWritten) =>
|
||||
_hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
|
||||
|
||||
public sealed override void Initialize() => _hashProvider.Reset();
|
||||
|
||||
protected sealed override void Dispose(bool disposing)
|
||||
{
|
||||
_hashProvider.Dispose(disposing);
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
376
PspCrypto/Security/Cryptography/SHAManagedHashProvider.cs
Normal file
376
PspCrypto/Security/Cryptography/SHAManagedHashProvider.cs
Normal file
|
@ -0,0 +1,376 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using static System.Numerics.BitOperations;
|
||||
|
||||
namespace PspCrypto.Security.Cryptography
|
||||
{
|
||||
internal sealed class SHAManagedHashProvider : HashProvider
|
||||
{
|
||||
private int hashSizeInBytes;
|
||||
private SHAManagedImplementationBase impl;
|
||||
private MemoryStream buffer;
|
||||
|
||||
public SHAManagedHashProvider(string hashAlgorithmId)
|
||||
{
|
||||
switch (hashAlgorithmId)
|
||||
{
|
||||
case HashAlgorithmNames.SHA224:
|
||||
impl = new SHA224ManagedImplementation();
|
||||
hashSizeInBytes = 28;
|
||||
break;
|
||||
default:
|
||||
throw new CryptographicException(string.Format("'{0}' is not a known hash algorithm.", hashAlgorithmId));
|
||||
}
|
||||
}
|
||||
|
||||
public override void AppendHashData(ReadOnlySpan<byte> data)
|
||||
{
|
||||
buffer ??= new MemoryStream(1000);
|
||||
|
||||
buffer.Write(data);
|
||||
}
|
||||
|
||||
public override int FinalizeHashAndReset(Span<byte> destination)
|
||||
{
|
||||
GetCurrentHash(destination);
|
||||
buffer = null;
|
||||
|
||||
return hashSizeInBytes;
|
||||
}
|
||||
|
||||
public override int GetCurrentHash(Span<byte> destination)
|
||||
{
|
||||
Debug.Assert(destination.Length >= hashSizeInBytes);
|
||||
|
||||
impl.Initialize();
|
||||
if (buffer != null)
|
||||
{
|
||||
impl.HashCore(buffer.GetBuffer(), 0, (int)buffer.Length);
|
||||
}
|
||||
impl.HashFinal().CopyTo(destination);
|
||||
|
||||
return hashSizeInBytes;
|
||||
}
|
||||
|
||||
public override int HashSizeInBytes => hashSizeInBytes;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
buffer = null;
|
||||
impl.Initialize();
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
private abstract class SHAManagedImplementationBase
|
||||
{
|
||||
public abstract void Initialize();
|
||||
public abstract void HashCore(byte[] partIn, int ibStart, int cbSize);
|
||||
public abstract byte[] HashFinal();
|
||||
}
|
||||
|
||||
private sealed class SHA224ManagedImplementation : SHAManagedImplementationBase
|
||||
{
|
||||
private byte[] _buffer;
|
||||
private long _count; // Number of bytes in the hashed message
|
||||
private uint[] _stateSHA224;
|
||||
private uint[] _W;
|
||||
|
||||
public SHA224ManagedImplementation()
|
||||
{
|
||||
_stateSHA224 = new uint[8];
|
||||
_buffer = new byte[64];
|
||||
_W = new uint[64];
|
||||
|
||||
InitializeState();
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
InitializeState();
|
||||
|
||||
// Zeroize potentially sensitive information.
|
||||
Array.Clear(_buffer, 0, _buffer.Length);
|
||||
Array.Clear(_W, 0, _W.Length);
|
||||
}
|
||||
|
||||
private void InitializeState()
|
||||
{
|
||||
_count = 0;
|
||||
|
||||
_stateSHA224[0] = 0xc1059ed8;
|
||||
_stateSHA224[1] = 0x367cd507;
|
||||
_stateSHA224[2] = 0x3070dd17;
|
||||
_stateSHA224[3] = 0xf70e5939;
|
||||
_stateSHA224[4] = 0xffc00b31;
|
||||
_stateSHA224[5] = 0x68581511;
|
||||
_stateSHA224[6] = 0x64f98fa7;
|
||||
_stateSHA224[7] = 0xbefa4fa4;
|
||||
}
|
||||
|
||||
/* SHA256 block update operation. Continues an SHA message-digest
|
||||
operation, processing another message block, and updating the
|
||||
context.
|
||||
*/
|
||||
public override unsafe void HashCore(byte[] partIn, int ibStart, int cbSize)
|
||||
{
|
||||
int bufferLen;
|
||||
int partInLen = cbSize;
|
||||
int partInBase = ibStart;
|
||||
|
||||
/* Compute length of buffer */
|
||||
bufferLen = (int)(_count & 0x3f);
|
||||
|
||||
/* Update number of bytes */
|
||||
_count += partInLen;
|
||||
|
||||
fixed (uint* stateSHA256 = _stateSHA224)
|
||||
{
|
||||
fixed (byte* buffer = _buffer)
|
||||
{
|
||||
fixed (uint* expandedBuffer = _W)
|
||||
{
|
||||
if (bufferLen > 0 && bufferLen + partInLen >= 64)
|
||||
{
|
||||
Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, 64 - bufferLen);
|
||||
partInBase += 64 - bufferLen;
|
||||
partInLen -= 64 - bufferLen;
|
||||
SHATransform(expandedBuffer, stateSHA256, buffer);
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/* Copy input to temporary buffer and hash */
|
||||
while (partInLen >= 64)
|
||||
{
|
||||
Buffer.BlockCopy(partIn, partInBase, _buffer, 0, 64);
|
||||
partInBase += 64;
|
||||
partInLen -= 64;
|
||||
SHATransform(expandedBuffer, stateSHA256, buffer);
|
||||
}
|
||||
|
||||
if (partInLen > 0)
|
||||
{
|
||||
Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SHA256 finalization. Ends an SHA256 message-digest operation, writing
|
||||
the message digest.
|
||||
*/
|
||||
public override byte[] HashFinal()
|
||||
{
|
||||
byte[] pad;
|
||||
int padLen;
|
||||
long bitCount;
|
||||
byte[] hash = new byte[28]; // HashSizeValue = 224
|
||||
|
||||
/* Compute padding: 80 00 00 ... 00 00 <bit count>
|
||||
*/
|
||||
|
||||
padLen = 64 - (int)(_count & 0x3f);
|
||||
if (padLen <= 8)
|
||||
padLen += 64;
|
||||
|
||||
pad = new byte[padLen];
|
||||
pad[0] = 0x80;
|
||||
|
||||
// Convert count to bit count
|
||||
bitCount = _count * 8;
|
||||
|
||||
pad[padLen - 8] = (byte)(bitCount >> 56 & 0xff);
|
||||
pad[padLen - 7] = (byte)(bitCount >> 48 & 0xff);
|
||||
pad[padLen - 6] = (byte)(bitCount >> 40 & 0xff);
|
||||
pad[padLen - 5] = (byte)(bitCount >> 32 & 0xff);
|
||||
pad[padLen - 4] = (byte)(bitCount >> 24 & 0xff);
|
||||
pad[padLen - 3] = (byte)(bitCount >> 16 & 0xff);
|
||||
pad[padLen - 2] = (byte)(bitCount >> 8 & 0xff);
|
||||
pad[padLen - 1] = (byte)(bitCount >> 0 & 0xff);
|
||||
|
||||
/* Digest padding */
|
||||
HashCore(pad, 0, pad.Length);
|
||||
|
||||
/* Store digest */
|
||||
SHAUtils.DWORDToBigEndian(hash, _stateSHA224, 7);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
private static readonly uint[] _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
|
||||
};
|
||||
|
||||
private static unsafe void SHATransform(uint* expandedBuffer, uint* state, byte* block)
|
||||
{
|
||||
uint a, b, c, d, e, f, h, g;
|
||||
uint aa, bb, cc, dd, ee, ff, hh, gg;
|
||||
uint T1;
|
||||
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
|
||||
// fill in the first 16 bytes of W.
|
||||
SHAUtils.DWORDFromBigEndian(expandedBuffer, 16, block);
|
||||
SHA256Expand(expandedBuffer);
|
||||
|
||||
/* Apply the SHA256 compression function */
|
||||
// We are trying to be smart here and avoid as many copies as we can
|
||||
// The perf gain with this method over the straightforward modify and shift
|
||||
// forward is >= 20%, so it's worth the pain
|
||||
for (int j = 0; j < 64;)
|
||||
{
|
||||
T1 = h + Sigma_1(e) + Ch(e, f, g) + _K[j] + expandedBuffer[j];
|
||||
ee = d + T1;
|
||||
aa = T1 + Sigma_0(a) + Maj(a, b, c);
|
||||
j++;
|
||||
|
||||
T1 = g + Sigma_1(ee) + Ch(ee, e, f) + _K[j] + expandedBuffer[j];
|
||||
ff = c + T1;
|
||||
bb = T1 + Sigma_0(aa) + Maj(aa, a, b);
|
||||
j++;
|
||||
|
||||
T1 = f + Sigma_1(ff) + Ch(ff, ee, e) + _K[j] + expandedBuffer[j];
|
||||
gg = b + T1;
|
||||
cc = T1 + Sigma_0(bb) + Maj(bb, aa, a);
|
||||
j++;
|
||||
|
||||
T1 = e + Sigma_1(gg) + Ch(gg, ff, ee) + _K[j] + expandedBuffer[j];
|
||||
hh = a + T1;
|
||||
dd = T1 + Sigma_0(cc) + Maj(cc, bb, aa);
|
||||
j++;
|
||||
|
||||
T1 = ee + Sigma_1(hh) + Ch(hh, gg, ff) + _K[j] + expandedBuffer[j];
|
||||
h = aa + T1;
|
||||
d = T1 + Sigma_0(dd) + Maj(dd, cc, bb);
|
||||
j++;
|
||||
|
||||
T1 = ff + Sigma_1(h) + Ch(h, hh, gg) + _K[j] + expandedBuffer[j];
|
||||
g = bb + T1;
|
||||
c = T1 + Sigma_0(d) + Maj(d, dd, cc);
|
||||
j++;
|
||||
|
||||
T1 = gg + Sigma_1(g) + Ch(g, h, hh) + _K[j] + expandedBuffer[j];
|
||||
f = cc + T1;
|
||||
b = T1 + Sigma_0(c) + Maj(c, d, dd);
|
||||
j++;
|
||||
|
||||
T1 = hh + Sigma_1(f) + Ch(f, g, h) + _K[j] + expandedBuffer[j];
|
||||
e = dd + T1;
|
||||
a = T1 + Sigma_0(b) + Maj(b, c, d);
|
||||
j++;
|
||||
}
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
}
|
||||
|
||||
private static uint Ch(uint x, uint y, uint z)
|
||||
{
|
||||
return x & y ^ (x ^ 0xffffffff) & z;
|
||||
}
|
||||
|
||||
private static uint Maj(uint x, uint y, uint z)
|
||||
{
|
||||
return x & y ^ x & z ^ y & z;
|
||||
}
|
||||
|
||||
private static uint sigma_0(uint x)
|
||||
{
|
||||
return RotateRight(x, 7) ^ RotateRight(x, 18) ^ x >> 3;
|
||||
}
|
||||
|
||||
private static uint sigma_1(uint x)
|
||||
{
|
||||
return RotateRight(x, 17) ^ RotateRight(x, 19) ^ x >> 10;
|
||||
}
|
||||
|
||||
private static uint Sigma_0(uint x)
|
||||
{
|
||||
return RotateRight(x, 2) ^ RotateRight(x, 13) ^ RotateRight(x, 22);
|
||||
}
|
||||
|
||||
private static uint Sigma_1(uint x)
|
||||
{
|
||||
return RotateRight(x, 6) ^ RotateRight(x, 11) ^ RotateRight(x, 25);
|
||||
}
|
||||
|
||||
/* This function creates W_16,...,W_63 according to the formula
|
||||
W_j <- sigma_1(W_{j-2}) + W_{j-7} + sigma_0(W_{j-15}) + W_{j-16};
|
||||
*/
|
||||
private static unsafe void SHA256Expand(uint* x)
|
||||
{
|
||||
for (int i = 16; i < 64; i++)
|
||||
{
|
||||
x[i] = sigma_1(x[i - 2]) + x[i - 7] + sigma_0(x[i - 15]) + x[i - 16];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SHAUtils
|
||||
{
|
||||
// digits == number of DWORDs
|
||||
public static unsafe void DWORDFromBigEndian(uint* x, int digits, byte* block)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0, j = 0; i < digits; i++, j += 4)
|
||||
x[i] = (uint)(block[j] << 24 | block[j + 1] << 16 | block[j + 2] << 8 | block[j + 3]);
|
||||
}
|
||||
|
||||
// encodes x (DWORD) into block (unsigned char), most significant byte first.
|
||||
// digits == number of DWORDs
|
||||
public static void DWORDToBigEndian(byte[] block, uint[] x, int digits)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0, j = 0; i < digits; i++, j += 4)
|
||||
{
|
||||
block[j] = (byte)(x[i] >> 24 & 0xff);
|
||||
block[j + 1] = (byte)(x[i] >> 16 & 0xff);
|
||||
block[j + 2] = (byte)(x[i] >> 8 & 0xff);
|
||||
block[j + 3] = (byte)(x[i] & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
264
PspCrypto/Structs.cs
Normal file
264
PspCrypto/Structs.cs
Normal file
|
@ -0,0 +1,264 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public enum SceExecFileDecryptMode : byte
|
||||
{
|
||||
/* Not an executable. */
|
||||
DECRYPT_MODE_NO_EXEC = 0,
|
||||
/* 1.50 Kernel module. */
|
||||
DECRYPT_MODE_BOGUS_MODULE = 1,
|
||||
DECRYPT_MODE_KERNEL_MODULE = 2,
|
||||
DECRYPT_MODE_VSH_MODULE = 3,
|
||||
DECRYPT_MODE_USER_MODULE = 4,
|
||||
DECRYPT_MODE_UMD_GAME_EXEC = 9,
|
||||
DECRYPT_MODE_GAMESHARING_EXEC = 10,
|
||||
/* USB/WLAN module. */
|
||||
DECRYPT_MODE_UNKNOWN_11 = 11,
|
||||
DECRYPT_MODE_MS_UPDATER = 12,
|
||||
DECRYPT_MODE_DEMO_EXEC = 13,
|
||||
DECRYPT_MODE_APP_MODULE = 14,
|
||||
DECRYPT_MODE_UNKNOWN_18 = 18,
|
||||
DECRYPT_MODE_UNKNOWN_19 = 19,
|
||||
DECRYPT_MODE_POPS_EXEC = 20,
|
||||
/* MS module. */
|
||||
DECRYPT_MODE_UNKNOWN_21 = 21,
|
||||
/* APP module. */
|
||||
DECRYPT_MODE_UNKNOWN_22 = 22,
|
||||
/* USER module. */
|
||||
DECRYPT_MODE_UNKNOWN_23 = 23,
|
||||
/* USER module. */
|
||||
DECRYPT_MODE_UNKNOWN_25 = 25,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public unsafe struct PSPHeader2
|
||||
{
|
||||
public Span<byte> RawHdr
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (uint* ptr = &magic)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
public uint magic;
|
||||
public ushort modAttribute;
|
||||
public ushort compAttribute;
|
||||
public byte moduleVerLo;
|
||||
public byte moduleVerHi;
|
||||
private fixed byte _modName[27];
|
||||
|
||||
public Span<byte> modName
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _modName)
|
||||
{
|
||||
return new Span<byte>(ptr, 27);
|
||||
}
|
||||
}
|
||||
}
|
||||
public byte terminal;
|
||||
public byte modVersion;
|
||||
public byte nSegments;
|
||||
public int elfSize;
|
||||
public int pspSize;
|
||||
public uint bootEntry;
|
||||
public int modInfoOffset;
|
||||
public uint bssSize;
|
||||
private fixed ushort _segAlign[4];
|
||||
|
||||
public Span<ushort> segAlign
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (ushort* ptr = _segAlign)
|
||||
{
|
||||
return new Span<ushort>(ptr, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed uint _segAddress[4];
|
||||
|
||||
public Span<uint> segAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (uint* ptr = _segAddress)
|
||||
{
|
||||
return new Span<uint>(ptr, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed uint _segSize[4];
|
||||
|
||||
public Span<uint> segSize
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (uint* ptr = _segSize)
|
||||
{
|
||||
return new Span<uint>(ptr, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
public fixed uint reserved[5];
|
||||
public uint devkitVersion;
|
||||
public SceExecFileDecryptMode decryptMode;
|
||||
public byte padding;
|
||||
public ushort overlapSize;
|
||||
private fixed byte _aesKey[16];
|
||||
public Span<byte> aesKey
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _aesKey)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Span<byte> keyData
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _aesKey)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Span<byte> keyData50
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _aesKey)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fixed byte _cmacKey[16];
|
||||
public Span<byte> cmacKey
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _cmacKey)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _cmacHeaderHash[16];
|
||||
public Span<byte> cmacHeaderHash
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _cmacHeaderHash)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Span<byte> sizeInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (int* ptr = &dataSize)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
public int dataSize;
|
||||
public int dataOffset;
|
||||
public uint unk184;
|
||||
public uint unk188;
|
||||
private fixed byte _cmacDataHash[16];
|
||||
|
||||
public Span<byte> cmacDataHash
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _cmacDataHash)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Span<byte> CheckData
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (uint* ptr = &tag)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
public uint tag;
|
||||
private fixed byte _sCheck[0x58];
|
||||
|
||||
public Span<byte> sCheck
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _sCheck)
|
||||
{
|
||||
return new Span<byte>(ptr, 0x58);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _sha1Hash[20];
|
||||
|
||||
public Span<byte> sha1Hash
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _sha1Hash)
|
||||
{
|
||||
return new Span<byte>(ptr, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
private fixed byte _keyData4[16];
|
||||
|
||||
public Span<byte> keyData4
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* ptr = _keyData4)
|
||||
{
|
||||
return new Span<byte>(ptr, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct PbpHeader
|
||||
{
|
||||
public int Sig;
|
||||
public int Version;
|
||||
public int ParamOff;
|
||||
public int Icon0Off;
|
||||
public int Icon1Off;
|
||||
public int Pic0Off;
|
||||
public int Pic1Off;
|
||||
public int Snd0Off;
|
||||
public int DataPspOff;
|
||||
public int DataPsarOff;
|
||||
}
|
||||
}
|
34
PspCrypto/Utils.cs
Normal file
34
PspCrypto/Utils.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PspCrypto
|
||||
{
|
||||
public static class Utils
|
||||
{
|
||||
public static bool IsEmpty(Span<byte> buf, int buf_size)
|
||||
{
|
||||
if (buf != null && buf.Length >= buf_size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < buf_size; i++)
|
||||
{
|
||||
if (buf[i] != 0) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void BuildDrmBBMacFinal2(Span<byte> mac)
|
||||
{
|
||||
Span<byte> checksum = new byte[20 + 0x10];
|
||||
ref var aesHdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(checksum);
|
||||
aesHdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
|
||||
aesHdr.keyseed = 0x63;
|
||||
aesHdr.data_size = 0x10;
|
||||
mac.CopyTo(checksum.Slice(20));
|
||||
KIRKEngine.sceUtilsBufferCopyWithRange(checksum, 0x10, checksum, 0x10,
|
||||
KIRKEngine.KIRK_CMD_ENCRYPT_IV_0);
|
||||
checksum.Slice(20, 0x10).CopyTo(mac);
|
||||
}
|
||||
}
|
||||
}
|
BIN
PspCrypto/__sce_discinfo
Normal file
BIN
PspCrypto/__sce_discinfo
Normal file
Binary file not shown.
52
Vita/ContentManager/Account.cs
Normal file
52
Vita/ContentManager/Account.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Vita.ContentManager
|
||||
{
|
||||
public class Account
|
||||
{
|
||||
public Account(UInt64 accountId)
|
||||
{
|
||||
this.accountId = accountId;
|
||||
}
|
||||
private UInt64 accountId;
|
||||
public bool Devkit;
|
||||
|
||||
public byte[] AccountId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Devkit) return new byte[8];
|
||||
return BitConverter.GetBytes(accountId);
|
||||
}
|
||||
}
|
||||
public string AccountIdStr
|
||||
{
|
||||
get
|
||||
{
|
||||
return BitConverter.ToString(AccountId).Replace("-", "").ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
public string CmaKeyStr
|
||||
{
|
||||
get
|
||||
{
|
||||
return KeyGenerator.GenerateKeyStr(AccountIdStr);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] CmaKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return KeyGenerator.GenerateKey(AccountId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace KeyDerivation
|
||||
namespace Vita.ContentManager
|
||||
{
|
||||
class CmaKeys
|
||||
public class KeyGenerator
|
||||
{
|
||||
static Byte[] Passphrase = Encoding.ASCII.GetBytes("Sri Jayewardenepura Kotte");
|
||||
static Byte[] Key = { 0xA9, 0xFA, 0x5A, 0x62, 0x79, 0x9F, 0xCC, 0x4C, 0x72, 0x6B, 0x4E, 0x2C, 0xE3, 0x50, 0x6D, 0x38 };
|
||||
|
@ -19,7 +19,7 @@ namespace KeyDerivation
|
|||
byte[] AidBytes = BitConverter.GetBytes(longlong);
|
||||
Array.Reverse(AidBytes);
|
||||
|
||||
byte[] DerivedKey = CmaKeys.GenerateKey(AidBytes);
|
||||
byte[] DerivedKey = GenerateKey(AidBytes);
|
||||
|
||||
|
||||
return BitConverter.ToString(DerivedKey).Replace("-", "");
|
||||
|
@ -46,8 +46,7 @@ namespace KeyDerivation
|
|||
return DerviedKey;
|
||||
}
|
||||
|
||||
private static byte[] Decrypt(byte[] cipherData,
|
||||
byte[] Key)
|
||||
private static byte[] Decrypt(byte[] cipherData, byte[] Key)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
Aes alg = Aes.Create();
|
177
Vita/ContentManager/SettingsReader.cs
Normal file
177
Vita/ContentManager/SettingsReader.cs
Normal file
|
@ -0,0 +1,177 @@
|
|||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Vita.ContentManager
|
||||
{
|
||||
public class SettingsReader
|
||||
{
|
||||
private static string? overrideBackupsFolder = null;
|
||||
public static string AppFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(BackupsFolder, "APP");
|
||||
}
|
||||
}
|
||||
public static string PspSavedataFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(BackupsFolder, "PSAVEDATA");
|
||||
}
|
||||
}
|
||||
|
||||
public static string PsmFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(BackupsFolder, "PSM");
|
||||
}
|
||||
}
|
||||
public static string SystemFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(BackupsFolder, "SYSTEM");
|
||||
}
|
||||
}
|
||||
public static string Ps1Folder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(BackupsFolder, "PSGAME");
|
||||
}
|
||||
}
|
||||
public static string PspFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(BackupsFolder, "PGAME");
|
||||
}
|
||||
}
|
||||
public static string BackupsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (overrideBackupsFolder is not null) return overrideBackupsFolder;
|
||||
|
||||
string? cmaFolder = getQcmaPSVitaFolder();
|
||||
if (cmaFolder is not null) return cmaFolder;
|
||||
cmaFolder = getDevkitCmaPSVitaFolder();
|
||||
if (cmaFolder is not null) return cmaFolder;
|
||||
cmaFolder = getSonyCmaPSVitaFolder();
|
||||
if (cmaFolder is not null) return cmaFolder;
|
||||
return getDefaultCmaPSVitaFolder();
|
||||
}
|
||||
set
|
||||
{
|
||||
overrideBackupsFolder = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static string getDefaultCmaPSVitaFolder()
|
||||
{
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "PS Vita");
|
||||
}
|
||||
|
||||
private static string getQcmaConfFile()
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "codestation", "qcma.conf");
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Preferences", "com.codestation.qcma.plist");
|
||||
else
|
||||
throw new PlatformNotSupportedException("cannot open qcma config as i dont know where it is.");
|
||||
}
|
||||
private static string? getQcmaConfigSetting(string file, string key)
|
||||
{
|
||||
if (!File.Exists(file)) return null;
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
using (TextReader confFile = File.OpenText(file))
|
||||
{
|
||||
for (string? ln = confFile.ReadLine();
|
||||
ln is not null;
|
||||
ln = confFile.ReadLine())
|
||||
{
|
||||
ln = ln.Trim();
|
||||
if (ln.StartsWith("[")) continue;
|
||||
|
||||
string[] kvp = ln.Split('=');
|
||||
if (kvp.Length < 2) continue;
|
||||
|
||||
string settingKey = kvp[0].Trim();
|
||||
string settingValue = kvp[1].Trim();
|
||||
|
||||
|
||||
if (settingKey == key)
|
||||
return settingValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
throw new PlatformNotSupportedException("TODO: Implement reading bplist file from mac os");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? getRegistryKey(string registryPath, string keyName)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
using (RegistryKey? regKey = Registry.CurrentUser.OpenSubKey(registryPath))
|
||||
{
|
||||
if (regKey is null) return null;
|
||||
string? keyData = (regKey.GetValue(keyName) as string);
|
||||
if (keyData is null) return null;
|
||||
return keyData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException("cannot use registry on os other than windows");
|
||||
}
|
||||
}
|
||||
|
||||
private static string? getSonyCmaPSVitaFolder()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return getRegistryKey(@"Software\Sony Corporation\Sony Corporation\Content Manager Assistant\Settings", "ApplicationHomePath");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static string? getDevkitCmaPSVitaFolder()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return getRegistryKey(@"Software\SCE\PSP2\Content Manager Assistant for PlayStation(R)Vita DevKit\Settings", "ApplicationHomePath");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static string? getQcmaPSVitaFolder()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return getRegistryKey(@"Software\codestation\qcma", "appsPath");
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
string qcmaConf = getQcmaConfFile();
|
||||
return getQcmaConfigSetting(qcmaConf, "appsPath");
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
string qcmaConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Preferences", "com.codestation.qcma.plist");
|
||||
// TODO: read file
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,14 @@
|
|||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Li.Progress;
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using static PSVIMGTOOLS.SceIoStat;
|
||||
using static Vita.PsvImgTools.SceIoStat;
|
||||
|
||||
namespace PSVIMGTOOLS
|
||||
namespace Vita.PsvImgTools
|
||||
{
|
||||
class PSVIMGBuilder
|
||||
public class PSVIMGBuilder : ProgressTracker
|
||||
{
|
||||
private const Int64 BUFFER_SZ = 0x10000;
|
||||
private byte[] IV = new byte[0x10];
|
||||
private byte[] KEY;
|
||||
private Random rnd = new Random();
|
||||
|
@ -19,7 +18,6 @@ namespace PSVIMGTOOLS
|
|||
private MemoryStream blockStream;
|
||||
private long contentSize = 0;
|
||||
|
||||
|
||||
//async
|
||||
private int blocksWritten = 0;
|
||||
private bool finished = false;
|
||||
|
@ -58,8 +56,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
/*
|
||||
*- DEBUG Disable Encryption
|
||||
/* DEBUG Disable Encryption
|
||||
ms.Write(plainText, 0x00, size);
|
||||
ms.Seek(0x00,SeekOrigin.Begin);
|
||||
return ms.ToArray();*/
|
||||
|
@ -86,8 +83,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
/*
|
||||
*- DEBUG Disable Encryption
|
||||
/* DEBUG Disable Encryption
|
||||
ms.Write(plainText, 0x00, size);
|
||||
ms.Seek(0x00,SeekOrigin.Begin);
|
||||
return ms.ToArray();*/
|
||||
|
@ -105,6 +101,7 @@ namespace PSVIMGTOOLS
|
|||
return cipherText;
|
||||
}
|
||||
|
||||
// TODO: Switch to Li.Utilities.StreamUtil for this .
|
||||
private void writeUInt64(Stream dst,UInt64 value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
|
@ -137,7 +134,7 @@ namespace PSVIMGTOOLS
|
|||
dst.Write(ValueBytes, 0x00, 0x4);
|
||||
}
|
||||
|
||||
private SceDateTime dateTimeToSceDateTime(DateTime dt)
|
||||
internal virtual SceDateTime dateTimeToSceDateTime(DateTime dt)
|
||||
{
|
||||
SceDateTime sdt = new SceDateTime();
|
||||
sdt.Day = Convert.ToUInt16(dt.Day);
|
||||
|
@ -151,8 +148,57 @@ namespace PSVIMGTOOLS
|
|||
sdt.Microsecond = Convert.ToUInt32(dt.Millisecond * 1000);
|
||||
return sdt;
|
||||
}
|
||||
internal virtual SceIoStat sceIoStat()
|
||||
{
|
||||
SceIoStat stats = new SceIoStat();
|
||||
|
||||
private SceIoStat sceIoStat(string path)
|
||||
stats.Mode |= Modes.Directory;
|
||||
// set size..
|
||||
stats.Size = 0;
|
||||
|
||||
// fake the rest--
|
||||
stats.Mode |= Modes.GroupRead;
|
||||
stats.Mode |= Modes.GroupWrite;
|
||||
|
||||
stats.Mode |= Modes.OthersRead;
|
||||
stats.Mode |= Modes.OthersWrite;
|
||||
|
||||
stats.Mode |= Modes.UserRead;
|
||||
stats.Mode |= Modes.UserWrite;
|
||||
|
||||
stats.CreationTime = dateTimeToSceDateTime(DateTime.Now);
|
||||
stats.AccessTime = dateTimeToSceDateTime(DateTime.Now);
|
||||
stats.ModificaionTime = dateTimeToSceDateTime(DateTime.Now);
|
||||
|
||||
return stats;
|
||||
}
|
||||
internal virtual SceIoStat sceIoStat(Stream str)
|
||||
{
|
||||
SceIoStat stats = new SceIoStat();
|
||||
|
||||
// streams being a directory doesnt really make sense ..
|
||||
stats.Mode |= Modes.File;
|
||||
|
||||
// set size..
|
||||
stats.Size = Convert.ToUInt64(str.Length);
|
||||
|
||||
// fake the rest--
|
||||
stats.Mode |= Modes.GroupRead;
|
||||
stats.Mode |= Modes.GroupWrite;
|
||||
|
||||
stats.Mode |= Modes.OthersRead;
|
||||
stats.Mode |= Modes.OthersWrite;
|
||||
|
||||
stats.Mode |= Modes.UserRead;
|
||||
stats.Mode |= Modes.UserWrite;
|
||||
|
||||
stats.CreationTime = dateTimeToSceDateTime(DateTime.Now);
|
||||
stats.AccessTime = dateTimeToSceDateTime(DateTime.Now);
|
||||
stats.ModificaionTime = dateTimeToSceDateTime(DateTime.Now);
|
||||
|
||||
return stats;
|
||||
}
|
||||
internal virtual SceIoStat sceIoStat(string path)
|
||||
{
|
||||
SceIoStat stats = new SceIoStat();
|
||||
FileAttributes attrbutes = File.GetAttributes(path);
|
||||
|
@ -166,7 +212,6 @@ namespace PSVIMGTOOLS
|
|||
{
|
||||
stats.Mode |= Modes.File;
|
||||
stats.Size = Convert.ToUInt64(new FileInfo(path).Length);
|
||||
|
||||
}
|
||||
|
||||
if(attrbutes.HasFlag(FileAttributes.ReadOnly))
|
||||
|
@ -196,7 +241,7 @@ namespace PSVIMGTOOLS
|
|||
return stats;
|
||||
}
|
||||
|
||||
private void writeSceDateTime(Stream dst,SceDateTime time)
|
||||
internal virtual void writeSceDateTime(Stream dst,SceDateTime time)
|
||||
{
|
||||
writeUInt16(dst, time.Year);
|
||||
writeUInt16(dst, time.Month);
|
||||
|
@ -208,7 +253,7 @@ namespace PSVIMGTOOLS
|
|||
writeUInt32(dst, time.Microsecond);
|
||||
}
|
||||
|
||||
private void writeSceIoStat(Stream dst, SceIoStat stats)
|
||||
internal virtual void writeSceIoStat(Stream dst, SceIoStat stats)
|
||||
{
|
||||
writeUInt32(dst, Convert.ToUInt32(stats.Mode));
|
||||
writeUInt32(dst, Convert.ToUInt32(stats.Attributes));
|
||||
|
@ -222,7 +267,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
private void memset(byte[] buf, byte content, long length)
|
||||
internal virtual void memset(byte[] buf, byte content, long length)
|
||||
{
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
|
@ -230,7 +275,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
private void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78)
|
||||
internal virtual void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78)
|
||||
{
|
||||
int StrLen = str.Length;
|
||||
if(StrLen > padSize)
|
||||
|
@ -244,7 +289,7 @@ namespace PSVIMGTOOLS
|
|||
writePadding(dst, padByte, PaddingLen);
|
||||
}
|
||||
|
||||
private void writeString(Stream dst, string str, int len=-1)
|
||||
internal virtual void writeString(Stream dst, string str, int len=-1)
|
||||
{
|
||||
if(len < 0)
|
||||
{
|
||||
|
@ -255,13 +300,29 @@ namespace PSVIMGTOOLS
|
|||
dst.Write(StrBytes, 0x00, len);
|
||||
}
|
||||
|
||||
private void writePadding(Stream dst, byte paddingByte, long paddingLen)
|
||||
internal virtual void writePadding(Stream dst, byte paddingByte, long paddingLen)
|
||||
{
|
||||
byte[] paddingData = new byte[paddingLen];
|
||||
memset(paddingData, paddingByte, paddingLen);
|
||||
dst.Write(paddingData, 0x00, paddingData.Length);
|
||||
}
|
||||
private byte[] getHeader(string FilePath, string ParentPath, string PathRel)
|
||||
internal virtual byte[] getHeader(SceIoStat Stat, string ParentPath, string PathRel)
|
||||
{
|
||||
using (MemoryStream Header = new MemoryStream())
|
||||
{
|
||||
writeInt64(Header, DateTime.UtcNow.Ticks); // SysTime
|
||||
writeInt64(Header, 0); // Flags
|
||||
writeSceIoStat(Header, Stat);
|
||||
writeStringWithPadding(Header, ParentPath, 256); // Parent Path
|
||||
writeUInt32(Header, 1); //unk_16C
|
||||
writeStringWithPadding(Header, PathRel, 256); //Relative Path
|
||||
writePadding(Header, 0x78, 904); //'x'
|
||||
writeString(Header, PSVIMGConstants.PSVIMG_HEADER_END); //EndOfHeader
|
||||
Header.Seek(0x00, SeekOrigin.Begin);
|
||||
return Header.ToArray();
|
||||
}
|
||||
}
|
||||
internal virtual byte[] getHeader(string FilePath, string ParentPath, string PathRel)
|
||||
{
|
||||
using (MemoryStream Header = new MemoryStream())
|
||||
{
|
||||
|
@ -278,14 +339,14 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
private void startNewBlock()
|
||||
internal virtual void startNewBlock()
|
||||
{
|
||||
blockData = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE];
|
||||
blockStream = new MemoryStream(blockData, 0x00, PSVIMGConstants.FULL_PSVIMG_SIZE);
|
||||
}
|
||||
|
||||
|
||||
private byte[] shaBlock(int length = PSVIMGConstants.PSVIMG_BLOCK_SIZE,bool final=false)
|
||||
internal virtual byte[] shaBlock(int length = PSVIMGConstants.PSVIMG_BLOCK_SIZE,bool final=false)
|
||||
{
|
||||
byte[] outbytes = new byte[PSVIMGConstants.SHA256_BLOCK_SIZE];
|
||||
shaCtx.BlockUpdate(blockData, 0x00, length);
|
||||
|
@ -294,7 +355,7 @@ namespace PSVIMGTOOLS
|
|||
return outbytes;
|
||||
}
|
||||
|
||||
private void finishBlock(bool final = false)
|
||||
internal virtual void finishBlock(bool final = false)
|
||||
{
|
||||
int len = Convert.ToInt32(blockStream.Position);
|
||||
byte[] shaBytes = shaBlock(len, final);
|
||||
|
@ -315,12 +376,12 @@ namespace PSVIMGTOOLS
|
|||
blockStream.Dispose();
|
||||
}
|
||||
|
||||
private int remainingBlockSize()
|
||||
internal virtual int remainingBlockSize()
|
||||
{
|
||||
return Convert.ToInt32((PSVIMGConstants.PSVIMG_BLOCK_SIZE - blockStream.Position));
|
||||
}
|
||||
|
||||
private void writeBlock(byte[] data, bool update=false)
|
||||
internal virtual void writeBlock(byte[] data, bool update=false)
|
||||
{
|
||||
long dLen = data.Length;
|
||||
long writeTotal = 0;
|
||||
|
@ -341,10 +402,8 @@ namespace PSVIMGTOOLS
|
|||
finishBlock();
|
||||
startNewBlock();
|
||||
if (update)
|
||||
{
|
||||
blocksWritten += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] dataRemains = new byte[dLen];
|
||||
|
@ -356,7 +415,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
}
|
||||
private byte[] getPadding(long size)
|
||||
internal virtual byte[] getPadding(long size)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
|
@ -371,7 +430,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] getTailer()
|
||||
internal virtual byte[] getTailer()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
|
@ -384,22 +443,20 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
private void writeStream(Stream dst)
|
||||
internal virtual void writeStream(Stream dst, string file)
|
||||
{
|
||||
while(dst.Position < dst.Length)
|
||||
{
|
||||
byte[] work_buf;
|
||||
Int64 bytes_remain = (dst.Length - dst.Position);
|
||||
if (bytes_remain > 0x33554432)
|
||||
{
|
||||
work_buf = new byte[0x33554432];
|
||||
}
|
||||
if (bytes_remain > BUFFER_SZ)
|
||||
work_buf = new byte[BUFFER_SZ];
|
||||
else
|
||||
{
|
||||
work_buf = new byte[bytes_remain];
|
||||
}
|
||||
dst.Read(work_buf, 0x00, work_buf.Length);
|
||||
writeBlock(work_buf, true);
|
||||
|
||||
updateProgress(Convert.ToInt32(dst.Position), Convert.ToInt32(dst.Length), "PSVIMG Package File: " + Path.GetFileName(file));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,24 +474,23 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public void AddFileAsync(string FilePath, string ParentPath, string PathRel)
|
||||
public void AddFile(byte[] sData, string ParentPath, string PathRel)
|
||||
{
|
||||
finished = false;
|
||||
new Thread(() =>
|
||||
using (MemoryStream ms = new MemoryStream(sData))
|
||||
{
|
||||
long sz = Convert.ToInt64(sceIoStat(FilePath).Size);
|
||||
writeBlock(getHeader(FilePath, ParentPath, PathRel));
|
||||
using (FileStream fs = File.OpenRead(FilePath))
|
||||
{
|
||||
writeStream(fs);
|
||||
AddFile(ms, ParentPath, PathRel);
|
||||
}
|
||||
}
|
||||
public void AddFile(Stream sData, string ParentPath, string PathRel)
|
||||
{
|
||||
SceIoStat stat = sceIoStat(sData);
|
||||
long sz = Convert.ToInt64(stat.Size);
|
||||
writeBlock(getHeader(stat, ParentPath, PathRel));
|
||||
writeStream(sData, PathRel);
|
||||
writeBlock(getPadding(sz));
|
||||
writeBlock(getTailer());
|
||||
contentSize += sz;
|
||||
finished = true;
|
||||
}).Start();
|
||||
|
||||
}
|
||||
public void AddFile(string FilePath, string ParentPath, string PathRel)
|
||||
{
|
||||
|
@ -442,14 +498,18 @@ namespace PSVIMGTOOLS
|
|||
long sz = Convert.ToInt64(sceIoStat(FilePath).Size);
|
||||
writeBlock(getHeader(FilePath, ParentPath, PathRel));
|
||||
using (FileStream fs = File.OpenRead(FilePath))
|
||||
{
|
||||
writeStream(fs);
|
||||
}
|
||||
writeStream(fs, PathRel);
|
||||
writeBlock(getPadding(sz));
|
||||
writeBlock(getTailer());
|
||||
contentSize += sz;
|
||||
finished = true;
|
||||
}
|
||||
public void AddDir(string ParentPath, string PathRel)
|
||||
{
|
||||
writeBlock(getHeader(sceIoStat(), ParentPath, PathRel));
|
||||
writeBlock(getPadding(0));
|
||||
writeBlock(getTailer());
|
||||
}
|
||||
|
||||
public void AddDir(string DirPath, string ParentPath, string PathRel)
|
||||
{
|
||||
writeBlock(getHeader(DirPath, ParentPath, PathRel));
|
||||
|
@ -463,7 +523,7 @@ namespace PSVIMGTOOLS
|
|||
mainStream.Write(footer, 0x00, footer.Length);
|
||||
|
||||
blockStream.Dispose();
|
||||
mainStream.Dispose();
|
||||
//mainStream.Dispose();
|
||||
return contentSize;
|
||||
}
|
||||
|
350
Vita/PsvImgTools/PSVIMGFileStream.cs
Normal file
350
Vita/PsvImgTools/PSVIMGFileStream.cs
Normal file
|
@ -0,0 +1,350 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using static Vita.PsvImgTools.SceIoStat;
|
||||
|
||||
namespace Vita.PsvImgTools
|
||||
{
|
||||
public class PSVIMGFileStream : Stream
|
||||
{
|
||||
|
||||
long length = 0;
|
||||
long startPos = 0;
|
||||
long endPos = 0;
|
||||
long position = 0;
|
||||
|
||||
private PSVIMGStream psvStream;
|
||||
public PSVIMGFileStream(PSVIMGStream psv, string Path)
|
||||
{
|
||||
psvStream = psv;
|
||||
if (Path.First() == '/')
|
||||
findFile(Path);
|
||||
else
|
||||
findFileMatching(Path);
|
||||
}
|
||||
|
||||
public void WriteToFile(string FilePath)
|
||||
{
|
||||
using (FileStream fs = File.OpenWrite(FilePath))
|
||||
{
|
||||
fs.SetLength(0);
|
||||
int written = 0;
|
||||
long left = length - written;
|
||||
byte[] work_buf;
|
||||
Seek(0x00, SeekOrigin.Begin);
|
||||
while (left > 0)
|
||||
{
|
||||
left = length - written;
|
||||
if (left < 0x10000)
|
||||
{
|
||||
work_buf = new byte[left];
|
||||
}
|
||||
else
|
||||
{
|
||||
work_buf = new byte[0x10000];
|
||||
}
|
||||
Read(work_buf, 0x00, work_buf.Length);
|
||||
fs.Write(work_buf, 0x00, work_buf.Length);
|
||||
written += work_buf.Length;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return position;
|
||||
}
|
||||
set
|
||||
{
|
||||
Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
psvStream.Flush();
|
||||
}
|
||||
private int _read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
int read = 0;
|
||||
while (true)
|
||||
{
|
||||
int remainBlock = Convert.ToInt32(psvStream.BlockRemaining - PSVIMGConstants.SHA256_BLOCK_SIZE);
|
||||
int remainRead = count - read;
|
||||
|
||||
if (remainRead < remainBlock)
|
||||
{
|
||||
byte[] tmp = new byte[remainRead];
|
||||
psvStream.Read(tmp, 0x00, remainRead);
|
||||
ms.Write(tmp, 0x00, tmp.Length);
|
||||
read += remainRead;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] tmp = new byte[remainBlock];
|
||||
psvStream.Read(tmp, 0x00, remainBlock);
|
||||
ms.Write(tmp, 0x00, tmp.Length);
|
||||
psvStream.Seek(PSVIMGConstants.SHA256_BLOCK_SIZE, SeekOrigin.Current);
|
||||
read += Convert.ToInt32(remainBlock);
|
||||
}
|
||||
}
|
||||
ms.Seek(0x00, SeekOrigin.Begin);
|
||||
return ms.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private long _seek(long amount, SeekOrigin orig)
|
||||
{
|
||||
long ToSeek = 0;
|
||||
long SeekAdd = 0;
|
||||
long remainBlock = psvStream.BlockRemaining - PSVIMGConstants.SHA256_BLOCK_SIZE;
|
||||
while (true)
|
||||
{
|
||||
long remainSeek = amount - ToSeek;
|
||||
|
||||
if (remainSeek < remainBlock)
|
||||
{
|
||||
ToSeek += remainSeek;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToSeek += remainBlock;
|
||||
SeekAdd += PSVIMGConstants.SHA256_BLOCK_SIZE;
|
||||
}
|
||||
remainBlock = PSVIMGConstants.PSVIMG_BLOCK_SIZE;
|
||||
}
|
||||
ToSeek += SeekAdd;
|
||||
return psvStream.Seek(ToSeek, orig);
|
||||
}
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (startPos + count > endPos)
|
||||
{
|
||||
count = Convert.ToInt32(endPos);
|
||||
}
|
||||
return _read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (origin == SeekOrigin.Begin)
|
||||
{
|
||||
if (offset <= endPos)
|
||||
{
|
||||
psvStream.Seek(startPos, SeekOrigin.Begin);
|
||||
_seek(offset, SeekOrigin.Current);
|
||||
position = offset;
|
||||
return position;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Offset is out of range of file");
|
||||
}
|
||||
|
||||
}
|
||||
else if (origin == SeekOrigin.Current)
|
||||
{
|
||||
if (offset <= endPos)
|
||||
{
|
||||
_seek(offset, SeekOrigin.Current);
|
||||
position += offset;
|
||||
return position;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Offset is out of range of file");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long realOffset = endPos + offset;
|
||||
if (realOffset <= endPos)
|
||||
{
|
||||
_seek(realOffset, SeekOrigin.Begin);
|
||||
return Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Offset is out of range of file");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException("PSVFileStream is Read-Only");
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException("PSVFileStream is Read-Only");
|
||||
}
|
||||
|
||||
private ushort readUInt16()
|
||||
{
|
||||
byte[] intBuf = new byte[0x2];
|
||||
_read(intBuf, 0x00, 0x02);
|
||||
return BitConverter.ToUInt16(intBuf, 0);
|
||||
}
|
||||
private uint readUInt32()
|
||||
{
|
||||
byte[] intBuf = new byte[0x4];
|
||||
_read(intBuf, 0x00, 0x04);
|
||||
return BitConverter.ToUInt32(intBuf, 0);
|
||||
}
|
||||
private ulong readUInt64()
|
||||
{
|
||||
byte[] intBuf = new byte[0x8];
|
||||
_read(intBuf, 0x00, 0x08);
|
||||
return BitConverter.ToUInt64(intBuf, 0);
|
||||
}
|
||||
private SceDateTime readDatetime()
|
||||
{
|
||||
SceDateTime dateTime = new SceDateTime();
|
||||
dateTime.Year = readUInt16();
|
||||
dateTime.Month = readUInt16();
|
||||
dateTime.Day = readUInt16();
|
||||
dateTime.Hour = readUInt16();
|
||||
dateTime.Minute = readUInt16();
|
||||
dateTime.Second = readUInt16();
|
||||
dateTime.Microsecond = readUInt32();
|
||||
return dateTime;
|
||||
}
|
||||
private SceIoStat readStats()
|
||||
{
|
||||
SceIoStat stat = new SceIoStat();
|
||||
stat.Mode = (Modes)readUInt32();
|
||||
stat.Attributes = (AttributesEnum)readUInt32();
|
||||
stat.Size = readUInt64();
|
||||
stat.CreationTime = readDatetime();
|
||||
stat.AccessTime = readDatetime();
|
||||
stat.ModificaionTime = readDatetime();
|
||||
for (int i = 0; i < stat.Private.Length; i++)
|
||||
{
|
||||
stat.Private[i] = readUInt32();
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
private PsvImgHeader readHeader()
|
||||
{
|
||||
PsvImgHeader header = new PsvImgHeader();
|
||||
header.SysTime = readUInt64();
|
||||
header.Flags = readUInt64();
|
||||
header.Statistics = readStats();
|
||||
_read(header.bParentPath, 0x00, 256);
|
||||
header.unk_16C = readUInt32();
|
||||
_read(header.bPath, 0x00, 256);
|
||||
_read(header.Padding, 0x00, 904);
|
||||
_read(header.bEnd, 0x00, 12);
|
||||
return header;
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
psvStream.Dispose();
|
||||
base.Close();
|
||||
}
|
||||
|
||||
private PsvImgTailer readTailer()
|
||||
{
|
||||
PsvImgTailer tailer = new PsvImgTailer();
|
||||
tailer.Flags = readUInt64();
|
||||
_read(tailer.Padding, 0x00, 1004);
|
||||
_read(tailer.bEnd, 0x00, 12);
|
||||
return tailer;
|
||||
}
|
||||
|
||||
private void findFileMatching(string path)
|
||||
{
|
||||
_seek(0x00, SeekOrigin.Begin);
|
||||
while (psvStream.Position < psvStream.Length)
|
||||
{
|
||||
PsvImgHeader header = readHeader();
|
||||
long size = (long)header.Statistics.Size;
|
||||
long padding = PSVIMGPadding.GetPadding(size);
|
||||
|
||||
if (header.Path.Contains(path, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
length = size;
|
||||
startPos = psvStream.Position;
|
||||
endPos = startPos + length;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_seek(size + padding, SeekOrigin.Current);
|
||||
PsvImgTailer tailer = readTailer();
|
||||
}
|
||||
|
||||
}
|
||||
throw new FileNotFoundException("Cannot find file specified");
|
||||
|
||||
}
|
||||
private void findFile(string path)
|
||||
{
|
||||
_seek(0x00, SeekOrigin.Begin);
|
||||
while (psvStream.Position < psvStream.Length)
|
||||
{
|
||||
PsvImgHeader header = readHeader();
|
||||
long size = (long)header.Statistics.Size;
|
||||
long padding = PSVIMGPadding.GetPadding(size);
|
||||
|
||||
if (header.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
length = size;
|
||||
startPos = psvStream.Position;
|
||||
endPos = startPos + length;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_seek(size + padding, SeekOrigin.Current);
|
||||
PsvImgTailer tailer = readTailer();
|
||||
}
|
||||
|
||||
}
|
||||
throw new FileNotFoundException("Cannot find file specified");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
365
Vita/PsvImgTools/PSVIMGStream.cs
Normal file
365
Vita/PsvImgTools/PSVIMGStream.cs
Normal file
|
@ -0,0 +1,365 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
|
||||
namespace Vita.PsvImgTools
|
||||
{
|
||||
public class PSVIMGStream : Stream
|
||||
{
|
||||
private Stream baseStream;
|
||||
private MemoryStream blockStream;
|
||||
private byte[] key;
|
||||
public Stream BaseStream
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return key;
|
||||
}
|
||||
set
|
||||
{
|
||||
key = value;
|
||||
}
|
||||
}
|
||||
|
||||
public long BlockNo
|
||||
{
|
||||
get
|
||||
{
|
||||
return getBlockIndex();
|
||||
}
|
||||
set
|
||||
{
|
||||
seekToBlock(value);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
public long BlockRemaining
|
||||
{
|
||||
get
|
||||
{
|
||||
return getRemainingBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public long BlockPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return blockStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
blockStream.Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Length - PSVIMGConstants.AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return baseStream.Position - PSVIMGConstants.AES_BLOCK_SIZE;
|
||||
}
|
||||
set
|
||||
{
|
||||
Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PSVIMGStream(Stream file, byte[] KEY)
|
||||
{
|
||||
baseStream = file;
|
||||
key = KEY;
|
||||
if (!verifyFooter())
|
||||
{
|
||||
throw new Exception("Invalid KEY!");
|
||||
}
|
||||
blockStream = new MemoryStream();
|
||||
baseStream.Seek(PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin);
|
||||
update();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int remaining = (int)getRemainingBlock();
|
||||
int read = 0;
|
||||
|
||||
if (count < remaining)
|
||||
{
|
||||
read += blockStream.Read(buffer, offset, count);
|
||||
baseStream.Seek(count, SeekOrigin.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
update();
|
||||
remaining = (int)getRemainingBlock();
|
||||
int curPos = count - read;
|
||||
|
||||
if (curPos > remaining)
|
||||
{
|
||||
read += remaining;
|
||||
blockStream.CopyTo(ms, remaining);
|
||||
baseStream.Seek(remaining, SeekOrigin.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
read += curPos;
|
||||
blockStream.CopyTo(ms, curPos);
|
||||
baseStream.Seek(curPos, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
ms.Seek(0x00, SeekOrigin.Begin);
|
||||
ms.Read(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
return read;
|
||||
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
update();
|
||||
baseStream.Flush();
|
||||
blockStream.Flush();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
long ret = 0;
|
||||
if (origin == SeekOrigin.Begin)
|
||||
{
|
||||
ret = baseStream.Seek(offset + PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin);
|
||||
}
|
||||
else if (origin == SeekOrigin.Current)
|
||||
{
|
||||
long pos = baseStream.Position;
|
||||
if (pos + offset >= PSVIMGConstants.AES_BLOCK_SIZE)
|
||||
{
|
||||
ret = baseStream.Seek(offset, SeekOrigin.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = baseStream.Seek(offset + PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Current);
|
||||
}
|
||||
}
|
||||
else if (origin == SeekOrigin.End)
|
||||
{
|
||||
long pos = baseStream.Length;
|
||||
if (pos + offset >= PSVIMGConstants.AES_BLOCK_SIZE)
|
||||
{
|
||||
ret = baseStream.Seek(offset, SeekOrigin.End);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = baseStream.Seek(offset + PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.End);
|
||||
}
|
||||
}
|
||||
update();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException("PSVIMGStream is Read-Only");
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException("PSVIMGStream is Read-Only");
|
||||
}
|
||||
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
blockStream.Dispose();
|
||||
baseStream.Dispose();
|
||||
base.Close();
|
||||
}
|
||||
private void update()
|
||||
{
|
||||
long offset = Position % PSVIMGConstants.FULL_PSVIMG_SIZE;
|
||||
long blockIndex = getBlockIndex();
|
||||
byte[] decryptedBlock = getBlock(blockIndex);
|
||||
blockStream.Seek(0x00, SeekOrigin.Begin);
|
||||
blockStream.SetLength(decryptedBlock.Length);
|
||||
blockStream.Write(decryptedBlock, 0x00, decryptedBlock.Length);
|
||||
seekToBlock(blockIndex);
|
||||
baseStream.Seek(offset, SeekOrigin.Current);
|
||||
blockStream.Seek(offset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
private long getBlockIndex()
|
||||
{
|
||||
long i = 0;
|
||||
long curPos = baseStream.Position;
|
||||
long fullBlock;
|
||||
long blockOffset;
|
||||
|
||||
while (true)
|
||||
{
|
||||
blockOffset = i * PSVIMGConstants.FULL_PSVIMG_SIZE + PSVIMGConstants.AES_BLOCK_SIZE;
|
||||
long remaining = getRemainingBase();
|
||||
if (remaining < PSVIMGConstants.FULL_PSVIMG_SIZE)
|
||||
{
|
||||
fullBlock = blockOffset + remaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
fullBlock = blockOffset + PSVIMGConstants.FULL_PSVIMG_SIZE;
|
||||
}
|
||||
if (curPos >= blockOffset && curPos < fullBlock)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (blockOffset > baseStream.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
|
||||
|
||||
}
|
||||
private long getRemainingBase()
|
||||
{
|
||||
return baseStream.Length - baseStream.Position;
|
||||
}
|
||||
private long getRemainingBlock()
|
||||
{
|
||||
return blockStream.Length - blockStream.Position;
|
||||
}
|
||||
private byte[] getIV(long blockindex)
|
||||
{
|
||||
byte[] iv = new byte[0x10];
|
||||
seekToBlock(blockindex);
|
||||
baseStream.Seek(baseStream.Position - PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin);
|
||||
baseStream.Read(iv, 0x00, iv.Length);
|
||||
return iv;
|
||||
}
|
||||
private byte[] aes_cbc_decrypt(byte[] cipherData, byte[] IV)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
Aes alg = Aes.Create();
|
||||
alg.Mode = CipherMode.CBC;
|
||||
alg.Padding = PaddingMode.None;
|
||||
alg.KeySize = 256;
|
||||
alg.BlockSize = 128;
|
||||
alg.Key = key;
|
||||
alg.IV = IV;
|
||||
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
|
||||
cs.Write(cipherData, 0, cipherData.Length);
|
||||
cs.Close();
|
||||
byte[] decryptedData = ms.ToArray();
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
private void seekToBlock(long blockIndex)
|
||||
{
|
||||
long blockOffset;
|
||||
blockOffset = blockIndex * PSVIMGConstants.FULL_PSVIMG_SIZE + PSVIMGConstants.AES_BLOCK_SIZE;
|
||||
|
||||
if (blockOffset > baseStream.Length)
|
||||
{
|
||||
blockOffset = baseStream.Length;
|
||||
}
|
||||
|
||||
baseStream.Seek(blockOffset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
private bool verifyFooter()
|
||||
{
|
||||
byte[] Footer = new byte[0x10];
|
||||
byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE];
|
||||
|
||||
baseStream.Seek(baseStream.Length - (Footer.Length + IV.Length), SeekOrigin.Begin);
|
||||
baseStream.Read(IV, 0x00, PSVIMGConstants.AES_BLOCK_SIZE);
|
||||
baseStream.Read(Footer, 0x00, 0x10);
|
||||
|
||||
byte[] FooterDec = aes_cbc_decrypt(Footer, IV);
|
||||
ulong FooterLen;
|
||||
using (MemoryStream ms = new MemoryStream(FooterDec))
|
||||
{
|
||||
ms.Seek(0x4, SeekOrigin.Current);
|
||||
ms.Seek(0x4, SeekOrigin.Current);
|
||||
byte[] LenInt = new byte[0x8];
|
||||
ms.Read(LenInt, 0x00, 0x8);
|
||||
FooterLen = BitConverter.ToUInt64(LenInt, 0x00);
|
||||
}
|
||||
if (Convert.ToUInt64(baseStream.Length) == FooterLen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getBlock(long blockIndex)
|
||||
{
|
||||
byte[] iv = getIV(blockIndex);
|
||||
long remaining = getRemainingBase();
|
||||
byte[] encryptedBlock;
|
||||
if (PSVIMGConstants.FULL_PSVIMG_SIZE < remaining)
|
||||
{
|
||||
encryptedBlock = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
encryptedBlock = new byte[remaining];
|
||||
}
|
||||
|
||||
|
||||
baseStream.Read(encryptedBlock, 0x00, encryptedBlock.Length);
|
||||
byte[] decryptedBlock = aes_cbc_decrypt(encryptedBlock, iv);
|
||||
return decryptedBlock;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace PSVIMGTOOLS
|
||||
namespace Vita.PsvImgTools
|
||||
{
|
||||
|
||||
internal class PSVIMGConstants
|
||||
public class PSVIMGConstants
|
||||
{
|
||||
public const int AES_BLOCK_SIZE = 0x10;
|
||||
public const int SHA256_BLOCK_SIZE = 0x20;
|
||||
|
@ -39,13 +39,13 @@ namespace PSVIMGTOOLS
|
|||
|
||||
internal class SceDateTime
|
||||
{
|
||||
public UInt16 Year;
|
||||
public UInt16 Month;
|
||||
public UInt16 Day;
|
||||
public UInt16 Hour;
|
||||
public UInt16 Minute;
|
||||
public UInt16 Second;
|
||||
public UInt32 Microsecond;
|
||||
public ushort Year;
|
||||
public ushort Month;
|
||||
public ushort Day;
|
||||
public ushort Hour;
|
||||
public ushort Minute;
|
||||
public ushort Second;
|
||||
public uint Microsecond;
|
||||
|
||||
public SceDateTime()
|
||||
{
|
||||
|
@ -55,7 +55,8 @@ namespace PSVIMGTOOLS
|
|||
|
||||
internal class SceIoStat
|
||||
{
|
||||
public enum Modes{
|
||||
public enum Modes
|
||||
{
|
||||
/** Format bits mask */
|
||||
FormatBits = 0xF000,
|
||||
/** Symbolic link */
|
||||
|
@ -121,7 +122,7 @@ namespace PSVIMGTOOLS
|
|||
public Modes Mode;
|
||||
public AttributesEnum Attributes;
|
||||
/** Size of the file in bytes. */
|
||||
public UInt64 Size;
|
||||
public ulong Size;
|
||||
/** Creation time. */
|
||||
public SceDateTime CreationTime;
|
||||
/** Access time. */
|
||||
|
@ -129,7 +130,7 @@ namespace PSVIMGTOOLS
|
|||
/** Modification time. */
|
||||
public SceDateTime ModificaionTime;
|
||||
/** Device-specific data. */
|
||||
public UInt32[] Private = new UInt32[6];
|
||||
public uint[] Private = new uint[6];
|
||||
public SceIoStat()
|
||||
{
|
||||
for (int i = 0; i < Private.Length; i++)
|
||||
|
@ -141,11 +142,11 @@ namespace PSVIMGTOOLS
|
|||
|
||||
internal class PsvImgTailer
|
||||
{
|
||||
public UInt64 Flags;
|
||||
public Byte[] Padding = new Byte[1004];
|
||||
public Byte[] bEnd = new Byte[12];
|
||||
public ulong Flags;
|
||||
public byte[] Padding = new byte[1004];
|
||||
public byte[] bEnd = new byte[12];
|
||||
|
||||
public String End
|
||||
public string End
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -158,9 +159,9 @@ namespace PSVIMGTOOLS
|
|||
public static long GetPadding(long size)
|
||||
{
|
||||
long padding;
|
||||
if ((size & (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1)) >= 1)
|
||||
if ((size & PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1) >= 1)
|
||||
{
|
||||
padding = (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - (size & (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1)));
|
||||
padding = PSVIMGConstants.PSVIMG_ENTRY_ALIGN - (size & PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -172,16 +173,16 @@ namespace PSVIMGTOOLS
|
|||
|
||||
internal class PsvImgHeader
|
||||
{
|
||||
public UInt64 SysTime;
|
||||
public UInt64 Flags;
|
||||
public ulong SysTime;
|
||||
public ulong Flags;
|
||||
public SceIoStat Statistics;
|
||||
public Byte[] bParentPath = new Byte[256];
|
||||
public UInt32 unk_16C; // set to 1
|
||||
public Byte[] bPath = new Byte[256];
|
||||
public Byte[] Padding = new Byte[904];
|
||||
public Byte[] bEnd = new Byte[12];
|
||||
public byte[] bParentPath = new byte[256];
|
||||
public uint unk_16C; // set to 1
|
||||
public byte[] bPath = new byte[256];
|
||||
public byte[] Padding = new byte[904];
|
||||
public byte[] bEnd = new byte[12];
|
||||
|
||||
public String Path
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -189,7 +190,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
public String End
|
||||
public string End
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -197,7 +198,7 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
public String ParentPath
|
||||
public string ParentPath
|
||||
{
|
||||
get
|
||||
{
|
|
@ -3,9 +3,9 @@ using System;
|
|||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
namespace PSVIMGTOOLS
|
||||
namespace Vita.PsvImgTools
|
||||
{
|
||||
class PSVMDBuilder
|
||||
public class PSVMDBuilder
|
||||
{
|
||||
private static void memset(byte[] buf, byte content, long length)
|
||||
{
|
||||
|
@ -15,33 +15,33 @@ namespace PSVIMGTOOLS
|
|||
}
|
||||
}
|
||||
|
||||
private static void writeUInt64(Stream dst, UInt64 value)
|
||||
private static void writeUInt64(Stream dst, ulong value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
dst.Write(ValueBytes, 0x00, 0x8);
|
||||
}
|
||||
private static void writeInt64(Stream dst, Int64 value)
|
||||
private static void writeInt64(Stream dst, long value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
dst.Write(ValueBytes, 0x00, 0x8);
|
||||
}
|
||||
private static void writeUInt16(Stream dst, UInt16 value)
|
||||
private static void writeUInt16(Stream dst, ushort value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
dst.Write(ValueBytes, 0x00, 0x2);
|
||||
}
|
||||
private static void writeInt16(Stream dst, Int16 value)
|
||||
private static void writeInt16(Stream dst, short value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
dst.Write(ValueBytes, 0x00, 0x2);
|
||||
}
|
||||
|
||||
private static void writeInt32(Stream dst, Int32 value)
|
||||
private static void writeInt32(Stream dst, int value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
dst.Write(ValueBytes, 0x00, 0x4);
|
||||
}
|
||||
private static void writeUInt32(Stream dst, UInt32 value)
|
||||
private static void writeUInt32(Stream dst, uint value)
|
||||
{
|
||||
byte[] ValueBytes = BitConverter.GetBytes(value);
|
||||
dst.Write(ValueBytes, 0x00, 0x4);
|
||||
|
@ -73,7 +73,7 @@ namespace PSVIMGTOOLS
|
|||
StrLen = padSize;
|
||||
}
|
||||
|
||||
int PaddingLen = (padSize - StrLen) - 1;
|
||||
int PaddingLen = padSize - StrLen - 1;
|
||||
writeString(dst, str, StrLen);
|
||||
dst.WriteByte(0x00);
|
||||
writePadding(dst, padByte, PaddingLen);
|
||||
|
@ -177,12 +177,12 @@ namespace PSVIMGTOOLS
|
|||
byte[] shadata = sha.ComputeHash(psvMdCompressed);
|
||||
ms.Write(shadata, 0x00, shadata.Length);
|
||||
|
||||
int PaddingLen = Convert.ToInt32(PSVIMGConstants.AES_BLOCK_SIZE - (ms.Length & (PSVIMGConstants.AES_BLOCK_SIZE - 1)));
|
||||
int PaddingLen = Convert.ToInt32(PSVIMGConstants.AES_BLOCK_SIZE - (ms.Length & PSVIMGConstants.AES_BLOCK_SIZE - 1));
|
||||
writePadding(ms, 0x00, PaddingLen);
|
||||
|
||||
writeInt32(ms, PaddingLen); //Padding Length
|
||||
writeUInt32(ms, 0x00);
|
||||
writeInt64(ms, (ms.Length+0x8)+IV.Length);
|
||||
writeInt64(ms, ms.Length + 0x8 + IV.Length);
|
||||
ms.Seek(0x00, SeekOrigin.Begin);
|
||||
byte[] toEncrypt = ms.ToArray();
|
||||
ms.Close();
|
18
Vita/Vita.csproj
Normal file
18
Vita/Vita.csproj
Normal file
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.0" />
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LiLib\LiLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
BIN
packages/BouncyCastle.1.8.5/BouncyCastle.1.8.5.nupkg
vendored
BIN
packages/BouncyCastle.1.8.5/BouncyCastle.1.8.5.nupkg
vendored
Binary file not shown.
30
packages/BouncyCastle.1.8.5/README.md
vendored
30
packages/BouncyCastle.1.8.5/README.md
vendored
|
@ -1,30 +0,0 @@
|
|||
# The Bouncy Castle Crypto Package For C Sharp
|
||||
|
||||
The Bouncy Castle Crypto package is a C\# implementation of cryptographic algorithms and protocols, it was developed by the Legion of the Bouncy Castle, a registered Australian Charity, with a little help! The Legion, and the latest goings on with this package, can be found at [http://www.bouncycastle.org](http://www.bouncycastle.org). In addition to providing basic cryptography algorithms, the package also provides support for CMS, TSP, X.509 certificate generation and a variety of other standards such as OpenPGP.
|
||||
|
||||
The Legion also gratefully acknowledges the contributions made to this package by others (see [here](http://www.bouncycastle.org/csharp/contributors.html) for the current list). If you would like to contribute to our efforts please feel free to get in touch with us or visit our [donations page](https://www.bouncycastle.org/donate), sponsor some specific work, or purchase a support contract through [Crypto Workshop](http://www.cryptoworkshop.com).
|
||||
|
||||
Except where otherwise stated, this software is distributed under a license based on the MIT X Consortium license. To view the license, [see here](http://www.bouncycastle.org/licence.html). The OpenPGP library also includes a modified BZIP2 library which is licensed under the [Apache Software License, Version 2.0](http://www.apache.org/licenses/).
|
||||
|
||||
**Note**: this source tree is not the FIPS version of the APIs - if you are interested in our FIPS version please contact us directly at [office@bouncycastle.org](mailto:office@bouncycastle.org).
|
||||
|
||||
## Mailing Lists
|
||||
|
||||
For those who are interested, there are 2 mailing lists for participation in this project. To subscribe use the links below and include the word subscribe in the message body. (To unsubscribe, replace **subscribe** with **unsubscribe** in the message body)
|
||||
|
||||
* [announce-crypto-csharp-request@bouncycastle.org](mailto:announce-crypto-csharp-request@bouncycastle.org)
|
||||
This mailing list is for new release announcements only, general subscribers cannot post to it.
|
||||
* [dev-crypto-csharp-request@bouncycastle.org](mailto:dev-crypto-csharp-request@bouncycastle.org)
|
||||
This mailing list is for discussion of development of the package. This includes bugs, comments, requests for enhancements, questions about use or operation.
|
||||
|
||||
**NOTE:**You need to be subscribed to send mail to the above mailing list.
|
||||
|
||||
## Feedback
|
||||
|
||||
If you want to provide feedback directly to the members of **The Legion** then please use [feedback-crypto@bouncycastle.org](mailto:feedback-crypto@bouncycastle.org), if you want to help this project survive please consider [donating](https://www.bouncycastle.org/donate).
|
||||
|
||||
For bug reporting/requests you can report issues here on github, via feedback-crypto if required, and we also have a [Jira issue tracker](http://www.bouncycastle.org/jira). We will accept pull requests based on this repository as well.
|
||||
|
||||
## Finally
|
||||
|
||||
Enjoy!
|
Binary file not shown.
BIN
packages/DotNetZip.1.13.4/DotNetZip.1.13.4.nupkg
vendored
BIN
packages/DotNetZip.1.13.4/DotNetZip.1.13.4.nupkg
vendored
Binary file not shown.
BIN
packages/DotNetZip.1.13.4/lib/net40/DotNetZip.dll
vendored
BIN
packages/DotNetZip.1.13.4/lib/net40/DotNetZip.dll
vendored
Binary file not shown.
BIN
packages/DotNetZip.1.13.4/lib/net40/DotNetZip.pdb
vendored
BIN
packages/DotNetZip.1.13.4/lib/net40/DotNetZip.pdb
vendored
Binary file not shown.
18529
packages/DotNetZip.1.13.4/lib/net40/DotNetZip.xml
vendored
18529
packages/DotNetZip.1.13.4/lib/net40/DotNetZip.xml
vendored
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
18031
packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.xml
vendored
18031
packages/DotNetZip.1.13.4/lib/netstandard2.0/DotNetZip.xml
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user