diff --git a/.gitignore b/.gitignore
index a07ef6a..f3ac88e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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/*
\ No newline at end of file
diff --git a/CHOVY-GEN/CHOVY-GEN.vcxproj b/CHOVY-GEN/CHOVY-GEN.vcxproj
deleted file mode 100644
index 6da94f8..0000000
--- a/CHOVY-GEN/CHOVY-GEN.vcxproj
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
-
-
-
-
-
-
- 15.0
- {DCDBF747-DFB6-450E-A403-1C592D20EAEB}
- Win32Proj
- CHOVYGEN
- 10.0
-
-
-
- DynamicLibrary
- true
- v143
- Unicode
-
-
- DynamicLibrary
- false
- v143
- true
- Unicode
-
-
- DynamicLibrary
- true
- v143
- Unicode
-
-
- DynamicLibrary
- false
- v143
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)
- CHOVY
-
-
- true
-
-
- false
-
- CHOVY
- $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)
-
-
- false
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)
- C:\openssl\include;%(AdditionalIncludeDirectories)
- MultiThreaded
-
-
- Windows
- C:\openssl\lib;%(AdditionalLibraryDirectories)
- ws2_32.lib;libsslMT.lib;Crypt32.lib;libcryptoMT.lib;%(AdditionalDependencies)
-
-
-
-
-
-
- Level3
- Disabled
- _DEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)
-
-
- Windows
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)
- MultiThreaded
- C:\openssl\include;%(AdditionalIncludeDirectories)
-
-
- Windows
- true
- true
- C:\openssl\lib;%(AdditionalLibraryDirectories)
- ws2_32.lib;libsslMT.lib;Crypt32.lib;libcryptoMT.lib;%(AdditionalDependencies)
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- NDEBUG;_WINDOWS;_USRDLL;CHOVYGEN_EXPORTS;%(PreprocessorDefinitions)
-
-
- Windows
- true
- true
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CHOVY-GEN/CHOVY-GEN.vcxproj.filters b/CHOVY-GEN/CHOVY-GEN.vcxproj.filters
deleted file mode 100644
index dc521e5..0000000
--- a/CHOVY-GEN/CHOVY-GEN.vcxproj.filters
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
- Header Files
-
-
-
-
- Source Files
-
-
-
\ No newline at end of file
diff --git a/CHOVY-GEN/CHOVY-GEN.vcxproj.user b/CHOVY-GEN/CHOVY-GEN.vcxproj.user
deleted file mode 100644
index d9462ff..0000000
--- a/CHOVY-GEN/CHOVY-GEN.vcxproj.user
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)\CHOVY-TRANSFER.EXE
- WindowsLocalDebugger
- Mixed
-
-
- $(SolutionDir)CHOVY-TRANSFER\bin\$(Configuration)\CHOVY-TRANSFER.EXE
- WindowsLocalDebugger
- Mixed
-
-
\ No newline at end of file
diff --git a/CHOVY-GEN/chovy-gen.c b/CHOVY-GEN/chovy-gen.c
deleted file mode 100644
index a7f6ac2..0000000
--- a/CHOVY-GEN/chovy-gen.c
+++ /dev/null
@@ -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
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#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;
-}
diff --git a/CHOVY-GEN/key_vault.h b/CHOVY-GEN/key_vault.h
deleted file mode 100644
index 2488e5e..0000000
--- a/CHOVY-GEN/key_vault.h
+++ /dev/null
@@ -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};
diff --git a/CHOVY-TRANSFER.sln b/CHOVY-TRANSFER.sln
index 61b3e78..149950f 100644
--- a/CHOVY-TRANSFER.sln
+++ b/CHOVY-TRANSFER.sln
@@ -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
diff --git a/CHOVY-TRANSFER/App.config b/CHOVY-TRANSFER/App.config
index a3f4642..f5d114b 100644
--- a/CHOVY-TRANSFER/App.config
+++ b/CHOVY-TRANSFER/App.config
@@ -2,5 +2,5 @@
-
+
diff --git a/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj
index c981102..36d7475 100644
--- a/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj
+++ b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj
@@ -1,107 +1,32 @@
-
-
-
+
- Debug
- AnyCPU
- {B4CAD2C0-BA54-46B6-A8D0-43A9C2390D3C}
+ net6.0-windows
WinExe
CHOVY_TRANSFER
CHOVY-TRANS
- v4.5.2
- 512
- true
-
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- true
- false
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- true
- false
+ false
+ true
+ true
chovy-trans.ico
+ CHOVY-TRANSFER
+ CHOVY-TRANSFER
+ Copyright © 2019
+ 1.0.0.0
+ 1.0.0.0
-
-
- ..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll
-
-
- ..\packages\DotNetZip.1.13.4\lib\net40\DotNetZip.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Form
-
-
- CHOVYTRANSFER.cs
-
-
-
-
-
-
-
-
-
- CHOVYTRANSFER.cs
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
- Designer
-
-
- True
- Resources.resx
- True
-
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
- True
- Settings.settings
- True
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user
new file mode 100644
index 0000000..5d596ed
--- /dev/null
+++ b/CHOVY-TRANSFER/CHOVY-TRANSFER.csproj.user
@@ -0,0 +1,11 @@
+
+
+
+ <_LastSelectedProfileId>C:\Users\Li\Documents\git\chovy-trans\CHOVY-TRANSFER\Properties\PublishProfiles\FolderProfile.pubxml
+
+
+
+ Form
+
+
+
\ No newline at end of file
diff --git a/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs b/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs
index 9d7ad8f..15ef931 100644
--- a/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs
+++ b/CHOVY-TRANSFER/CHOVYTRANSFER.Designer.cs
@@ -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);
diff --git a/CHOVY-TRANSFER/CHOVYTRANSFER.cs b/CHOVY-TRANSFER/CHOVYTRANSFER.cs
index 1c7b3d8..d47babc 100644
--- a/CHOVY-TRANSFER/CHOVYTRANSFER.cs
+++ b/CHOVY-TRANSFER/CHOVYTRANSFER.cs
@@ -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 licenseFiles = new List();
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,74 +420,44 @@ namespace CHOVY_TRANSFER
File.Delete(sigFile);
}
- int ChovyGenRes = 100;
- Thread ChovyGen = new Thread(() =>
- {
- ChovyGenRes = chovy_gen(ebootFile, uAid, sigFile);
- });
-
- 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;
- }
+ byte[] EbootSig = chovy_gen(ebootFile, uAid);
+ Account CmaAccount = new Account(uAid);
+ CmaAccount.Devkit = IsDexAidSet();
+
/*
* BUILD PSVIMG FILE(s)
*/
// 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,94 +465,95 @@ 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);
- PSVIMGBuilder builder = new PSVIMGBuilder(gamePsvimg, CmaKey);
-
- foreach (string entry in entrys)
+ await Task.Run(() =>
{
- string relativePath = entry.Remove(0, gameFolder.Length);
- relativePath = relativePath.Replace('\\', '/');
-
- if(Path.GetExtension(entry).ToUpperInvariant() == ".EDAT")
+ using (FileStream gamePsvimg = File.Open(psvimgFilepath, FileMode.Create, FileAccess.ReadWrite))
{
- string edatContentId = GetContentIdFromPspEdat(entry);
- string rifPath = Path.Combine(driveLetterSrc.Text, pspFolder.Text, "LICENSE", edatContentId + ".RIF");
- if (!licenseFiles.Contains(rifPath) && File.Exists(rifPath))
- licenseFiles.Add(rifPath);
- }
-
- bool isDir = File.GetAttributes(entry).HasFlag(FileAttributes.Directory);
-
- if (isDir)
- {
- builder.AddDir(entry, parentPath, relativePath);
- }
- else
- {
- builder.AddFileAsync(entry, parentPath, relativePath);
- while (!builder.HasFinished)
+ PSVIMGBuilder builder = new PSVIMGBuilder(gamePsvimg, CmaKey);
+ builder.RegisterCallback((ProgressInfo inf) =>
{
- try
- {
+ 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 = "Processing: " + Path.GetFileName(entry);
+ currentFile.Text = inf.CurrentProcess;
+ });
+ });
+
+ foreach (string entry in entrys)
+ {
+ string relativePath = entry.Remove(0, gameFolder.Length);
+ relativePath = relativePath.Replace('\\', '/');
+
+ if (Path.GetExtension(entry).ToUpperInvariant() == ".EDAT")
+ {
+ string edatContentId = GetContentIdFromPspEdat(entry);
+ string rifPath = Path.Combine(pspDir, "LICENSE", edatContentId + ".RIF");
+ if (!licenseFiles.Contains(rifPath) && File.Exists(rifPath))
+ licenseFiles.Add(rifPath);
}
- catch (Exception) { }
- Application.DoEvents();
+ bool isDir = File.GetAttributes(entry).HasFlag(FileAttributes.Directory);
+
+ if (isDir)
+ {
+ builder.AddDir(entry, parentPath, relativePath);
+ }
+ else
+ {
+ builder.AddFile(entry, parentPath, relativePath);
+ }
}
+
+ // add __sce_ebootpbp
+ if(!isDlc)
+ builder.AddFile(EbootSig, parentPath, "/__sce_ebootpbp");
+
+ long ContentSize = builder.Finish();
+
+ using (FileStream gamePsvmd = File.Open(psvmdFilepath, FileMode.Create, FileAccess.ReadWrite))
+ PSVMDBuilder.CreatePsvmd(gamePsvmd, gamePsvimg, ContentSize, "game", CmaKey);
}
- }
-
- long ContentSize = builder.Finish();
- gamePsvimg = File.OpenRead(psvimgFilepath);
- FileStream gamePsvmd = File.OpenWrite(psvmdFilepath);
- 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);
- foreach(string licenseFile in licenseFiles)
- builder.AddFile(licenseFile, "ux0:pspemu/temp/game/PSP/LICENSE", "/" + Path.GetFileNameWithoutExtension(licenseFile) + ".rif");
- ContentSize = builder.Finish();
-
- licensePsvimg = File.OpenRead(psvimgFilepathl);
- FileStream licensePsvmd = File.OpenWrite(psvmdFilepathl);
- PSVMDBuilder.CreatePsvmd(licensePsvmd, licensePsvimg, ContentSize, "license", CmaKey);
- licensePsvmd.Close();
- licensePsvimg.Close();
+ // Package LICENSE
+ 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");
+ long ContentSize = builder.Finish();
+ using (FileStream licensePsvmd = File.Open(psvmdFilepathLicense, FileMode.Create, FileAccess.ReadWrite))
+ PSVMDBuilder.CreatePsvmd(licensePsvmd, licensePsvimg, ContentSize, "license", CmaKey);
+ }
+ });
+
// Write PARAM.SFO & ICON0.PNG
byte[] ParamSfo = GetSfo(ebootFile);
diff --git a/CHOVY-TRANSFER/CHOVYTRANSFER.resx b/CHOVY-TRANSFER/CHOVYTRANSFER.resx
index fb7c757..ff44fd5 100644
--- a/CHOVY-TRANSFER/CHOVYTRANSFER.resx
+++ b/CHOVY-TRANSFER/CHOVYTRANSFER.resx
@@ -1,64 +1,4 @@
-
-
-
+
diff --git a/CHOVY-TRANSFER/Properties/AssemblyInfo.cs b/CHOVY-TRANSFER/Properties/AssemblyInfo.cs
index 89b2172..8cfac4e 100644
--- a/CHOVY-TRANSFER/Properties/AssemblyInfo.cs
+++ b/CHOVY-TRANSFER/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..9c7c088
--- /dev/null
+++ b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ Release
+ Any CPU
+ bin\Release\net6.0-windows\publish\win-x86\
+ FileSystem
+ <_TargetId>Folder
+ net6.0-windows
+ win-x86
+ true
+ true
+ true
+
+
\ No newline at end of file
diff --git a/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml.user b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml.user
new file mode 100644
index 0000000..5b523f4
--- /dev/null
+++ b/CHOVY-TRANSFER/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -0,0 +1,10 @@
+
+
+
+
+ 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;
+
+
+
\ No newline at end of file
diff --git a/CHOVY-TRANSFER/Properties/Resources.Designer.cs b/CHOVY-TRANSFER/Properties/Resources.Designer.cs
index d2bd39e..18c5fdc 100644
--- a/CHOVY-TRANSFER/Properties/Resources.Designer.cs
+++ b/CHOVY-TRANSFER/Properties/Resources.Designer.cs
@@ -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 {
diff --git a/CHOVY-TRANSFER/Properties/Settings.Designer.cs b/CHOVY-TRANSFER/Properties/Settings.Designer.cs
index 24a2001..54c4a3c 100644
--- a/CHOVY-TRANSFER/Properties/Settings.Designer.cs
+++ b/CHOVY-TRANSFER/Properties/Settings.Designer.cs
@@ -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())));
diff --git a/CHOVY-TRANSFER/Sfo.cs b/CHOVY-TRANSFER/Sfo.cs
new file mode 100644
index 0000000..dd7ed35
--- /dev/null
+++ b/CHOVY-TRANSFER/Sfo.cs
@@ -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 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();
+ }
+
+
+ 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);
+ }
+ }
+ }
+}
diff --git a/CHOVY-TRANSFER/packages.config b/CHOVY-TRANSFER/packages.config
deleted file mode 100644
index 5e69641..0000000
--- a/CHOVY-TRANSFER/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/CHOVY-TRANSFER/param.cs b/CHOVY-TRANSFER/param.cs
deleted file mode 100644
index d20730d..0000000
--- a/CHOVY-TRANSFER/param.cs
+++ /dev/null
@@ -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 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);
- }
-
-
- ///
- /// This is the SaveSFO Function for PS3/PS4/PSVita/And PSP no longer needed for Sony's CMD
- ///
- /// SFO That has been opened
- /// Save Location
- 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 <>
-
- //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;
- }
-
- ///
- /// Start Reading the Parameter file
- ///
- /// Input Stream
- private void Init(Stream input)
- {
- using (var br = new BinaryReader(input))
- {
- Header.Read(br);
- var tables = new List();
- for (int i = 0; i < Header.IndexTableEntries; i++)
- {
- var t = new index_table();
- t.Read(br);
- tables.Add(t);
- }
- var xtables = new List();
- 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 >>
-
- }
-}
\ No newline at end of file
diff --git a/LiLib/LiLib.csproj b/LiLib/LiLib.csproj
new file mode 100644
index 0000000..132c02c
--- /dev/null
+++ b/LiLib/LiLib.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/LiLib/MathUtil.cs b/LiLib/MathUtil.cs
new file mode 100644
index 0000000..2f1783e
--- /dev/null
+++ b/LiLib/MathUtil.cs
@@ -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;
+ }
+ }
+}
diff --git a/LiLib/Progress/ProgressInfo.cs b/LiLib/Progress/ProgressInfo.cs
new file mode 100644
index 0000000..74e27c7
--- /dev/null
+++ b/LiLib/Progress/ProgressInfo.cs
@@ -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;
+ }
+ }
+}
diff --git a/LiLib/Progress/ProgressTracker.cs b/LiLib/Progress/ProgressTracker.cs
new file mode 100644
index 0000000..a69bcee
--- /dev/null
+++ b/LiLib/Progress/ProgressTracker.cs
@@ -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> progressCallbacks = new List>();
+
+ public void RegisterCallback(Action 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 cb in progressCallbacks)
+ cb(inf);
+ }
+ }
+}
diff --git a/LiLib/StreamUtil.cs b/LiLib/StreamUtil.cs
new file mode 100644
index 0000000..5fc228e
--- /dev/null
+++ b/LiLib/StreamUtil.cs
@@ -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);
+ }
+
+ }
+}
diff --git a/PspCrypto/AMCTRL.cs b/PspCrypto/AMCTRL.cs
new file mode 100644
index 0000000..36ac756
--- /dev/null
+++ b/PspCrypto/AMCTRL.cs
@@ -0,0 +1,710 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace PspCrypto
+{
+ public class AMCTRL
+ {
+ static readonly Memory kirk_buf = new byte[0x0814];
+ static readonly Memory 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 key
+ {
+ get
+ {
+ fixed (byte* ptr = _key)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+ private fixed byte _pad[16];
+
+ public Span pad
+ {
+ get
+ {
+ fixed (byte* ptr = _pad)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+ public int pad_size;
+ }
+
+ public unsafe struct CIPHER_KEY
+ {
+ public int type;
+ public int seed;
+ fixed byte _key[16];
+
+ public Span key
+ {
+ get
+ {
+ fixed (byte* ptr = _key)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+ }
+
+ /*
+ * KIRK wrapper functions.
+ */
+ static int Kirk4(Span buf, int size, int type)
+ {
+ int retv;
+ ref var hdr = ref MemoryMarshal.AsRef(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 buf, int size)
+ {
+ int retv;
+ ref var hdr = ref MemoryMarshal.AsRef(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 buf, int size, int type)
+ {
+ int retv;
+ ref var hdr = ref MemoryMarshal.AsRef(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 buf, int size)
+ {
+ int retv;
+ ref var hdr = ref MemoryMarshal.AsRef(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 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 buf, int size, Span 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 buf, int size, Span key, int key_type)
+ {
+ int i, retv;
+ Span 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 kbuf, Span dbuf, int size, ref CIPHER_KEY ckey)
+ {
+ int i, retv;
+ Span 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 mkey, int type)
+ {
+ ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey);
+ macKey.type = type;
+ macKey.key.Clear();
+ macKey.pad.Clear();
+ return 0;
+ }
+
+ public static int sceDrmBBMacUpdate(Span mkey, ReadOnlySpan buf, int size)
+ {
+ ref MAC_KEY macKey = ref MemoryMarshal.AsRef(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 mkey, Span buf, int size)
+ {
+ ref MAC_KEY macKey = ref MemoryMarshal.AsRef(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 mkey, Span buf, ReadOnlySpan vkey)
+ {
+ ref MAC_KEY macKey = ref MemoryMarshal.AsRef(mkey);
+ int i, retv, code;
+ Span 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 mkey, ReadOnlySpan bbmac, Span vkey)
+ {
+ int i, retv, type, code;
+ Span tmp = stackalloc byte[16], tmp1 = stackalloc byte[16];
+ int kbuf;
+ ref MAC_KEY macKey = ref MemoryMarshal.AsRef(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 mkey, ReadOnlySpan hash, ReadOnlySpan vkey)
+ {
+ int retv, type;
+ byte[] tmp = new byte[16];
+ int kbuf;
+ ref MAC_KEY macKey = ref MemoryMarshal.AsRef(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 header_key, ReadOnlySpan 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 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;
+ }
+ }
+}
diff --git a/PspCrypto/AesHelper.cs b/PspCrypto/AesHelper.cs
new file mode 100644
index 0000000..0a7b99b
--- /dev/null
+++ b/PspCrypto/AesHelper.cs
@@ -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 dst, ReadOnlySpan 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 oubput, ReadOnlySpan 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(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 dst, ReadOnlySpan 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 src, Span dst, ReadOnlySpan key)
+ {
+ Aes aes = Aes.Create();
+ aes.Key = key[..16].ToArray();
+ return aes.DecryptEcb(src[..16], dst, PaddingMode.None);
+ }
+
+ public static int AesEncrypt(ReadOnlySpan src, Span dst, ReadOnlySpan key)
+ {
+ Aes aes = Aes.Create();
+ aes.Key = key[..16].ToArray();
+ return aes.EncryptEcb(src[..16], dst, PaddingMode.None);
+ }
+ }
+}
diff --git a/PspCrypto/AtracCrypto.cs b/PspCrypto/AtracCrypto.cs
new file mode 100644
index 0000000..898d2cd
--- /dev/null
+++ b/PspCrypto/AtracCrypto.cs
@@ -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 ptr = MemoryMarshal.Cast(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 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 ptr = MemoryMarshal.Cast(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 ptr = MemoryMarshal.Cast(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
+ }
+ }
+ }
+}
diff --git a/PspCrypto/DNASHelper.cs b/PspCrypto/DNASHelper.cs
new file mode 100644
index 0000000..088c79a
--- /dev/null
+++ b/PspCrypto/DNASHelper.cs
@@ -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 pgdData, ReadOnlySpan data, ReadOnlySpan 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(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(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 data, int size, ReadOnlySpan key, Span hash, int macType, int seed = 0)
+ {
+ Span mkey = stackalloc byte[Marshal.SizeOf()];
+ Span 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(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;
+ }
+ }
+}
diff --git a/PspCrypto/DNASStream.cs b/PspCrypto/DNASStream.cs
new file mode 100644
index 0000000..f3e6093
--- /dev/null
+++ b/PspCrypto/DNASStream.cs
@@ -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 _gMemory = new byte[0x640];
+ private static Memory _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 DescKey
+ {
+ get
+ {
+ fixed (byte* ptr = _descKey)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ private fixed byte _keyHash[0x10];
+ public Span KeyHash
+ {
+ get
+ {
+ fixed (byte* ptr = _keyHash)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ private fixed byte _pgdDesc[0x30];
+ public Span PgdDesc
+ {
+ get
+ {
+ fixed (byte* ptr = _pgdDesc)
+ {
+ return new Span(ptr, 0x30);
+ }
+ }
+ }
+ private fixed byte _macTableHash[0x10];
+ public Span MacTableHash
+ {
+ get
+ {
+ fixed (byte* ptr = _macTableHash)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ private fixed byte _hash70[0x10];
+ public Span Hash70
+ {
+ get
+ {
+ fixed (byte* ptr = _hash70)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ private fixed byte _hash80[0x10];
+ public Span Hash80
+ {
+ get
+ {
+ fixed (byte* ptr = _hash80)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ }
+
+ internal unsafe struct PgdDesc
+ {
+ private fixed byte _key[0x10];
+
+ public Span Key
+ {
+ get
+ {
+ fixed (byte* ptr = _key)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ public int Version;
+ public int DataSize;
+ public int BlockSize;
+ public int DataOffset;
+ private fixed byte _unk20[0x10];
+
+ public Span Unk20
+ {
+ get
+ {
+ fixed (byte* ptr = _unk20)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+
+ }
+
+ public int BlockSize => _desc.BlockSize;
+
+ public DNASStream(Stream stream, long pgdOffset, ReadOnlySpan 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 hdr = _gMemory[..0x90].Span;
+ var size = stream.Read(hdr);
+ if (size != 0x90)
+ {
+ throw new ArgumentException("stream too small", nameof(stream));
+ }
+ var header = MemoryMarshal.AsRef(hdr);
+ _keyIndex = header.KeyIndex;
+ if (_keyIndex == 1)
+ {
+ _versionKey = versionKey ?? new byte[16];
+ }
+ else
+ {
+ if (versionKey == null)
+ {
+ throw new ArgumentNullException(nameof(versionKey));
+ }
+ Span mkey = stackalloc byte[Marshal.SizeOf()];
+ 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(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 mkey = stackalloc byte[Marshal.SizeOf()];
+ ret = AMCTRL.sceDrmBBMacInit(mkey, macType);
+ stream.Seek(_tableOffset, SeekOrigin.Begin);
+ int read = 0;
+ if (tableSize != 0)
+ {
+ Span 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 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 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 data, int size, ReadOnlySpan key, ReadOnlySpan hash, int macType, int seed = 0)
+ {
+ Span mkey = stackalloc byte[Marshal.SizeOf()];
+ Span 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(tmpKey);
+ tmpXor[0] ^= seed;
+ }
+
+ ret = AMCTRL.sceDrmBBMacFinal2(mkey, hash, tmpKey);
+ if (ret != 0)
+ {
+ ret = unchecked((int)0x80510207);
+ }
+
+ }
+
+ return ret;
+ }
+
+ internal static int GetMacKey(ReadOnlySpan data, int size, Span key, ReadOnlySpan hash, int macType, int seed = 0)
+ {
+ Span mkey = stackalloc byte[Marshal.SizeOf()];
+ Span 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(tmpKey);
+ tmpXor[0] ^= seed;
+ }
+ tmpKey.CopyTo(key);
+
+ }
+
+ return ret;
+ }
+
+ internal static int DoBBCipher(Span data, int size, int seed, ReadOnlySpan versionKey,
+ ReadOnlySpan 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;
+ }
+ }
+}
diff --git a/PspCrypto/ECDsaHelper.cs b/PspCrypto/ECDsaHelper.cs
new file mode 100644
index 0000000..c8a57e3
--- /dev/null
+++ b/PspCrypto/ECDsaHelper.cs
@@ -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 pubx, Span 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 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 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 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 param, Span 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 data, Span 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);
+ }
+ }
+}
diff --git a/PspCrypto/KIRKEngine.cs b/PspCrypto/KIRKEngine.cs
new file mode 100644
index 0000000..b6d03de
--- /dev/null
+++ b/PspCrypto/KIRKEngine.cs
@@ -0,0 +1,1113 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace PspCrypto
+{
+ public static class KIRKEngine
+ {
+ // KIRK return values
+ public const int KIRK_OPERATION_SUCCESS = 0;
+ public const int KIRK_NOT_ENABLED = 1;
+ public const int KIRK_INVALID_MODE = 2;
+ public const int KIRK_HEADER_HASH_INVALID = 3;
+ public const int KIRK_DATA_HASH_INVALID = 4;
+ public const int KIRK_SIG_CHECK_INVALID = 5;
+ public const int KIRK_UNK_1 = 6;
+ public const int KIRK_UNK_2 = 7;
+ public const int KIRK_UNK_3 = 8;
+ public const int KIRK_UNK_4 = 9;
+ public const int KIRK_UNK_5 = 0xA;
+ public const int KIRK_UNK_6 = 0xB;
+ public const int KIRK_NOT_INITIALIZED = 0xC;
+ public const int KIRK_INVALID_OPERATION = 0xD;
+ public const int KIRK_INVALID_SEED_CODE = 0xE;
+ public const int KIRK_INVALID_SIZE = 0xF;
+ public const int KIRK_DATA_SIZE_ZERO = 0x10;
+
+ // sceUtilsBufferCopyWithRange modes
+ public const int KIRK_CMD_DECRYPT_PRIVATE = 1;
+ public const int KIRK_CMD_2 = 2;
+ public const int KIRK_CMD_3 = 3;
+ public const int KIRK_CMD_ENCRYPT_IV_0 = 4;
+ public const int KIRK_CMD_ENCRYPT_IV_FUSE = 5;
+ public const int KIRK_CMD_ENCRYPT_IV_USER = 6;
+ public const int KIRK_CMD_DECRYPT_IV_0 = 7;
+ public const int KIRK_CMD_DECRYPT_IV_FUSE = 8;
+ public const int KIRK_CMD_DECRYPT_IV_USER = 9;
+ public const int KIRK_CMD_PRIV_SIGN_CHECK = 10;
+ public const int KIRK_CMD_SHA1_HASH = 11;
+ public const int KIRK_CMD_ECDSA_GEN_KEYS = 12;
+ public const int KIRK_CMD_ECDSA_MULTIPLY_POINT = 13;
+ public const int KIRK_CMD_PRNG = 14;
+ public const int KIRK_CMD_15 = 15;
+ public const int KIRK_CMD_ECDSA_SIGN = 16;
+ public const int KIRK_CMD_ECDSA_VERIFY = 17;
+
+ // KIRK header modes
+ public const int KIRK_MODE_CMD1 = 1;
+ public const int KIRK_MODE_CMD2 = 2;
+ public const int KIRK_MODE_CMD3 = 3;
+ public const int KIRK_MODE_ENCRYPT_CBC = 4;
+ public const int KIRK_MODE_DECRYPT_CBC = 5;
+
+ // sceUtilsBufferCopyWithRange errors
+ public const int SUBCWR_NOT_16_ALGINED = 0x90A;
+ public const int SUBCWR_HEADER_HASH_INVALID = 0x920;
+ public const int SUBCWR_BUFFER_TOO_SMALL = 0x1000;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct KIRK_AES128CBC_HEADER
+ {
+ public int mode;
+ public int unk_4;
+ public int unk_8;
+ public int keyseed;
+ public int data_size;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public unsafe struct KIRK_CMD1_HEADER
+ {
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ private fixed byte _AES_key[16];
+ public Span AES_Key
+ {
+ get
+ {
+ fixed (byte* ptr = _AES_key)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+ public Span AESKeys
+ {
+ get
+ {
+ fixed (byte* ptr = _AES_key)
+ {
+ return new Span(ptr, 32);
+ }
+ }
+ }
+
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ private fixed byte _CMAC_key[16]; // 0x10
+ public Span CMAC_key
+ {
+ get
+ {
+ fixed (byte* ptr = _CMAC_key)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ private fixed byte _CMAC_header_hash[16]; // 0x20
+ public Span CMAC_header_hash
+ {
+ get
+ {
+ fixed (byte* ptr = _CMAC_header_hash)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ private fixed byte _CMAC_data_hash[16]; // 0x30
+ public Span CMAC_data_hash
+ {
+ get
+ {
+ fixed (byte* ptr = _CMAC_data_hash)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+
+ public Span content
+ {
+ get
+ {
+ fixed (byte* ptr = unused)
+ {
+ return new Span(ptr, 0x40);
+ }
+ }
+ }
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ fixed byte unused[32]; // 0x40
+ public uint mode; // 0x60
+ public byte ecdsa_hash; // 0x64
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
+ fixed byte unk3[11]; // 0x65
+ public int data_size; // 0x70
+
+ public Span off70
+ {
+ get
+ {
+ fixed (int* ptr = &data_size)
+ {
+ return new Span(ptr, 0x10);
+ }
+ }
+ }
+ public int data_offset; // 0x74
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ fixed byte unk4[8]; // 0x78
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ fixed byte unk5[16]; // 0x80
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct KIRK_CMD1_ECDSA_HEADER
+ {
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ private fixed byte _AES_key[16];
+
+ public Span AES_Key
+ {
+ get
+ {
+ fixed (byte* ptr = _AES_key)
+ {
+ return new Span(ptr, 16);
+ }
+ }
+ }
+
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
+ private fixed byte _header_sig_r[20]; // 0x10
+
+ public Span header_sig_r
+ {
+ get
+ {
+ fixed (byte* ptr = _header_sig_r)
+ {
+ return new Span(ptr, 20);
+ }
+ }
+ }
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
+ private fixed byte _header_sig_s[20]; // 0x24
+
+ public Span header_sig_s
+ {
+ get
+ {
+ fixed (byte* ptr = _header_sig_s)
+ {
+ return new Span(ptr, 20);
+ }
+ }
+ }
+
+ public Span header_sig
+ {
+ get
+ {
+ fixed (byte* ptr = _header_sig_r)
+ {
+ return new Span(ptr, 40);
+ }
+ }
+ }
+
+
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
+ private fixed byte _data_sig_r[20]; // 0x38
+
+ public Span data_sig_r
+ {
+ get
+ {
+ fixed (byte* ptr = _data_sig_r)
+ {
+ return new Span(ptr, 20);
+ }
+ }
+ }
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
+ private fixed byte _data_sig_s[20]; // 0x4c
+ public Span data_sig_s
+ {
+ get
+ {
+ fixed (byte* ptr = _data_sig_s)
+ {
+ return new Span(ptr, 20);
+ }
+ }
+ }
+
+ public Span data_sig
+ {
+ get
+ {
+ fixed (byte* ptr = _data_sig_r)
+ {
+ return new Span(ptr, 40);
+ }
+ }
+ }
+
+
+ public uint mode; //0x60
+ public byte ecdsa_hash;
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
+ fixed byte unk3[11];
+ uint data_size;
+ uint data_offset;
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ fixed byte unk4[8];
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ fixed byte unk5[16];
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct ECDSA_SIG
+ {
+ private fixed byte _r[0x14];
+
+ public Span r
+ {
+ get
+ {
+ fixed (byte* ptr = _r)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+ private fixed byte _s[0x14];
+
+ public Span s
+ {
+ get
+ {
+ fixed (byte* ptr = _s)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+
+ public Span sig
+ {
+ get
+ {
+ fixed (byte* ptr = _r)
+ {
+ return new Span(ptr, 0x28);
+ }
+ }
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct ECDSA_POINT
+ {
+ private fixed byte _x[0x14];
+
+ public Span x
+ {
+ get
+ {
+ fixed (byte* ptr = _x)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+ private fixed byte _y[0x14];
+
+
+ public Span y
+ {
+ get
+ {
+ fixed (byte* ptr = _y)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+
+ public Span point
+ {
+ get
+ {
+ fixed (byte* ptr = _x)
+ {
+ return new Span(ptr, 0x28);
+ }
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct KIRK_SHA1_HEADER
+ {
+ public int data_size;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct KIRK_CMD12_BUFFER
+ {
+ private fixed byte private_key_[0x14];
+
+ public Span private_key
+ {
+ get
+ {
+ fixed (byte* ptr = private_key_)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+ public ECDSA_POINT public_key;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct KIRK_CMD13_BUFFER
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x14)]
+ public byte[] multiplier;
+ public ECDSA_POINT public_key;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct KIRK_CMD16_BUFFER
+ {
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
+ private fixed byte enc_private_[0x20];
+
+ public Span enc_private
+ {
+ get
+ {
+ fixed (byte* ptr = enc_private_)
+ {
+ return new Span(ptr, 0x20);
+ }
+ }
+ }
+ // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x14)]
+ private fixed byte message_hash_[0x14];
+
+ public Span message_hash
+ {
+ get
+ {
+ fixed (byte* ptr = message_hash_)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct KIRK_CMD17_BUFFER
+ {
+ public ECDSA_POINT public_key;
+ private fixed byte _message_hash[0x14];
+
+ public Span message_hash
+ {
+ get
+ {
+ fixed (byte* ptr = _message_hash)
+ {
+ return new Span(ptr, 0x14);
+ }
+ }
+ }
+ public ECDSA_SIG signature;
+ }
+ // KIRK commands
+ /*
+ // Private Sig + Cipher
+ 0x01: Super-Duper decryption (no inverse)
+ 0x02: Encrypt Operation (inverse of 0x03)
+ 0x03: Decrypt Operation (inverse of 0x02)
+
+ // Cipher
+ 0x04: Encrypt Operation (inverse of 0x07) (IV=0)
+ 0x05: Encrypt Operation (inverse of 0x08) (IV=FuseID)
+ 0x06: Encrypt Operation (inverse of 0x09) (IV=UserDefined)
+ 0x07: Decrypt Operation (inverse of 0x04)
+ 0x08: Decrypt Operation (inverse of 0x05)
+ 0x09: Decrypt Operation (inverse of 0x06)
+
+ // Sig Gens
+ 0x0A: Private Signature Check (checks for private SCE sig)
+ 0x0B: SHA1 Hash
+ 0x0C: Mul1
+ 0x0D: Mul2
+ 0x0E: Random Number Gen
+ 0x0F: (absolutely no idea could be KIRK initialization)
+ 0x10: Signature Gen
+
+ // Sig Checks
+ 0x11: Signature Check (checks for generated sigs)
+ 0x12: Certificate Check (idstorage signatures)
+ */
+
+ // Internal variables
+ [StructLayout(LayoutKind.Sequential)]
+ private unsafe struct kirk16_data
+ {
+ private fixed byte fuseid_[8];
+
+ public Span fuseid
+ {
+ get
+ {
+ fixed (byte* ptr = fuseid_)
+ {
+ return new Span(ptr, 8);
+ }
+ }
+ }
+ private fixed byte mesh_[0x40];
+
+ public Span mesh
+ {
+ get
+ {
+ fixed (byte* ptr = mesh_)
+ {
+ return new Span(ptr, 0x40);
+ }
+ }
+ }
+ }
+
+ //[StructLayout(LayoutKind.Sequential)]
+ //private unsafe struct header_keys
+ //{
+ // // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ // public fixed byte AES[16];
+ // // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ // public fixed byte CMAC[16];
+ //}
+
+ private static uint g_fuse90;
+ private static uint g_fuse94;
+
+ private static Aes aes_kirk1;
+ private static byte[] PRNG_DATA = new byte[0x14];
+
+ private static bool is_kirk_initialized;
+ private static readonly byte[] IV0 = new byte[16];
+
+ // Internal functions
+ private static byte[] kirk_4_7_get_key(int key_type)
+ {
+ if ((key_type < 0) || (key_type >= 0x80)) throw new Exception("KIRK_INVALID_SIZE");
+ return KeyVault.kirkKeys[key_type];
+ }
+
+ private static Aes CreateAes()
+ {
+ var aes_ctx = Aes.Create();
+ aes_ctx.Mode = CipherMode.CBC;
+ aes_ctx.Padding = PaddingMode.None;
+ aes_ctx.IV = IV0;
+ return aes_ctx;
+ }
+
+ public static void decrypt_kirk16_private(Span dA_out, Span dA_enc)
+ {
+ int i, k;
+ kirk16_data keydata;
+ byte[] subkey_1 = new byte[0x10], subkey_2 = new byte[0x10];
+ using var aes_ctx = CreateAes();
+
+ keydata.fuseid[7] = (byte)(g_fuse90 & 0xFF);
+ keydata.fuseid[6] = (byte)((g_fuse90 >> 8) & 0xFF);
+ keydata.fuseid[5] = (byte)((g_fuse90 >> 16) & 0xFF);
+ keydata.fuseid[4] = (byte)((g_fuse90 >> 24) & 0xFF);
+ keydata.fuseid[3] = (byte)(g_fuse94 & 0xFF);
+ keydata.fuseid[2] = (byte)((g_fuse94 >> 8) & 0xFF);
+ keydata.fuseid[1] = (byte)((g_fuse94 >> 16) & 0xFF);
+ keydata.fuseid[0] = (byte)((g_fuse94 >> 24) & 0xFF);
+
+ /* set encryption key */
+ aes_ctx.Key = KeyVault.kirk16_key;
+
+ /* set the subkeys */
+ for (i = 0; i < 0x10; i++)
+ {
+ /* set to the fuseid */
+ subkey_2[i] = subkey_1[i] = keydata.fuseid[i % 8];
+ }
+ /* do aes crypto */
+ using (var encryptor = aes_ctx.CreateEncryptor())
+ {
+ using var decryptor = aes_ctx.CreateDecryptor();
+ for (i = 0; i < 3; i++)
+ {
+ /* encrypt + decrypt */
+ encryptor.TransformBlock(subkey_1, 0, subkey_1.Length, subkey_1, 0);
+ decryptor.TransformBlock(subkey_2, 0, subkey_2.Length, subkey_2, 0);
+ }
+ }
+
+ /* set new key */
+ aes_ctx.Key = subkey_1;
+ using (var encryptor = aes_ctx.CreateEncryptor())
+ {
+ /* now lets make the key mesh */
+ for (i = 0; i < 3; i++)
+ {
+ /* do encryption in group of 3 */
+ for (k = 0; k < 3; k++)
+ {
+ /* crypto */
+ encryptor.TransformBlock(subkey_2, 0, subkey_2.Length, subkey_2, 0);
+ }
+
+ /* copy to out block */
+ subkey_2.AsSpan().CopyTo(keydata.mesh[(i * 0x10)..]);
+ }
+ }
+
+ /* set the key to the mesh */
+ aes_ctx.Key = keydata.mesh.Slice(0x20, 0x10).ToArray();
+
+ using (var encryptor = aes_ctx.CreateEncryptor())
+ {
+ /* do the encryption routines for the aes key */
+ for (i = 0; i < 2; i++)
+ {
+ /* encrypt the data */
+ var tmp = encryptor.TransformFinalBlock(keydata.mesh.ToArray(), 0x10, 0x30);
+ tmp.CopyTo(keydata.mesh[0x10..]);
+ }
+ }
+
+ /* set the key to that mesh shit */
+ using var aes = CreateAes();
+ aes.Key = keydata.mesh.Slice(0x10, 0x10).ToArray();
+
+
+ /* cbc decrypt the dA */
+ AesHelper.AesDecrypt(aes, dA_out, dA_enc, 0x20);
+ }
+
+ public static void encrypt_kirk16_private(Span dA_out, Span dA_dec)
+ {
+ int i, k;
+ kirk16_data keydata;
+ byte[] subkey_1 = new byte[0x10], subkey_2 = new byte[0x10];
+ using var aes_ctx = CreateAes();
+
+ keydata.fuseid[7] = (byte)(g_fuse90 & 0xFF);
+ keydata.fuseid[6] = (byte)((g_fuse90 >> 8) & 0xFF);
+ keydata.fuseid[5] = (byte)((g_fuse90 >> 16) & 0xFF);
+ keydata.fuseid[4] = (byte)((g_fuse90 >> 24) & 0xFF);
+ keydata.fuseid[3] = (byte)(g_fuse94 & 0xFF);
+ keydata.fuseid[2] = (byte)((g_fuse94 >> 8) & 0xFF);
+ keydata.fuseid[1] = (byte)((g_fuse94 >> 16) & 0xFF);
+ keydata.fuseid[0] = (byte)((g_fuse94 >> 24) & 0xFF);
+
+ /* set encryption key */
+ aes_ctx.Key = KeyVault.kirk16_key;
+
+ /* set the subkeys */
+ for (i = 0; i < 0x10; i++)
+ {
+ /* set to the fuseid */
+ subkey_2[i] = subkey_1[i] = keydata.fuseid[i % 8];
+ }
+ /* do aes crypto */
+ using (var encryptor = aes_ctx.CreateEncryptor())
+ {
+ using var decryptor = aes_ctx.CreateDecryptor();
+ for (i = 0; i < 3; i++)
+ {
+ /* encrypt + decrypt */
+ subkey_1 = encryptor.TransformFinalBlock(subkey_1, 0, subkey_1.Length);
+ subkey_2 = decryptor.TransformFinalBlock(subkey_2, 0, subkey_2.Length);
+ }
+ }
+
+ /* set new key */
+ aes_ctx.Key = subkey_1;
+ using (var encryptor = aes_ctx.CreateEncryptor())
+ {
+ /* now lets make the key mesh */
+ for (i = 0; i < 3; i++)
+ {
+ /* do encryption in group of 3 */
+ for (k = 0; k < 3; k++)
+ {
+ /* crypto */
+ encryptor.TransformBlock(subkey_2, 0, subkey_2.Length, subkey_2, 0);
+ }
+
+ /* copy to out block */
+ subkey_2.AsSpan().CopyTo(keydata.mesh.Slice(i * 0x10));
+ }
+ }
+
+ /* set the key to the mesh */
+ aes_ctx.Key = keydata.mesh.Slice(0x20, 0x10).ToArray();
+
+ using (var encryptor = aes_ctx.CreateEncryptor())
+ {
+ /* do the encryption routines for the aes key */
+ for (i = 0; i < 2; i++)
+ {
+ /* encrypt the data */
+ var tmp = encryptor.TransformFinalBlock(keydata.mesh.ToArray(), 0x10, 0x30);
+ tmp.CopyTo(keydata.mesh.Slice(0x10));
+ }
+ }
+
+ /* set the key to that mesh shit */
+ using var aes = CreateAes();
+ aes.Key = keydata.mesh.Slice(0x10, 0x10).ToArray();
+
+
+ /* cbc encrypt the dA */
+ AesHelper.AesEncrypt(aes, dA_out, dA_dec, 0x20);
+ }
+
+ static KIRKEngine()
+ {
+ kirk_init();
+ }
+
+ // KIRK commands
+
+ public static int kirk_init()
+ {
+ //94 90
+ //0x0000332 e6e050311 3000
+ //0x0000772 ccda50f12 2000
+ //0x1008010 1ef1e7101 vita
+ return kirk_init2(Encoding.ASCII.GetBytes("Lazy Dev should have initialized!"), 33, 0xBABEF00D, 0xDEADBEEF);
+ }
+
+ public static int kirk_init2(byte[] rnd_seed, int seed_size, uint fuseid_90, uint fuseid_94)
+ {
+ Span temp = stackalloc byte[0x104];
+
+ // Another randomly selected data for a "key" to add to each randomization
+ ReadOnlySpan key = stackalloc byte[] { 0x07, 0xAB, 0xEF, 0xF8, 0x96, 0x8C, 0xF3, 0xD6, 0x14, 0xE0, 0xEB, 0xB2, 0x9D, 0x8B, 0x4E, 0x74 };
+ uint curtime;
+
+ is_kirk_initialized = true;
+
+ //Set PRNG_DATA initially, otherwise use what ever uninitialized data is in the buffer
+ if (seed_size > 0)
+ {
+ Span seedbuf = stackalloc byte[seed_size + 4];
+ RandomNumberGenerator.Fill(seedbuf);
+ var seedheader = new KIRK_SHA1_HEADER
+ {
+ data_size = seed_size
+ };
+ MemoryMarshal.Write(seedbuf, ref seedheader);
+ kirk_CMD11(PRNG_DATA, seedbuf, seed_size + 4);
+ }
+ // Buffer.BlockCopy(PRNG_DATA, 0, header.data, 0, 0x14);
+ PRNG_DATA.CopyTo(temp.Slice(4));
+
+ // This uses the standard C time function for portability.
+ curtime = (uint)DateTimeOffset.Now.ToUnixTimeMilliseconds();
+ temp[0x18] = (byte)(curtime & 0xFF);
+ temp[0x19] = (byte)((curtime >> 8) & 0xFF);
+ temp[0x1A] = (byte)((curtime >> 16) & 0xFF);
+ temp[0x1B] = (byte)((curtime >> 24) & 0xFF);
+ // Buffer.BlockCopy(key, 0, header.data, 0x18, 0x10);
+ key.CopyTo(temp.Slice(0x1c));
+
+ // This leaves the remainder of the 0x100 bytes in temp to whatever remains on the stack
+ // in an uninitialized state. This should add unpredicableness to the results as well
+
+ var header = new KIRK_SHA1_HEADER
+ {
+ data_size = 0x100
+ };
+ MemoryMarshal.Write(temp, ref header);
+ kirk_CMD11(PRNG_DATA, temp, 0x104);
+
+
+ //Set Fuse ID
+ g_fuse90 = fuseid_90;
+ g_fuse94 = fuseid_94;
+
+ // Set KIRK1 main key
+ aes_kirk1 = CreateAes();
+ aes_kirk1.Key = KeyVault.kirk1_key;
+ return 0;
+ }
+
+ static int kirk_CMD0(Span outbuff, ReadOnlySpan inbuff, int size, bool generate_trash)
+ {
+ KIRK_CMD1_HEADER header = MemoryMarshal.AsRef(outbuff);
+ // header_keys keys = Utils.AsRef(outbuff);
+ int chk_size;
+ Aes k1;
+ Aes cmac_key;
+
+ if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED;
+
+ inbuff[..size].CopyTo(outbuff);
+
+ if (header.mode != KIRK_MODE_CMD1) return KIRK_INVALID_MODE;
+
+ // FILL PREDATA WITH RANDOM DATA
+ if (generate_trash) kirk_CMD14(outbuff[Unsafe.SizeOf()..], header.data_offset);
+
+ // Make sure data is 16 aligned
+ chk_size = header.data_size;
+ if (chk_size % 16 != 0) chk_size += 16 - (chk_size % 16);
+
+ // ENCRYPT DATA
+
+ // ENCRYPT DATA
+ using (k1 = CreateAes())
+ {
+ k1.Key = header.AES_Key.ToArray();
+ AesHelper.AesEncrypt(k1, outbuff[(Unsafe.SizeOf() + header.data_offset)..],
+ inbuff.Slice(Unsafe.SizeOf() + header.data_offset, header.data_size));
+ //byte[] encData = AesHelper.AesEncrypt(k1, inbuff.ToArray(),
+ // Unsafe.SizeOf() + header.data_offset,
+ // chk_size);
+ //encData.CopyTo(outbuff.Slice(Unsafe.SizeOf() + header.data_offset));
+ }
+
+
+ // CMAC HASHES
+ using (cmac_key = CreateAes())
+ {
+ cmac_key.Key = header.CMAC_key.ToArray();
+ //var cmac_header_hash = AesHelper.Cmac(cmac_key, outbuff.ToArray(), 0x60, 0x30);
+ //var cmac_data_hash = AesHelper.Cmac(cmac_key, outbuff.ToArray(), 0x60, 0x30 + chk_size);
+ Span cmac_header_hash = stackalloc byte[16];
+ Span cmac_data_hash = stackalloc byte[16];
+ AesHelper.Cmac(cmac_key, cmac_header_hash, outbuff.Slice(0x60, 0x30));
+ AesHelper.Cmac(cmac_key, cmac_data_hash, outbuff.Slice(0x60, 0x30 + chk_size));
+ cmac_header_hash.CopyTo(header.CMAC_header_hash);
+ cmac_data_hash.CopyTo(header.CMAC_data_hash);
+ }
+
+ // ENCRYPT KEYS
+ // AesHelper.AesEncrypt(aes_kirk1)
+ return KIRK_OPERATION_SUCCESS;
+ }
+
+ static int kirk_CMD1(Span outbuff, ReadOnlySpan inbuff, int size)
+ {
+ KIRK_CMD1_HEADER header = MemoryMarshal.AsRef(inbuff);
+ // header_keys keys; //0-15 AES key, 16-31 CMAC key
+ Aes k1;
+
+ if (size < 0x90) return KIRK_INVALID_SIZE;
+ if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED;
+ if (header.mode != KIRK_MODE_CMD1) return KIRK_INVALID_MODE;
+ // byte[] keytmp = AesHelper.AesDecrypt(aes_kirk1, inbuff.ToArray(), 0, 32);
+ Span keytmp = stackalloc byte[32];
+ AesHelper.AesDecrypt(aes_kirk1, keytmp, inbuff, 32);
+
+
+ if (header.ecdsa_hash == 1)
+ {
+ KIRK_CMD1_ECDSA_HEADER eheader = MemoryMarshal.AsRef(inbuff);
+ var curve = ECDsaHelper.SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b1, KeyVault.ec_N1, KeyVault.Gx1,
+ KeyVault.Gy1);
+ unsafe
+ {
+ var ecdsa = ECDsaHelper.Create(curve, KeyVault.ec_Priv1);
+ if (!ecdsa.VerifyData(inbuff.Slice(0x60, 0x30), eheader.header_sig.ToArray(),
+ HashAlgorithmName.SHA1))
+ {
+ return KIRK_HEADER_HASH_INVALID;
+ }
+ ecdsa = ECDsaHelper.Create(curve, KeyVault.ec_Priv1);
+ if (!ecdsa.VerifyData(inbuff[0x60..size], eheader.data_sig.ToArray(), HashAlgorithmName.SHA1))
+ {
+ return KIRK_DATA_HASH_INVALID;
+ }
+ }
+ }
+ else
+ {
+ int ret = kirk_CMD10(inbuff, size);
+ if (ret != KIRK_OPERATION_SUCCESS) return ret;
+ }
+
+ k1 = CreateAes();
+ k1.Key = keytmp.Slice(0, 16).ToArray();
+ //var outtmp = AesHelper.AesDecrypt(k1, inbuff.ToArray(), Unsafe.SizeOf() + header.data_offset, header.data_size);
+ // Buffer.BlockCopy(outtmp, 0, outbuff, 0, (int)header.data_size);
+
+ AesHelper.AesDecrypt(k1, outbuff, inbuff.Slice(Unsafe.SizeOf() + header.data_offset), header.data_size);
+
+ return KIRK_OPERATION_SUCCESS;
+ }
+
+ static int kirk_CMD4(Span outbuff, ReadOnlySpan inbuff, int size)
+ {
+ KIRK_AES128CBC_HEADER header = MemoryMarshal.AsRef(inbuff);
+ byte[] key;
+ Aes aes;
+
+ if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED;
+ if (header.mode != KIRK_MODE_ENCRYPT_CBC) return KIRK_INVALID_MODE;
+ if (header.data_size == 0) return KIRK_DATA_SIZE_ZERO;
+ // size = size - 20;
+ using (aes = CreateAes())
+ {
+ key = kirk_4_7_get_key(header.keyseed);
+
+ // Set the key
+ aes.Key = key;
+ //var enc = AesHelper.AesEncrypt(aes, inbuff.ToArray(), Unsafe.SizeOf(), size);
+ // Buffer.BlockCopy(enc, 0, outbuff, Marshal.SizeOf() + outOffset, size);
+ //enc.AsSpan(0, size).CopyTo(outbuff.Slice(Unsafe.SizeOf(), size));
+ AesHelper.AesEncrypt(aes, outbuff.Slice(Unsafe.SizeOf()),
+ inbuff.Slice(Unsafe.SizeOf(), header.data_size));
+ }
+ return KIRK_OPERATION_SUCCESS;
+ }
+
+ static int kirk_CMD7(Span outbuff, ReadOnlySpan inbuff, int size)
+ {
+ KIRK_AES128CBC_HEADER header = MemoryMarshal.AsRef(inbuff);
+ byte[] key;
+ Aes aes;
+
+ if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED;
+ if (header.mode != KIRK_MODE_DECRYPT_CBC) return KIRK_INVALID_MODE;
+ if (header.data_size == 0) return KIRK_DATA_SIZE_ZERO;
+ using (aes = CreateAes())
+ {
+ key = kirk_4_7_get_key(header.keyseed);
+
+ // Set the key
+ aes.Key = key;
+ //var enc = AesHelper.AesDecrypt(aes, inbuff.ToArray(), Unsafe.SizeOf(), header.data_size);
+ //Buffer.BlockCopy(enc, 0, outbuff, outOffset, header.data_size);
+ //enc.AsSpan(0, header.data_size).CopyTo(outbuff);
+ AesHelper.AesDecrypt(aes, outbuff, inbuff.Slice(Unsafe.SizeOf()), header.data_size);
+ }
+ return KIRK_OPERATION_SUCCESS;
+ }
+
+ static int kirk_CMD10(ReadOnlySpan inbuff, int insize)
+ {
+ KIRK_CMD1_HEADER header = MemoryMarshal.AsRef