Beispiel #1
0
 private byte[] calculateBlockKey(int blk, NPD npd)
 {
     byte[] baseKey = (npd.getVersion() <= 1)?(new byte[0x10]):npd.getDevHash();
     byte[] result  = new byte[0x10];
     ConversionUtils.arraycopy(baseKey, 0, result, 0, 0xC);
     result[0xC] = (byte)(blk >> 24 & 0xFF);
     result[0xD] = (byte)(blk >> 16 & 0xFF);
     result[0xE] = (byte)(blk >> 8 & 0xFF);
     result[0xF] = (byte)(blk & 0xFF);
     return(result);
 }
Beispiel #2
0
 private byte[] calculateBlockKey(int blk, NPD npd)
 {
     byte[] baseKey = (npd.getVersion() <= 1)?(new byte[0x10]):npd.getDevHash();
     byte[] result = new byte[0x10];
     ConversionUtils.arraycopy(baseKey, 0, result, 0, 0xC);
     result[0xC] = (byte) (blk >> 24 & 0xFF);
     result[0xD] = (byte) (blk >> 16 & 0xFF);
     result[0xE] = (byte) (blk >> 8 & 0xFF);
     result[0xF] = (byte) (blk & 0xFF);
     return result;
 }
Beispiel #3
0
        /**
         *
         * Performs checks on the header:
         * -Version check: Must be between 0 and 3 included
         * -Flags check: Checks that only valid active flags are set for given version.
         *  Ver 0, 1 : Debug and compress
         *  Ver 2 : Debug, compress, SDAT, Keys encrypted,..
         *  Ver 3: Debug, compress, SDAT, Keys encrypted...
         * -Metadata section hash: Checks that metadata section is valid (uses encryption key)
         * -Header hash: Checks that header is correct (uses encryption key)
         * @param rifKey
         * @param data
         * @param npd
         * @param in
         * @return
         * @throws IOException
         */
        private int checkHeader(byte[] rifKey, EDATData data, NPD npd, FileStream i)
        {
            i.Seek(0, SeekOrigin.Begin);
            byte[] header       = new byte[0xA0];
            byte[] o            = new byte[0xA0];
            byte[] expectedHash = new byte[0x10];
            //Version check
            Debug.WriteLine("Checking NPD Version:" + npd.getVersion());
            if ((npd.getVersion() == 0) || (npd.getVersion() == 1))
            {
                if ((data.getFlags() & 0x7FFFFFFE) != 0)
                {
                    return(STATUS_ERROR_INCORRECT_FLAGS);
                }
            }
            else if (npd.getVersion() == 2)
            {
                if ((data.getFlags() & 0x7EFFFFE0) != 0)
                {
                    return(STATUS_ERROR_INCORRECT_FLAGS);
                }
            }
            else if (npd.getVersion() == 3)
            {
                if ((data.getFlags() & 0x7EFFFFC0) != 0)
                {
                    return(STATUS_ERROR_INCORRECT_FLAGS);
                }
            }
            else
            {
                return(STATUS_ERROR_INCORRECT_VERSION);
            }

            i.Read(header, 0, header.Length);
            i.Read(expectedHash, 0, expectedHash.Length);
            Debug.WriteLine("Checking header hash:");
            AppLoader a        = new AppLoader();
            int       hashFlag = ((data.getFlags() & FLAG_KEYENCRYPTED) == 0) ? 0x00000002 : 0x10000002;

            if ((data.getFlags() & FLAG_DEBUG) != 0)
            {
                hashFlag |= 0x01000000;
            }

            //Veryfing header
            bool result = a.doAll(hashFlag, 0x00000001, header, 0, o, 0, header.Length, new byte[0x10], new byte[0x10], rifKey, expectedHash, 0);

            if (!result)
            {
                Debug.WriteLine("Error verifying header. Is rifKey valid?.");
                return(STATUS_ERROR_HEADERCHECK);
            }
            Debug.WriteLine("Checking metadata hash:");
            a = new AppLoader();
            a.doInit(hashFlag, 0x00000001, new byte[0x10], new byte[0x10], rifKey);

            int sectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0) ? 0x20 : 0x010; //BUG??? What about FLAG0x20??
            //Determine the metadatasection total len
            int numBlocks = (int)((data.getFileLen() + data.getBlockSize() - 11) / data.getBlockSize());

            int readed     = 0;
            int baseOffset = 0x100;
            //baseOffset +=  modifier; //There is an unknown offset to add to the metadatasection... value seen 0
            long remaining = sectionSize * numBlocks;

            while (remaining > 0)
            {
                int lenToRead = (HEADER_MAX_BLOCKSIZE > remaining) ? (int)remaining : HEADER_MAX_BLOCKSIZE;
                i.Seek(baseOffset + readed, SeekOrigin.Begin);
                byte[] content = new byte[lenToRead];
                o = new byte[lenToRead];
                i.Read(content, 0, content.Length);
                a.doUpdate(content, 0, o, 0, lenToRead);
                readed    += lenToRead;
                remaining -= lenToRead;
            }
            result = a.doFinal(header, 0x90);


            if (!result)
            {
                Debug.WriteLine("Error verifying metadatasection. Data tampered");
                return(STATUS_ERROR_HEADERCHECK);
            }
            return(STATUS_OK);
        }
Beispiel #4
0
        private int decryptData(FileStream ii, FileStream o, NPD npd, EDATData data, byte[] rifkey)
        {
            int numBlocks           = (int)((data.getFileLen() + data.getBlockSize() - 1) / data.getBlockSize());
            int metadataSectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0 || (data.getFlags() & FLAG_0x20) != 0) ? 0x20 : 0x10;
            int baseOffset          = 0x100; //+ offset (unknown)

            for (int i = 0; i < numBlocks; i++)
            {
                ii.Seek(baseOffset + i * metadataSectionSize, SeekOrigin.Begin);
                byte[] expectedHash = new byte[0x10];
                long   offset;
                int    len;
                int    compressionEndBlock = 0;
                if ((data.getFlags() & FLAG_COMPRESSED) != 0)
                {
                    byte[] metadata = new byte[0x20];
                    ii.Read(metadata, 0, metadata.Length);
                    byte[] result = decryptMetadataSection(metadata);
                    offset = (int)(ConversionUtils.be64(result, 0)); // + offset (unknown)
                    len    = (int)(ConversionUtils.be32(result, 8));
                    compressionEndBlock = (int)(ConversionUtils.be32(result, 0xC));
                    ConversionUtils.arraycopy(metadata, 0, expectedHash, 0, 0x10);
                }
                else if ((data.getFlags() & FLAG_0x20) != 0)
                {
                    //NOT TESTED: CASE WHERE METADATASECTION IS 0x20 BYTES LONG
                    byte[] metadata = new byte[0x20];
                    ii.Read(metadata, 0, metadata.Length);
                    for (int j = 0; j < 0x10; j++)
                    {
                        expectedHash[j] = (byte)(metadata[j] ^ metadata[j + 0x10]);
                    }
                    offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize;
                    len    = (int)(data.getBlockSize());
                    if (i == numBlocks - 1)
                    {
                        len = (int)(data.getFileLen() % (new BigInteger(data.getBlockSize())));
                    }
                }
                else
                {
                    ii.Read(expectedHash, 0, expectedHash.Length);
                    offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize;
                    len    = (int)(data.getBlockSize());
                    if (i == numBlocks - 1)
                    {
                        len = (int)(data.getFileLen() % (new BigInteger(data.getBlockSize())));
                    }
                }
                int realLen = len;
                len = (int)((uint)(len + 0xF) & 0xFFFFFFF0);
                Debug.Print("Offset: %016X, len: %08X, realLen: %08X, endCompress: %d\r\n", offset, len, realLen, compressionEndBlock);
                ii.Seek(offset, SeekOrigin.Begin);
                byte[] encryptedData = new byte[len];
                byte[] decryptedData = new byte[len];
                ii.Read(encryptedData, 0, encryptedData.Length);
                byte[] key      = new byte[0x10];
                byte[] hash     = new byte[0x10];
                byte[] blockKey = calculateBlockKey(i, npd);

                ToolsImpl.aesecbEncrypt(rifkey, blockKey, 0, key, 0, blockKey.Length);
                if ((data.getFlags() & FLAG_0x10) != 0)
                {
                    ToolsImpl.aesecbEncrypt(rifkey, key, 0, hash, 0, key.Length);
                }
                else
                {
                    ConversionUtils.arraycopy(key, 0, hash, 0, key.Length);
                }
                int cryptoFlag = ((data.getFlags() & FLAG_0x02) == 0) ? 0x2 : 0x1;
                int hashFlag;
                if ((data.getFlags() & FLAG_0x10) == 0)
                {
                    hashFlag = 0x02;
                }
                else if ((data.getFlags() & FLAG_0x20) == 0)
                {
                    hashFlag = 0x04;
                }
                else
                {
                    hashFlag = 0x01;
                }
                if ((data.getFlags() & FLAG_KEYENCRYPTED) != 0)
                {
                    cryptoFlag |= 0x10000000;
                    hashFlag   |= 0x10000000;
                }
                if ((data.getFlags() & FLAG_DEBUG) != 0)
                {
                    cryptoFlag |= 0x01000000;
                    hashFlag   |= 0x01000000;
                }
                AppLoader a  = new AppLoader();
                byte[]    iv = (npd.getVersion() <= 1)?(new byte[0x10]):npd.getDigest();

                bool rresult = a.doAll(hashFlag, cryptoFlag, encryptedData, 0, decryptedData, 0, encryptedData.Length, key, npd.getDigest(), hash, expectedHash, 0);
                if (!rresult)
                {
                    Debug.WriteLine("Error decrypting block " + i);
                    // KDSBest find out why block 30 errors
                    //return STATUS_ERROR_DECRYPTING;
                }
                if ((data.getFlags() & FLAG_COMPRESSED) != 0)
                {
                    //byte[] decompress = new byte[Long.valueOf(data.getBlockSize()).intValue()];
                    //DECOMPRESS: MISSING ALGORITHM
                    //out.write(decompress, 0, data.getBlockSize());
                }
                else
                {
                    o.Write(decryptedData, 0, realLen);
                }
            }
            return(STATUS_OK);
        }
Beispiel #5
0
        private int decryptData(FileStream ii, FileStream o, NPD npd, EDATData data, byte[] rifkey)
        {
            int numBlocks = (int) ((data.getFileLen() + data.getBlockSize() - 1) / data.getBlockSize());
            int metadataSectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0 || (data.getFlags() & FLAG_0x20) != 0) ? 0x20 : 0x10;
            int baseOffset = 0x100; //+ offset (unknown)
            for (int i = 0; i < numBlocks; i++) {
            ii.Seek(baseOffset + i * metadataSectionSize, SeekOrigin.Begin);
            byte[] expectedHash = new byte[0x10];
            long offset;
            int len;
            int compressionEndBlock = 0;
            if ((data.getFlags() & FLAG_COMPRESSED) != 0) {
                byte[] metadata = new byte[0x20];
                ii.Read(metadata, 0, metadata.Length);
                byte[] result = decryptMetadataSection(metadata);
                offset = (int)(ConversionUtils.be64(result, 0)); // + offset (unknown)
                len = (int)(ConversionUtils.be32(result, 8));
                compressionEndBlock = (int)(ConversionUtils.be32(result, 0xC));
                ConversionUtils.arraycopy(metadata, 0, expectedHash, 0, 0x10);
            } else if ((data.getFlags() & FLAG_0x20) != 0) {
                //NOT TESTED: CASE WHERE METADATASECTION IS 0x20 BYTES LONG
                byte[] metadata = new byte[0x20];
                ii.Read(metadata, 0, metadata.Length);
                for (int j = 0; j<0x10;j++) {
                    expectedHash[j] = (byte)(metadata[j] ^ metadata[j+0x10]);
                }
                offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize;
                len = (int)(data.getBlockSize());
                if (i == numBlocks - 1) {
                    len = (int) (data.getFileLen() % (new BigInteger(data.getBlockSize())));
                }
            } else {
                ii.Read(expectedHash, 0, expectedHash.Length);
                offset = baseOffset + i * data.getBlockSize() + numBlocks * metadataSectionSize;
                len = (int)(data.getBlockSize());
                if (i == numBlocks - 1) {
                    len = (int) (data.getFileLen() % (new BigInteger(data.getBlockSize())));
                }
            }
            int realLen = len;
            len = (int) ((uint)(len + 0xF) & 0xFFFFFFF0);
            Debug.Print("Offset: %016X, len: %08X, realLen: %08X, endCompress: %d\r\n", offset, len, realLen,compressionEndBlock);
            ii.Seek(offset, SeekOrigin.Begin);
            byte[] encryptedData = new byte[len];
            byte[] decryptedData = new byte[len];
            ii.Read(encryptedData, 0, encryptedData.Length);
            byte[] key = new byte[0x10];
            byte[] hash = new byte[0x10];
            byte[] blockKey = calculateBlockKey(i, npd);

            ToolsImpl.aesecbEncrypt(rifkey, blockKey, 0, key, 0, blockKey.Length);
            if ((data.getFlags() & FLAG_0x10) != 0) {
                ToolsImpl.aesecbEncrypt(rifkey, key, 0, hash, 0, key.Length);
            } else {
                ConversionUtils.arraycopy(key, 0, hash, 0, key.Length);
            }
            int cryptoFlag = ((data.getFlags() & FLAG_0x02) == 0) ? 0x2 : 0x1;
            int hashFlag;
            if ((data.getFlags() & FLAG_0x10) == 0) {
                hashFlag = 0x02;
            } else if ((data.getFlags() & FLAG_0x20) == 0) {
                hashFlag = 0x04;
            } else {
                hashFlag = 0x01;
            }
            if ((data.getFlags() & FLAG_KEYENCRYPTED) != 0) {
                cryptoFlag |= 0x10000000;
                hashFlag |= 0x10000000;
            }
            if ((data.getFlags() & FLAG_DEBUG) != 0) {
                cryptoFlag |= 0x01000000;
                hashFlag |= 0x01000000;
            }
            AppLoader a = new AppLoader();
            byte[] iv = (npd.getVersion() <= 1)?(new byte[0x10]):npd.getDigest();

            bool rresult = a.doAll(hashFlag, cryptoFlag, encryptedData, 0, decryptedData, 0, encryptedData.Length, key, npd.getDigest(), hash, expectedHash, 0);
            if (!rresult) {
                Debug.WriteLine("Error decrypting block " + i);
                // KDSBest find out why block 30 errors
                //return STATUS_ERROR_DECRYPTING;
            }
            if ((data.getFlags() & FLAG_COMPRESSED) != 0) {
                //byte[] decompress = new byte[Long.valueOf(data.getBlockSize()).intValue()];
                //DECOMPRESS: MISSING ALGORITHM
                //out.write(decompress, 0, data.getBlockSize());
            } else {
                o.Write(decryptedData, 0, realLen);
            }
            }
            return STATUS_OK;
        }
Beispiel #6
0
        /**
         *
         * Performs checks on the header:
         * -Version check: Must be between 0 and 3 included
         * -Flags check: Checks that only valid active flags are set for given version.
         *  Ver 0, 1 : Debug and compress
         *  Ver 2 : Debug, compress, SDAT, Keys encrypted,..
         *  Ver 3: Debug, compress, SDAT, Keys encrypted...
         * -Metadata section hash: Checks that metadata section is valid (uses encryption key)
         * -Header hash: Checks that header is correct (uses encryption key)
         * @param rifKey
         * @param data
         * @param npd
         * @param in
         * @return
         * @throws IOException
         */
        private int checkHeader(byte[] rifKey, EDATData data, NPD npd, FileStream i)
        {
            i.Seek(0, SeekOrigin.Begin);
            byte[] header = new byte[0xA0];
            byte[] o = new byte[0xA0];
            byte[] expectedHash = new byte[0x10];
            //Version check
            Debug.WriteLine("Checking NPD Version:" + npd.getVersion());
            if ((npd.getVersion() == 0) || (npd.getVersion() == 1)) {
            if ((data.getFlags() & 0x7FFFFFFE) != 0) return STATUS_ERROR_INCORRECT_FLAGS;
            } else if (npd.getVersion() == 2) {
            if ((data.getFlags() & 0x7EFFFFE0) != 0) return STATUS_ERROR_INCORRECT_FLAGS;
            } else if (npd.getVersion() == 3) {
            if ((data.getFlags() & 0x7EFFFFC0) != 0) return STATUS_ERROR_INCORRECT_FLAGS;
            } else return STATUS_ERROR_INCORRECT_VERSION;

            i.Read(header, 0, header.Length);
            i.Read(expectedHash, 0, expectedHash.Length);
            Debug.WriteLine("Checking header hash:");
            AppLoader a = new AppLoader();
            int hashFlag = ((data.getFlags() & FLAG_KEYENCRYPTED) == 0) ? 0x00000002 : 0x10000002;
            if ((data.getFlags() & FLAG_DEBUG) != 0) hashFlag |= 0x01000000;

            //Veryfing header
            bool result = a.doAll(hashFlag, 0x00000001, header, 0, o, 0, header.Length, new byte[0x10], new byte[0x10], rifKey, expectedHash, 0);
            if (!result) {
            Debug.WriteLine("Error verifying header. Is rifKey valid?.");
            return STATUS_ERROR_HEADERCHECK;
            }
            Debug.WriteLine("Checking metadata hash:");
            a = new AppLoader();
            a.doInit(hashFlag, 0x00000001, new byte[0x10], new byte[0x10], rifKey);

            int sectionSize = ((data.getFlags() & FLAG_COMPRESSED) != 0) ? 0x20 : 0x010; //BUG??? What about FLAG0x20??
            //Determine the metadatasection total len
            int numBlocks = (int) ((data.getFileLen() + data.getBlockSize() - 11) / data.getBlockSize());

            int readed = 0;
            int baseOffset = 0x100;
            //baseOffset +=  modifier; //There is an unknown offset to add to the metadatasection... value seen 0
            long remaining = sectionSize * numBlocks;
            while (remaining > 0) {
            int lenToRead = (HEADER_MAX_BLOCKSIZE > remaining) ? (int) remaining : HEADER_MAX_BLOCKSIZE;
            i.Seek(baseOffset + readed, SeekOrigin.Begin);
            byte[] content = new byte[lenToRead];
            o = new byte[lenToRead];
            i.Read(content, 0, content.Length);
            a.doUpdate(content, 0, o, 0, lenToRead);
            readed += lenToRead;
            remaining -= lenToRead;
            }
            result = a.doFinal(header, 0x90);

            if (!result) {
            Debug.WriteLine("Error verifying metadatasection. Data tampered");
            return STATUS_ERROR_HEADERCHECK;
            }
            return STATUS_OK;
        }