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); }
// Encrypt with AESCBC128 using keys from table. private int executeKIRKCmd5(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 CMD4 format header. AES128_CBC_Header header = new AES128_CBC_Header(@in); if (header.mode != PSP_KIRK_CMD_MODE_ENCRYPT_CBC) { return(PSP_KIRK_INVALID_MODE); // Only valid for mode ENCRYPT_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[] encKey = new sbyte[16]; for (int i = 0; i < encKey.Length; i++) { encKey[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.encrypt(inBuf, encKey, priv_iv); @out.position(outPosition); // The header is kept in the output and the header.mode is even updated from // PSP_KIRK_CMD_MODE_ENCRYPT_CBC to PSP_KIRK_CMD_MODE_DECRYPT_CBC. @out.putInt(PSP_KIRK_CMD_MODE_DECRYPT_CBC); @out.putInt(header.unk1); @out.putInt(header.unk2); @out.putInt(header.keySeed); @out.putInt(header.dataSize); @out.put(outBuf); @in.clear(); return(0); }
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)); }
public virtual sbyte[] GetConsoleKey(sbyte[] openPSID) { AES128 aes = new AES128("AES/ECB/NoPadding"); sbyte[] actdatKey = new sbyte[KeyVault.drmActdatKey.Length]; for (int i = 0; i < KeyVault.drmActdatKey.Length; i++) { actdatKey[i] = unchecked ((sbyte)(KeyVault.drmActdatKey[i] & 0xFF)); } return(aes.encrypt(openPSID, actdatKey, iv)); }
/* * sceNpDrm - npdrm.prx */ public virtual sbyte[] hleNpDrmGetFixedKey(sbyte[] hash, sbyte[] data, int mode) { // Setup the crypto and keygen modes and initialize both context structs. AMCTRL.BBMac_Ctx bbctx = new AMCTRL.BBMac_Ctx(); AES128 aes = new AES128("AES/CBC/NoPadding"); // Get the encryption key. sbyte[] encKey = new sbyte[0x10]; if ((mode & 0x1) == 0x1) { for (int i = 0; i < 0x10; i++) { encKey[i] = unchecked ((sbyte)(KeyVault.drmEncKey1[i] & 0xFF)); } } else if ((mode & 0x2) == 0x2) { for (int i = 0; i < 0x10; i++) { encKey[i] = unchecked ((sbyte)(KeyVault.drmEncKey2[i] & 0xFF)); } } else if ((mode & 0x3) == 0x3) { for (int i = 0; i < 0x10; i++) { encKey[i] = unchecked ((sbyte)(KeyVault.drmEncKey3[i] & 0xFF)); } } else { return(null); } // Get the fixed key. sbyte[] fixedKey = new sbyte[0x10]; for (int i = 0; i < 0x10; i++) { fixedKey[i] = unchecked ((sbyte)(KeyVault.drmFixedKey[i] & 0xFF)); } // Call the BBMac functions. amctrl.hleDrmBBMacInit(bbctx, 1); amctrl.hleDrmBBMacUpdate(bbctx, data, data.Length); amctrl.hleDrmBBMacFinal(bbctx, hash, fixedKey); // Encrypt and return the hash. return(aes.encrypt(hash, encKey, iv)); }
// Decrypt with AESCBC128 using keys from table. private int executeKIRKCmd7(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); } int[] key = getAESKeyFromSeed(header.keySeed); if (key == null) { return(PSP_KIRK_INVALID_SEED); } 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); }