/* 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; public class PGD { private static AMCTRL amctrl; private AMCTRL.BBCipher_Ctx pgdCipherContext; private AMCTRL.BBMac_Ctx pgdMacContext; public PGD() { amctrl = new AMCTRL(); } // Plain PGD handling functions. public byte[] DecryptPGD(byte[] inbuf, int size, byte[] key, int seed) { // Setup the crypto and keygen modes and initialize both context structs. int sdEncMode = 1; int sdGenMode = 2; pgdMacContext = new AMCTRL.BBMac_Ctx(); pgdCipherContext = new AMCTRL.BBCipher_Ctx(); // Align the buffers to 16-bytes. int alignedSize = ((size + 0xF) >> 4) << 4; byte[] outbuf = new byte[alignedSize - 0x10]; byte[] dataBuf = new byte[alignedSize]; // Fully copy the contents of the encrypted file. System.arraycopy(inbuf, 0, dataBuf, 0, size); amctrl.hleDrmBBMacInit(pgdMacContext, sdEncMode); amctrl.hleDrmBBCipherInit(pgdCipherContext, sdEncMode, sdGenMode, dataBuf, key, seed); amctrl.hleDrmBBMacUpdate(pgdMacContext, dataBuf, 0x10); System.arraycopy(dataBuf, 0x10, outbuf, 0, alignedSize - 0x10); amctrl.hleDrmBBMacUpdate(pgdMacContext, outbuf, alignedSize - 0x10); amctrl.hleDrmBBCipherUpdate(pgdCipherContext, outbuf, alignedSize - 0x10); return outbuf; } public byte[] UpdatePGDCipher(byte[] inbuf, int size) { // Align the buffers to 16-bytes. int alignedSize = ((size + 0xF) >> 4) << 4; byte[] outbuf = new byte[alignedSize - 0x10]; byte[] dataBuf = new byte[alignedSize]; System.arraycopy(inbuf, 0, dataBuf, 0, size); System.arraycopy(dataBuf, 0x10, outbuf, 0, alignedSize - 0x10); amctrl.hleDrmBBCipherUpdate(pgdCipherContext, outbuf, alignedSize - 0x10); return outbuf; } public void FinishPGDCipher() { amctrl.hleDrmBBCipherFinal(pgdCipherContext); } public byte[] GetEDATPGDKey(byte[] inbuf, int size) { // Setup the crypto and keygen modes and initialize both context structs. int macEncMode; int pgdFlag = 2; pgdMacContext = new AMCTRL.BBMac_Ctx(); // Align the buffer to 16-bytes. int alignedSize = ((size + 0xF) >> 4) << 4; byte[] dataBuf = new byte[alignedSize]; // Fully copy the contents of the encrypted file. System.arraycopy(inbuf, 0, dataBuf, 0, size); int keyIndex = dataBuf[0x4]; int drmType = dataBuf[0x8]; if ((drmType & 0x1) == 0x1) { macEncMode = 1; pgdFlag |= 4; if (keyIndex > 0x1) { macEncMode = 3; pgdFlag |= 8; } } else { macEncMode = 2; } // Get fixed DNAS keys. byte[] dnasKey = new byte[0x10]; if ((pgdFlag & 0x2) == 0x2) { for (int i = 0; i < KeyVault.drmDNASKey1.length; i++) { dnasKey[i] = (byte) (KeyVault.drmDNASKey1[i] & 0xFF); } } else if ((pgdFlag & 0x1) == 0x1) { for (int i = 0; i < KeyVault.drmDNASKey2.length; i++) { dnasKey[i] = (byte) (KeyVault.drmDNASKey2[i] & 0xFF); } } else { return null; } // Get mac80 from input. byte[] macKey80 = new byte[0x10]; System.arraycopy(dataBuf, 0x80, macKey80, 0, 0x10); // Get mac70 from input. byte[] macKey70 = new byte[0x10]; System.arraycopy(dataBuf, 0x70, macKey70, 0, 0x10); // MAC_0x80 amctrl.hleDrmBBMacInit(pgdMacContext, macEncMode); amctrl.hleDrmBBMacUpdate(pgdMacContext, dataBuf, 0x80); amctrl.hleDrmBBMacFinal2(pgdMacContext, macKey80, dnasKey); // MAC_0x70 amctrl.hleDrmBBMacInit(pgdMacContext, macEncMode); amctrl.hleDrmBBMacUpdate(pgdMacContext, dataBuf, 0x70); // Get the decryption key from BBMAC. return amctrl.GetKeyFromBBMac(pgdMacContext, macKey70); } public boolean CheckEDATRenameKey(byte[] fileName, byte[] hash, byte[] data) { // Set up MAC context. pgdMacContext = new AMCTRL.BBMac_Ctx(); // Perform hash check. amctrl.hleDrmBBMacInit(pgdMacContext, 3); amctrl.hleDrmBBMacUpdate(pgdMacContext, data, 0x30); amctrl.hleDrmBBMacUpdate(pgdMacContext, fileName, fileName.length); // Get the fixed rename key. byte[] renameKey = new byte[0x10]; for (int i = 0; i < 0x10; i++) { renameKey[i] = (byte) (KeyVault.drmRenameKey[i] & 0xFF); } // Compare and return. return (amctrl.hleDrmBBMacFinal2(pgdMacContext, hash, renameKey) == 0); } }