/* KDSBEST START */
        public int encryptFile(String inFile, String outFile, byte[] devKLic, byte[] keyFromRif, byte[] contentID, byte[] flags, byte[] type, byte[] version)
        {
            FileStream fin = File.Open(inFile, FileMode.Open);

            //  MemoryMappedFile fin1 = MemoryMappedFile.CreateFromFile(inFile, FileMode.Open);
            NPD[]      ptr = new NPD[1]; //Ptr to Ptr
            FileStream o   = File.Open(outFile, FileMode.Create);

            string[] fn  = o.Name.Split('\\');
            byte[]   npd = writeValidNPD(fn[fn.Length - 1], devKLic, ptr, fin, contentID, flags, version, type);
            o.Write(npd, 0, npd.Length);
            byte[] buffer = new byte[4];
            // FLAGS
            buffer[0] = 0x00;
            buffer[1] = 0x00;
            buffer[2] = 0x00;
            buffer[3] = 0x00;
            o.Write(buffer, 0, 4);

            // blocksize 0x00004000
            buffer[2] = 0x40;
            o.Write(buffer, 0, 4);
            long len = fin.Length;

            byte[] lenBuf  = BitConverter.GetBytes(len);
            byte[] rLenBuf = new byte[8];
            for (int i = 0; i < 8; i++)
            {
                rLenBuf[i] = 0x00;
            }
            for (int i = 0; i < lenBuf.Length; i++)
            {
                rLenBuf[7 - i] = lenBuf[i];
            }
            o.Write(rLenBuf, 0, 8);

            // Fill the rest 0x10 bytes with dummy we generate the metasection hash later!
            // the bytes till 0x100 are unknown
            buffer[0] = 0x00;
            while (o.Length < 0x100)
            {
                o.Write(buffer, 0, 1);
            }

            EDATData data = new EDATData();

            data.flags     = 0x00000000;
            data.blockSize = 0x00004000;
            data.fileLen   = new BigInteger(len);
            byte[] rifkey   = getKey(ptr[0], data, devKLic, keyFromRif); //Obtain the key for decryption (result of sc471 or sdatkey)
            int    hashFlag = 0x00000002;


            encryptData(fin, o, ptr[0], data, rifkey);

            o.Seek(0x90, SeekOrigin.Begin);
            AppLoader aa = new AppLoader();

            aa.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;
                o.Seek(baseOffset + readed, SeekOrigin.Begin);
                byte[] content = new byte[lenToRead];
                byte[] ooo     = new byte[lenToRead];
                o.Read(content, 0, content.Length);
                aa.doUpdate(content, 0, ooo, 0, lenToRead);
                readed    += lenToRead;
                remaining -= lenToRead;
            }
            byte[] headerHash = new byte[0x10];
            aa.doFinalButGetHash(headerHash);
            o.Seek(0x90, SeekOrigin.Begin);
            o.Write(headerHash, 0, headerHash.Length);

            // Header Complete

            // Generate Header Hash
            o.Seek(0, SeekOrigin.Begin);
            byte[] header       = new byte[0xA0];
            byte[] headerODummy = new byte[0xA0];
            o.Read(header, 0, header.Length);
            AppLoaderReverse a = new AppLoaderReverse();

            byte[] generatedHash = new byte[0x10];
            bool   result        = a.doAll(hashFlag, 0x00000001, header, 0, headerODummy, 0, header.Length, new byte[0x10], new byte[0x10], rifkey, generatedHash, 0);

            o.Seek(0xA0, SeekOrigin.Begin);
            o.Write(generatedHash, 0, generatedHash.Length);


            //KDSBest We don't know the DATA 0xB0 to 0x100!!!

            while (o.Length < 0x100)
            {
                o.Write(buffer, 0, 1);
            }


            o.Close();
            fin.Close();
            return(STATUS_OK);
        }
        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
            Console.WriteLine("Checking NPD Version:" + npd.getVersion());
            if ((npd.getVersion() == 0) || (npd.getVersion() == 1))
            {
                if ((data.getFlags() & 0x7FFFFFFE) != 0)
                {
                    Console.WriteLine("ERROR: Incorrect Header Flags"); return(STATUS_ERROR_INCORRECT_FLAGS);
                }
            }
            else if (npd.getVersion() == 2)
            {
                if ((data.getFlags() & 0x7EFFFFE0) != 0)
                {
                    Console.WriteLine("ERROR: Incorrect Header Flags"); return(STATUS_ERROR_INCORRECT_FLAGS);
                }
            }
            else if (npd.getVersion() == 3 || (npd.getVersion() == 4))
            {
                if ((data.getFlags() & 0x7EFFFFC0) != 0)
                {
                    Console.WriteLine("ERROR: Incorrect Header Flags"); return(STATUS_ERROR_INCORRECT_FLAGS);
                }
            }
            else
            {
                Console.WriteLine("ERROR: Unsupported EDAT version (need keys)"); return(STATUS_ERROR_INCORRECT_VERSION);
            }

            {
                int keyIndex = 0;
                if (npd.getVersion() == 4)
                {
                    keyIndex = 1;
                }


                i.Read(header, 0, header.Length);
                i.Read(expectedHash, 0, expectedHash.Length);
                Console.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)
                {
                    Console.WriteLine("Error verifying header. Is rifKey valid?.");
                    return(STATUS_ERROR_HEADERCHECK);
                }
                Console.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)
                {
                    Console.WriteLine("Error verifying metadatasection. Data tampered");
                    return(STATUS_ERROR_HEADERCHECK);
                }
                return(STATUS_OK);
            }
        }