/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.crypto; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class PRX { private static KIRK kirk; public PRX() { kirk = new KIRK(); } // PRXDecrypter TAG struct. private class TAG_INFO { int tag; // 4 byte value at offset 0xD0 in the PRX file int[] key; // 144 bytes keys int code; // code for scramble int codeExtra; // code extra for scramble (old tags) public TAG_INFO(int tag, int[] key, int code, int codeExtra) { this.tag = tag; this.key = intArrayToTagArray(key); this.code = code; this.codeExtra = codeExtra; } public TAG_INFO(int tag, int[] key, int code) { this.tag = tag; this.key = key; this.code = code; this.codeExtra = 0; } private int[] intArrayToTagArray(int[] array) { int[] tagArray = new int[144]; for (int i = 0; i < array.length; i++) { tagArray[i * 4 + 3] = ((array[i] >> 24) & 0xFF); tagArray[i * 4 + 2] = ((array[i] >> 16) & 0xFF); tagArray[i * 4 + 1] = ((array[i] >> 8) & 0xFF); tagArray[i * 4 + 0] = (array[i] & 0xFF); } return tagArray; } } private TAG_INFO g_tagInfo[] = { new TAG_INFO(0x4C949CF0, KeyVault.keys210_vita_k0, 0x43), new TAG_INFO(0x4C9494F0, KeyVault.keys660_k1, 0x43), new TAG_INFO(0x4C9495F0, KeyVault.keys660_k2, 0x43), new TAG_INFO(0x4C9490F0, KeyVault.keys660_k3, 0x43), new TAG_INFO(0x4C9491F0, KeyVault.keys660_k8, 0x43), new TAG_INFO(0x4C9493F0, KeyVault.keys660_k4, 0x43), new TAG_INFO(0x4C9497F0, KeyVault.keys660_k5, 0x43), new TAG_INFO(0x4C9492F0, KeyVault.keys660_k6, 0x43), new TAG_INFO(0x4C9496F0, KeyVault.keys660_k7, 0x43), new TAG_INFO(0x457B90F0, KeyVault.keys660_v1, 0x5B), new TAG_INFO(0x457B91F0, KeyVault.keys660_v7, 0x5B), new TAG_INFO(0x457B92F0, KeyVault.keys660_v6, 0x5B), new TAG_INFO(0x457B93F0, KeyVault.keys660_v3, 0x5B), new TAG_INFO(0x380290F0, KeyVault.keys660_v2, 0x5A), new TAG_INFO(0x380291F0, KeyVault.keys660_v8, 0x5A), new TAG_INFO(0x380292F0, KeyVault.keys660_v4, 0x5A), new TAG_INFO(0x380293F0, KeyVault.keys660_v5, 0x5A), new TAG_INFO(0x4C948CF0, KeyVault.keys639_k3, 0x43), new TAG_INFO(0x4C948DF0, KeyVault.keys638_k4, 0x43), new TAG_INFO(0x4C948BF0, KeyVault.keys636_k2, 0x43), new TAG_INFO(0x4C948AF0, KeyVault.keys636_k1, 0x43), new TAG_INFO(0x457B8AF0, KeyVault.keys636_1, 0x5B), new TAG_INFO(0x4C9487F0, KeyVault.keys630_k8, 0x43), new TAG_INFO(0x457B83F0, KeyVault.keys630_k7, 0x5B), new TAG_INFO(0x4C9486F0, KeyVault.keys630_k6, 0x43), new TAG_INFO(0x457B82F0, KeyVault.keys630_k5, 0x5B), new TAG_INFO(0x457B81F0, KeyVault.keys630_k4, 0x5B), new TAG_INFO(0x4C9485F0, KeyVault.keys630_k3, 0x43), new TAG_INFO(0x457B80F0, KeyVault.keys630_k2, 0x5B), new TAG_INFO(0x4C9484F0, KeyVault.keys630_k1, 0x43), new TAG_INFO(0x457B28F0, KeyVault.keys620_e, 0x5B), new TAG_INFO(0x457B0CF0, KeyVault.keys620_a, 0x5B), new TAG_INFO(0x380228F0, KeyVault.keys620_5v, 0x5A), new TAG_INFO(0x4C942AF0, KeyVault.keys620_5k, 0x43), new TAG_INFO(0x4C9428F0, KeyVault.keys620_5, 0x43), new TAG_INFO(0x4C941DF0, KeyVault.keys620_1, 0x43), new TAG_INFO(0x4C941CF0, KeyVault.keys620_0, 0x43), new TAG_INFO(0x4C9422F0, KeyVault.keys600_2, 0x43), new TAG_INFO(0x4C941EF0, KeyVault.keys600_1, 0x43), new TAG_INFO(0x4C9429F0, KeyVault.keys570_5k, 0x43), new TAG_INFO(0x457B0BF0, KeyVault.keys505_a, 0x5B), new TAG_INFO(0x4C9419F0, KeyVault.keys505_1, 0x43), new TAG_INFO(0x4C9418F0, KeyVault.keys505_0, 0x43), new TAG_INFO(0x457B1EF0, KeyVault.keys500_c, 0x5B), new TAG_INFO(0x4C941FF0, KeyVault.keys500_2, 0x43), new TAG_INFO(0x4C9417F0, KeyVault.keys500_1, 0x43), new TAG_INFO(0x4C9416F0, KeyVault.keys500_0, 0x43), new TAG_INFO(0x4C9414F0, KeyVault.keys390_0, 0x43), new TAG_INFO(0x4C9415F0, KeyVault.keys390_1, 0x43), new TAG_INFO(0x4C9412F0, KeyVault.keys370_0, 0x43), new TAG_INFO(0x4C9413F0, KeyVault.keys370_1, 0x43), new TAG_INFO(0x457B10F0, KeyVault.keys370_2, 0x5B), new TAG_INFO(0x4C940DF0, KeyVault.keys360_0, 0x43), new TAG_INFO(0x4C9410F0, KeyVault.keys360_1, 0x43), new TAG_INFO(0x4C940BF0, KeyVault.keys330_0, 0x43), new TAG_INFO(0x457B0AF0, KeyVault.keys330_1, 0x5B), new TAG_INFO(0x38020AF0, KeyVault.keys330_2, 0x5A), new TAG_INFO(0x4C940AF0, KeyVault.keys330_3, 0x43), new TAG_INFO(0x4C940CF0, KeyVault.keys330_4, 0x43), new TAG_INFO(0xcfef09f0, KeyVault.keys310_0, 0x62), new TAG_INFO(0x457b08f0, KeyVault.keys310_1, 0x5B), new TAG_INFO(0x380208F0, KeyVault.keys310_2, 0x5A), new TAG_INFO(0xcfef08f0, KeyVault.keys310_3, 0x62), new TAG_INFO(0xCFEF07F0, KeyVault.keys303_0, 0x62), new TAG_INFO(0xCFEF06F0, KeyVault.keys300_0, 0x62), new TAG_INFO(0x457B06F0, KeyVault.keys300_1, 0x5B), new TAG_INFO(0x380206F0, KeyVault.keys300_2, 0x5A), new TAG_INFO(0xCFEF05F0, KeyVault.keys280_0, 0x62), new TAG_INFO(0x457B05F0, KeyVault.keys280_1, 0x5B), new TAG_INFO(0x380205F0, KeyVault.keys280_2, 0x5A), new TAG_INFO(0x16D59E03, KeyVault.keys260_0, 0x62), new TAG_INFO(0x76202403, KeyVault.keys260_1, 0x5B), new TAG_INFO(0x0F037303, KeyVault.keys260_2, 0x5A), new TAG_INFO(0x4C940FF0, KeyVault.key_2DA8, 0x43), new TAG_INFO(0x4467415D, KeyVault.key_22E0, 0x59), new TAG_INFO(0x00000000, KeyVault.key_21C0, 0x42), new TAG_INFO(0x01000000, KeyVault.key_2250, 0x43), new TAG_INFO(0x2E5E10F0, KeyVault.key_2E5E10F0, 0x48), new TAG_INFO(0x2E5E12F0, KeyVault.key_2E5E12F0, 0x48), new TAG_INFO(0x2E5E13F0, KeyVault.key_2E5E13F0, 0x48), new TAG_INFO(0x2FD30BF0, KeyVault.key_2FD30BF0, 0x47), new TAG_INFO(0x2FD311F0, KeyVault.key_2FD311F0, 0x47), new TAG_INFO(0x2FD312F0, KeyVault.key_2FD312F0, 0x47), new TAG_INFO(0x2FD313F0, KeyVault.key_2FD313F0, 0x47), new TAG_INFO(0xD91605F0, KeyVault.key_D91605F0, 0x5D), new TAG_INFO(0xD91606F0, KeyVault.key_D91606F0, 0x5D), new TAG_INFO(0xD91608F0, KeyVault.key_D91608F0, 0x5D), new TAG_INFO(0xD91609F0, KeyVault.key_D91609F0, 0x5D), new TAG_INFO(0xD9160AF0, KeyVault.key_D9160AF0, 0x5D), new TAG_INFO(0xD9160BF0, KeyVault.key_D9160BF0, 0x5D), new TAG_INFO(0xD91611F0, KeyVault.key_D91611F0, 0x5D), new TAG_INFO(0xD91612F0, KeyVault.key_D91612F0, 0x5D), new TAG_INFO(0xD91613F0, KeyVault.key_D91613F0, 0x5D), new TAG_INFO(0xD91614F0, KeyVault.key_D91614F0, 0x5D), new TAG_INFO(0xD91615F0, KeyVault.key_D91615F0, 0x5D), new TAG_INFO(0xD91616F0, KeyVault.key_D91616F0, 0x5D), new TAG_INFO(0xD91617F0, KeyVault.key_D91617F0, 0x5D), new TAG_INFO(0xD91618F0, KeyVault.key_D91618F0, 0x5D), new TAG_INFO(0xD91619F0, KeyVault.key_D91619F0, 0x5D), new TAG_INFO(0xD9161AF0, KeyVault.key_D9161AF0, 0x5D), new TAG_INFO(0xD91620F0, KeyVault.key_D91620F0, 0x5D), new TAG_INFO(0xD91621F0, KeyVault.key_D91621F0, 0x5D), new TAG_INFO(0xD91622F0, KeyVault.key_D91622F0, 0x5D), new TAG_INFO(0xD91623F0, KeyVault.key_D91623F0, 0x5D), new TAG_INFO(0xD91624F0, KeyVault.key_D91624F0, 0x5D), new TAG_INFO(0xD91628F0, KeyVault.key_D91628F0, 0x5D), new TAG_INFO(0xD91680F0, KeyVault.key_D91680F0, 0x5D), new TAG_INFO(0xD91681F0, KeyVault.key_D91681F0, 0x5D), new TAG_INFO(0xD82310F0, KeyVault.keys02G_E, 0x51), new TAG_INFO(0xD8231EF0, KeyVault.keys03G_E, 0x51), new TAG_INFO(0xD82328F0, KeyVault.keys05G_E, 0x51), new TAG_INFO(0x279D08F0, KeyVault.oneseg_310, 0x61), new TAG_INFO(0x279D06F0, KeyVault.oneseg_300, 0x61), new TAG_INFO(0x279D05F0, KeyVault.oneseg_280, 0x61), new TAG_INFO(0xD66DF703, KeyVault.oneseg_260_271, 0x61), new TAG_INFO(0x279D10F0, KeyVault.oneseg_slim, 0x61), new TAG_INFO(0x3C2A08F0, KeyVault.ms_app_main, 0x67), new TAG_INFO(0xADF305F0, KeyVault.demokeys_280, 0x60), new TAG_INFO(0xADF306F0, KeyVault.demokeys_3XX_1, 0x60), new TAG_INFO(0xADF308F0, KeyVault.demokeys_3XX_2, 0x60), new TAG_INFO(0x8004FD03, KeyVault.ebootbin_271_new, 0x5D), new TAG_INFO(0xD91605F0, KeyVault.ebootbin_280_new, 0x5D), new TAG_INFO(0xD91606F0, KeyVault.ebootbin_300_new, 0x5D), new TAG_INFO(0xD91608F0, KeyVault.ebootbin_310_new, 0x5D), new TAG_INFO(0x0A35EA03, KeyVault.gameshare_260_271, 0x5E), new TAG_INFO(0x7B0505F0, KeyVault.gameshare_280, 0x5E), new TAG_INFO(0x7B0506F0, KeyVault.gameshare_300, 0x5E), new TAG_INFO(0x7B0508F0, KeyVault.gameshare_310, 0x5E), new TAG_INFO(0x380210F0, KeyVault.key_380210F0, 0x5A), new TAG_INFO(0x380280F0, KeyVault.key_380280F0, 0x5A), new TAG_INFO(0x380283F0, KeyVault.key_380283F0, 0x5A), new TAG_INFO(0x407810F0, KeyVault.key_407810F0, 0x6A), new TAG_INFO(0xE92410F0, KeyVault.drmkeys_6XX_1, 0x40), new TAG_INFO(0x692810F0, KeyVault.drmkeys_6XX_2, 0x40), new TAG_INFO(0x00000000, KeyVault.g_key0, 0x42, 0x00), new TAG_INFO(0x02000000, KeyVault.g_key2, 0x45, 0x00), new TAG_INFO(0x03000000, KeyVault.g_key3, 0x46, 0x00), new TAG_INFO(0x4467415d, KeyVault.g_key44, 0x59, 0x59), new TAG_INFO(0x207bbf2f, KeyVault.g_key20, 0x5A, 0x5A), new TAG_INFO(0x3ace4dce, KeyVault.g_key3A, 0x5B, 0x5B), new TAG_INFO(0x07000000, KeyVault.g_key_INDEXDAT1xx, 0x4A), new TAG_INFO(0x08000000, KeyVault.g_keyEBOOT1xx, 0x4B, 0x00), new TAG_INFO(0xC0CB167C, KeyVault.g_keyEBOOT2xx, 0x5D, 0x5D), new TAG_INFO(0x0B000000, KeyVault.g_keyUPDATER, 0x4E, 0x00), new TAG_INFO(0x0C000000, KeyVault.g_keyDEMOS27X, 0x4F, 0x00), new TAG_INFO(0x0F000000, KeyVault.g_keyMEIMG250, 0x52, 0x00), new TAG_INFO(0x862648D1, KeyVault.g_keyMEIMG260, 0x52, 0x52), new TAG_INFO(0x207BBF2F, KeyVault.g_keyUNK1, 0x5A, 0x5A), new TAG_INFO(0x09000000, KeyVault.g_key_GAMESHARE1xx, 0x4C, 0x00), new TAG_INFO(0xBB67C59F, KeyVault.g_key_GAMESHARE2xx, 0x5E, 0x5E)}; private TAG_INFO GetTagInfo(int tag) { int iTag; for (iTag = 0; iTag < g_tagInfo.length; iTag++) { if (g_tagInfo[iTag].tag == tag) { return g_tagInfo[iTag]; } } return null; } private void ScramblePRX(byte[] buf, int size, byte code) { // Set CBC mode. buf[0] = 0; buf[1] = 0; buf[2] = 0; buf[3] = 5; // Set unkown parameters to 0. buf[4] = 0; buf[5] = 0; buf[6] = 0; buf[7] = 0; buf[8] = 0; buf[9] = 0; buf[10] = 0; buf[11] = 0; // Set the the key seed to code. buf[12] = 0; buf[13] = 0; buf[14] = 0; buf[15] = code; // Set the the data size to size. buf[16] = (byte) ((size >> 24) & 0xFF); buf[17] = (byte) ((size >> 16) & 0xFF); buf[18] = (byte) ((size >> 8) & 0xFF); buf[19] = (byte) (size & 0xFF); ByteBuffer bBuf = ByteBuffer.wrap(buf); kirk.hleUtilsBufferCopyWithRange(bBuf, size, bBuf, size, KIRK.PSP_KIRK_CMD_DECRYPT); } private static boolean isNullKey(byte[] key) { if (key != null) { for (int i = 0; i < key.length; i++) { if (key[i] != (byte) 0) { return false; } } } return true; } private boolean TestBlacklist(byte[] inbuf, byte[] blacklist, int blacklistsize) { if (blacklistsize / 16 != 0) { for (int i = 0; i < blacklistsize / 16; i++) { for (int j = 0; j < 0x10; j++) { byte b = blacklist[(i * 16) + j]; byte bb = inbuf[0x140 + j]; if (b != bb) { return true; } } } } return false; } private void MixXOR(byte[] outbuf, int size, byte[] inbuf, byte[] xor) { for (int i = 0; i < size; i++) { outbuf[i] = (byte) ((inbuf[i] & 0xFF) ^ (xor[i] & 0xFF)); } } private void RoundXOR(byte[] buf, int size, byte[] xor1, byte[] xor2) { for (int i = 0; i < size; i++) { if (!isNullKey(xor1)) { buf[i] ^= xor1[i & 0xf]; } if (!isNullKey(xor2)) { buf[i] ^= xor2[i & 0xf]; } } } public int DecryptPRX(byte[] buf, int size, byte[] blacklist, int blacklistsize, int type, byte[] xor1, byte[] xor2) { // Setup temporary buffers. byte[] buf1 = new byte[0x150]; byte[] buf2 = new byte[0x150]; byte[] buf3 = new byte[0x90]; byte[] buf4 = new byte[0xB4]; byte[] buf5 = new byte[0x20]; byte[] buf6 = new byte[0x28]; byte[] sigbuf = new byte[0x28]; byte[] sha1buf = new byte[0x14]; int unk_0xD4 = 0; // Copy the first header to buf1. System.arraycopy(buf, 0, buf1, 0, 0x150); // Fetch the PRX tag. int tag = ((buf[0xD0] & 0xFF) << 24) | ((buf[0xD1] & 0xFF) << 16) | ((buf[0xD2] & 0xFF) << 8) | (buf[0xD3] & 0xFF); // Get the tag info. TAG_INFO pti = GetTagInfo(Integer.reverseBytes(tag)); if (pti == null) { return -1; } // Check for blacklisted tags. if ((blacklist != null) && (blacklistsize != 0)) { if (TestBlacklist(buf1, blacklist, blacklistsize)) { return -1; } } // Fetch the final ELF size. int retsize = ((buf[0xB3] & 0xFF) << 24) | ((buf[0xB2] & 0xFF) << 16) | ((buf[0xB1] & 0xFF) << 8) | ((buf[0xB0] & 0xFF)); // Old encryption method (144 bytes key). if (pti.key.length > 0x10) { // Setup the buffers. byte[] oldbuf = new byte[size]; byte[] oldbuf1 = new byte[0x150]; System.arraycopy(buf, 0, oldbuf, 0, size); for (int i = 0; i < 0x150; i++) { oldbuf[i] = 0; } for (int i = 0; i < 0x40; i++) { oldbuf[i] = 0x55; } oldbuf[0x2C + 0] = 0; oldbuf[0x2C + 1] = 0; oldbuf[0x2C + 2] = 0; oldbuf[0x2C + 3] = 5; oldbuf[0x2C + 4] = 0; oldbuf[0x2C + 5] = 0; oldbuf[0x2C + 6] = 0; oldbuf[0x2C + 7] = 0; oldbuf[0x2C + 8] = 0; oldbuf[0x2C + 9] = 0; oldbuf[0x2C + 10] = 0; oldbuf[0x2C + 11] = 0; oldbuf[0x2C + 12] = 0; oldbuf[0x2C + 13] = 0; oldbuf[0x2C + 14] = 0; oldbuf[0x2C + 15] = (byte) pti.code; oldbuf[0x2C + 16] = 0; oldbuf[0x2C + 17] = 0; oldbuf[0x2C + 18] = 0; oldbuf[0x2C + 19] = (byte) 0x70; System.arraycopy(buf, 0xD0, oldbuf1, 0, 0x80); System.arraycopy(buf, 0x80, oldbuf1, 0x80, 0x50); System.arraycopy(buf, 0, oldbuf1, 0xD0, 0x80); if (pti.codeExtra != 0) { byte[] tmp = new byte[0x14 + 0xA0]; System.arraycopy(oldbuf1, 0x10, tmp, 0x14, 0xA0); ScramblePRX(tmp, 0xA0, (byte) pti.codeExtra); System.arraycopy(tmp, 0, oldbuf1, 0x10, 0xA0); } System.arraycopy(oldbuf1, 0x40, oldbuf, 0x40, 0x40); for (int iXOR = 0; iXOR < 0x70; iXOR++) { oldbuf[0x40 + iXOR] = (byte) (oldbuf[0x40 + iXOR] ^ (byte) pti.key[0x14 + iXOR]); } // Scramble the data by calling CMD7. ByteBuffer bScrambleOut = ByteBuffer.allocate(oldbuf.length); ByteBuffer bScrambleIn = ByteBuffer.wrap(oldbuf); bScrambleIn.position(0x2C); kirk.hleUtilsBufferCopyWithRange(bScrambleOut, 0x70, bScrambleIn, 0x70, KIRK.PSP_KIRK_CMD_DECRYPT); System.arraycopy(bScrambleOut.array(), 0, oldbuf, 0x2C, 0x70); for (int iXOR = 0x6F; iXOR >= 0; iXOR--) { oldbuf[0x40 + iXOR] = (byte) (oldbuf[0x2C + iXOR] ^ (byte) pti.key[0x20 + iXOR]); } for (int k = 0; k < 0x30; k++) { oldbuf[k + 0x80] = 0; } // Set mode field to 1. oldbuf[0xA0] = 0x0; oldbuf[0xA1] = 0x0; oldbuf[0xA2] = 0x0; oldbuf[0xA3] = 0x1; System.arraycopy(buf, 0xB0, oldbuf, 0xB0, 0x20); System.arraycopy(buf, 0, oldbuf, 0xD0, 0x80); // Call KIRK CMD1 for final decryption. ByteBuffer bDataOut = ByteBuffer.wrap(oldbuf); ByteBuffer bHeaderIn = bDataOut.duplicate().order(ByteOrder.LITTLE_ENDIAN); bHeaderIn.position(0x40); kirk.hleUtilsBufferCopyWithRange(bDataOut, size, bHeaderIn, size, KIRK.PSP_KIRK_CMD_DECRYPT_PRIVATE); // Copy back the decrypted file. System.arraycopy(oldbuf, 0, buf, 0, size); } else { // New encryption method (16 bytes key). // Read in the user key and apply scramble. if ((type >= 2) && (type <= 7) || (type == 9) || (type == 10)) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 0x10; j++) { buf2[0x14 + ((i << 4) + j)] = (byte) pti.key[j]; } buf2[0x14 + ((i << 4))] = (byte) i; } } else { for (int i = 0; i < 0x90; i++) { buf2[0x14 + i] = (byte) pti.key[i]; } } ScramblePRX(buf2, 0x90, (byte) (pti.code & 0xFF)); // Round XOR key for PRX type 3,5,7 and 10. if ((type == 3) || (type == 5) || (type == 7) || (type == 10)) { if (!isNullKey(xor2)) { RoundXOR(buf2, 0x90, xor2, null); } } System.arraycopy(buf2, 0, buf3, 0, 0x90); // Type 9 and 10 specific step. if ((type == 9) || (type == 10)) { System.arraycopy(buf, 0x104, buf6, 0, buf6.length); for (int i = 0; i < buf6.length; i++) { buf[0x104 + i] = 0; } System.arraycopy(buf6, 0, sigbuf, 0, sigbuf.length); buf[0] = (byte) (((size - 4) & 0xFF) << 24); buf[1] = (byte) (((size - 4) & 0xFF) << 16); buf[2] = (byte) (((size - 4) & 0xFF) << 8); buf[3] = (byte) (((size - 4) & 0xFF)); // Generate SHA1 hash. ByteBuffer bSHA1 = ByteBuffer.wrap(buf); kirk.hleUtilsBufferCopyWithRange(bSHA1, size, bSHA1, size, KIRK.PSP_KIRK_CMD_SHA1_HASH); System.arraycopy(buf, 0, sha1buf, 0, sha1buf.length); System.arraycopy(buf, 0, buf1, 0, 0x20); if ((((tag << 16) & 0xFF) & 0x16) == 0x16) { System.arraycopy(KeyVault.g_pubkey_28752, 0, buf4, 0, KeyVault.g_pubkey_28752.length); } else if ((((tag << 16) & 0xFF) & 0x5E) == 0x5E) { System.arraycopy(KeyVault.g_pubkey_28712, 0, buf4, 0, KeyVault.g_pubkey_28712.length); } else { System.arraycopy(KeyVault.g_pubkey_28672, 0, buf4, 0, KeyVault.g_pubkey_28672.length); } System.arraycopy(sha1buf, 0, buf4, 0x28, sha1buf.length); System.arraycopy(sigbuf, 0, buf4, 0x28 + sha1buf.length, sigbuf.length); // Verify ECDSA signature. ByteBuffer bECDSA = ByteBuffer.wrap(buf4); kirk.hleUtilsBufferCopyWithRange(null, 0, bECDSA, 100, KIRK.PSP_KIRK_CMD_ECDSA_VERIFY); } if (type == 3) { System.arraycopy(buf1, 0xEC, buf2, 0, 0x40); for (int i = 0; i < 0x50; i++) { buf2[0x40 + i] = 0; } buf2[0x60] = 0x03; buf2[0x70] = 0x50; System.arraycopy(buf1, 0x80, buf2, 0x90, 0x30); System.arraycopy(buf1, 0xC0, buf2, 0x90 + 0x30, 0x10); System.arraycopy(buf1, 0x12C, buf2, 0x90 + 0x30 + 0x10, 0x10); byte[] tmp = new byte[0x50]; for (int i = 0; i < tmp.length; i++) { tmp[i] = buf2[0x90 + i]; } // Round XOR with xor1 and xor2. RoundXOR(tmp, 0x50, xor1, xor2); System.arraycopy(tmp, 0, buf2, 0x90, 0x50); // Decrypt signature (type 3). ByteBuffer bSIGin = ByteBuffer.wrap(buf2); ByteBuffer bSIGout = ByteBuffer.wrap(buf4); kirk.hleUtilsBufferCopyWithRange(bSIGout, 0xB4, bSIGin, 0x150, KIRK.PSP_KIRK_CMD_DECRYPT_SIGN); // Regenerate signature. System.arraycopy(buf1, 0xD0, buf2, 0, 0x4); for (int i = 0; i < 0x58; i++) { buf2[0x4 + i] = 0; } System.arraycopy(buf1, 0x140, buf2, 0x5C, 0x10); System.arraycopy(buf1, 0x12C, buf2, 0x6C, 0x14); System.arraycopy(buf4, 0x40, buf2, 0x6C, 0x10); System.arraycopy(buf4, 0, buf2, 0x80, 0x30); System.arraycopy(buf4, 0x30, buf2, 0xB0, 0x10); System.arraycopy(buf1, 0xB0, buf2, 0xC0, 0x10); System.arraycopy(buf1, 0, buf2, 0xD0, 0x80); } else if ((type == 5) || (type == 7) || (type == 10)) { System.arraycopy(buf1, 0x80, buf2, 0x14, 0x30); System.arraycopy(buf1, 0xC0, buf2, 0x44, 0x10); System.arraycopy(buf1, 0x12C, buf2, 0x54, 0x10); byte[] tmp = new byte[0x50]; for (int i = 0; i < tmp.length; i++) { tmp[i] = buf2[0x14 + i]; } // Round XOR with xor1 and xor2. RoundXOR(tmp, 0x50, xor1, xor2); System.arraycopy(tmp, 0, buf2, 0x14, 0x50); // Apply scramble. ScramblePRX(buf2, 0x50, (byte) (pti.code & 0xFF)); // Copy to buf4. System.arraycopy(buf2, 0, buf4, 0, 0x50); // Regenerate signature. System.arraycopy(buf1, 0xD0, buf2, 0, 0x4); for (int i = 0; i < 0x58; i++) { buf2[0x4 + i] = 0; } System.arraycopy(buf1, 0x140, buf2, 0x5C, 0x10); System.arraycopy(buf1, 0x12C, buf2, 0x6C, 0x14); System.arraycopy(buf4, 0x40, buf2, 0x6C, 0x10); System.arraycopy(buf4, 0, buf2, 0x80, 0x30); System.arraycopy(buf4, 0x30, buf2, 0xB0, 0x10); System.arraycopy(buf1, 0xB0, buf2, 0xC0, 0x10); System.arraycopy(buf1, 0, buf2, 0xD0, 0x80); } else if ((type == 2) || (type == 4) || (type == 6) || (type == 9)) { // Regenerate sig check. System.arraycopy(buf1, 0xD0, buf2, 0, 0x5C); System.arraycopy(buf1, 0x140, buf2, 0x5C, 0x10); System.arraycopy(buf1, 0x12C, buf2, 0x6C, 0x14); System.arraycopy(buf1, 0x80, buf2, 0x80, 0x30); System.arraycopy(buf1, 0xC0, buf2, 0xB0, 0x10); System.arraycopy(buf1, 0xB0, buf2, 0xC0, 0x10); System.arraycopy(buf1, 0, buf2, 0xD0, 0x80); } else { // Regenerate sig check. System.arraycopy(buf1, 0xD0, buf2, 0, 0x80); System.arraycopy(buf1, 0x80, buf2, 0x80, 0x50); System.arraycopy(buf1, 0, buf2, 0xD0, 0x80); } if (type == 1) { System.arraycopy(buf2, 0x10, buf4, 0x14, 0xA0); ScramblePRX(buf4, 0xA0, (byte) (pti.code & 0xFF)); System.arraycopy(buf4, 0, buf2, 0x10, 0xA0); } else if ((type >= 2) && (type <= 7) || (type == 9) || (type == 10)) { System.arraycopy(buf2, 0x5C, buf4, 0x14, 0x60); if ((type == 3) || (type == 5) || (type == 7) || (type == 10)) { byte[] tmp = new byte[0x60]; for (int i = 0; i < tmp.length; i++) { tmp[i] = buf4[0x14 + i]; } RoundXOR(tmp, 0x60, xor1, null); System.arraycopy(tmp, 0, buf4, 0x14, 0x60); } ScramblePRX(buf4, 0x60, (byte) (pti.code & 0xFF)); System.arraycopy(buf4, 0, buf2, 0x5C, 0x60); } if ((type >= 2) && (type <= 7) || (type == 9) || (type == 10)) { System.arraycopy(buf2, 0x6C, buf4, 0, 0x14); if (type == 4) { System.arraycopy(buf2, 0, buf2, 0x18, 0x67); for (int i = 0; i < 0x18; i++) { buf2[i] = 0; } } else { System.arraycopy(buf2, 0x5C, buf2, 0x70, 0x10); if ((type == 6) || (type == 7)) { System.arraycopy(buf2, 0x3C, buf5, 0, 0x20); System.arraycopy(buf5, 0, buf2, 0x50, 0x20); for (int i = 0; i < 0x38; i++) { buf2[0x18 + i] = 0; } } else { for (int i = 0; i < 0x58; i++) { buf2[0x18 + i] = 0; } } if (unk_0xD4 == 0x80) { buf2[0x18] = (byte) 0x80; } } // Set the SHA1 block size to digest. System.arraycopy(buf2, 0, buf2, 0x4, 4); buf2[0] = 0x00; buf2[1] = 0x00; buf2[2] = 0x01; buf2[3] = 0x4C; System.arraycopy(buf3, 0, buf2, 0x8, 0x10); } else { // Set the SHA1 block size to digest. System.arraycopy(buf2, 0x4, buf4, 0, 0x14); buf2[0] = 0x00; buf2[1] = 0x00; buf2[2] = 0x01; buf2[3] = 0x4C; System.arraycopy(buf3, 0, buf2, 0x4, 0x14); } // Generate SHA1 hash. ByteBuffer bSHA1Out = ByteBuffer.wrap(buf2); kirk.hleUtilsBufferCopyWithRange(bSHA1Out, 0x150, bSHA1Out, 0x150, KIRK.PSP_KIRK_CMD_SHA1_HASH); if ((type >= 2) && (type <= 7) || (type == 9) || (type == 10)) { byte[] tmp1 = new byte[0x40]; byte[] tmp2 = new byte[0x40]; byte[] tmp3 = new byte[0x40 + 0x14]; byte[] tmp4 = new byte[0x40]; byte[] tmp5 = new byte[0x40]; byte[] tmp6 = new byte[0x40]; for (int i = 0; i < 0x40; i++) { tmp1[i] = buf2[0x80 + i]; tmp2[i] = buf3[0x10 + i]; } MixXOR(tmp1, 0x40, tmp1, tmp2); System.arraycopy(tmp1, 0, tmp3, 0x14, 0x40); ScramblePRX(tmp3, 0x40, (byte) (pti.code & 0xFF)); System.arraycopy(tmp3, 0, buf2, 0x80, 0x40); for (int i = 0; i < 0x40; i++) { tmp4[i] = buf[0x40 + i]; tmp5[i] = buf2[0x80 + i]; tmp6[i] = buf3[0x50 + i]; } MixXOR(tmp4, 0x40, tmp5, tmp6); System.arraycopy(tmp4, 0, buf, 0x40, 0x40); if ((type == 6) || (type == 7)) { System.arraycopy(buf5, 0, buf, 0x80, 0x20); for (int i = 0; i < 0x10; i++) { buf[0xA0 + i] = 0; } buf[0xA4] = 0x0; buf[0xA5] = 0x0; buf[0xA6] = 0x0; buf[0xA7] = 0x1; buf[0xA0] = 0x0; buf[0xA1] = 0x0; buf[0xA2] = 0x0; buf[0xA3] = 0x1; } else { for (int i = 0; i < 0x30; i++) { buf[0x80 + i] = 0; } buf[0xA0] = 0x0; buf[0xA1] = 0x0; buf[0xA2] = 0x0; buf[0xA3] = 0x1; } System.arraycopy(buf2, 0xC0, buf, 0xB0, 0x10); for (int i = 0; i < 0x10; i++) { buf[0xC0 + i] = 0; } System.arraycopy(buf2, 0xD0, buf, 0xD0, 0x80); } else { byte[] tmp7 = new byte[0x70]; byte[] tmp8 = new byte[0x70]; byte[] tmp9 = new byte[0x70 + 0x14]; byte[] tmp10 = new byte[0x70]; byte[] tmp11 = new byte[0x70]; byte[] tmp12 = new byte[0x70]; for (int i = 0; i < 0x70; i++) { tmp7[i] = buf2[0x40 + i]; tmp8[i] = buf3[0x14 + i]; } MixXOR(tmp7, 0x70, tmp7, tmp8); System.arraycopy(tmp7, 0, tmp9, 0x14, 0x70); ScramblePRX(tmp9, 0x70, (byte) (pti.code & 0xFF)); System.arraycopy(tmp9, 0, buf2, 0x40, 0x40); for (int i = 0; i < 0x70; i++) { tmp10[i] = buf[0x40 + i]; tmp11[i] = buf2[0x40 + i]; tmp12[i] = buf3[0x20 + i]; } MixXOR(tmp10, 0x70, tmp11, tmp12); System.arraycopy(tmp10, 0, buf, 0x40, 0x70); System.arraycopy(buf2, 0xB0, buf, 0xB0, 0xA0); } if (type == 8) { if ((buf[0xA4] & 0x1) != 0x1) { return -1; } } if (unk_0xD4 == 0x80) { if ((buf[0x590] & 0x1) == 0x1) { return -1; } buf[0x590] |= 0x80; } // Call KIRK CMD1 for final decryption. ByteBuffer bDataOut = ByteBuffer.wrap(buf); ByteBuffer bHeaderIn = bDataOut.duplicate().order(ByteOrder.LITTLE_ENDIAN); bHeaderIn.position(0x40); kirk.hleUtilsBufferCopyWithRange(bDataOut, size, bHeaderIn, size, KIRK.PSP_KIRK_CMD_DECRYPT_PRIVATE); if (retsize < 0x150) { for (int i = 0; i < (0x150 - retsize); i++) { buf[retsize + i] = 0; } } } return retsize; } }