public virtual sbyte[] GetKeyFromRif(sbyte[] rifBuf, sbyte[] actdatBuf, sbyte[] openPSID) { AES128 aes = new AES128("AES/ECB/NoPadding"); sbyte[] rifIndex = new sbyte[0x10]; sbyte[] rifDatKey = new sbyte[0x10]; sbyte[] encRifIndex = new sbyte[0x10]; sbyte[] encRifDatKey = new sbyte[0x10]; sbyte[] rifKey = new sbyte[KeyVault.drmRifKey.Length]; for (int i = 0; i < KeyVault.drmRifKey.Length; i++) { rifKey[i] = unchecked ((sbyte)(KeyVault.drmRifKey[i] & 0xFF)); } Array.Copy(rifBuf, 0x40, encRifIndex, 0x0, 0x10); Array.Copy(rifBuf, 0x50, encRifDatKey, 0x0, 0x10); rifIndex = aes.decrypt(encRifIndex, rifKey, iv); long index = rifIndex[0xF]; if (index < 0x80) { sbyte[] actDat = DecryptActdat(actdatBuf, openPSID); sbyte[] datKey = new sbyte[0x10]; Array.Copy(actDat, (int)index * 16, datKey, 0, 0x10); rifDatKey = aes.decrypt(encRifDatKey, datKey, iv); } return(rifDatKey); }
public virtual sbyte[] DecryptActdat(sbyte[] actdatBuf, sbyte[] openPSID) { AES128 aes = new AES128("AES/ECB/NoPadding"); sbyte[] actdat = new sbyte[0x800]; sbyte[] consoleKey = GetConsoleKey(openPSID); Array.Copy(actdatBuf, 0x10, actdat, 0x0, actdat.Length - 0x10); return(aes.decrypt(actdat, consoleKey, iv)); }
// Decrypt with AESCBC128 using keys from table. private int executeKIRKCmd8(ByteBuffer @out, ByteBuffer @in, int size) { // Return an error if the crypto engine hasn't been initialized. if (!CryptoEngine.CryptoEngineStatus) { return(PSP_KIRK_NOT_INIT); } int outPosition = @out.position(); // Read in the CMD7 format header. AES128_CBC_Header header = new AES128_CBC_Header(@in); if (header.mode != PSP_KIRK_CMD_MODE_DECRYPT_CBC) { return(PSP_KIRK_INVALID_MODE); // Only valid for mode DECRYPT_CBC. } if (header.dataSize == 0) { return(PSP_KIRK_DATA_SIZE_IS_ZERO); } sbyte[] key = null; if (header.keySeed == 0x100) { key = priv_iv; } else { return(PSP_KIRK_INVALID_SIZE); // Dummy. } sbyte[] decKey = new sbyte[16]; for (int i = 0; i < decKey.Length; i++) { decKey[i] = (sbyte)key[i]; } AES128 aes = new AES128("AES/CBC/NoPadding"); sbyte[] inBuf = new sbyte[header.dataSize]; @in.get(inBuf, 0, header.dataSize); sbyte[] outBuf = aes.decrypt(inBuf, decKey, priv_iv); @out.position(outPosition); @out.put(outBuf); @in.clear(); return(0); }
// CMAC Sig check. private int executeKIRKCmd10(ByteBuffer @in, int size) { // Return an error if the crypto engine hasn't been initialized. if (!CryptoEngine.CryptoEngineStatus) { return(PSP_KIRK_NOT_INIT); } int headerOffset = @in.position(); // Read in the CMD10 format header. AES128_CMAC_Header header = new AES128_CMAC_Header(@in); if ((header.mode != PSP_KIRK_CMD_MODE_CMD1) && (header.mode != PSP_KIRK_CMD_MODE_CMD2) && (header.mode != PSP_KIRK_CMD_MODE_CMD3)) { return(PSP_KIRK_INVALID_MODE); // Only valid for modes CMD1, CMD2 and CMD3. } if (header.dataSize == 0) { return(PSP_KIRK_DATA_SIZE_IS_ZERO); } AES128 aes = new AES128("AES/CBC/NoPadding"); // Convert the AES CMD1 key into a real byte array. sbyte[] k = new sbyte[16]; for (int i = 0; i < KeyVault.kirkAESKey0.Length; i++) { k[i] = (sbyte)KeyVault.kirkAESKey0[i]; } // Decrypt and extract the new AES and CMAC keys from the top of the data. sbyte[] encryptedKeys = new sbyte[32]; Array.Copy(header.AES128Key, 0, encryptedKeys, 0, 16); Array.Copy(header.CMACKey, 0, encryptedKeys, 16, 16); sbyte[] decryptedKeys = aes.decrypt(encryptedKeys, k, priv_iv); sbyte[] cmacHeaderHash = new sbyte[16]; sbyte[] cmacDataHash = new sbyte[16]; sbyte[] cmacBuf = new sbyte[16]; Array.Copy(decryptedKeys, 16, cmacBuf, 0, cmacBuf.Length); // Position the buffer at the CMAC keys offset. sbyte[] inBuf = new sbyte[@in.capacity() - 0x60 - headerOffset]; Array.Copy(@in.array(), headerOffset + 0x60, inBuf, 0, inBuf.Length); // Calculate CMAC header hash. aes.doInitCMAC(cmacBuf); aes.doUpdateCMAC(inBuf, 0, 0x30); cmacHeaderHash = aes.doFinalCMAC(); int blockSize = header.dataSize; if ((blockSize % 16) != 0) { blockSize += (16 - (blockSize % 16)); } // Calculate CMAC data hash. aes.doInitCMAC(cmacBuf); aes.doUpdateCMAC(inBuf, 0, 0x30 + blockSize + header.dataOffset); cmacDataHash = aes.doFinalCMAC(); for (int i = 0; i < cmacHeaderHash.Length; i++) { if (cmacHeaderHash[i] != header.CMACHeaderHash[i]) { return(PSP_KIRK_INVALID_HEADER_HASH); } } for (int i = 0; i < cmacDataHash.Length; i++) { if (cmacDataHash[i] != header.CMACDataHash[i]) { return(PSP_KIRK_INVALID_DATA_HASH); } } return(0); }
/* * KIRK commands: main emulated crypto functions. */ // Decrypt with AESCBC128-CMAC header and sig check. private int executeKIRKCmd1(ByteBuffer @out, ByteBuffer @in, int size) { // Return an error if the crypto engine hasn't been initialized. if (!CryptoEngine.CryptoEngineStatus) { return(PSP_KIRK_NOT_INIT); } int outPosition = @out.position(); // Copy the input for sig check. ByteBuffer sigIn = @in.duplicate(); sigIn.order(@in.order()); // duplicate() does not copy the order() int headerSize = AES128_CMAC_Header.SIZEOF(); int headerOffset = @in.position(); // Read in the CMD1 format header. AES128_CMAC_Header header = new AES128_CMAC_Header(@in); if (header.mode != PSP_KIRK_CMD_MODE_CMD1) { return(PSP_KIRK_INVALID_MODE); // Only valid for mode CMD1. } // Start AES128 processing. AES128 aes = new AES128("AES/CBC/NoPadding"); // Convert the AES CMD1 key into a real byte array for SecretKeySpec. sbyte[] k = new sbyte[16]; for (int i = 0; i < KeyVault.kirkAESKey0.Length; i++) { k[i] = (sbyte)KeyVault.kirkAESKey0[i]; } // Decrypt and extract the new AES and CMAC keys from the top of the data. sbyte[] encryptedKeys = new sbyte[32]; Array.Copy(header.AES128Key, 0, encryptedKeys, 0, 16); Array.Copy(header.CMACKey, 0, encryptedKeys, 16, 16); sbyte[] decryptedKeys = aes.decrypt(encryptedKeys, k, priv_iv); // Check for a valid signature. int sigCheck = executeKIRKCmd10(sigIn, size); if (decryptedKeys == null) { // Only return the sig check result if the keys are invalid // to allow skipping the CMAC comparision. // TODO: Trace why the CMAC hashes aren't matching. return(sigCheck); } // Get the newly decrypted AES key and proceed with the // full data decryption. sbyte[] aesBuf = new sbyte[16]; Array.Copy(decryptedKeys, 0, aesBuf, 0, aesBuf.Length); // Extract the sealed override ELF params. int elfDataSize = header.dataSize; int elfDataOffset = header.dataOffset; // Input buffer for decryption must have a Length aligned on 16 bytes int paddedElfDataSize = Utilities.alignUp(elfDataSize, 15); // Decrypt all the ELF data. sbyte[] inBuf = new sbyte[paddedElfDataSize]; Array.Copy(@in.array(), elfDataOffset + headerOffset + headerSize, inBuf, 0, paddedElfDataSize); sbyte[] outBuf = aes.decrypt(inBuf, aesBuf, priv_iv); @out.position(outPosition); @out.put(outBuf); @out.limit(elfDataSize); @in.clear(); return(0); }