예제 #1
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);
        }
예제 #2
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);
        }