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