using System;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using CryptoSysAPI;

/*   $Id: TestAPIcsharp.cs $
 *   Last updated:
 *   $Date: 2018-09-16 13:31:00 $
 *   $Version: 5.3.0 $
 */

/* Some tests using the CryptoSysAPI .NET interface.
 * 
 * Requires `CryptoSys API` to be installed on your system: available from <http://cryptosys.net/api.html>.
 * Add a reference to `diCrSysAPINet.dll` installed in `C:\Program Files (x86)\CryptoSysAPI\DotNet`.
 * 
 * This is a Console Application written for target .NET Framework 2.0 and above.
 * Please report any bugs to <http://www.cryptosys.net/contact>.
 */
/******************************* LICENSE ***********************************
 * Copyright (C) 2005-18 David Ireland, DI Management Services Pty Limited.
 * All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
 * The code in this module is licensed under the terms of the MIT license.  
 * For a copy, see <http://opensource.org/licenses/MIT>
****************************************************************************
*/

/* [2015-04] Re-organised into modular form */
/* [2018-09] Changed license on this code to MIT */

namespace TestAPIExamples
{
	/// <summary>
	/// Test examples for CryptoSysAPI interface
	/// </summary>
	class TestAPIExamples
	{
        private const int MIN_API_VERSION = 50300;

        // Global vars set by command-line args
        private static bool doPrompt = false;
 
        /// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
            string origdir;  // To store CWD before changed to temp

            // Make sure minimum required version of CryptoSys API is installed...
            Console.WriteLine("API Version is " + General.Version());
            if (General.Version() < MIN_API_VERSION)
            {
                Console.WriteLine("FATAL ERROR: Require API version " + MIN_API_VERSION + " or later.");
                return;
            }

            /* HANDLE COMMAND-LINE ARGUMENTS
             * [some]      just do some tests (default = do all)
             * [prompt]    prompt for keystrokes and passwords
             * [noask]     do not ask to delete temp dir
             */
            bool doSome = false;
            bool askDelete = true;
            // Global vars...
            doPrompt = false;
            for (int iarg = 0; iarg < args.Length; iarg++)
			{
                if (args[iarg] == "some")
                    doSome = true;
                if (args[iarg] == "prompt")
					doPrompt = true;
                if (args[iarg] == "noask")
                    askDelete = false;
            }

            // Setup temp directory
            origdir = SetupTestDirectory();
            if (null == origdir) return;

            //*************
            // DO THE TESTS
            //*************
            if (doSome) // Use "some" in the command line
            {   // Do some tests - comment these out as required
                Console.WriteLine("Just doing some tests...");

                //test_General();
                //test_Convert();
                //test_ErrorLookup();
                //test_Blowfish();
                //test_Des();
                //test_Tdea();
                //test_AES128();
                //test_AES192();
                //test_AES256();
                //test_KeyWrap();
                //test_SHA1();
                //test_SHA256();
                //test_MD5();
                //test_Hash();
                //test_HashBit();
                //test_HMAC();
                //test_CMAC();
                //test_PBKDF2();
                //test_scrypt();
                //test_ZLIB();
                //test_Random();
                //test_Wipe();
                //test_CRC();
                //test_GCM();
                //test_CipherFileExtended();
                //test_CipherPad();
                //test_StreamCipher();
                //test_Poly1305();
                //test_AEAD();
                //test_AEAD_incremental();
                //test_Padding();
                //test_SHA3_obj();
                //test_SHA3();
                //test_KMAC();
                test_XOF();
            }
            else
            {   // Do all the test modules (default)
                Console.WriteLine("Doing all tests...");
                DoAllTests();
            }

            // FINALLY, DISPLAY QUICK INFO ABOUT THE CORE DLL
            Console.WriteLine("\nDETAILS OF CORE DLL...");
            Console.WriteLine("DLL Version={0} [{1}] Lic={2} Compiled=[{3}] ",
                General.Version(), General.Platform(), General.LicenceType(), General.CompileTime());
            Console.WriteLine("[{0}]", General.ModuleName());


            //********************************************
            Console.WriteLine("\nALL TESTS COMPLETED.");

            // Put CWD back to original and offer to remove the test dir
            RestoreDirectory(origdir, askDelete);
        }

        static void DoAllTests()
        {   //%-
            test_General();
            test_Convert();
            test_ErrorLookup();
            test_Blowfish();
            test_Des();
            test_Tdea();
            test_AES128();
            test_AES192();
            test_AES256();
            test_KeyWrap();
            test_SHA1();
            test_SHA256();
            test_MD5();
            test_Hash();
            test_HashBit();
            test_HMAC();
            test_CMAC();
            test_PBKDF2();
            test_scrypt();
            test_ZLIB();
            test_Random();
            test_Wipe();
            test_CRC();
            test_GCM();
            test_CipherFileExtended();
            test_CipherPad();
            test_StreamCipher();
            test_Poly1305();
            test_AEAD();
            test_AEAD_incremental();
            test_Padding();
            test_SHA3_obj();
            test_SHA3();
            test_KMAC();
            test_XOF();
        }

        //********************
        // THE TEST MODULES...
        //********************

        static void test_General()
        {
            int n;
            char ch;
            string s;
            //************
            // GENERAL TESTS *
            //****************
			Console.WriteLine("\nGENERAL FUNCTIONS:");
			n = General.Version();
			Console.WriteLine("Version={0}", n);          
            n = General.PowerUpTests();
			Console.WriteLine("PowerUpTests={0}", n);			
			s = General.CompileTime();
			Console.WriteLine("CompileTime={0}", s);
			s = General.ModuleName();
			Console.WriteLine("ModuleName={0}", s);
            n = General.IsWin64();
            Console.WriteLine("IsWin64={0}", n);
            s = General.Platform();
            Console.WriteLine("Platform={0}", s);
            ch = General.LicenceType();
			Console.WriteLine("LicenceType={0}", ch);
        }

        static void test_Convert()
        {
            string s;
            byte[] b;
            string b64str;
            //%+
			//***************************
            // HEXADECIMAL CONVERSION TESTS *
            //*******************************
            Console.WriteLine("\nHEX CONVERSION TESTS:");
            b = Cnv.FromHex("deadbeef");
            s = Cnv.ToHex(b);
            Console.WriteLine("ToHex={0}", s);
            s = Cnv.StringFromHex("616263");
            Console.WriteLine("0x616263='{0}'", s);

            //%+
			//**********************
            // BASE64 CONVERSION TESTS *
            //**************************
            Console.WriteLine("BASE64 CONVERSION TESTS:");
            // 0xFEDCBA9876543210 in base64
            b64str = "/ty6mHZUMhA=";
            b = Cnv.FromBase64(b64str);
            Console.WriteLine("'{0}'=0x{1}", b64str, Cnv.ToHex(b));
            // Back to base64
            s = Cnv.ToBase64(b);
            Console.WriteLine("In base64='{0}'", s);
            // Directly to hex
            Console.WriteLine("In hex='{0}'", Cnv.HexFromBase64(b64str));
            // hex -> base64
            s = "FEDCBA9876543210";
            b64str = Cnv.Base64FromHex(s);
            Console.WriteLine("0x{0}='{1}'", s, b64str);

        }

        static void test_ErrorLookup()
        {
            string s;
            //%+
			//*****************
            // ERROR LOOKUP TESTS *
            //*********************
            Console.WriteLine("\nERROR CODES:");
            for (int i = 0; i < 10000; i++)
            {
                s = General.ErrorLookup(i);
                if (!s.Equals(String.Empty))
                    Console.WriteLine("Error {0}={1}", i, s);
            }
        }

        static void test_Blowfish()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr, ivStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrOk;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
			
            //****************************
            // BLOWFISH ENCRYPTION TESTS *
            //****************************
            //%+
            Console.WriteLine("\nTESTING BLOWFISH:");
            keyStr = "FEDCBA9876543210";
            ptStr = "0123456789ABCDEF";
            ctStr = "0ACEAB0FC6A0A28D";
            // Encrypt in ECB mode using hex strings
            s = Blowfish.Encrypt(ptStr, keyStr, Mode.ECB, null);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Blowfish.Encrypt failed");
            // Decrypt
            s = Blowfish.Decrypt(ctStr, keyStr, Mode.ECB, null);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Blowfish.Decrypt failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            b = Blowfish.Encrypt(arrPlain, arrKey, Mode.ECB, null);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), ctStr, true) == 0, "Blowfish.Encrypt failed");
            b = Blowfish.Decrypt(arrCipher, arrKey, Mode.ECB, null);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), ptStr, true) == 0, "Blowfish.Decrypt failed");

            //%+
            // Encrypt in CBC mode using hex strings
            keyStr = "0123456789ABCDEFF0E1D2C3B4A59687";
            ivStr = "FEDCBA9876543210";
            ptStr = "37363534333231204E6F77206973207468652074696D6520666F722000000000";
            ctStr = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC";
            s = Blowfish.Encrypt(ptStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Blowfish.Encrypt (CBC) failed");
            // Decrypt
            s = Blowfish.Decrypt(ctStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Blowfish.Decrypt (CBC) failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            arrIV = Cnv.FromHex(ivStr);
            b = Blowfish.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), ctStr, true) == 0, "Blowfish.Encrypt (CBC) failed");
            b = Blowfish.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), ptStr, true) == 0, "Blowfish.Decrypt (CBC) failed");

            //%-
            // And again using base64 strings
            keyStr = "ASNFZ4mrze/w4dLDtKWWhw==";
            ivStr = "/ty6mHZUMhA=";
            ptStr = "NzY1NDMyMSBOb3cgaXMgdGhlIHRpbWUgZm9yIAAAAAA=";
            ctStr = "a3e01jAG3uYFsVbidAOXk1jeuecVRhbZWfFlK9X/ksw=";
            s = Blowfish.Encrypt(ptStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Blowfish.Encrypt (CBC-base64) failed");
            // Decrypt
            s = Blowfish.Decrypt(ctStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Blowfish.Decrypt (CBC-base64) failed");

            //%-
            // Pad some data ready for encryption - first in hex format
            okhex = "ffffff";
            s = okhex;
            ptStr = Blowfish.Pad(s);
            Console.WriteLine("Blowfish.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Blowfish.BlockSize * 2)) == 0, "Blowfish.Pad(hex) failed");
            // and remove it
            s = Blowfish.Unpad(ptStr);
            Console.WriteLine("Blowfish.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Blowfish.Unpad(hex) failed");
            // again padding an empty string
            okhex = "";
            s = okhex;
            ptStr = Blowfish.Pad(s);
            Console.WriteLine("Blowfish.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Blowfish.BlockSize * 2)) == 0, "Blowfish.Pad(hex) failed");
            // and remove it
            s = Blowfish.Unpad(ptStr);
            Console.WriteLine("Blowfish.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Blowfish.Unpad(hex) failed");
            // Pad using bytes
            arrOk = Cnv.FromHex("ffffffffffffffff");
            b = arrOk;
            arrPlain = Blowfish.Pad(b);
            Console.WriteLine("Blowfish.Pad(0x{0})=0x{1}", Cnv.ToHex(b), Cnv.ToHex(arrPlain));
            Debug.Assert((arrPlain.Length % Blowfish.BlockSize) == 0, "Blowfish.Pad(bytes) failed");
            b = Blowfish.Unpad(arrPlain);
            Console.WriteLine("Blowfish.Unpad(0x{0})=0x{1}", Cnv.ToHex(arrPlain), Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), Cnv.ToHex(arrOk)) == 0, "Blowfish.Unpad(bytes) failed");

            //%+
            // Now use Init-Update-Final
            keyStr = "FEDCBA9876543210";
            ivStr = "0123456789abcdef";
            // Instantiate a new encryption object
            Blowfish oBlf = Blowfish.Instance();
            // Setup to encrypt in CBC mode
            n = oBlf.InitEncrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oBlf.ErrCode == 0, "Blowfish.Initialize failed");

            ptStr = "0101010101010101";
            ctStr = "46733BCD9C72C5E3";
            s = oBlf.Update(ptStr);
            Console.WriteLine("PT1={0}", ptStr);
            Console.WriteLine("CT1={0}", s);
            Console.WriteLine("OK1={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Blowfish.Update failed");
            // Line 2 using bytes
            ptStr = "0202020202020202";
            ctStr = "F434DA62B6869A06";
            b = Cnv.FromHex(ptStr);
            b = oBlf.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("PT2={0}", ptStr);
            Console.WriteLine("CT2={0}", s);
            Console.WriteLine("OK2={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Blowfish.Update failed");
            // Lines 3 and 4 together using hex and a longer input
            ptStr = "03030303030303030404040404040404";
            ctStr = "2AE6DFE458559138DEEBF97D6F83A5F3";
            s = oBlf.Update(ptStr);
            Console.WriteLine("PT3={0}", ptStr);
            Console.WriteLine("CT3={0}", s);
            Console.WriteLine("OK3={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Blowfish.Update failed");

            //%-
            // Create a second object this time to decrypt
            // NB You can only have one Instance at a time in the same thread
            // So this just overwrites the previous one as a test
            // TODO: perhaps return an error here to emphasise the point?
            Blowfish oBlf2 = Blowfish.Instance();
            n = oBlf2.InitDecrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oBlf2.ErrCode == 0, "Blowfish.Init failed");

            ptStr = "0101010101010101";
            ctStr = "46733BCD9C72C5E3";
            s = oBlf2.Update(ctStr);
            Console.WriteLine("CT1={0}", ctStr);
            Console.WriteLine("PT1={0}", s);
            Console.WriteLine("OK1={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Blowfish.Update failed");
            // Line 2 using bytes
            ptStr = "0202020202020202";
            ctStr = "F434DA62B6869A06";
            b = Cnv.FromHex(ctStr);
            b = oBlf2.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("CT2={0}", ctStr);
            Console.WriteLine("PT2={0}", s);
            Console.WriteLine("OK2={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Blowfish.Update failed");
            // Lines 3 and 4 using hex
            ptStr = "03030303030303030404040404040404";
            ctStr = "2AE6DFE458559138DEEBF97D6F83A5F3";
            s = oBlf2.Update(ctStr);
            Console.WriteLine("CT3={0}", ctStr);
            Console.WriteLine("PT3={0}", s);
            Console.WriteLine("OK3={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Blowfish.Update failed");

            // Experiment with object methods
            s = oBlf.ToString();
            Console.WriteLine("oBlf.ToString()={0}", s);
            Type ty = oBlf.GetType();
            Console.WriteLine("oBlf.GetType()={0}", ty);
            n = oBlf.GetHashCode();
            Console.WriteLine("oBlf.GetHashCode()={0}", n);
            n = oBlf2.GetHashCode();
            Console.WriteLine("oBlf2.GetHashCode()={0}", n);

            // Make sure keys are disposed of
            oBlf.Dispose();
            oBlf2.Dispose();
            Console.WriteLine("Blf Objects disposed of.");

            //%+
            // Create a test text file
            excontent = "This is some sample content.";
            fnameData = "excontent.txt";
            File.WriteAllText(fnameData, excontent);

            // Encrypt a file
            keyStr = "fedcba9876543210";
            fnameEnc = "excontent.blf.enc.dat";
            okhex = "D45B1B15FA7960E34D67F6366B5ECDD91E941467F21F5BE34A1F5A5158A8569C";
            n = Blowfish.FileEncrypt(fnameEnc, fnameData, keyStr, Mode.ECB, null);
            if (0 == n)
                Console.WriteLine("Blowfish.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("Blowfish.File returned error code {0}", n);
            Debug.Assert(0 == n, "Blowfish.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "Blowfish.FileEncrypt failed");

            // Decrypt it using byte format of key instead of hex
            fnameCheck = "excontent.blf.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = Blowfish.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, null);
            if (0 == n)
            {
                Console.WriteLine("Blowfish.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("Blowfish.File returned error code {0}", n);
            Debug.Assert(0 == n, "Blowfish.File failed.");


        }

        static void test_Des()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr, ivStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrOk;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
            string keyHex;
            //***************************
            // DES ENCRYPTION TESTS *
            //***************************
            Console.WriteLine("\nTESTING DES:");
            keyStr = "0123456789abcdef";
            ptStr = "4e6f772069732074";
            ctStr = "3fa40e8a984d4815";
            // Encrypt in ECB mode using hex strings
            s = Des.Encrypt(ptStr, keyStr, Mode.ECB, null);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Des.HexECB failed");
            // Decrypt
            s = Des.Decrypt(ctStr, keyStr, Mode.ECB, null);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Des.HexECB failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            b = Des.Encrypt(arrPlain, arrKey, Mode.ECB, null);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Des.Decrypt(arrCipher, arrKey, Mode.ECB, null);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));

            // Encrypt in CBC mode using hex strings
            keyStr = "0123456789abcdef";
            ivStr = "1234567890abcdef";
            ptStr = "4e6f77206973207468652074696d6520666f7220616c6c20";
            ctStr = "e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6";
            s = Des.Encrypt(ptStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Des.Encrypt{Hex,CBC} failed");
            // Decrypt
            s = Des.Decrypt(ctStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Des.Decrypt{Hex,CBC} failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            arrIV = Cnv.FromHex(ivStr);
            b = Des.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Des.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(arrPlain), Cnv.ToHex(b)) == 0, "Des.BytesCBC failed");

            // And again using base64 strings
            keyStr = "ASNFZ4mrze8=";
            ivStr = "EjRWeJCrze8=";
            ptStr = "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwg";
            ctStr = "5cfN3ocr8nxD6TQAjDicD2g3iEmafAX2";
            s = Des.Encrypt(ptStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Des.Encrypt{base64,CBC} failed");
            // Decrypt
            s = Des.Decrypt(ctStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Des.Decrypt{base64,CBC} failed");

            // Pad some data ready for encryption - first in hex format
            okhex = "ffffff";
            s = okhex;
            ptStr = Des.Pad(s);
            Console.WriteLine("Des.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Des.BlockSize * 2)) == 0, "Des.Pad(hex) failed");
            // and remove it
            s = Des.Unpad(ptStr);
            Console.WriteLine("Des.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Des.Unpad(hex) failed");
            // Pad using bytes
            arrOk = Cnv.FromHex("ffffffffffffffff");
            b = arrOk;
            arrPlain = Des.Pad(b);
            Console.WriteLine("Des.Pad(0x{0})=0x{1}", Cnv.ToHex(b), Cnv.ToHex(arrPlain));
            Debug.Assert((arrPlain.Length % Des.BlockSize) == 0, "Des.Pad(bytes) failed");
            b = Des.Unpad(arrPlain);
            Console.WriteLine("Des.Unpad(0x{0})=0x{1}", Cnv.ToHex(arrPlain), Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), Cnv.ToHex(arrOk)) == 0, "Des.Unpad(bytes) failed");

            // Now use Init-Update-Final
            keyStr = "0123456789abcdef";
            ivStr = "1234567890abcdef";
            // Instantiate a new encryption object
            Des oDes = Des.Instance();
            n = oDes.InitEncrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oDes.ErrCode == 0, "Des.Initialize failed");

            ptStr = "4e6f772069732074";
            ctStr = "E5C7CDDE872BF27C";
            s = oDes.Update(ptStr);
            Console.WriteLine("PT1={0}", ptStr);
            Console.WriteLine("CT1={0}", s);
            Console.WriteLine("OK1={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Des.Update failed");
            // Line 2 using bytes
            ptStr = "68652074696d6520";
            ctStr = "43E934008C389C0F";
            b = Cnv.FromHex(ptStr);
            b = oDes.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("PT2={0}", ptStr);
            Console.WriteLine("CT2={0}", s);
            Console.WriteLine("OK2={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Des.Update failed");
            // Line 3 using hex
            ptStr = "666f7220616c6c20";
            ctStr = "683788499A7C05F6";
            s = oDes.Update(ptStr);
            Console.WriteLine("PT3={0}", ptStr);
            Console.WriteLine("CT3={0}", s);
            Console.WriteLine("OK3={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Des.Update failed");

            n = oDes.InitDecrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oDes.ErrCode == 0, "Des.Initialize failed");

            ptStr = "4e6f772069732074";
            ctStr = "E5C7CDDE872BF27C";
            s = oDes.Update(ctStr);
            Console.WriteLine("CT1={0}", ctStr);
            Console.WriteLine("PT1={0}", s);
            Console.WriteLine("OK1={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Des.Update failed");
            // Line 2 using bytes
            ptStr = "68652074696d6520";
            ctStr = "43E934008C389C0F";
            b = Cnv.FromHex(ctStr);
            b = oDes.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("CT2={0}", ctStr);
            Console.WriteLine("PT2={0}", s);
            Console.WriteLine("OK2={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Des.Update failed");
            // Line 3 using hex
            ptStr = "666f7220616c6c20";
            ctStr = "683788499A7C05F6";
            s = oDes.Update(ctStr);
            Console.WriteLine("CT3={0}", ctStr);
            Console.WriteLine("PT3={0}", s);
            Console.WriteLine("OK3={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Des.Update failed");

            // Make sure keys are disposed of
            oDes.Dispose();
            Console.WriteLine("Des Object disposed of.");

            // Create a test text file
            excontent = "This is some sample content.";
            fnameData = "excontent.txt";
            File.WriteAllText(fnameData, excontent);

            // Encrypt a file
            keyStr = "fedcba9876543210";
            fnameEnc = "excontent.des.enc.dat";
            okhex = "84D1604C0A33D9335F7EDB5C7ABE73F86B9C87F0639D45F2C8172C8AA976B247";
            n = Des.FileEncrypt(fnameEnc, fnameData, keyStr, Mode.ECB, null);
            if (0 == n)
                Console.WriteLine("Des.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("Des.File returned error code {0}", n);
            Debug.Assert(0 == n, "Des.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "Des.FileEncrypt failed");

            // Decrypt it using byte format of key instead of hex
            fnameCheck = "excontent.des.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = Des.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, null);
            if (0 == n)
            {
                Console.WriteLine("Des.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("Des.File returned error code {0}", n);
            Debug.Assert(0 == n, "Des.File failed.");

            // Check for a DES weak key (chances of finding in a random-generated key = nil)
            Console.WriteLine("Test Des.CheckKey...");
            keyHex = "0101010101010101";    // WEAK KEY
            n = Des.CheckKey(keyHex);
            Console.WriteLine("Des.CheckKey returned {0} for weak DES key {1} in hex format.", n, keyHex);
            Debug.Assert(0 != n, "Des.CheckKey failed.");
            // again for key in byte array form
            arrKey = Cnv.FromHex(keyHex);
            n = Des.CheckKey(arrKey);
            Console.WriteLine("Des.CheckKey returned {0} for weak DES key {1} in byte format.", n, Cnv.ToHex(arrKey));
            Debug.Assert(0 != n, "Des.CheckKey failed.");

            keyHex = "0101010101010102";    // NOT QUITE WEAK KEY
            n = Des.CheckKey(keyHex);
            Console.WriteLine("Des.CheckKey returned {0} for OK DES key {1} in hex format.", n, keyHex);
            Debug.Assert(0 == n, "Des.CheckKey failed.");
            // again for key in byte array form
            arrKey = Cnv.FromHex(keyHex);
            n = Des.CheckKey(arrKey);
            Console.WriteLine("Des.CheckKey returned {0} for OK DES key {1} in byte format.", n, Cnv.ToHex(arrKey));
            Debug.Assert(0 == n, "Des.CheckKey failed.");

        }

        static void test_Tdea()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr, ivStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrOk;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
            string keyHex;
            //*****************************************************
            // TDEA (Triple DES, 3DES, DES-EDE3) ENCRYPTION TESTS *
            //*****************************************************
            Console.WriteLine("\nTESTING TRIPLE DES:");
            keyStr = "010101010101010101010101010101010101010101010101";
            ptStr = "8000000000000000";
            ctStr = "95F8A5E5DD31D900";
            // Encrypt in ECB mode using hex strings
            s = Tdea.Encrypt(ptStr, keyStr, Mode.ECB, null);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Tdea.HexECB failed");
            // Decrypt
            s = Tdea.Decrypt(ctStr, keyStr, Mode.ECB, null);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Tdea.HexECB failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            b = Tdea.Encrypt(arrPlain, arrKey, Mode.ECB, null);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Tdea.Decrypt(arrCipher, arrKey, Mode.ECB, null);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));

            // Encrypt in CBC mode using hex strings
            keyStr = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32";
            ivStr = "B36B6BFB6231084E";
            ptStr = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808";
            ctStr = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4";
            s = Tdea.Encrypt(ptStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Tdea.Encrypt{Hex,CBC} failed");
            // Decrypt
            s = Tdea.Decrypt(ctStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Tdea.Decrypt{Hex,CBC} failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            arrIV = Cnv.FromHex(ivStr);
            b = Tdea.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Tdea.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(arrPlain), Cnv.ToHex(b)) == 0, "Tdea.BytesCBC failed");

            // ditto using base64 data
            keyStr = "c3x5HyXq0OBGKSVDUvfcYpHlyyaRetoy";
            ivStr = "s2tr+2IxCE4=";
            ptStr = "VGhpcyBzb21lIHNhbXBlIGNvbnRlbnQuCAgICAgICAg=";
            ctStr = "12/RF4+9AvhCMfXB0qL3SkFZSClk9nUkglQiPa+a+OQ=";
            s = Tdea.Encrypt(ptStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Tdea.Encrypt{Base64,CBC} failed");
            // Decrypt
            s = Tdea.Decrypt(ctStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Tdea.Decrypt{Base64,CBC} failed");

            // Pad some data ready for encryption - first in hex format
            okhex = "ffffff";
            s = okhex;
            ptStr = Tdea.Pad(s);
            Console.WriteLine("Tdea.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Tdea.BlockSize * 2)) == 0, "Tdea.Pad(hex) failed");
            // and remove it
            s = Tdea.Unpad(ptStr);
            Console.WriteLine("Tdea.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Tdea.Unpad(hex) failed");
            // Pad using bytes
            arrOk = Cnv.FromHex("ffffffffffffffff");
            b = arrOk;
            arrPlain = Tdea.Pad(b);
            Console.WriteLine("Tdea.Pad(0x{0})=0x{1}", Cnv.ToHex(b), Cnv.ToHex(arrPlain));
            Debug.Assert((arrPlain.Length % Tdea.BlockSize) == 0, "Tdea.Pad(bytes) failed");
            b = Tdea.Unpad(arrPlain);
            Console.WriteLine("Tdea.Unpad(0x{0})=0x{1}", Cnv.ToHex(arrPlain), Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), Cnv.ToHex(arrOk)) == 0, "Tdea.Unpad(bytes) failed");

            // Now use Init-Update-Final
            keyStr = "0123456789abcdeffedcba987654321089abcdef01234567";
            ivStr = "1234567890abcdef";
            // Instantiate a new encryption object
            Tdea oTdea = Tdea.Instance();
            n = oTdea.InitEncrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oTdea.ErrCode == 0, "Tdea.Initialize failed");

            ptStr = "4e6f772069732074";
            ctStr = "204011f986e35647";
            s = oTdea.Update(ptStr);
            Console.WriteLine("PT1={0}", ptStr);
            Console.WriteLine("CT1={0}", s);
            Console.WriteLine("OK1={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Tdea.Update failed");
            // Line 2 using bytes
            ptStr = "68652074696d6520";
            ctStr = "199e47af391620c5";
            b = Cnv.FromHex(ptStr);
            b = oTdea.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("PT2={0}", ptStr);
            Console.WriteLine("CT2={0}", s);
            Console.WriteLine("OK2={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Tdea.Update failed");
            // Line 3 using hex
            ptStr = "666f7220616c6c20";
            ctStr = "bb9a5bcfc86db0bb";
            s = oTdea.Update(ptStr);
            Console.WriteLine("PT3={0}", ptStr);
            Console.WriteLine("CT3={0}", s);
            Console.WriteLine("OK3={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Tdea.Update failed");

            // Now decrypt
            n = oTdea.InitDecrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oTdea.ErrCode == 0, "Tdea.Initialize failed");

            ptStr = "4e6f772069732074";
            ctStr = "204011f986e35647";
            s = oTdea.Update(ctStr);
            Console.WriteLine("CT1={0}", ctStr);
            Console.WriteLine("PT1={0}", s);
            Console.WriteLine("OK1={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Tdea.Update failed");
            // Line 2 using bytes
            ptStr = "68652074696d6520";
            ctStr = "199e47af391620c5";
            b = Cnv.FromHex(ctStr);
            b = oTdea.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("CT2={0}", ctStr);
            Console.WriteLine("PT2={0}", s);
            Console.WriteLine("OK2={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Tdea.Update failed");
            // Line 3 using hex
            ptStr = "666f7220616c6c20";
            ctStr = "bb9a5bcfc86db0bb";
            s = oTdea.Update(ctStr);
            Console.WriteLine("CT3={0}", ctStr);
            Console.WriteLine("PT3={0}", s);
            Console.WriteLine("OK3={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Tdea.Update failed");

            // Make sure keys are disposed of
            oTdea.Dispose();
            Console.WriteLine("Tdea Object disposed of.");

            // Create a test text file
            excontent = "This is some sample content.";
            fnameData = "excontent.txt";
            File.WriteAllText(fnameData, excontent);

            // Encrypt a file
            keyStr = "fedcba98765432100123456789abcdeffedcba9876543210";
            fnameEnc = "excontent.tdea.enc.dat";
            okhex = "DD1E1FA430AE6BE1D3B83245F7A5B17C4BF03688238778E95F2CCD05AF1A8F44";
            n = Tdea.FileEncrypt(fnameEnc, fnameData, keyStr, Mode.ECB, null);
            if (0 == n)
                Console.WriteLine("Tdea.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("Tdea.File returned error code {0}", n);
            Debug.Assert(0 == n, "Tdea.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "Tdea.FileEncrypt failed");

            // Decrypt it using byte format of key instead of hex
            fnameCheck = "excontent.tdea.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = Tdea.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, null);
            if (0 == n)
            {
                Console.WriteLine("Tdea.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("Tdea.File returned error code {0}", n);
            Debug.Assert(0 == n, "Tdea.File failed.");

            // Attempt to encrypt a file with key and IV of invalid length
            Console.WriteLine("Expecting errors...");
            arrIV = Cnv.FromHex("BADBAD");  // 3 bytes, expecting 8
            // Good key, bad IV
            n = Tdea.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("Tdea.File returned error code {0} {1}", n, General.ErrorLookup(n));
            arrKey = Cnv.FromHex("BADBADBADBAD");   // 6 bytes, expecting 24
            // Bad key
            n = Tdea.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.ECB, null);
            Console.WriteLine("Tdea.File returned error code {0} {1}", n, General.ErrorLookup(n));


            // Check for a TDEA weak key (chances of finding in a random-generated key = nil)
            Console.WriteLine("Test Tdea.CheckKey...");
            keyHex = "0101010101010101ffeeccddbbaa99887766554433221100";    // WEAK KEY
            n = Tdea.CheckKey(keyHex);
            Console.WriteLine("Tdea.CheckKey returned {0} for weak TDEA key {1} in hex format.", n, keyHex);
            Debug.Assert(0 != n, "Tdea.CheckKey failed.");
            // again for key in byte array form
            arrKey = Cnv.FromHex(keyHex);
            n = Tdea.CheckKey(arrKey);
            Console.WriteLine("Tdea.CheckKey returned {0} for weak TDEA key {1} in byte format.", n, Cnv.ToHex(arrKey));
            Debug.Assert(0 != n, "Tdea.CheckKey failed.");

            keyHex = "0101010101010102ffeeccddbbaa99887766554433221100";    // NOT QUITE WEAK KEY
            n = Tdea.CheckKey(keyHex);
            Console.WriteLine("Tdea.CheckKey returned {0} for OK TDEA key {1} in hex format.", n, keyHex);
            Debug.Assert(0 == n, "Tdea.CheckKey failed.");
            // again for key in byte array form
            arrKey = Cnv.FromHex(keyHex);
            n = Tdea.CheckKey(arrKey);
            Console.WriteLine("Tdea.CheckKey returned {0} for OK TDEA key {1} in byte format.", n, Cnv.ToHex(arrKey));
            Debug.Assert(0 == n, "Tdea.CheckKey failed.");

        }

        static void test_AES128()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr, ivStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrOk;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
            //***************************
            // AES-128 ENCRYPTION TESTS *
            //***************************
            Console.WriteLine("\nTESTING AES-128:");
            keyStr = "000102030405060708090a0b0c0d0e0f";
            ptStr = "00112233445566778899aabbccddeeff";
            ctStr = "69c4e0d86a7b0430d8cdb78070b4c55a";
            // Encrypt in ECB mode using hex strings
            s = Aes128.Encrypt(ptStr, keyStr, Mode.ECB, null);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes128.HexECB failed");
            // Decrypt
            s = Aes128.Decrypt(ctStr, keyStr, Mode.ECB, null);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes128.HexECB failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            b = Aes128.Encrypt(arrPlain, arrKey, Mode.ECB, null);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Aes128.Decrypt(arrCipher, arrKey, Mode.ECB, null);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));

            // Encrypt in CBC mode using hex strings
            keyStr = "56e47a38c5598974bc46903dba290349";
            ivStr = "8ce82eefbea0da3c44699ed7db51b7d9";
            ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
                + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
                + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
                + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
            ctStr = "c30e32ffedc0774e6aff6af0869f71aa"
                + "0f3af07a9a31a9c684db207eb0ef8e4e"
                + "35907aa632c3ffdf868bb7b29d3d46ad"
                + "83ce9f9a102ee99d49a53e87f4c3da55";
            s = Aes128.Encrypt(ptStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            // Decrypt
            s = Aes128.Decrypt(ctStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            arrIV = Cnv.FromHex(ivStr);
            b = Aes128.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Aes128.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(arrPlain), Cnv.ToHex(b)) == 0, "Aes128.BytesCBC failed");

            // Ditto using base64 strings
            keyStr = "VuR6OMVZiXS8RpA9uikDSQ==";
            ivStr = "jOgu776g2jxEaZ7X21G32Q==";
            ptStr = "oKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/"
                + "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3w==";
            ctStr = "ww4y/+3Ad05q/2rwhp9xqg868HqaManGhNsgfrDvjk"
                + "41kHqmMsP/34aLt7KdPUatg86fmhAu6Z1JpT6H9MPaVQ==";
            s = Aes128.Encrypt(ptStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            // Decrypt
            s = Aes128.Decrypt(ctStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);

            // Pad some data ready for encryption - first in hex format
            okhex = "ffffff";
            s = okhex;
            ptStr = Aes128.Pad(s);
            Console.WriteLine("Aes128.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Aes128.BlockSize * 2)) == 0, "Aes128.Pad(hex) failed");
            // and remove it
            s = Aes128.Unpad(ptStr);
            Console.WriteLine("Aes128.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Aes128.Unpad(hex) failed");
            // again padding an empty string
            okhex = "";
            s = okhex;
            ptStr = Aes128.Pad(s);
            Console.WriteLine("Aes128.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Aes128.BlockSize * 2)) == 0, "Aes128.Pad(hex) failed");
            // and remove it
            s = Aes128.Unpad(ptStr);
            Console.WriteLine("Aes128.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Aes128.Unpad(hex) failed");
            // Pad using bytes
            arrOk = Cnv.FromHex("ffffffffffffffff");
            b = arrOk;
            arrPlain = Aes128.Pad(b);
            Console.WriteLine("Aes128.Pad(0x{0})=0x{1}", Cnv.ToHex(b), Cnv.ToHex(arrPlain));
            Debug.Assert((arrPlain.Length % Aes128.BlockSize) == 0, "Aes128.Pad(bytes) failed");
            b = Aes128.Unpad(arrPlain);
            Console.WriteLine("Aes128.Unpad(0x{0})=0x{1}", Cnv.ToHex(arrPlain), Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), Cnv.ToHex(arrOk)) == 0, "Aes128.Unpad(bytes) failed");

            // Now use Init-Update-Final
            keyStr = "56e47a38c5598974bc46903dba290349";
            ivStr = "8ce82eefbea0da3c44699ed7db51b7d9";
            // Instantiate a new encryption object
            Aes128 oAes128 = Aes128.Instance();
            n = oAes128.InitEncrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oAes128.ErrCode == 0, "Aes128.Initialize failed");

            ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
            ctStr = "c30e32ffedc0774e6aff6af0869f71aa";
            s = oAes128.Update(ptStr);
            Console.WriteLine("PT1={0}", ptStr);
            Console.WriteLine("CT1={0}", s);
            Console.WriteLine("OK1={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes128.Update failed");
            // Line 2 using bytes
            ptStr = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
            ctStr = "0f3af07a9a31a9c684db207eb0ef8e4e";
            b = Cnv.FromHex(ptStr);
            b = oAes128.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("PT2={0}", ptStr);
            Console.WriteLine("CT2={0}", s);
            Console.WriteLine("OK2={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes128.Update failed");
            // Lines 3 and 4 using hex
            ptStr = "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
            ctStr = "35907aa632c3ffdf868bb7b29d3d46ad83ce9f9a102ee99d49a53e87f4c3da55";
            s = oAes128.Update(ptStr);
            Console.WriteLine("PT3={0}", ptStr);
            Console.WriteLine("CT3={0}", s);
            Console.WriteLine("OK3={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes128.Update failed");

            // Now decrypt using the same object
            n = oAes128.InitDecrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oAes128.ErrCode == 0, "Aes128.Initialize failed");

            ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
            ctStr = "c30e32ffedc0774e6aff6af0869f71aa";
            s = oAes128.Update(ctStr);
            Console.WriteLine("CT1={0}", ctStr);
            Console.WriteLine("PT1={0}", s);
            Console.WriteLine("OK1={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes128.Update failed");
            // Line 2 using bytes
            ptStr = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
            ctStr = "0f3af07a9a31a9c684db207eb0ef8e4e";
            b = Cnv.FromHex(ctStr);
            b = oAes128.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("CT2={0}", ctStr);
            Console.WriteLine("PT2={0}", s);
            Console.WriteLine("OK2={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes128.Update failed");
            // Lines 3 and 4 using hex
            ptStr = "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
            ctStr = "35907aa632c3ffdf868bb7b29d3d46ad83ce9f9a102ee99d49a53e87f4c3da55";
            s = oAes128.Update(ctStr);
            Console.WriteLine("CT3={0}", ctStr);
            Console.WriteLine("PT3={0}", s);
            Console.WriteLine("OK3={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes128.Update failed");

            // Make sure keys are disposed of
            oAes128.Dispose();
            Console.WriteLine("AES128 Objects disposed of.");

            // Create a test text file
            excontent = "This is some sample content.";
            fnameData = "excontent.txt";
            File.WriteAllText(fnameData, excontent);

            // Encrypt a file
            keyStr = "fedcba98765432100123456789abcdef";
            fnameEnc = "excontent.aes128.enc.dat";
            okhex = "DBBACBCC97FBFBE869079864B5077245FA9FD96992CFFF3F4387BD0ABC04EBCA";
            n = Aes128.FileEncrypt(fnameEnc, fnameData, keyStr, Mode.ECB, null);
            if (0 == n)
                Console.WriteLine("Aes128.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("Aes128.File returned error code {0}", n);
            Debug.Assert(0 == n, "Aes128.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "Aes128.FileEncrypt failed");

            // Decrypt it using byte format of key instead of hex
            fnameCheck = "excontent.aes128.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = Aes128.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, null);
            if (0 == n)
            {
                Console.WriteLine("Aes128.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("Aes128.File returned error code {0}", n);
            Debug.Assert(0 == n, "Aes128.File failed.");


        }

        static void test_AES192()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr, ivStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrOk;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
 			//***************************
			// AES-192 ENCRYPTION TESTS *
			//***************************
			Console.WriteLine("\nTESTING AES-192:");
			keyStr = "000102030405060708090a0b0c0d0e0f1011121314151617";
			ptStr = "00112233445566778899aabbccddeeff";
			ctStr = "dda97ca4864cdfe06eaf70a0ec0d7191";
			// Encrypt in ECB mode using hex strings
			s = Aes192.Encrypt(ptStr, keyStr, Mode.ECB, null);
			Console.WriteLine("KY={0}",keyStr);
			Console.WriteLine("PT={0}",ptStr);
			Console.WriteLine("CT={0}",s);
			Console.WriteLine("OK={0}",ctStr);
			Debug.Assert(String.Compare(s, ctStr, true)==0, "Aes192.HexECB failed");
			// Decrypt
			s = Aes192.Decrypt(ctStr, keyStr, Mode.ECB, null);
			Console.WriteLine("P'={0}",s);
			Console.WriteLine("OK={0}",ptStr);
			Debug.Assert(String.Compare(s, ptStr, true)==0, "Aes192.HexECB failed");

			// Ditto using byte arrays
			arrPlain = Cnv.FromHex(ptStr);
			arrCipher = Cnv.FromHex(ctStr);
			arrKey = Cnv.FromHex(keyStr);
			b = Aes192.Encrypt(arrPlain, arrKey, Mode.ECB, null);
			Console.WriteLine("CT={0}",Cnv.ToHex(b));
			b = Aes192.Decrypt(arrCipher, arrKey, Mode.ECB, null);
			Console.WriteLine("P'={0}",Cnv.ToHex(b));

			// Encrypt in CBC mode using hex strings
			keyStr = "56e47a38c5598974bc46903dba29034906a9214036b8a15b";
			ivStr = "8ce82eefbea0da3c44699ed7db51b7d9";
			ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
				+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
				+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
				+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
			ctStr = "738237036dfdde9dda3374fa182600c5"
				+ "38d9187a0299725d0a7fdbe844d77578"
				+ "1539e401b5597cbbfa836efd22d998d2"
				+ "1605d8df340622417b911467b5e51a12";
			s = Aes192.Encrypt(ptStr, keyStr, Mode.CBC, ivStr);
			Console.WriteLine("KY={0}",keyStr);
			Console.WriteLine("IV={0}",ivStr);
			Console.WriteLine("PT={0}",ptStr);
			Console.WriteLine("CT={0}",s);
			Console.WriteLine("OK={0}",ctStr);
			// Decrypt
			s = Aes192.Decrypt(ctStr, keyStr, Mode.CBC, ivStr);
			Console.WriteLine("P'={0}",s);
			Console.WriteLine("OK={0}",ptStr);

			// Ditto using byte arrays
			arrPlain = Cnv.FromHex(ptStr);
			arrCipher = Cnv.FromHex(ctStr);
			arrKey = Cnv.FromHex(keyStr);
			arrIV = Cnv.FromHex(ivStr);
			b = Aes192.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV);
			Console.WriteLine("CT={0}",Cnv.ToHex(b));
			b = Aes192.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV);
			Console.WriteLine("P'={0}",Cnv.ToHex(b));
			Debug.Assert(String.Compare(Cnv.ToHex(arrPlain), Cnv.ToHex(b))==0, "Aes192.BytesCBC failed");

			// Ditto using base64 strings
			keyStr = "VuR6OMVZiXS8RpA9uikDSQapIUA2uKFb";
			ivStr = "jOgu776g2jxEaZ7X21G32Q==";
			ptStr = "oKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/"
				+ "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3w==";
			ctStr = "c4I3A2393p3aM3T6GCYAxTjZGHoCmXJdCn/b6"
				+ "ETXdXgVOeQBtVl8u/qDbv0i2ZjSFgXY3zQGIkF7kRRnteUaEg==";
			s = Aes192.Encrypt(ptStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
			Console.WriteLine("KY={0}",keyStr);
			Console.WriteLine("IV={0}",ivStr);
			Console.WriteLine("PT={0}",ptStr);
			Console.WriteLine("CT={0}",s);
			Console.WriteLine("OK={0}",ctStr);
			// Decrypt
			s = Aes192.Decrypt(ctStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
			Console.WriteLine("P'={0}",s);
			Console.WriteLine("OK={0}",ptStr);

			// Pad some data ready for encryption - first in hex format
			okhex = "ffffff";
			s = okhex;
			ptStr = Aes192.Pad(s);
			Console.WriteLine("Aes192.Pad('{0}')='{1}'", s, ptStr);
			Debug.Assert((ptStr.Length % (Aes192.BlockSize * 2)) == 0, "Aes192.Pad(hex) failed");
			// and remove it
			s = Aes192.Unpad(ptStr);
			Console.WriteLine("Aes192.Unpad('{0}')='{1}'", ptStr, s);
			Debug.Assert(s == okhex, "Aes192.Unpad(hex) failed");
			// Pad using bytes
			arrOk = Cnv.FromHex("ffffffffffffffff");
			b = arrOk;
			arrPlain = Aes192.Pad(b);
			Console.WriteLine("Aes192.Pad(0x{0})=0x{1}", Cnv.ToHex(b), Cnv.ToHex(arrPlain));
			Debug.Assert((arrPlain.Length % Aes192.BlockSize) == 0, "Aes192.Pad(bytes) failed");
			b = Aes192.Unpad(arrPlain);
			Console.WriteLine("Aes192.Unpad(0x{0})=0x{1}", Cnv.ToHex(arrPlain), Cnv.ToHex(b));
			Debug.Assert(String.Compare(Cnv.ToHex(b), Cnv.ToHex(arrOk)) == 0, "Aes192.Unpad(bytes) failed");

			// Now use Init-Update-Final
			keyStr = "56e47a38c5598974bc46903dba29034906a9214036b8a15b";
			ivStr = "8ce82eefbea0da3c44699ed7db51b7d9";
			// Instantiate a new encryption object
			Aes192 oAes192 = Aes192.Instance();
			n = oAes192.InitEncrypt(keyStr, Mode.CBC, ivStr);
			Console.WriteLine("Initialize returns {0}", n);
			Debug.Assert(oAes192.ErrCode == 0, "Aes192.Initialize failed");

			ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
			ctStr = "738237036dfdde9dda3374fa182600c5";
			s = oAes192.Update(ptStr);
			Console.WriteLine("PT1={0}", ptStr);
			Console.WriteLine("CT1={0}", s);
			Console.WriteLine("OK1={0}", ctStr);
			Debug.Assert(String.Compare(s, ctStr, true)==0, "Aes192.Update failed");
			// Line 2 using bytes
			ptStr = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
			ctStr = "38d9187a0299725d0a7fdbe844d77578";
			b = Cnv.FromHex(ptStr);
			b = oAes192.Update(b);
			s = Cnv.ToHex(b);
			Console.WriteLine("PT2={0}", ptStr);
			Console.WriteLine("CT2={0}", s);
			Console.WriteLine("OK2={0}", ctStr);
			Debug.Assert(String.Compare(s, ctStr, true)==0, "Aes192.Update failed");
			// Lines 3 and 4 using hex
			ptStr  = "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
			ctStr = "1539e401b5597cbbfa836efd22d998d21605d8df340622417b911467b5e51a12";
			s = oAes192.Update(ptStr);
			Console.WriteLine("PT3={0}", ptStr);
			Console.WriteLine("CT3={0}", s);
			Console.WriteLine("OK3={0}", ctStr);
			Debug.Assert(String.Compare(s, ctStr, true)==0, "Aes192.Update failed");

			n = oAes192.InitDecrypt(keyStr, Mode.CBC, ivStr);
			Console.WriteLine("Initialize returns {0}", n);
			Debug.Assert(oAes192.ErrCode == 0, "Aes192.Initialize failed");

			ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
			ctStr = "738237036dfdde9dda3374fa182600c5";
			s = oAes192.Update(ctStr);
			Console.WriteLine("CT1={0}", ctStr);
			Console.WriteLine("PT1={0}", s);
			Console.WriteLine("OK1={0}", ptStr);
			Debug.Assert(String.Compare(s, ptStr, true)==0, "Aes192.Update failed");
			// Line 2 using bytes
			ptStr = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
			ctStr = "38d9187a0299725d0a7fdbe844d77578";
			b = Cnv.FromHex(ctStr);
			b = oAes192.Update(b);
			s = Cnv.ToHex(b);
			Console.WriteLine("CT2={0}", ctStr);
			Console.WriteLine("PT2={0}", s);
			Console.WriteLine("OK2={0}", ptStr);
			Debug.Assert(String.Compare(s, ptStr, true)==0, "Aes192.Update failed");
			// Lines 3 and 4 using hex
			ptStr = "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
			ctStr = "1539e401b5597cbbfa836efd22d998d21605d8df340622417b911467b5e51a12";
			s = oAes192.Update(ctStr);
			Console.WriteLine("CT3={0}", ctStr);
			Console.WriteLine("PT3={0}", s);
			Console.WriteLine("OK3={0}", ptStr);
			Debug.Assert(String.Compare(s, ptStr, true)==0, "Aes192.Update failed");

			// Make sure keys are disposed of
			oAes192.Dispose();
			Console.WriteLine("AES192 Objects disposed of.");

			// Create a test text file
			excontent = "This is some sample content.";
			fnameData = "excontent.txt";
			File.WriteAllText(fnameData, excontent);

			// Encrypt a file
			keyStr = "fedcba98765432100123456789abcdeffedcba9876543210";
			fnameEnc = "excontent.aes192.enc.dat";
			okhex = "37C94F74ADDC362FA16B2A16DE40B583296A25DB83136E2CD669351EFE61A6C0";
			n = Aes192.FileEncrypt(fnameEnc, fnameData, keyStr, Mode.ECB, null);
			if (0 == n)
				Console.WriteLine("Aes192.File created encrypted file '{0}'", fnameEnc);
			else
				Console.WriteLine("Aes192.File returned error code {0}", n);
			Debug.Assert(0 == n, "Aes192.File failed.");

			// Check we got what we should
			b = File.ReadAllBytes(fnameEnc);
			Console.WriteLine("CT={0}", Cnv.ToHex(b));
			Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true)==0, "Aes192.FileEncrypt failed");

			// Decrypt it using byte format of key instead of hex
			fnameCheck = "excontent.aes192.chk.txt";
			b = Cnv.FromHex(keyStr);
			n = Aes192.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, null);
			if (0 == n)
			{
				Console.WriteLine("Aes192.File decrypted to file '{0}'", fnameCheck);
				// Show contents of file
				s = File.ReadAllText(fnameCheck);
				Debug.Assert(String.Compare(s, excontent)==0, "Decrypted file data does not match");
			}
			else
				Console.WriteLine("Aes192.File returned error code {0}", n);
			Debug.Assert(0 == n, "Aes192.File failed.");

       }

        static void test_AES256()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr, ivStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrOk;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;

            //***************************
            // AES-256 ENCRYPTION TESTS *
            //***************************
            Console.WriteLine("\nTESTING AES-256:");
            keyStr = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
            ptStr = "00112233445566778899aabbccddeeff";
            ctStr = "8EA2B7CA516745BFEAFC49904B496089";
            // Encrypt in ECB mode using hex strings
            s = Aes256.Encrypt(ptStr, keyStr, Mode.ECB, null);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes256.HexECB failed");
            // Decrypt
            s = Aes256.Decrypt(ctStr, keyStr, Mode.ECB, null);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes256.HexECB failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            b = Aes256.Encrypt(arrPlain, arrKey, Mode.ECB, null);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Aes256.Decrypt(arrCipher, arrKey, Mode.ECB, null);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));

            // Encrypt in CBC mode using hex strings
            keyStr = "56e47a38c5598974bc46903dba29034906a9214036b8a15b512e03d534120006";
            ivStr = "8ce82eefbea0da3c44699ed7db51b7d9";
            ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
                + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
                + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
                + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
            ctStr = "28409A2982BD2CF7CE343A7D43F6927F"
                + "DB9EC532BBA569EEC92E57A209C4FDBA"
                + "59ADBA05A5C854694DDC9F7991C01634"
                + "E72BEB4FE0236CB3B119A463891E346F";
            s = Aes256.Encrypt(ptStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes256.Encrypt{Hex,CBC} failed");
            // Decrypt
            s = Aes256.Decrypt(ctStr, keyStr, Mode.CBC, ivStr);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes256.Decrypt{Hex,CBC} failed");

            // Ditto using byte arrays
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            arrKey = Cnv.FromHex(keyStr);
            arrIV = Cnv.FromHex(ivStr);
            b = Aes256.Encrypt(arrPlain, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            b = Aes256.Decrypt(arrCipher, arrKey, Mode.CBC, arrIV);
            Console.WriteLine("P'={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(arrPlain), Cnv.ToHex(b)) == 0, "Aes256.BytesCBC failed");

            // Ditto using base64 strings
            keyStr = "VuR6OMVZiXS8RpA9uikDSQapIUA2uKFbUS4D1TQSAAY=";
            ivStr = "jOgu776g2jxEaZ7X21G32Q==";
            ptStr = "oKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/"
                + "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3w==";
            ctStr = "KECaKYK9LPfONDp9Q/aSf9uexTK7pWnuyS5XognE/"
                + "bpZrboFpchUaU3cn3mRwBY05yvrT+AjbLOxGaRjiR40bw==";
            s = Aes256.Encrypt(ptStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("IV={0}", ivStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            // Decrypt
            s = Aes256.Decrypt(ctStr, keyStr, Mode.CBC, ivStr, EncodingBase.Base64);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);

            // Pad some data ready for encryption - first in hex format
            okhex = "ffffff";
            s = okhex;
            ptStr = Aes256.Pad(s);
            Console.WriteLine("Aes256.Pad('{0}')='{1}'", s, ptStr);
            Debug.Assert((ptStr.Length % (Aes256.BlockSize * 2)) == 0, "Aes256.Pad(hex) failed");
            // and remove it
            s = Aes256.Unpad(ptStr);
            Console.WriteLine("Aes256.Unpad('{0}')='{1}'", ptStr, s);
            Debug.Assert(s == okhex, "Aes256.Unpad(hex) failed");
            // Pad using bytes
            arrOk = Cnv.FromHex("ffffffffffffffff");
            b = arrOk;
            arrPlain = Aes256.Pad(b);
            Console.WriteLine("Aes256.Pad(0x{0})=0x{1}", Cnv.ToHex(b), Cnv.ToHex(arrPlain));
            Debug.Assert((arrPlain.Length % Aes256.BlockSize) == 0, "Aes256.Pad(bytes) failed");
            b = Aes256.Unpad(arrPlain);
            Console.WriteLine("Aes256.Unpad(0x{0})=0x{1}", Cnv.ToHex(arrPlain), Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), Cnv.ToHex(arrOk)) == 0, "Aes256.Unpad(bytes) failed");

            // Now use Init-Update-Final
            keyStr = "56e47a38c5598974bc46903dba29034906a9214036b8a15b512e03d534120006";
            ivStr = "8ce82eefbea0da3c44699ed7db51b7d9";
            // Instantiate a new encryption object
            Aes256 oAes256 = Aes256.Instance();
            n = oAes256.InitEncrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oAes256.ErrCode == 0, "Aes256.Initialize failed");

            ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
            ctStr = "28409A2982BD2CF7CE343A7D43F6927F";
            s = oAes256.Update(ptStr);
            Console.WriteLine("PT1={0}", ptStr);
            Console.WriteLine("CT1={0}", s);
            Console.WriteLine("OK1={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes256.Update failed");
            // Line 2 using bytes
            ptStr = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
            ctStr = "DB9EC532BBA569EEC92E57A209C4FDBA";
            b = Cnv.FromHex(ptStr);
            b = oAes256.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("PT2={0}", ptStr);
            Console.WriteLine("CT2={0}", s);
            Console.WriteLine("OK2={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes256.Update failed");
            // Lines 3 and 4 using hex
            ptStr = "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
            ctStr = "59ADBA05A5C854694DDC9F7991C01634E72BEB4FE0236CB3B119A463891E346F";
            s = oAes256.Update(ptStr);
            Console.WriteLine("PT3={0}", ptStr);
            Console.WriteLine("CT3={0}", s);
            Console.WriteLine("OK3={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Aes256.Update failed");

            n = oAes256.InitDecrypt(keyStr, Mode.CBC, ivStr);
            Console.WriteLine("Initialize returns {0}", n);
            Debug.Assert(oAes256.ErrCode == 0, "Aes256.Initialize failed");

            ptStr = "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
            ctStr = "28409A2982BD2CF7CE343A7D43F6927F";
            s = oAes256.Update(ctStr);
            Console.WriteLine("CT1={0}", ctStr);
            Console.WriteLine("PT1={0}", s);
            Console.WriteLine("OK1={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes256.Update failed");
            // Line 2 using bytes
            ptStr = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf";
            ctStr = "DB9EC532BBA569EEC92E57A209C4FDBA";
            b = Cnv.FromHex(ctStr);
            b = oAes256.Update(b);
            s = Cnv.ToHex(b);
            Console.WriteLine("CT2={0}", ctStr);
            Console.WriteLine("PT2={0}", s);
            Console.WriteLine("OK2={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes256.Update failed");
            // Lines 3 and 4 using hex
            ptStr = "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf";
            ctStr = "59ADBA05A5C854694DDC9F7991C01634E72BEB4FE0236CB3B119A463891E346F";
            s = oAes256.Update(ctStr);
            Console.WriteLine("CT3={0}", ctStr);
            Console.WriteLine("PT3={0}", s);
            Console.WriteLine("OK3={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Aes256.Update failed");

            // Make sure keys are disposed of
            oAes256.Dispose();
            Console.WriteLine("AES256 Objects disposed of.");

            // Create a test text file
            excontent = "This is some sample content.";
            fnameData = "excontent.txt";
            File.WriteAllText(fnameData, excontent);

            // Encrypt a file
            keyStr = "fedcba98765432100123456789abcdeffedcba98765432100123456789abcdef";
            fnameEnc = "excontent.aes256.enc.dat";
            okhex = "7F94B5E5A76B747B9778FD20D033E804790E633D34F78C9194F799DD967996C4";
            n = Aes256.FileEncrypt(fnameEnc, fnameData, keyStr, Mode.ECB, null);
            if (0 == n)
                Console.WriteLine("Aes256.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("Aes256.File returned error code {0}", n);
            Debug.Assert(0 == n, "Aes256.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "Aes256.FileEncrypt failed");

            // Decrypt it using byte format of key instead of hex
            fnameCheck = "excontent.aes256.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = Aes256.FileDecrypt(fnameCheck, fnameEnc, b, Mode.ECB, null);
            if (0 == n)
            {
                Console.WriteLine("Aes256.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("Aes256.File returned error code {0}", n);
            Debug.Assert(0 == n, "Aes256.File failed.");

        }

        static void test_StreamCipher()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            string keyStr;
            string ptStr, ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
            //***********************
            // STREAM CIPHER TESTS *
            //***********************
            Console.WriteLine("\nTESTING STREAM CIPHERS:");
            Console.WriteLine("ARCFOUR (RC4, PC1):");
            // Our original pseudonym for RC4 was PC1
            // [v4.8] Pc1 methods now superseded by CipherStream.

            keyStr = "0123456789abcdef";
            ptStr = "0123456789abcdef";
            ctStr = "75b7878099e0c596";
            // convert to byte arrays
            arrKey = Cnv.FromHex(keyStr);
            arrPlain = Cnv.FromHex(ptStr);
            arrCipher = Cnv.FromHex(ctStr);
            // encrypt
            b = Pc1.Encrypt(arrPlain, arrKey);
            Console.WriteLine("PC1:");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("PT={0}", Cnv.ToHex(arrPlain));
            s = Cnv.ToHex(b);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Pc1.Encrypt failed");
            // decrypt by encrypting again
            b = Pc1.Encrypt(b, arrKey);
            s = Cnv.ToHex(b);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Pc1.Encrypt(2) failed");

            // NEW in v4.8: Pc1 methods are superseded. Use CipherStream. methods instead
            b = CipherStream.Bytes(arrPlain, arrKey, null, 0, CipherStream.Algorithm.Arcfour);
            Console.WriteLine("ARCFOUR:");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("PT={0}", Cnv.ToHex(arrPlain));
            s = Cnv.ToHex(b);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "CipherStream.Bytes failed");
            // decrypt by encrypting again
            b = CipherStream.Bytes(b, arrKey, null, 0, CipherStream.Algorithm.Arcfour);
            s = Cnv.ToHex(b);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "CipherStream.Bytes(2) failed");


            // Again using data directly in hex format
            keyStr = "ef012345";
            ptStr = "00000000000000000000";
            ctStr = "d6a141a7ec3c38dfbd61";
            s = Pc1.Encrypt(ptStr, keyStr);
            Console.WriteLine("PC1:");
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "Pc1.Encrypt(Hex) failed");
            // decrypt by encrypting again
            s = Pc1.Encrypt(s, keyStr);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "Pc1.Encrypt(Hex, 2) failed");

            s = CipherStream.Hex(ptStr, keyStr, "", 0, CipherStream.Algorithm.Arcfour);
            Console.WriteLine("ARCFOUR:");
            Console.WriteLine("KY={0}", keyStr);
            Console.WriteLine("PT={0}", ptStr);
            Console.WriteLine("CT={0}", s);
            Console.WriteLine("OK={0}", ctStr);
            Debug.Assert(String.Compare(s, ctStr, true) == 0, "CipherStream.Hex failed");
            // decrypt by encrypting again
            s = CipherStream.Hex(s, keyStr, "", 0, CipherStream.Algorithm.Arcfour);
            Console.WriteLine("P'={0}", s);
            Console.WriteLine("OK={0}", ptStr);
            Debug.Assert(String.Compare(s, ptStr, true) == 0, "CipherStream.Hex(2) failed");

            // Create a test text file
            excontent = "This is some sample content.";
            fnameData = "excontent.txt";
            File.WriteAllText(fnameData, excontent);

            // Encrypt a file
            keyStr = "fedcba98765432100123456789abcdeffedcba98765432100123456789abcdef";
            fnameEnc = "excontent.pc1.enc.dat";
            okhex = "E61C8126AC8B830C32E5ECF1862BCD70778C42B7C130310206151AB1";
            b = Cnv.FromHex(keyStr);


            n = Pc1.File(fnameEnc, fnameData, b);
            if (0 == n)
                Console.WriteLine("Pc1.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("Pc1.File returned error code {0}", n);
            Debug.Assert(0 == n, "Pc1.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "Pc1.FileEncrypt failed");

            // Decrypt it by encrypting again
            fnameCheck = "excontent.pc1.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = Pc1.File(fnameCheck, fnameEnc, b);
            if (0 == n)
            {
                Console.WriteLine("Pc1.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("Pc1.File returned error code {0}", n);
            Debug.Assert(0 == n, "Pc1.File failed.");

            // DO WITH CipherStream.
            fnameEnc = "excontent.rc4.enc.dat";
            n = CipherStream.File(fnameEnc, fnameData, b, null, 0, CipherStream.Algorithm.Arcfour);
            if (0 == n)
                Console.WriteLine("CipherStream.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("CipherStream.File returned error code {0}", n);
            Debug.Assert(0 == n, "CipherStream.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "CipherStream.File failed");

            // Decrypt it by encrypting again
            fnameCheck = "excontent.rc4.chk.txt";
            b = Cnv.FromHex(keyStr);
            n = CipherStream.File(fnameCheck, fnameEnc, b, null, 0, CipherStream.Algorithm.Arcfour);
            if (0 == n)
            {
                Console.WriteLine("CipherStream.File decrypted to file '{0}'", fnameCheck);
                // Show contents of file
                s = File.ReadAllText(fnameCheck);
                Debug.Assert(String.Compare(s, excontent) == 0, "Decrypted file data does not match");
            }
            else
                Console.WriteLine("CipherStream.File returned error code {0}", n);
            Debug.Assert(0 == n, "CipherStream.File failed.");

            // Create a test text file (Ref: "ChaCha20 and Poly1305 for IETF protocols")
            excontent = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
            fnameData = "sunscreen.txt";
            File.WriteAllText(fnameData, excontent);
            fnameEnc = "sunscreen-chacha.dat";
            okhex = "6E2E359A2568F98041BA0728DD0D6981E97E7AEC1D4360C20A27AFCCFD9FAE0BF91B65C5524733AB8F593DABCD62B3571639D624E65152AB8F530C359F0861D807CA0DBF500D6A6156A38E088A22B65E52BC514D16CCF806818CE91AB77937365AF90BBF74A35BE6B40B8EEDF2785E42874D";

            // ENCRYPT WITH CHACHA20
            Console.WriteLine("\nCHACHA20:");
            arrKey = Cnv.FromHex("00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f");
            arrIV = Cnv.FromHex("00:00:00:00:00:00:00:4a:00:00:00:00");
            Console.WriteLine("Key   = " + Cnv.ToHex(arrKey));
            Console.WriteLine("Nonce = " + Cnv.ToHex(arrIV));
            // Counter = 1
            n = CipherStream.File(fnameEnc, fnameData, arrKey, arrIV, 1, CipherStream.Algorithm.Chacha20);
            if (0 == n)
                Console.WriteLine("CipherStream.File created encrypted file '{0}'", fnameEnc);
            else
                Console.WriteLine("CipherStream.File returned error code {0}", n);
            Debug.Assert(0 == n, "CipherStream.File failed.");

            // Check we got what we should
            b = File.ReadAllBytes(fnameEnc);
            Console.WriteLine("CT={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), okhex, true) == 0, "CipherStream.File failed");

            // Stream cipher of 65-byte block
            Console.WriteLine("\nSTREAM CIPHER 65-BYTE KEYSTREAM:");
            // To generate a keystream of N bytes, encrypt input of N x zero bytes
            arrPlain = new byte[65];    // All zeros

            Console.WriteLine("ARCFOUR:");
            // Ref: RFC6229. Test Vector 7, Key length: 256 bits.
            arrKey = Cnv.FromHex("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20");
            okhex = "eaa6bd25880bf93d3f5d1e4ca2611d91cfa45c9f7e714b54bdfa80027cb14380";
            Console.WriteLine("Key: " + Cnv.ToHex(arrKey));
            Console.WriteLine("IV : " + "n/a");
            b = CipherStream.Bytes(arrPlain, arrKey, null, 0, CipherStream.Algorithm.Arcfour);
            Debug.Assert(b.Length == arrPlain.Length);
            Console.WriteLine("Keystream:\n" + Cnv.ToHex(b));
            // Check bytes we have test vector for
            Debug.Assert(String.Compare(Cnv.ToHex(b).Substring(0, okhex.Length), okhex, true) == 0, "CipherStream.File failed");

            Console.WriteLine("SALSA20:");
            // Ref: `verified.test-vectors.txt` Set 3, vector#  0:
            arrKey = Cnv.FromHex("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
            arrIV = Cnv.FromHex("0000000000000000");
            okhex = "B580F7671C76E5F7441AF87C146D6B513910DC8B4146EF1B3211CF12AF4A4B49E5C874B3EF4F85E7D7ED539FFEBA73EB73E0CCA74FBD306D8AA716C7783E89AF";
            Console.WriteLine("Key: " + Cnv.ToHex(arrKey));
            Console.WriteLine("IV : " + Cnv.ToHex(arrIV));
            b = CipherStream.Bytes(arrPlain, arrKey, arrIV, 0, CipherStream.Algorithm.Salsa20);
            Debug.Assert(b.Length == arrPlain.Length);
            Console.WriteLine("Keystream:\n" + Cnv.ToHex(b));
            // Check bytes we have test vector for
            Debug.Assert(String.Compare(Cnv.ToHex(b).Substring(0, okhex.Length), okhex, true) == 0, "CipherStream.File failed");

            Console.WriteLine("CHACHA20:");
            // Ref: `draft-strombergson-chacha-test-vectors-02.txt` TC7: Sequence patterns in key and IV. Rounds: 20
            arrKey = Cnv.FromHex("00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100");
            arrIV = Cnv.FromHex("0f1e2d3c4b5a6978");
            okhex = "9fadf409c00811d00431d67efbd88fba59218d5d6708b1d685863fabbb0e961eea480fd6fb532bfd494b2151015057423ab60a63fe4f55f7a212e2167ccab931fb";
            Console.WriteLine("Key: " + Cnv.ToHex(arrKey));
            Console.WriteLine("IV : " + Cnv.ToHex(arrIV));
            b = CipherStream.Bytes(arrPlain, arrKey, arrIV, 0, CipherStream.Algorithm.Chacha20);
            Debug.Assert(b.Length == arrPlain.Length);
            Console.WriteLine("Keystream:\n" + Cnv.ToHex(b));
            // Check bytes we have test vector for
            Debug.Assert(String.Compare(Cnv.ToHex(b).Substring(0, okhex.Length), okhex, true) == 0, "CipherStream.File failed");

            // USE INCREMENTAL METHODS
            Console.WriteLine("CHACHA20 (incremental):");
            arrKey = Cnv.FromHex("00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100");
            arrIV = Cnv.FromHex("0f1e2d3c4b5a6978");
            okhex = "9fadf409c00811d00431d67efbd88fba59218d5d6708b1d685863fabbb0e961eea480fd6fb532bfd494b2151015057423ab60a63fe4f55f7a212e2167ccab931fb";
            
            CipherStream oCStream = CipherStream.Instance();
            n = oCStream.Init(arrKey, arrIV, 0, CipherStream.Algorithm.Chacha20);
            Console.WriteLine("oCStream.Init returns {0} (expecting 0)", n);
            Debug.Assert(oCStream.ErrCode == 0, "oCStream.Init failed");

            // Encrypt a 65-byte input of zeros in chunks of 1, 62 and 2 bytes
            arrCipher = new byte[0];    // We'll build up the full ciphertext as we go, for a check
            arrPlain = new byte[1];
            b = oCStream.Update(arrPlain);
            Console.WriteLine(Cnv.ToHex(b));
            arrCipher = ByteArraysConcat(arrCipher, b);

            arrPlain = new byte[62];
            b = oCStream.Update(arrPlain);
            Console.WriteLine(Cnv.ToHex(b));
            arrCipher = ByteArraysConcat(arrCipher, b);

            arrPlain = new byte[2];
            b = oCStream.Update(arrPlain);
            Console.WriteLine(Cnv.ToHex(b));
            arrCipher = ByteArraysConcat(arrCipher, b);

            Console.WriteLine(Cnv.ToHex(arrCipher));
            Debug.Assert(String.Compare(Cnv.ToHex(arrCipher).Substring(0, okhex.Length), okhex, true) == 0, "CipherStream.Update failed");

            
            // We are done with CipherStream object
            oCStream.Dispose();

        }

        static void test_KeyWrap()
        {
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] bcheck;
            string strCheck;
            // **************
            // KEY WRAPPING
            // **************
            Console.WriteLine("\nKEY WRAPPING WITH BLOCK CIPHER:");
            // Some test AES-128 key material data
            Console.WriteLine("Using AES128-Wrap");
            arrPlain = Cnv.FromHex("00112233 44556677 8899aabb ccddeeff");
            Console.WriteLine("Key material={0}", Cnv.ToHex(arrPlain));
            // Key Encryption Key
            arrKey = Cnv.FromHex("c17a44e8 e28d7d64 81d1ddd5 0a3b8914");
            Console.WriteLine("KEK         ={0}", Cnv.ToHex(arrKey));
            // Wrap with AES128-Wrap algorithm
            arrCipher = Cipher.KeyWrap(arrPlain, arrKey, CipherAlgorithm.Aes128);
            Debug.Assert(arrCipher.Length > 0, "Cipher.KeyWrap failed.");
            Console.WriteLine("Wrapped Key ={0}", Cnv.ToHex(arrCipher));
            // Compare to known test vector (AES wrap always gives the same result for the same input)
            strCheck = "503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054";
            Debug.Assert(String.Compare(strCheck, Cnv.ToHex(arrCipher), true) == 0, "AES128-Wrap key material does not match test vector");

            // Check we can unwrap it
            bcheck = Cipher.KeyUnwrap(arrCipher, arrKey, CipherAlgorithm.Aes128);
            Debug.Assert(arrCipher.Length > 0, "Cipher.KeyUnwrap failed.");
            Console.WriteLine("Unwrapped   ={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Unwrapped key is different.");

            // Some test Triple DES key material data
            Console.WriteLine("Using 3DES-Wrap");
            arrPlain = Cnv.FromHex("84e7f2d8 78f89fcc cd2d5eba fc56daf7 3300f27e f771cd68");
            Console.WriteLine("Key material={0}", Cnv.ToHex(arrPlain));
            // Key Encryption Key
            arrKey = Cnv.FromHex("8ad8274e 56f46773 8edd83d4 394e5e29 af7c4089 e4f8d9f4");
            Console.WriteLine("KEK         ={0}", Cnv.ToHex(arrKey));
            // Wrap with 3DES-Wrap algorithm
            arrCipher = Cipher.KeyWrap(arrPlain, arrKey, CipherAlgorithm.Tdea);
            Debug.Assert(arrCipher.Length > 0, "Cipher.KeyWrap failed.");
            Console.WriteLine("Wrapped Key ={0}", Cnv.ToHex(arrCipher));
            // NOTE: We can't compare to known test vector because 3DES wrap gives a different result each time.
            // Check we can unwrap it
            bcheck = Cipher.KeyUnwrap(arrCipher, arrKey, CipherAlgorithm.Tdea);
            Debug.Assert(arrCipher.Length > 0, "Cipher.KeyUnwrap failed.");
            Console.WriteLine("Unwrapped   ={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Unwrapped key is different.");

        }

        static void test_Padding()
        {
            string s;
            int i;
            byte[] b;
            Padding[] arrPads = new Padding[] { 
                Padding.Default,
                Padding.Pkcs5,
                Padding.OneAndZeroes,
                Padding.AnsiX923,
            };

            // *************************
            // PADDING FOR BLOCK CIPHERS
            // *************************
            Console.WriteLine("\nPADDING FOR BLOCK CIPHERS:");
            foreach (Padding padding in arrPads) {
                Console.WriteLine("PADDING={0}", padding.ToString());
                // 1. Pad a byte array of 5 bytes for Triple DES ECB/CBC mode
                b = new byte[5] { 0xff, 0xff, 0xff, 0xff, 0xff };
                Console.WriteLine("Input   =0x{0}", Cnv.ToHex(b));
                b = Cipher.Pad(b, CipherAlgorithm.Tdea, padding);
                Console.WriteLine("Padded  =0x{0}", Cnv.ToHex(b));
                // Now strip the padding
                b = Cipher.Unpad(b, CipherAlgorithm.Tdea, padding);
                Console.WriteLine("Unpadded=0x{0}", Cnv.ToHex(b));
                // 2. Pad a byte array of 18 bytes for AES ECB/CBC mode
                b = new byte[18];
                for (i = 0; i < b.Length; i++) {
                    b[i] = 0xFF;
                }
                Console.WriteLine("Input   =0x{0}", Cnv.ToHex(b));
                b = Cipher.Pad(b, CipherAlgorithm.Aes128, padding);
                Console.WriteLine("Padded  =0x{0}", Cnv.ToHex(b));
                // Now strip the padding
                b = Cipher.Unpad(b, CipherAlgorithm.Aes128, padding);
                Console.WriteLine("Unpadded=0x{0}", Cnv.ToHex(b));
                // 3. Pad an empty byte array for TDEA
                b = new byte[0];
                Console.WriteLine("Input   =0x{0}", Cnv.ToHex(b));
                b = Cipher.Pad(b, CipherAlgorithm.Tdea, padding);
                Console.WriteLine("Padded  =0x{0}", Cnv.ToHex(b));
                // Now strip the padding
                b = Cipher.Unpad(b, CipherAlgorithm.Tdea, padding);
                Console.WriteLine("Unpadded=0x{0}", Cnv.ToHex(b));
                // 4. Pad a hex string for AES
                s = "ff";
                Console.WriteLine("Input   ='{0}'", s);
                s = Cipher.Pad(s, CipherAlgorithm.Aes128, padding);
                Console.WriteLine("Padded  ='{0}'", s);
                // Now strip the padding
                s = Cipher.Unpad(s, CipherAlgorithm.Aes128, padding);
                Console.WriteLine("Unpadded='{0}'", s);
                // 5. Pad an empty hex string for AES
                s = "";
                Console.WriteLine("Input   ='{0}'", s);
                s = Cipher.Pad(s, CipherAlgorithm.Aes128, padding);
                Console.WriteLine("Padded  ='{0}'", s);
                // Now strip the padding
                s = Cipher.Unpad(s, CipherAlgorithm.Aes128, padding);
                Console.WriteLine("Unpadded='{0}'", s);
            }

        }

        static void test_SHA1()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            bool isok;
            int i;
            string fnameData;
            byte[] a1000;
            //**************************
            // SHA-1 HASH DIGEST TESTS *
            //**************************
            Console.WriteLine("\nTESTING SHA-1:");
            // Ansi string input
            s = Sha1.HexHash("abc");
            Console.WriteLine("Sha1('abc')={0}", s);
            // Correct answers from FIPS-180-2
            okhex = "a9993e364706816aba3e25717850c26c9cd0d89d";
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Sha1('abc') failed");

            // byte data input, hex output
            b = new byte[] { 0x61, 0x62, 0x63 };
            s = Sha1.HexHash(b);
            Console.WriteLine("Sha1('abc')={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Sha1('abc') failed");

            // byte data input, byte output
            b = Sha1.BytesHash(b);
            Console.WriteLine("Sha1('abc')={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(okhex, Cnv.ToHex(b), true) == 0, "Sha1('abc') failed");

            // file input
            fnameData = "abc.txt";
            File.WriteAllText(fnameData, "abc");
            s = Sha1.FileHexHash(fnameData);
            Console.WriteLine("Sha1('abc')={0}", s);

            // Get digest of core DLL file
            // See http://www.cryptosys.net/integrity.html
            fnameData = General.ModuleName();
            s = Sha1.FileHexHash(fnameData);
            Console.WriteLine("Sha1(DLL module)={0}", s);

            // Instantiate a new object
            Sha1 oSha1 = Sha1.Instance();
            isok = oSha1.Init();
            Console.WriteLine("oSha1.Init returned {0}", isok);
            Debug.Assert(isok, "Sha1.Init failed");

            n = oSha1.AddData("a");
            n = oSha1.AddData("bc");
            s = oSha1.HexDigest();
            Console.WriteLine("Sha1('abc')={0}", s);

            // Compute SHA1(one million repetitions of 'a')
            oSha1.Init();
            a1000 = new byte[1000];
            for (i = 0; i < 1000; i++)
                a1000[i] = 0x61;	// 'a' in ascii form
            for (i = 0; i < 1000; i++)
            {
                n = oSha1.AddData(a1000);
                Debug.Assert(0 == n, "Sha1.Adddata failed");
            }
            s = oSha1.HexDigest();
            Console.WriteLine("Sha1(1M x 'a')={0}", s);
            okhex = "34aa973cd4c4daa4f61eeb2bdbad27316534016f";
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Sha1(1M x 'a') failed");

        }

        static void test_SHA256()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            bool isok;
            int i;
            string fnameData;
            byte[] a1000;
			//****************************
			// SHA-256 HASH DIGEST TESTS *
			//****************************
			Console.WriteLine("\nTESTING SHA-256:");
			// Ansi string input
			s = Sha256.HexHash("abc");
			Console.WriteLine("Sha256('abc')={0}", s);
			// Correct answers from FIPS-180-2
			okhex = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
			Debug.Assert(String.Compare(okhex, s, true)==0, "Sha256('abc') failed");

			// byte data input, hex output
			b = new byte[] {0x61, 0x62, 0x63};
			s = Sha256.HexHash(b);
			Console.WriteLine("Sha256('abc')={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Sha256('abc') failed");

			// byte data input, byte output
			b = Sha256.BytesHash(b);
			Console.WriteLine("Sha256('abc')={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(Cnv.ToHex(b), s, true) == 0, "Sha256('abc') failed");

			// file input
			fnameData = "abc.txt";
			File.WriteAllText(fnameData, "abc");
			s = Sha256.FileHexHash(fnameData);
			Console.WriteLine("Sha256('abc')={0}", s);

			// Get digest of core DLL file
			// See http://www.cryptosys.net/integrity.html
			fnameData = General.ModuleName();
			s = Sha256.FileHexHash(fnameData);
			Console.WriteLine("Sha256(DLL module)={0}", s);

			// Instantiate a new object
			Sha256 oSha256 = Sha256.Instance();
			isok = oSha256.Init();
			Console.WriteLine("oSha256.Init returned {0}", isok);
			Debug.Assert(isok, "Sha256.Init failed");

			n = oSha256.AddData("a");
			n = oSha256.AddData("bc");
			s = oSha256.HexDigest();
			Console.WriteLine("Sha256('abc')={0}", s);

			// Compute SHA256(one million repetitions of 'a')
			oSha256.Init();
			a1000 = new byte[1000];
			for (i = 0; i < 1000; i++)
				a1000[i] = 0x61;	// 'a' in ascii form
			for (i = 0; i < 1000; i++)
			{
				n = oSha256.AddData(a1000);
				Debug.Assert(0 == n, "Sha256.Adddata failed");
			}
			s = oSha256.HexDigest();
			Console.WriteLine("Sha256(1M x 'a')={0}", s);
			okhex = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0";
			Debug.Assert(String.Compare(okhex, s, true)==0, "Sha256(1M x 'a') failed");

        }

        static void test_MD5()
        {
            string s;
            int n;
            byte[] b;
            string okhex;
            bool isok;
            int i;
            string fnameData;
            byte[] a1000;
            //************************
            // MD5 HASH DIGEST TESTS *
            //************************
            Console.WriteLine("\nTESTING MD5:");
            // Ansi string input
            s = Md5.HexHash("abc");
            Console.WriteLine("Md5('abc')={0}", s);
            // Correct answers from RFC 1321
            okhex = "900150983cd24fb0d6963f7d28e17f72";
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Md5('abc') failed");

            // byte data input, hex output
            b = new byte[] { 0x61, 0x62, 0x63 };
            s = Md5.HexHash(b);
            Console.WriteLine("Md5('abc')={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Md5('abc') failed");

            // byte data input, byte output
            b = Md5.BytesHash(b);
            Console.WriteLine("Md5('abc')={0}", Cnv.ToHex(b));
            Debug.Assert(String.Compare(okhex, Cnv.ToHex(b), true) == 0, "Md5('abc') failed");

            // file input
            fnameData = "abc.txt";
            File.WriteAllText(fnameData, "abc");
            s = Md5.FileHexHash(fnameData);
            Console.WriteLine("Md5('abc')={0}", s);

            // Get digest of core DLL file
            // See http://www.cryptosys.net/integrity.html
            fnameData = General.ModuleName();
            s = Md5.FileHexHash(fnameData);
            Console.WriteLine("Md5(DLL module)={0}", s);

            // Instantiate a new object
            Md5 oMd5 = Md5.Instance();
            isok = oMd5.Init();
            Console.WriteLine("oMd5.Init returned {0}", isok);
            Debug.Assert(isok, "Md5.Init failed");

            n = oMd5.AddData("a");
            n = oMd5.AddData("bc");
            s = oMd5.HexDigest();
            Console.WriteLine("Md5('abc')={0}", s);

            // Compute MD5(one million repetitions of 'a')
            oMd5.Init();
            a1000 = new byte[1000];
            for (i = 0; i < 1000; i++)
                a1000[i] = 0x61;	// 'a' in ascii form
            for (i = 0; i < 1000; i++)
            {
                n = oMd5.AddData(a1000);
                Debug.Assert(0 == n, "Md5.Adddata failed");
            }
            s = oMd5.HexDigest();
            Console.WriteLine("Md5(1M x 'a')={0}", s);
            okhex = "7707d6ae4e027c70eea2a935c2296f21";
            Debug.Assert(String.Compare(okhex, s, true) == 0, "Md5(1M x 'a') failed");
        }

        static void test_Hash()
        {
            string s;
            string fnameInput;

            //*************
            // HASH TESTS *
            //*************
            Console.WriteLine("HASH DIGEST TESTS:");
            // Known test vectors for Hash('abc')
            const string OK_MD5_ABC = "900150983cd24fb0d6963f7d28e17f72";
            const string OK_MD2_ABC = "da853b0d3f88d99b30283a69e6ded6bb";
            const string OK_SHA1_ABC = "a9993e364706816aba3e25717850c26c9cd0d89d";
            const string OK_SHA256_ABC = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
            const string OK_SHA384_ABC = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
            const string OK_SHA512_ABC = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
            const string OK_SHA224_ABC = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7";
            const string OK_RMD160_ABC = "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc";
            //----

            s = Hash.HexFromString("abc", HashAlgorithm.Sha1);
            Console.WriteLine("SHA-1('abc')  ={0}", s);
            Debug.Assert(String.Compare(OK_SHA1_ABC, s, true) == 0, "SHA-1('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Md5);
            Console.WriteLine("MD5('abc')    ={0}", s);
            Debug.Assert(String.Compare(OK_MD5_ABC, s, true) == 0, "MD5('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Md2);
            Console.WriteLine("MD2('abc')    ={0}", s);
            Debug.Assert(String.Compare(OK_MD2_ABC, s, true) == 0, "MD2('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Ripemd160);
            Console.WriteLine("RIPEMD-160('abc')    ={0}", s);
            Debug.Assert(String.Compare(OK_RMD160_ABC, s, true) == 0, "RIPEMD-160('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Sha224);
            Console.WriteLine("SHA-224('abc')=\n{0}", s);
            Debug.Assert(String.Compare(OK_SHA224_ABC, s, true) == 0, "SHA-224('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Sha256);
            Console.WriteLine("SHA-256('abc')=\n{0}", s);
            Debug.Assert(String.Compare(OK_SHA256_ABC, s, true) == 0, "SHA-256('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Sha384);
            Console.WriteLine("SHA-384('abc')=\n{0}", s);
            Debug.Assert(String.Compare(OK_SHA384_ABC, s, true) == 0, "SHA-384('abc')");

            s = Hash.HexFromString("abc", HashAlgorithm.Sha512);
            Console.WriteLine("SHA-512('abc')=\n{0}", s);
            Debug.Assert(String.Compare(OK_SHA512_ABC, s, true) == 0, "SHA-512('abc')");

            // Hex input
            s = Hash.HexFromHex("616263", HashAlgorithm.Sha1);
            Console.WriteLine("SHA-1(0x616263)  ={0}", s);
            Debug.Assert(String.Compare(OK_SHA1_ABC, s, true) == 0, "SHA-1(0x616263)");

            s = Hash.HexFromHex("616263", HashAlgorithm.Sha512);
            Console.WriteLine("SHA-512(0x616263)=\n{0}", s);
            Debug.Assert(String.Compare(OK_SHA512_ABC, s, true) == 0, "SHA-512(0x616263)");

            // Create a test file
            fnameInput = "hello.txt";
            File.WriteAllText(fnameInput, "hello world\r\n");
            // get digest from binary file
            s = Hash.HexFromFile(fnameInput, HashAlgorithm.Sha1);
            Console.WriteLine("SHA1('hello world+CR+LF')={0}", s);
            // and again treating CR-LF as a single LF
            // (we use this when moving between Unix and Windows systems)
            s = Hash.HexFromTextFile(fnameInput, HashAlgorithm.Sha1);
            Console.WriteLine("SHA1('hello world+LF')=   {0}", s);

        }

        static void test_HashBit()
        {
            string s;
            int nbitlen;
            byte[] msg;
            string msgHex;
            //**************************
            // BIT-ORIENTED HASH TESTS *
            //**************************
            // New in v4.6
            Console.WriteLine("\nBIT-ORIENTED HASH TESTS:");
            nbitlen = 9;
            msgHex = "5180";
            msg = Cnv.FromHex(msgHex);
            Console.WriteLine("[SHA-1]");
            Console.WriteLine("[L = {0}]", Hash.LengthInBytes(HashAlgorithm.Sha1));
            Console.WriteLine("Len = {0}", nbitlen);
            Console.WriteLine("Msg = {0}", Cnv.ToHex(msg));
            s = Hash.HexFromBits(msg, nbitlen, HashAlgorithm.Sha1);
            Console.WriteLine("MD = {0}", s);
            Debug.Assert(String.Compare("0f582fa68b71ecdf1dcfc4946019cf5a18225bd2", s, true) == 0, "Hash.HexFromBits failed");
        }

        static void test_HMAC()
        {
            string s;
            byte[] b;
            int i;
            byte[] arrKey;
            byte[] msg;
            string strCheck;
            //*************
			// HMAC TESTS *
			//*************
			Console.WriteLine("\nHMAC TESTS:");
			//  Test case 2 from RFC 2202 and RFC 4231
			//	key =           "Jefe"
			//	key_len         4
			//	data =          "what do ya want for nothing?"
			//	data_len =      28
			
			Console.WriteLine("Test case 2 from RFC 2202 and RFC 4231...");
			// Convert strings to byte arrays
			arrKey = System.Text.Encoding.Default.GetBytes("Jefe");
			msg = System.Text.Encoding.Default.GetBytes("what do ya want for nothing?");
			// Compute HMAC-SHA-1 then check against known test vector
			s = Mac.HexFromBytes(msg, arrKey, MacAlgorithm.HmacSha1);
			Console.WriteLine("HMAC-SHA-1('WDYWFN?','Jefe')={0}", s);
			strCheck = "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79";
			Console.WriteLine("CORRECT=                     {0}", strCheck);
			Debug.Assert(String.Compare(strCheck, s, true)==0, "HMAC does not match test vector");
			// Compute HMAC-SHA-256 then check against known test vector
			s = Mac.HexFromBytes(msg, arrKey, MacAlgorithm.HmacSha256);
			Console.WriteLine("HMAC-SHA-256('WDYWFN?','Jefe')=\n{0}", s);
			strCheck = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843";
			Console.WriteLine("CORRECT=\n{0}", strCheck);
			Debug.Assert(String.Compare(strCheck, s, true)==0, "HMAC does not match test vector");

			//  Test case 4 from RFC 2202 and RFC 4231
			//	key =           0x0102030405060708090a0b0c0d0e0f10111213141516171819
			//	key_len         25
			//	data =          0xcd repeated 50 times
			//	data_len =      50
			
			Console.WriteLine("Test case 4 from RFC 2202 and RFC 4231...");
			arrKey = new byte[25];
			for (i = 0; i < 25; i++)
				arrKey[i] = (byte)(i+1);
			Console.WriteLine("Key={0}", Cnv.ToHex(arrKey));
			msg = new byte[50];
			for (i = 0; i < 50; i++)
				msg[i] = 0xcd;
			Console.WriteLine("Msg={0}", Cnv.ToHex(msg));
			// Output in byte format
			// Compute HMAC-SHA-1 then check against known test vector
			b = Mac.BytesFromBytes(msg, arrKey, MacAlgorithm.HmacSha1);
			Console.WriteLine("HMAC-SHA-1(50(0xcd), 0x0102..19)={0}", Cnv.ToHex(b));
			strCheck = "4c9007f4026250c6bc8414f9bf50c86c2d7235da";
			Console.WriteLine("CORRECT=                         {0}", strCheck);
			Debug.Assert(String.Compare(strCheck, Cnv.ToHex(b), true)==0, "HMAC does not match test vector");
            // Compute HMAC-SHA-224 then check against known test vector
            b = Mac.BytesFromBytes(msg, arrKey, MacAlgorithm.HmacSha224);
            Console.WriteLine("HMAC-SHA-224(50(0xcd), 0x0102..19)=\n{0}", Cnv.ToHex(b));
            strCheck = "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, Cnv.ToHex(b), true) == 0, "HMAC does not match test vector");
			// Compute HMAC-SHA-256 then check against known test vector
			b = Mac.BytesFromBytes(msg, arrKey, MacAlgorithm.HmacSha256);
			Console.WriteLine("HMAC-SHA-256(50(0xcd), 0x0102..19)=\n{0}", Cnv.ToHex(b));
			strCheck = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b";
			Console.WriteLine("CORRECT=\n{0}", strCheck);
			Debug.Assert(String.Compare(strCheck, Cnv.ToHex(b), true)==0, "HMAC does not match test vector");
            // Compute HMAC-SHA-512 then check against known test vector
            b = Mac.BytesFromBytes(msg, arrKey, MacAlgorithm.HmacSha512);
            Console.WriteLine("HMAC-SHA-512(50(0xcd), 0x0102..19)=\n{0}", Cnv.ToHex(b));
            strCheck = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, Cnv.ToHex(b), true) == 0, "HMAC does not match test vector");
            // Compute HMAC-RIPEMD-160 then check against known test vector (RFC2286)
            b = Mac.BytesFromBytes(msg, arrKey, MacAlgorithm.HmacRipemd160);
            Console.WriteLine("HMAC-RIPEMD-160(50(0xcd), 0x0102..19)=\n{0}", Cnv.ToHex(b));
            strCheck = "d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, Cnv.ToHex(b), true) == 0, "HMAC does not match test vector");


        }

        static void test_CMAC()
        {
            string s;
            string strCheck;
            string keyHex;
            string msgHex;
            //*************
            // CMAC TESTS *
            //*************
            Console.WriteLine("\nCMAC TESTS:");
            Console.WriteLine("Test cases from SP800-38B...");
            keyHex = "2b7e151628aed2a6abf7158809cf4f3c";
            // CMAC-AES-128 on the empty string
            msgHex = "";
            s = Mac.HexFromHex(msgHex, keyHex, MacAlgorithm.CmacAes128);
            Console.WriteLine("CMAC-AES-128(K128, '')=\n{0}", s);
            strCheck = "bb1d6929e95937287fa37d129b756746";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, s, true) == 0, "CMAC does not match test vector");

            msgHex = "6bc1bee22e409f96e93d7e117393172a";
            s = Mac.HexFromHex(msgHex, keyHex, MacAlgorithm.CmacAes128);
            Console.WriteLine("CMAC-AES-128(K128, M128)=\n{0}", s);
            strCheck = "070a16b46b4d4144f79bdd9dd04a287c";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, s, true) == 0, "CMAC does not match test vector");

            /* CMAC_AES-256 on Example 12: Mlen = 512 */
            keyHex = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4";
            msgHex = "6bc1bee22e409f96e93d7e117393172a" +
                "ae2d8a571e03ac9c9eb76fac45af8e51" +
                "30c81c46a35ce411e5fbc1191a0a52ef" +
                "f69f2445df4f9b17ad2b417be66c3710";
            s = Mac.HexFromHex(msgHex, keyHex, MacAlgorithm.CmacAes256);
            Console.WriteLine("CMAC-AES-256(K256, M512)=\n{0}", s);
            strCheck = "e1992190549f6ed5696a2c056c315410";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, s, true) == 0, "CMAC does not match test vector");

            /* CMAC_TDEA on Example 16: Mlen = 256 */
            keyHex = "8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5";
            msgHex = "6bc1bee22e409f96e93d7e117393172a" +
                "ae2d8a571e03ac9c9eb76fac45af8e51";
            s = Mac.HexFromHex(msgHex, keyHex, MacAlgorithm.CmacTdea);
            Console.WriteLine("CMAC-DES-EDE(K192, M256)=\n{0}", s);
            strCheck = "33e6b1092400eae5";
            Console.WriteLine("CORRECT=\n{0}", strCheck);
            Debug.Assert(String.Compare(strCheck, s, true) == 0, "CMAC does not match test vector");

        }

        static void test_PBKDF2()
        {
            int n;
            string keyStr;
            string saltHex;
            byte[] arrKey;
            byte[] salt;
            byte[] arrPwd;
            string strCheck;
            //***************
            // PBKDF2 TESTS *
            //***************
            Console.WriteLine("\nTESTING PBKDF2...");
            // convert password string to bytes
            arrPwd = System.Text.Encoding.Default.GetBytes("password");
            // make a salt
            salt = new byte[] { 0x78, 0x57, 0x8e, 0x5a, 0x5d, 0x63, 0xcb, 0x06 };
            // create a 24-byte (192-bit) key
            n = 24;
            arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048);
            Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2");
            Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey));
            // and again for a 64-byte (512-bit) key
            n = 64;
            arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048);
            Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2");
            Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey));
            // Same example using hex format
            saltHex = "78578e5a5d63cb06";
            n = 24;
            strCheck = "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643";
            keyStr = Pbe.Kdf2(n, "password", saltHex, 2048);
            Debug.Assert(keyStr.Length > 0, "ERROR with PbeKdf2/Hex");
            Console.WriteLine("Key({0})={1}", n * 8, keyStr);
            // Compare with known test vector
            Debug.Assert(String.Compare(strCheck, keyStr, true) == 0, "PBKDF Derived key {HMAC-SHA-1} does not match test vector");

            // Use different hash function (SHA-256) in KDF
            Console.WriteLine("Using SHA-256 in KDF...");
            n = 24;
            arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048, HashAlgorithm.Sha256);
            Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2");
            Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey));
            // using hex format
            saltHex = "78578e5a5d63cb06";
            n = 24;
            strCheck = "97B5A91D35AF542324881315C4F849E327C4707D1BC9D322";
            keyStr = Pbe.Kdf2(n, "password", saltHex, 2048, HashAlgorithm.Sha256);
            Debug.Assert(keyStr.Length > 0, "ERROR with PbeKdf2/Hex");
            Console.WriteLine("Key({0})={1}", n * 8, keyStr);
            // Compare with known test vector
            Debug.Assert(String.Compare(strCheck, keyStr, true) == 0, "PBKDF Derived key {HMAC-SHA-256} does not match test vector");

            // And again using SHA-224 in KDF
            Console.WriteLine("Using SHA-224 in KDF...");
            n = 24;
            arrKey = Pbe.Kdf2(n, arrPwd, salt, 2048, HashAlgorithm.Sha224);
            Debug.Assert(arrKey.Length > 0, "ERROR with Pbe.Kdf2");
            Console.WriteLine("Key({0})={1}", n * 8, Cnv.ToHex(arrKey));
            // using hex format
            saltHex = "78578e5a5d63cb06";
            n = 24;
            strCheck = "10CFFEDFB13503519969151E466F587028E0720B387F9AEF";
            keyStr = Pbe.Kdf2(n, "password", saltHex, 2048, HashAlgorithm.Sha224);
            Debug.Assert(keyStr.Length > 0, "ERROR with PbeKdf2/Hex");
            Console.WriteLine("Key({0})={1}", n * 8, keyStr);
            // Compare with known test vector
            Debug.Assert(String.Compare(strCheck, keyStr, true) == 0, "PBKDF Derived key {HMAC-SHA-224} does not match test vector");

        }

        static void test_scrypt()
        {
            int dkLen;
            byte[] key;
            byte[] salt;
            byte[] pwd;
            string checkHex;
            int N, r, p;
            string P, S;
            string keyHex, saltHex;
            //***************
            // SCRYPT TESTS *
            //***************
            Console.WriteLine("\nTESTING SCRYPT...");
            // Test vectors from [RFC7914]
            // scrypt (P="password", S="NaCl", N=1024, r=8, p=16, dkLen=64)
            P = "password";
            S = "NaCl";
            N = 1024;
            r = 8;
            p = 16;
            dkLen = 64;
            // Convert password and salt strings to bytes
            pwd = System.Text.Encoding.Default.GetBytes(P);
            salt = System.Text.Encoding.Default.GetBytes(S);
            checkHex = "FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B3731622EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640";
            key = Pbe.Scrypt(dkLen, pwd, salt, N, r, p);
            Debug.Assert(key.Length > 0, "ERROR with Pbe.Scrypt");
            Console.WriteLine("scrypt(P='{0}',S='{1}',N={2},r={3},p={4})=\n{5}", P, S, N, r, p, Cnv.ToHex(key));
            // Compare with known test vector
            Debug.Assert(String.Compare(checkHex, Cnv.ToHex(key), true) == 0, "SCRYPT derived key does not match test vector");

            // scrypt (P="", S="", N=16, r=1, p=1, dkLen=64)
            P = "";
            S = "";
            N = 16;
            r = 1;
            p = 1;
            dkLen = 64;
            // Convert password and salt strings to bytes
            pwd = System.Text.Encoding.Default.GetBytes(P);
            salt = System.Text.Encoding.Default.GetBytes(S);
            checkHex = "77D6576238657B203B19CA42C18A0497F16B4844E3074AE8DFDFFA3FEDE21442FCD0069DED0948F8326A753A0FC81F17E8D3E0FB2E0D3628CF35E20C38D18906";
            key = Pbe.Scrypt(dkLen, pwd, salt, N, r, p);
            Debug.Assert(key.Length > 0, "ERROR with Pbe.Scrypt");
            Console.WriteLine("scrypt(P='{0}',S='{1}',N={2},r={3},p={4})=\n{5}", P, S, N, r, p, Cnv.ToHex(key));
            // Compare with known test vector
            Debug.Assert(String.Compare(checkHex, Cnv.ToHex(key), true) == 0, "SCRYPT derived key does not match test vector");

            // Work with hex salt and key but plaintext password
            keyHex = Pbe.Scrypt(64, "password", "4E61436C", 1024, 8, 16);

            Console.WriteLine("scrypt='{0}'", keyHex);
            checkHex = "FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B3731622EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640";
            Debug.Assert(String.Compare(checkHex, keyHex, true) == 0, "SCRYPT derived key does not match test vector");
            
            // scrypt (P="pleaseletmein", S="SodiumChloride", N=16384, r=8, p=1, dkLen=64)
            P = "pleaseletmein";
            saltHex = Cnv.ToHex("SodiumChloride");
            N = 16384;
            r = 8;
            p = 1;
            dkLen = 64;
            keyHex = Pbe.Scrypt(dkLen, P, saltHex, N, r, p);
            Console.WriteLine("scrypt(P='{0}',S='{1}',N={2},r={3},p={4})=\n{5}", P, Cnv.StringFromHex(saltHex), N, r, p, keyHex);
            checkHex = "7023BDCB3AFD7348461C06CD81FD38EBFDA8FBBA904F8E3EA9B543F6545DA1F2D5432955613F0FCF62D49705242A9AF9E61E85DC0D651E40DFCF017B45575887";
            Debug.Assert(String.Compare(checkHex, keyHex, true) == 0, "SCRYPT derived key does not match test vector");
        }


        static void test_ZLIB()
        {
            string s;
            int n;
            byte[] b;
            string excontent;
            //*************************
            // ZLIB COMPRESSION TESTS *
            //*************************
            Console.WriteLine("\nTESTING ZLIB COMPRESSION...");
            // Some sample text to compress
            excontent = "hello, hello, hello. This is a 'hello world' message for the world, repeat, for the world.";
            // Convert to bytes
            b = System.Text.Encoding.Default.GetBytes(excontent);
            // Remember uncompressed len for later
            n = b.Length;
            // Compress
            b = Zlib.Deflate(b);
            Debug.Assert(b.Length > 0, "ERROR with Zlib.Deflate");
            Console.WriteLine("Compressed {0} to {1} bytes", n, b.Length);
            Console.WriteLine("DEFL={0}", Cnv.ToHex(b));

            // Now inflate back (note we need the original uncompressed length here)
            b = Zlib.Inflate(b, n);
            Debug.Assert(b.Length > 0, "ERROR with Zlib.Deflate");
            s = System.Text.ASCIIEncoding.Default.GetString(b);
            Console.WriteLine("INFL={0}", s);

        }

        static void test_Random()
        {
            string s;
            int n;
            byte[] b;
            string filename, fname;
            string keyStr;
            byte[] arrKey;
            int i;
            bool isok;

            //**********************
            // RANDOM NUMBER TESTS *
            //**********************
            Console.WriteLine("\nSOME RANDOM NUMBERS...");
            for (i = 0; i < 3; i++)
            {
                s = Rng.NonceHex(8);
                Console.WriteLine("NonceHex={0}", s);
            }
            for (i = 0; i < 3; i++)
            {
                s = Rng.KeyHex(24, "");
                Console.WriteLine("KeyHex={0}", s);
            }
            for (i = 0; i < 3; i++)
            {
                b = Rng.KeyBytes(16, "");
                Console.WriteLine("KeyBytes={0}", Cnv.ToHex(b));
            }
            for (i = 0; i < 3; i++)
            {
                b = Rng.NonceBytes(8);
                Console.WriteLine("NonceBytes={0}", Cnv.ToHex(b));
            }
            for (i = 0; i < 3; i++)
            {
                n = Rng.Number(-100, +200);
                Console.WriteLine("Rng.Number(-100,+200)={0}", n);
            }
            for (i = 0; i < 3; i++)
            {
                n = Rng.Number(-2147483648, +2147483647);
                Console.WriteLine("Rng.Number(-2147483648,+2147483647)={0}", n);
            }

            for (i = 0; i < 3; i++)
            {
                n = Rng.Octet();
                Console.WriteLine("Rng.Octet={0:X2}", n);
            }

            // Initialize with a seed file
            fname = "seed.dat";
            if (!FileExists(fname) && doPrompt)
            {	// No seed file yet, so we'll make one and prompt the user for keyboard entropy
                Console.WriteLine("Creating a new seed file...");
                isok = Rng.MakeSeedFile(fname, "Please type some random keystrokes to create a new seedfile", Rng.Strength.Bits_128);
                Console.WriteLine("Rng.MakeSeedFile('{0}') returns {1} (expecting True)", fname, isok);
                Debug.Assert(true == isok, "Rng.MakeSeedFile failed");
            }
            // If seed file has not been created, Initialize() will create one anyway
            isok = Rng.Initialize(fname);
            Console.WriteLine("Rng.Initialize('{0}') returns {1} (expecting True)", fname, isok);
            Debug.Assert(true == isok, "Rng.Initialize failed");

            // Update the seedfile
            isok = Rng.UpdateSeedFile(fname);
            Console.WriteLine("Rng.UpdateSeedFile('{0}') returns {1} (expecting True)", fname, isok);
            Debug.Assert(true == isok, "Rng.UpdateSeedFile failed");

            if (doPrompt)
            {
                Console.WriteLine("Ask user to type some random keystrokes to add entropy...");
                b = Rng.BytesWithPrompt(16);
                Console.WriteLine("RNG=0x{0}", Cnv.ToHex(b));
                Console.WriteLine("And again with specified strength and custom prompt...");
                b = Rng.BytesWithPrompt(16, "Type until we reach 128 bits...", Rng.Strength.Bits_128);
                Console.WriteLine("RNG=0x{0}", Cnv.ToHex(b));
                Console.WriteLine("And again with output in hex format...");
                keyStr = Rng.HexWithPrompt(16);
                Console.WriteLine("RNG='{0}'", keyStr);
                Console.WriteLine("And again in hex with specified strength and custom prompt...");
                keyStr = Rng.HexWithPrompt(16, "Type until we reach 128 bits...", Rng.Strength.Bits_128);
                Console.WriteLine("RNG='{0}'", keyStr);
            }

            // Test the ability to add "user-entropy"...
            // ... as a string ...
            s = "this is some user entropy in a string, well it should be!";
            arrKey = Rng.KeyBytes(16, s);
            Console.WriteLine("RNG(seeded)=0x{0}", Cnv.ToHex(arrKey));
            keyStr = Rng.KeyHex(16, s);
            Console.WriteLine("RNG(seeded)='{0}'", keyStr);

            // and with some bytes as a "seed"...
            b = new byte[] { 0xde, 0xad, 0xbe, 0xef };
            Console.WriteLine("seed=0x{0}", Cnv.ToHex(b));
            arrKey = Rng.KeyBytes(16, b);
            Console.WriteLine("RNG(seeded)=0x{0}", Cnv.ToHex(arrKey));
            keyStr = Rng.KeyHex(16, b);
            Console.WriteLine("RNG(seeded)='{0}'", keyStr);

            // Do a health check and FIPS-140 stat test on the RNG function
            // NB As of [v4.0.0] Rng.Test now returns true/false, not an int.
            filename = "Fips140.txt";
            isok = Rng.Test(filename);
            Console.WriteLine("Rng.Test('{0}') returns {1} (expecting True)", filename, isok);
            Debug.Assert(isok, "Rng.Test Failed");
            // Test without creating a file
            isok = Rng.Test(null);
            Console.WriteLine("Rng.Test('{0}') returns {1} (expecting True)", null, isok);
            Debug.Assert(isok, "Rng.Test Failed");

            // New in [v4.6]...
            Console.WriteLine("CARRY OUT TESTS AS PER DRBGVS...");
            // Carry out tests as per DRBGVS...
            // DRBG mechanism = HMAC_DRBG SHA1
            // [SHA-1]
            // [PredictionResistance = False]
            // [ReturnedBitsLen = 160]

            // COUNT = 0
            // EntropyInput = d949a64fcf4cd79958e1eb025e750f0b
            // Nonce = ad67cdcbadd17e5e
            // PersonalizationString = 
            // AdditionalInput = 
            // EntropyInputReseed = f86c2fcc9e74102f591f9f276311a0af
            // AdditionalInputReseed = 
            // AdditionalInput = 
            // ReturnedBits = c8d171e7fdd084fc739275fa1e79bd3038857f37
            s = Rng.TestDrbgvs(160, "d949a64fcf4cd79958e1eb025e750f0b", "ad67cdcbadd17e5e", "", "",
                "f86c2fcc9e74102f591f9f276311a0af", "", "");
            Console.WriteLine("ReturnedBits = {0}", s);
            Debug.Assert((String.Compare(s, "c8d171e7fdd084fc739275fa1e79bd3038857f37", true) == 0), "Rng.TestDrbgvs failed");

            // COUNT = 0
            // EntropyInput = 329a2a877b897cf6cb95d54017fe4770
            // Nonce = 16d8e0c752cf4a25
            // PersonalizationString = 3535a9a540be9bd156dd440072f7d35e
            // AdditionalInput = 1b2c842d4a898f6919f1f3dbbbe3aaea
            // EntropyInputReseed = 9075150495f1ba810c37946f86526d9c
            // AdditionalInputReseed = 5b40ba5f1770f04bdfc9979279c58228
            // AdditionalInput = 97c88090b3aa6e60ea837ae38acaa47f
            // ReturnedBits = 90bd05566db522d5b95a292de90be1acde270bb0
            s = Rng.TestDrbgvs(160, "329a2a877b897cf6cb95d54017fe4770", "16d8e0c752cf4a25",
                "3535a9a540be9bd156dd440072f7d35e", "1b2c842d4a898f6919f1f3dbbbe3aaea",
                "9075150495f1ba810c37946f86526d9c", "5b40ba5f1770f04bdfc9979279c58228",
                "97c88090b3aa6e60ea837ae38acaa47f");
            Console.WriteLine("ReturnedBits = {0}", s);
            Debug.Assert((String.Compare(s, "90bd05566db522d5b95a292de90be1acde270bb0", true) == 0), "Rng.TestDrbgvs failed");

        }

        static void test_Wipe()
        {
            byte[] b;
            bool isok;
            string excontent;
            string fnameData;
            //******************
            // WIPE DATA TESTS *
            //******************
            Console.WriteLine("\nTESTING WIPE DATA...");

            // Create a test text file
            excontent = "This is some very secret data.";
            fnameData = "todelete.txt";
            File.WriteAllText(fnameData, excontent);
            isok = Wipe.File(fnameData);
            Console.WriteLine("Wipe.File returns {0}", isok);
            Debug.Assert(isok, "ERROR with Wipe.File");
            Debug.Assert(!FileExists(fnameData), "ERROR: Wipe.File did not delete file");
            // Again, but with simple wipe (one pass, all zeros)
            excontent = "This is some very secret data.";
            fnameData = "todelete.txt";
            File.WriteAllText(fnameData, excontent);
            isok = Wipe.File(fnameData, Wipe.Options.Simple);
            Console.WriteLine("Wipe.File(Simple) returns {0}", isok);
            Debug.Assert(isok, "ERROR with Wipe.File");
            Debug.Assert(!FileExists(fnameData), "ERROR: Wipe.File did not delete file");

            // Copy the string into a byte array
            b = System.Text.Encoding.Default.GetBytes(excontent);
            // Wipe the byte data
            Console.WriteLine("Before={0}", Cnv.ToHex(b));
            isok = Wipe.Data(b);
            Console.WriteLine("Wipe.Data returns {0}", isok);
            Console.WriteLine("After ={0}", Cnv.ToHex(b));
            Debug.Assert(isok, "ERROR with Wipe.Data");

            // Copy to a StringBuilder (we can't wipe a ptStr string)
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(excontent);
            Console.WriteLine("Before=[{0}]", sb.ToString());
            isok = Wipe.String(sb);
            Console.WriteLine("Wipe.String returns {0}", isok);
            Console.WriteLine("After =[{0}]", sb.ToString());
            Debug.Assert(isok, "ERROR with Wipe.String");
        }

        static void test_CRC()
        {
            string s;
            int n;
            byte[] b;
            string excontent;
            string fnameData;
            //************
            // CRC TESTS *
            //************
            Console.WriteLine("\nTESTING CRC CHECKSUMS...");
            // Create a test text file
            excontent = "hello world\r\n";
            fnameData = "hello.txt";
            File.WriteAllText(fnameData, excontent);
            n = Crc.File(fnameData);
            Console.WriteLine("CRC32('{0}')={1:x}", fnameData, n);

            s = "123456789";
            n = Crc.Data(s);
            Console.WriteLine("CRC32('{0}')={1:x}", s, n);

            // Convert to bytes
            b = System.Text.Encoding.Default.GetBytes(s);
            n = Crc.Data(b);
            Console.WriteLine("CRC32(0x{0})={1:x}", Cnv.ToHex(b), n);

        }

        static void test_GCM()
        {
            int n;
            string ctStr;
            byte[] arrPlain;
            byte[] arrCipher;
            byte[] arrKey;
            byte[] arrIV;
            byte[] arrTag;
            byte[] arrAAD;
            byte[] bcheck;
            // ******************************
            // GCM AUTHENTICATED ENCRYPTION *
            // ******************************
            Console.WriteLine("\nGCM AUTHENTICATED ENCRYPTION (AES-GCM) AND GMAC:");
            // Ref: McGrew & Viega, The Galois/Counter Mode of Operation (GCM), May, 31 2005

            Console.WriteLine("AES-GCM Test case 2:");
            arrKey = Cnv.FromHex("00000000000000000000000000000000");
            arrPlain = Cnv.FromHex("00000000000000000000000000000000");
            arrIV = Cnv.FromHex("000000000000000000000000");
            Console.WriteLine("K ={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("P ={0}", Cnv.ToHex(arrPlain));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            arrTag = new byte[16];    // Add this to avoid "before it has been assigned a value" error
            arrCipher = Gcm.Encrypt(out arrTag, arrPlain, arrKey, arrIV, null);
            Console.WriteLine("C ={0}", Cnv.ToHex(arrCipher));
            Console.WriteLine("T ={0}", Cnv.ToHex(arrTag));
            Debug.Assert(String.Compare(Cnv.ToHex(arrCipher), "0388dace60b6a392f328c2b971b2fe78", true) == 0, "Gcm.Encrypt failed");
            Debug.Assert(String.Compare(Cnv.ToHex(arrTag), "ab6e47d42cec13bdf53a67b21257bddf", true) == 0, "Gcm.Encrypt failed");
            // Decrypt and check against original plain text
            bcheck = Gcm.Decrypt(arrCipher, arrKey, arrIV, null, arrTag);
            Console.WriteLine("P'={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Gcm.Decrypt failed");
            // Try shorter tag value
            byte[] tag2 = new byte[4];
            Array.Copy(arrTag, tag2, tag2.Length);
            bcheck = Gcm.Decrypt(arrCipher, arrKey, arrIV, null, tag2);
            Console.WriteLine("T2={0}", Cnv.ToHex(tag2));
            Console.WriteLine("P2={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Gcm.Decrypt (short tag) failed");

            Console.WriteLine("AES-GCM Test case 17:");
            arrKey = Cnv.FromHex("feffe9928665731c6d6a8f9467308308" +
                "feffe9928665731c6d6a8f9467308308");
            arrPlain = Cnv.FromHex("d9313225f88406e5a55909c5aff5269a" +
                "86a7a9531534f7da2e4c303d8a318a72" +
                "1c3c0c95956809532fcf0e2449a6b525" +
                "b16aedf5aa0de657ba637b39");
            arrAAD = Cnv.FromHex("feedfacedeadbeeffeedfacedeadbeef" +
                "abaddad2");
            arrIV = Cnv.FromHex("cafebabefacedbad");
            ctStr = "c3762df1ca787d32ae47c13bf19844cb" +
                    "af1ae14d0b976afac52ff7d79bba9de0" +
                    "feb582d33934a4f0954cc2363bc73f78" +
                    "62ac430e64abe499f47c9b1f";
            Console.WriteLine("K ={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("P ={0}", Cnv.ToHex(arrPlain));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            arrCipher = Gcm.Encrypt(out arrTag, arrPlain, arrKey, arrIV, arrAAD);
            Console.WriteLine("C ={0}", Cnv.ToHex(arrCipher));
            Console.WriteLine("T ={0}", Cnv.ToHex(arrTag));
            Debug.Assert(String.Compare(Cnv.ToHex(arrCipher), ctStr, true) == 0, "Gcm.Encrypt failed");
            Debug.Assert(String.Compare(Cnv.ToHex(arrTag), "3a337dbf46a792c45e454913fe2ea8f2", true) == 0, "Gcm.Encrypt failed");
            // Decrypt and check against original plain text
            bcheck = Gcm.Decrypt(arrCipher, arrKey, arrIV, arrAAD, arrTag);
            Console.WriteLine("P'={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Gcm.Decrypt failed");

            Console.WriteLine("GMAC test vectors:");
            arrKey = Cnv.FromHex("feffe9928665731c6d6a8f9467308308");
            arrIV = Cnv.FromHex("cafebabefacedbaddecaf888");
            arrAAD = Cnv.FromHex("feedfacedeadbeeffeedfacedeadbeef");
            Console.WriteLine("K ={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            Console.WriteLine("A ={0}", Cnv.ToHex(arrAAD));
            arrTag = Gcm.Gmac(arrKey, arrIV, arrAAD);
            Console.WriteLine("T ={0}", Cnv.ToHex(arrTag));
            Debug.Assert(String.Compare(Cnv.ToHex(arrTag), "54df474f4e71a9ef8a09bf30da7b1a92", true) == 0, "Gcm.Gmac failed");

            Console.WriteLine("Use stateful InitKey-NextEncrypt-Dispose methods:");
            Gcm oGcm = Gcm.Instance();
            Console.WriteLine("First, try InitKey with bad key (too short)...");
            arrKey = Cnv.FromHex("badace");
            Console.WriteLine("K ={0}", Cnv.ToHex(arrKey));
            n = oGcm.InitKey(arrKey);
            Console.WriteLine("Gcm.InitKey returns {0}", n);
            Console.WriteLine("Error={0}", General.ErrorLookup(oGcm.ErrCode));
            Console.WriteLine("...line above should be an error.");

            // Do Test Case 3 then 4. Same key.
            Console.WriteLine("Setup AES-GCM key for continued use...");
            arrKey = Cnv.FromHex("feffe9928665731c6d6a8f9467308308");
            Console.WriteLine("K ={0}", Cnv.ToHex(arrKey));
            n = oGcm.InitKey(arrKey);
            Debug.Assert(0 == n, "oGcm.InitKey failed");

            Console.WriteLine("AES-GCM Test case 3:");
            arrPlain = Cnv.FromHex(
                "d9313225f88406e5a55909c5aff5269a" +
                "86a7a9531534f7da2e4c303d8a318a72" +
                "1c3c0c95956809532fcf0e2449a6b525" +
                "b16aedf5aa0de657ba637b391aafd255");
            arrAAD = null;
            arrIV = Cnv.FromHex("cafebabefacedbaddecaf888");
            ctStr = "42831ec2217774244b7221b784d0d49c" +
                    "e3aa212f2c02a4e035c17e2329aca12e" +
                    "21d514b25466931c7d8f6a5aac84aa05" +
                    "1ba30b396a0aac973d58e091473f5985";
            Console.WriteLine("P ={0}", Cnv.ToHex(arrPlain));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            arrCipher = oGcm.NextEncrypt(out arrTag, arrPlain, arrIV, arrAAD);
            Console.WriteLine("C ={0}", Cnv.ToHex(arrCipher));
            Console.WriteLine("T ={0}", Cnv.ToHex(arrTag));
            Debug.Assert(String.Compare(Cnv.ToHex(arrCipher), ctStr, true) == 0, "Gcm.Encrypt failed");
            Debug.Assert(String.Compare(Cnv.ToHex(arrTag), "4d5c2af327cd64a62cf35abd2ba6fab4", true) == 0, "Gcm.NextEncrypt failed");
            // Decrypt and check against original plain text
            bcheck = oGcm.NextDecrypt(arrCipher, arrIV, arrAAD, arrTag);
            Console.WriteLine("P'={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Gcm.NextDecrypt failed");

            Console.WriteLine("AES-GCM Test case 4:");
            arrPlain = Cnv.FromHex(
                "d9313225f88406e5a55909c5aff5269a" +
                "86a7a9531534f7da2e4c303d8a318a72" +
                "1c3c0c95956809532fcf0e2449a6b525" +
                "b16aedf5aa0de657ba637b39");
            arrAAD = Cnv.FromHex("feedfacedeadbeeffeedfacedeadbeefabaddad2");
            arrIV = Cnv.FromHex("cafebabefacedbaddecaf888");
            ctStr = "42831ec2217774244b7221b784d0d49c" +
                    "e3aa212f2c02a4e035c17e2329aca12e" +
                    "21d514b25466931c7d8f6a5aac84aa05" +
                    "1ba30b396a0aac973d58e091";
            Console.WriteLine("P ={0}", Cnv.ToHex(arrPlain));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            arrCipher = oGcm.NextEncrypt(out arrTag, arrPlain, arrIV, arrAAD);
            Console.WriteLine("C ={0}", Cnv.ToHex(arrCipher));
            Console.WriteLine("T ={0}", Cnv.ToHex(arrTag));
            Debug.Assert(String.Compare(Cnv.ToHex(arrCipher), ctStr, true) == 0, "Gcm.Encrypt failed");
            Debug.Assert(String.Compare(Cnv.ToHex(arrTag), "5bc94fbc3221a5db94fae95ae7121a47", true) == 0, "Gcm.NextEncrypt failed");
            // Decrypt and check against original plain text
            bcheck = oGcm.NextDecrypt(arrCipher, arrIV, arrAAD, arrTag);
            Console.WriteLine("P'={0}", Cnv.ToHex(bcheck));
            Debug.Assert(ByteArraysEqual(bcheck, arrPlain), "Gcm.NextDecrypt failed");

            // Destroy the key we set up
            oGcm.Dispose();
            Console.WriteLine("...Key has been destroyed.");

        }

        static void test_AEAD()
        {
            byte[] pt;
            byte[] ct;
            byte[] key;
            byte[] nonce;
            byte[] tag;
            byte[] aad;
            byte[] check;
            byte[] ctok;
            byte[] tagok;
            bool isok;
            // ***********************************************
            // AUTHENTICATED ENCRYPTION WITH ASSOCIATED DATA *
            // ***********************************************
            Console.WriteLine("\nAUTHENTICATED ENCRYPTION WITH ASSOCIATED DATA:");

            Console.WriteLine("NIST 800-38D AES-GCM Test case 2:");
            key = Cnv.FromHex("00000000000000000000000000000000");
            pt = Cnv.FromHex("00000000000000000000000000000000");
            nonce = Cnv.FromHex("000000000000000000000000");
            ctok = Cnv.FromHex("0388dace60b6a392f328c2b971b2fe78");
            tagok = Cnv.FromHex("ab6e47d42cec13bdf53a67b21257bddf");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            Console.WriteLine("P: " + Cnv.ToHex(pt));

            tag = new byte[0];    // Do this to avoid "before it has been assigned a value" error
            ct = Aead.Encrypt(out tag, pt, key, nonce, null, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("C: " + Cnv.ToHex(ct));
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Encrypt failed");
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");
            // Decrypt and check against original plain text
            check = Aead.Decrypt(ct, key, nonce, null, tag, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("P':" + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(check, pt), "Aead.Decrypt failed");
            // Try shorter tag value
            byte[] tag2 = new byte[4];
            Array.Copy(tag, tag2, tag2.Length);
            check = Gcm.Decrypt(ct, key, nonce, null, tag2);
            Console.WriteLine("T2:" + Cnv.ToHex(tag2));
            Console.WriteLine("P2:" + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(check, pt), "Aead.Decrypt (short tag) failed");

            Console.WriteLine("\nIEEE P802.1 MACsec 2.4.1 54-byte Packet Encryption Using GCM-AES-128:");
            key = Cnv.FromHex("071b113b 0ca743fe cccf3d05 1f737382");
            nonce = Cnv.FromHex("f0761e8d cd3d0001 76d457ed");
            aad = Cnv.FromHex("e20106d7 cd0df076 1e8dcd3d 88e54c2a 76d457ed");
            pt = Cnv.FromHex("08000f10 11121314 15161718 191a1b1c 1d1e1f20 21222324 25262728 292a2b2c 2d2e2f30 31323334 0004");
            ctok = Cnv.FromHex("13b4c72b 389dc501 8e72a171 dd85a5d3 752274d3 a019fbca ed09a425 cd9b2e1c 9b72eee7 c9de7d52 b3f3");
            tagok = Cnv.FromHex("d6a5284f 4a6d3fe2 2a5d6c2b 960494c3");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            Console.WriteLine("P: " + Cnv.ToHex(pt));
            tag = new byte[0];    // Do this to avoid "before it has been assigned a value" error
            ct = Aead.Encrypt(out tag, pt, key, nonce, aad, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("C: " + Cnv.ToHex(ct));
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Encrypt failed");
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");
            // Decrypt and check against original plain text
            check = Aead.Decrypt(ct, key, nonce, aad, tag, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("P':" + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(check, pt), "Aead.Decrypt failed");

            Console.WriteLine("\nIEEE P802.1 MACsec 2.6.2 61-byte Packet Encryption Using GCM-AES-256:");
            key = Cnv.FromHex("83c093b5 8de7ffe1 c0da926a c43fb360 9ac1c80f ee1b6244 97ef942e 2f79a823");
            nonce = Cnv.FromHex("7cfde9f9 e33724c6 8932d612");
            aad = Cnv.FromHex("84c5d513 d2aaf6e5 bbd27277 88e52f00 8932d612 7cfde9f9 e33724c6");
            pt = Cnv.FromHex("08000f10 11121314 15161718 191a1b1c 1d1e1f20 21222324 25262728 292a2b2c 2d2e2f30 31323334 35363738 393a3b00 06");
            ctok = Cnv.FromHex("110222ff 8050cbec e66a813a d09a73ed 7a9a089c 106b9593 89168ed6 e8698ea9 02eb1277 dbec2e68 e473155a 15a7daee d4");
            tagok = Cnv.FromHex("a10f4e05 139c23df 00b3aadc 71f0596a");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            Console.WriteLine("P: " + Cnv.ToHex(pt));
            tag = new byte[0];    // Do this to avoid "before it has been assigned a value" error
            ct = Aead.Encrypt(out tag, pt, key, nonce, aad, Aead.Algorithm.Aes_256_Gcm);
            Console.WriteLine("C: " + Cnv.ToHex(ct));
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Encrypt failed");
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");
            // Decrypt and check against original plain text
            check = Aead.Decrypt(ct, key, nonce, aad, tag, Aead.Algorithm.Aes_256_Gcm);
            Console.WriteLine("P':" + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(check, pt), "Aead.Decrypt failed");

            Console.WriteLine("\nIEEE P802.1 MACsec 2.1.1 54-byte Packet Authentication Using GCM-AES-128:");
            key = Cnv.FromHex("ad7a2bd0 3eac835a 6f620fdc b506b345");
            nonce = Cnv.FromHex("12153524 c0895e81 b2c28465");
            aad = Cnv.FromHex("d609b1f0 56637a0d 46df998d 88e5222a b2c28465 12153524 c0895e81 08000f10 11121314 15161718 191a1b1c 1d1e1f20 21222324 25262728 292a2b2c 2d2e2f30 31323334 0001");
            tagok = Cnv.FromHex("f09478a9 b09007d0 6f46e9b6 a1da25dd");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            // Compute MAC over AAD
            tag = Aead.Mac(key, nonce, aad, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Mac failed");
            // Authenticate over AAD
            isok = Aead.Authenticate(key, nonce, aad, tag, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("Aead.Authenticate returns " + isok);
            Debug.Assert(isok, "Aead.Authenticate failed");

            Console.WriteLine("\nRFC7739 ChaCha20_Poly1305 Sunscreen test:");
            key = Cnv.FromHex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
            nonce = Cnv.FromHex("070000004041424344454647");
            aad = Cnv.FromHex("50515253c0c1c2c3c4c5c6c7");
            pt = Cnv.FromHex("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e");
            ctok = Cnv.FromHex("d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116");
            tagok = Cnv.FromHex("1ae10b594f09e26a7e902ecbd0600691");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            Console.WriteLine("A: " + Cnv.ToHex(aad));
            Console.WriteLine("P: " + Cnv.ToHex(pt));

            tag = new byte[0];    // Do this to avoid "before it has been assigned a value" error
            ct = Aead.Encrypt(out tag, pt, key, nonce, aad, Aead.Algorithm.Chacha20_Poly1305);

            Console.WriteLine("C: " + Cnv.ToHex(ct));
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Encrypt failed");
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");

            // Decrypt and check against original plain text
            check = Aead.Decrypt(ct, key, nonce, aad, tag, Aead.Algorithm.Chacha20_Poly1305);
            Console.WriteLine("P':" + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(check, pt), "Aead.Decrypt failed");

            Console.WriteLine("\nChaCha20_Poly1305 empty PT and AAD strings:");
            key = Cnv.FromHex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
            nonce = Cnv.FromHex("070000004041424344454647");
            aad = Cnv.FromHex("");
            pt = Cnv.FromHex("");
            ctok = Cnv.FromHex("");
            tagok = Cnv.FromHex("A0784D7A4716F3FEB4F64E7F4B39BF04");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            Console.WriteLine("A: " + Cnv.ToHex(aad));
            Console.WriteLine("P: " + Cnv.ToHex(pt));

            tag = new byte[0];    // Do this to avoid "before it has been assigned a value" error
            ct = Aead.Encrypt(out tag, pt, key, nonce, aad, Aead.Algorithm.Chacha20_Poly1305);

            Console.WriteLine("C: " + Cnv.ToHex(ct));
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Encrypt failed");
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");

            // Decrypt and check against original plain text
            check = Aead.Decrypt(ct, key, nonce, aad, tag, Aead.Algorithm.Chacha20_Poly1305);
            Console.WriteLine("P':" + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(check, pt), "Aead.Decrypt failed");

            Console.WriteLine("Check we get same tag using .Mac() method");
            tag = Aead.Mac(key, nonce, aad, Aead.Algorithm.Chacha20_Poly1305);
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");


            Console.WriteLine("\nipsecme-chacha20-poly1305 Appendix B IKEv2 Example:");
            key = Cnv.FromHex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
            nonce = Cnv.FromHex("a0 a1 a2 a3 10 11 12 13 14 15 16 17");
            aad = Cnv.FromHex("c0c1c2c3c4c5c6c7d0d1d2d3d4d5d6d72e202500000000090000004529000029");
            pt = Cnv.FromHex("00 00 00 0c 00 00 40 01 00 00 00 0a 00");
            ctok = Cnv.FromHex("61 03 94 70 1f 8d 01 7f 7c 12 92 48 89");
            tagok = Cnv.FromHex("6b 71 bf e2 52 36 ef d7 cd c6 70 66 90 63 15 b2");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            Console.WriteLine("A: " + Cnv.ToHex(aad));
            Console.WriteLine("P: " + Cnv.ToHex(pt));

            tag = new byte[0];    // Do this to avoid "before it has been assigned a value" error
            ct = Aead.Encrypt(out tag, pt, key, nonce, aad, Aead.Algorithm.Chacha20_Poly1305);

            Console.WriteLine("C: " + Cnv.ToHex(ct));
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Encrypt failed");
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");


            // Compute tags for all empty strings for all algorithms
            Console.WriteLine("\nUse Aead.Mac() to compute tags for empty PT and AAD strings:");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));
            tag = Aead.Mac(key, nonce, aad, Aead.Algorithm.Chacha20_Poly1305);
            Console.WriteLine("T (e, Chacha20_Poly1305): " + Cnv.ToHex(tag));
            //Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.Encrypt failed");

            tag = Aead.Mac(key, nonce, aad, Aead.Algorithm.Aes_256_Gcm);
            Console.WriteLine("T (e, Aes_256_Gcm): " + Cnv.ToHex(tag));
            // Shorten the 256-bit key to 128 bits
            Array.Resize(ref key, 16);
            Console.WriteLine("K: " + Cnv.ToHex(key));
            tag = Aead.Mac(key, nonce, aad, Aead.Algorithm.Aes_128_Gcm);
            Console.WriteLine("T (e, Aes_128_Gcm): " + Cnv.ToHex(tag));
        }

        static void test_AEAD_incremental()
        {
            byte[] pt;
            byte[] ct;
            byte[] key;
            byte[] nonce;
            byte[] tag;
            byte[] aad;
            byte[] check;
            byte[] ctok;
            byte[] tagok;
            int r;
            byte[] chunk;
            bool isok;
            int offset, len, nleft, chunklen;
            Aead o;

            // *************************************************************
            // AUTHENTICATED ENCRYPTION WITH ASSOCIATED DATA - INCREMENTAL *
            // *************************************************************
            Console.WriteLine("\nAUTHENTICATED ENCRYPTION WITH ASSOCIATED DATA - INCREMENTAL:");

            Console.WriteLine("\nIEEE P802.1 MACsec 2.6.2 61-byte Packet Encryption Using GCM-AES-256:");
            key = Cnv.FromHex("83c093b5 8de7ffe1 c0da926a c43fb360 9ac1c80f ee1b6244 97ef942e 2f79a823");
            nonce = Cnv.FromHex("7cfde9f9 e33724c6 8932d612");
            pt = Cnv.FromHex("08000f10 11121314 15161718 191a1b1c 1d1e1f20 21222324 25262728 292a2b2c 2d2e2f30 31323334 35363738 393a3b00 06");
            ctok = Cnv.FromHex("110222ff 8050cbec e66a813a d09a73ed 7a9a089c 106b9593 89168ed6 e8698ea9 02eb1277 dbec2e68 e473155a 15a7daee d4");
            tagok = Cnv.FromHex("a10f4e05 139c23df 00b3aadc 71f0596a");
            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));

            // Setup a new Aead object, initialize the key and nonce
            o = Aead.Instance();
            r = o.InitKey(key, Aead.Algorithm.Aes_256_Gcm);
            Debug.Assert(0 == r, "Aead.InitKey failed");
            r = o.SetNonce(nonce);
            Debug.Assert(0 == r, "Aead.SetNonce failed");

            // Add the AAD in chunks
            aad = Cnv.FromHex("84c5d513 d2aaf6e5 bbd27277 88e52f00 8932d612 7cfde9f9 e33724c6");
            Console.WriteLine("A: " + Cnv.ToHex(aad));
            chunk = Cnv.FromHex("84c5d513 d2aaf6e5 bb");
            r = o.AddAAD(chunk);
            Debug.Assert(0 == r, "Aead.AddAAD failed");
            chunk = Cnv.FromHex("d27277 88e52f00 8932d612 7cfde9f9 e337");
            r = o.AddAAD(chunk);
            Debug.Assert(0 == r, "Aead.AddAAD failed");
            chunk = Cnv.FromHex("24c6");
            r = o.AddAAD(chunk);
            Debug.Assert(0 == r, "Aead.AddAAD failed");

            Console.WriteLine("ENCRYPTING IN CHUNKS...");
            r = o.StartEncrypt();
            Debug.Assert(0 == r, "Aead.StartEncrypt failed");

            Console.WriteLine("P-all: " + Cnv.ToHex(pt));

            // Encrypt PT in chunks
            chunklen = 17;
            nleft = pt.Length;
            ct = new byte[pt.Length];

            for (offset = 0, len = chunklen; nleft > 0; offset += len, nleft -= len)
            {
                if (nleft < len) len = nleft;
                chunk = new byte[len];
                Array.Copy(pt, offset, chunk, 0, len);
                Console.WriteLine("P-chunk: " + Cnv.ToHex(chunk));
                chunk = o.Update(chunk);
                Console.WriteLine("C-chunk: " + Cnv.ToHex(chunk));
                Array.Copy(chunk, 0, ct, offset, len);
            }
            Console.WriteLine("C-all: " + Cnv.ToHex(ct));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Update failed");

            tag = o.FinishEncrypt();
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.FinishEncrypt failed");

            // DECRYPT:
            Console.WriteLine("DECRYPTING IN CHUNKS...");
            // Key is set above, reset the nonce to decrypt
            r = o.SetNonce(nonce);
            Debug.Assert(0 == r, "Aead.SetNonce failed");

            // Add the AAD in toto
            aad = Cnv.FromHex("84c5d513 d2aaf6e5 bbd27277 88e52f00 8932d612 7cfde9f9 e33724c6");
            Console.WriteLine("A: " + Cnv.ToHex(aad));
            r = o.AddAAD(aad);

            r = o.StartDecrypt(tag);
            Debug.Assert(0 == r, "Aead.StartDecrypt failed");

            // Decrypt CT in chunks
            chunklen = 13;
            nleft = ct.Length;
            check = new byte[ct.Length];

            for (offset = 0, len = chunklen; nleft > 0; offset += len, nleft -= len)
            {
                if (nleft < len) len = nleft;
                chunk = new byte[len];
                Array.Copy(ct, offset, chunk, 0, len);
                Console.WriteLine("C-chunk: " + Cnv.ToHex(chunk));
                chunk = o.Update(chunk);
                Console.WriteLine("P-chunk: " + Cnv.ToHex(chunk));
                Array.Copy(chunk, 0, check, offset, len);
            }
            Console.WriteLine("P-all: " + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(pt, check), "Aead.Update failed");

            isok = o.FinishDecrypt();
            Console.WriteLine("FinishDecrypt: " + isok);
            Debug.Assert(isok, "Aead.FinishDecrypt failed");

            o.Dispose();

            //************************************
            // DO THE SAME USING CHACHA20_POLY1305
            //************************************

            Console.WriteLine("\nRFC7739 ChaCha20_Poly1305 Sunscreen test:");
            key = Cnv.FromHex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
            nonce = Cnv.FromHex("070000004041424344454647");
            aad = Cnv.FromHex("50515253c0c1c2c3c4c5c6c7");
            pt = Cnv.FromHex("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e");
            ctok = Cnv.FromHex("d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116");
            tagok = Cnv.FromHex("1ae10b594f09e26a7e902ecbd0600691");

            Console.WriteLine("K: " + Cnv.ToHex(key));
            Console.WriteLine("N: " + Cnv.ToHex(nonce));

            // Setup a new Aead object, initialize the key and nonce
            o = Aead.Instance();
            r = o.InitKey(key, Aead.Algorithm.Chacha20_Poly1305);
            Debug.Assert(0 == r, "Aead.InitKey failed");
            r = o.SetNonce(nonce);
            Debug.Assert(0 == r, "Aead.SetNonce failed");

            // Add the AAD in one go
            Console.WriteLine("A: " + Cnv.ToHex(aad));
            r = o.AddAAD(aad);
            Debug.Assert(0 == r, "Aead.AddAAD failed");

            Console.WriteLine("ENCRYPTING IN CHUNKS...");
            r = o.StartEncrypt();
            Debug.Assert(0 == r, "Aead.StartEncrypt failed");

            Console.WriteLine("P-all: " + Cnv.ToHex(pt));

            // Encrypt PT in chunks
            chunklen = 19;
            nleft = pt.Length;
            ct = new byte[pt.Length];

            for (offset = 0, len = chunklen; nleft > 0; offset += len, nleft -= len)
            {
                if (nleft < len) len = nleft;
                chunk = new byte[len];
                Array.Copy(pt, offset, chunk, 0, len);
                Console.WriteLine("P-chunk: " + Cnv.ToHex(chunk));
                chunk = o.Update(chunk);
                Console.WriteLine("C-chunk: " + Cnv.ToHex(chunk));
                Array.Copy(chunk, 0, ct, offset, len);
            }
            Console.WriteLine("C-all: " + Cnv.ToHex(ct));
            Debug.Assert(ByteArraysEqual(ct, ctok), "Aead.Update failed");

            tag = o.FinishEncrypt();
            Console.WriteLine("T: " + Cnv.ToHex(tag));
            Debug.Assert(ByteArraysEqual(tag, tagok), "Aead.FinishEncrypt failed");

            // DECRYPT:
            Console.WriteLine("DECRYPTING IN CHUNKS...");
            // Key is set above, reset the nonce and AAD to decrypt
            r = o.SetNonce(nonce);
            Debug.Assert(0 == r, "Aead.SetNonce failed");
            r = o.AddAAD(aad);
            Debug.Assert(0 == r, "Aead.AddAAD failed");

            r = o.StartDecrypt(tag);
            Debug.Assert(0 == r, "Aead.StartDecrypt failed");

            // Decrypt CT in chunks
            chunklen = 7;
            nleft = ct.Length;
            check = new byte[ct.Length];

            for (offset = 0, len = chunklen; nleft > 0; offset += len, nleft -= len)
            {
                if (nleft < len) len = nleft;
                chunk = new byte[len];
                Array.Copy(ct, offset, chunk, 0, len);
                Console.WriteLine("C-chunk: " + Cnv.ToHex(chunk));
                chunk = o.Update(chunk);
                Console.WriteLine("P-chunk: " + Cnv.ToHex(chunk));
                Array.Copy(chunk, 0, check, offset, len);
            }
            Console.WriteLine("P-all: " + Cnv.ToHex(check));
            Debug.Assert(ByteArraysEqual(pt, check), "Aead.Update failed");

            isok = o.FinishDecrypt();
            Console.WriteLine("FinishDecrypt: " + isok);
            Debug.Assert(isok, "Aead.FinishDecrypt failed");

            o.Dispose();

        }

        static void test_CipherFileExtended()
        {
            int n;
            byte[] arrKey;
            byte[] arrIV;
            string excontent;
            string fnameData;
            string fnameEnc;
            string fnameCheck;
            string fnameChk1;
            // *********************************
            // EXTENDED FILE CIPHER OPERATIONS *
            // *********************************
            Console.WriteLine("\nTESTING EXTENDED FILE CIPHER OPERATIONS:");
            // Create a test text file
            excontent = "Now is the time for";
            fnameData = "nowis19.txt";
            File.WriteAllText(fnameData, excontent);

            Console.WriteLine("Des.FileEncrypt/Decrypt with CipherFileOption...");
            // Encrypt file using DES in CBC mode using byte arrays for key and IV
            fnameEnc = "nowis.des-cbc.enc.dat";
            fnameCheck = "nowis.des-cbc.chk.txt";
            fnameChk1 = "nowis.des-cbc.chk1.txt";
            arrKey = Cnv.FromHex("0123456789ABCDEF");
            arrIV = Cnv.FromHex("1234567890ABCDEF");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            Console.WriteLine("Input file contents ({0} bytes):\n{1}", FileLength(fnameData), GetFileAsHex(fnameData));
            // Use default option
            n = Des.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.Default);
            Console.WriteLine("Des.FileEncrypt(CBC, Default) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Des.FileEncrypt(CBC, Default) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Use PrefixIV option
            n = Des.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.PrefixIV);
            Console.WriteLine("Des.FileEncrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Des.FileEncrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Now decrypt using same PrefixIV option
            n = Des.FileDecrypt(fnameCheck, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV);
            Console.WriteLine("Des.FileDecrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Des.FileDecrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameCheck, FileLength(fnameCheck), GetFileAsHex(fnameCheck));
            // Check we got what we started with
            Debug.Assert(FilesAreIdentical(fnameData, fnameCheck), "Decrypted file does not match original");
            // Now decrypt using LeavePadding option
            n = Des.FileDecrypt(fnameChk1, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV | CipherFileOption.LeavePadding);
            Console.WriteLine("Des.FileDecrypt(CBC, PrefixIV+LeavePadding) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Des.FileDecrypt(CBC, PrefixIV+LeavePadding) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
               fnameChk1, FileLength(fnameChk1), GetFileAsHex(fnameChk1));

            Console.WriteLine("");
            Console.WriteLine("Aes128.FileEncrypt/Decrypt with CipherFileOption...");
            fnameEnc = "nowis.aes128-cbc.enc.dat";
            fnameCheck = "nowis.aes128-cbc.chk.txt";
            fnameChk1 = "nowis.aes128-cbc.chk1.txt";
            arrKey = Cnv.FromHex("0123456789ABCDEFFEDCBA9876543210");
            arrIV = Cnv.FromHex("1234567890ABCDEFFEDCBA0987654321");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            Console.WriteLine("Input file contents ({0} bytes):\n{1}", FileLength(fnameData), GetFileAsHex(fnameData));
            // Use default option
            n = Aes128.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.Default);
            Console.WriteLine("Aes128.FileEncrypt(CBC, Default) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes128.FileEncrypt(CBC, Default) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Use PrefixIV option
            n = Aes128.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.PrefixIV);
            Console.WriteLine("Aes128.FileEncrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes128.FileEncrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Now decrypt using same PrefixIV option
            n = Aes128.FileDecrypt(fnameCheck, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV);
            Console.WriteLine("Aes128.FileDecrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes128.FileDecrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameCheck, FileLength(fnameCheck), GetFileAsHex(fnameCheck));
            // Check we got what we started with
            Debug.Assert(FilesAreIdentical(fnameData, fnameCheck), "Decrypted file does not match original");
            // Now decrypt using LeavePadding option
            n = Aes128.FileDecrypt(fnameChk1, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV | CipherFileOption.LeavePadding);
            Console.WriteLine("Aes128.FileDecrypt(CBC, PrefixIV+LeavePadding) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes128.FileDecrypt(CBC, PrefixIV+LeavePadding) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
               fnameChk1, FileLength(fnameChk1), GetFileAsHex(fnameChk1));

            // Call all other versions at least once
            // AES-192
            Console.WriteLine("Aes192.FileEncrypt/Decrypt with CipherFileOption...");
            fnameEnc = "nowis.aes192-cbc.enc.dat";
            fnameCheck = "nowis.aes192-cbc.chk.txt";
            arrKey = Cnv.FromHex("0123456789ABCDEFFEDCBA987654321089ABCDEF01234567");
            arrIV = Cnv.FromHex("1234567890ABCDEFFEDCBA0987654321");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            // Use PrefixIV option
            n = Aes192.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.PrefixIV);
            Console.WriteLine("Aes192.FileEncrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes192.FileEncrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Now decrypt using same PrefixIV option
            n = Aes192.FileDecrypt(fnameCheck, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV);
            Console.WriteLine("Aes192.FileDecrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes192.FileDecrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameCheck, FileLength(fnameCheck), GetFileAsHex(fnameCheck));
            // Check we got what we started with
            Debug.Assert(FilesAreIdentical(fnameData, fnameCheck), "Decrypted file does not match original");

            // AES-256
            Console.WriteLine("Aes256.FileEncrypt/Decrypt with CipherFileOption...");
            fnameEnc = "nowis.aes256-cbc.enc.dat";
            fnameCheck = "nowis.aes256-cbc.chk.txt";
            arrKey = Cnv.FromHex("0123456789ABCDEFFEDCBA987654321089ABCDEF0123456776543210FEDCBA98");
            arrIV = Cnv.FromHex("1234567890ABCDEFFEDCBA0987654321");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            // Use PrefixIV option
            n = Aes256.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.PrefixIV);
            Console.WriteLine("Aes256.FileEncrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes256.FileEncrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Now decrypt using same PrefixIV option
            n = Aes256.FileDecrypt(fnameCheck, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV);
            Console.WriteLine("Aes256.FileDecrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Aes256.FileDecrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameCheck, FileLength(fnameCheck), GetFileAsHex(fnameCheck));
            // Check we got what we started with
            Debug.Assert(FilesAreIdentical(fnameData, fnameCheck), "Decrypted file does not match original");

            // TDEA
            Console.WriteLine("Tdea.FileEncrypt/Decrypt with CipherFileOption...");
            fnameEnc = "nowis.tdea-cbc.enc.dat";
            fnameCheck = "nowis.tdea-cbc.chk.txt";
            arrKey = Cnv.FromHex("0123456789ABCDEFFEDCBA987654321089ABCDEF01234567");
            arrIV = Cnv.FromHex("1234567890ABCDEF");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            // Use PrefixIV option
            n = Tdea.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.PrefixIV);
            Console.WriteLine("Tdea.FileEncrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Tdea.FileEncrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Now decrypt using same PrefixIV option
            n = Tdea.FileDecrypt(fnameCheck, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV);
            Console.WriteLine("Tdea.FileDecrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Tdea.FileDecrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameCheck, FileLength(fnameCheck), GetFileAsHex(fnameCheck));
            // Check we got what we started with
            Debug.Assert(FilesAreIdentical(fnameData, fnameCheck), "Decrypted file does not match original");

            // Blowfish
            Console.WriteLine("Blowfish.FileEncrypt/Decrypt with CipherFileOption...");
            fnameEnc = "nowis.blf-cbc.enc.dat";
            fnameCheck = "nowis.blf-cbc.chk.txt";
            arrKey = Cnv.FromHex("0123456789abcdeff0e1d2c3b4a59687");
            arrIV = Cnv.FromHex("1234567890ABCDEF");
            Console.WriteLine("KY={0}", Cnv.ToHex(arrKey));
            Console.WriteLine("IV={0}", Cnv.ToHex(arrIV));
            // Use PrefixIV option
            n = Blowfish.FileEncrypt(fnameEnc, fnameData, arrKey, Mode.CBC, arrIV, CipherFileOption.PrefixIV);
            Console.WriteLine("Blowfish.FileEncrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Blowfish.FileEncrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameEnc, FileLength(fnameEnc), GetFileAsHex(fnameEnc));
            // Now decrypt using same PrefixIV option
            n = Blowfish.FileDecrypt(fnameCheck, fnameEnc, arrKey, Mode.CBC, null, CipherFileOption.PrefixIV);
            Console.WriteLine("Blowfish.FileDecrypt(CBC, PrefixIV) returns {0} (expecting 0)", n);
            Debug.Assert(0 == n, "Blowfish.FileDecrypt(CBC, PrefixIV) failed");
            Console.WriteLine("...created file {0} ({1} bytes). File contents:\n{2}",
                fnameCheck, FileLength(fnameCheck), GetFileAsHex(fnameCheck));
            // Check we got what we started with
            Debug.Assert(FilesAreIdentical(fnameData, fnameCheck), "Decrypted file does not match original");

        }

        static void test_CipherPad()
        {
            string s;
            byte[] key, iv, pt, ct, p1, correct;

            Console.WriteLine("\nTEST THE CIPHER CLASS WITH PADDING...");
            Console.WriteLine("Tdea/CBC/Pkcs5");
            key = Cnv.FromHex("737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32");
            iv = Cnv.FromHex("B36B6BFB6231084E");
            Console.WriteLine("KY=" + Cnv.ToHex(key));
            Console.WriteLine("IV=" + Cnv.ToHex(iv));
            pt = Cnv.FromHex("5468697320736F6D652073616D706520636F6E74656E742E");
            Console.WriteLine("PT=" + Cnv.ToHex(pt));
            Console.WriteLine("PT='" + System.Text.Encoding.Default.GetString(pt) + "'");
            correct = Cnv.FromHex("d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4");
            ct = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Tdea, Mode.CBC, Padding.Pkcs5);
            Console.WriteLine("CT=" + Cnv.ToHex(ct));
            Console.WriteLine("OK=" + Cnv.ToHex(correct));
            Debug.Assert(ByteArraysEqual(ct, correct), "Cipher.Encrypt with padding failed");
            // Now decrypt
            p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Tdea, Mode.CBC, Padding.Pkcs5);
            Console.WriteLine("P'=" + Cnv.ToHex(p1));
            Console.WriteLine("P'='" + System.Text.Encoding.Default.GetString(p1) + "'");
            Debug.Assert(ByteArraysEqual(p1, pt), "Cipher.Decrypt with padding failed");

            Console.WriteLine("Aes128/CBC/pkcs5");
            key = Cnv.FromHex("0123456789ABCDEFF0E1D2C3B4A59687");
            iv = Cnv.FromHex("FEDCBA9876543210FEDCBA9876543210");
            Console.WriteLine("KY=" + Cnv.ToHex(key));
            Console.WriteLine("IV=" + Cnv.ToHex(iv));
            s = "Now is the time for all good men to";
            pt = System.Text.Encoding.Default.GetBytes(s);
            Console.WriteLine("PT=" + Cnv.ToHex(pt));
            Console.WriteLine("PT='" + System.Text.Encoding.Default.GetString(pt) + "'");
            correct = Cnv.FromHex("C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A36677355F5C6584228B");
            ct = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.Pkcs5);
            Console.WriteLine("CT=" + Cnv.ToHex(ct));
            Console.WriteLine("OK=" + Cnv.ToHex(correct));
            Debug.Assert(ByteArraysEqual(ct, correct), "Cipher.Encrypt with padding failed");
            // Now decrypt
            p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.Pkcs5);
            Console.WriteLine("P'=" + Cnv.ToHex(p1));
            Console.WriteLine("P'='" + System.Text.Encoding.Default.GetString(p1) + "'");
            Debug.Assert(ByteArraysEqual(p1, pt), "Cipher.Decrypt with padding failed");
            p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.CBC, Padding.NoPad);
            Console.WriteLine("Pn=" + Cnv.ToHex(p1));

            Console.WriteLine("Aes128/ECB/OneAndZeroes...");
            ct = Cipher.Encrypt(pt, key, iv, CipherAlgorithm.Aes128, Mode.ECB, Padding.OneAndZeroes);
            Console.WriteLine("CT=" + Cnv.ToHex(ct));
            p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.ECB, Padding.NoPad);
            Console.WriteLine("Pn=" + Cnv.ToHex(p1));
            p1 = Cipher.Decrypt(ct, key, iv, CipherAlgorithm.Aes128, Mode.ECB, Padding.OneAndZeroes);
            Console.WriteLine("P'=" + Cnv.ToHex(p1));
            Console.WriteLine("P'='" + System.Text.Encoding.Default.GetString(p1) + "'");
            Debug.Assert(ByteArraysEqual(p1, pt));


        }

        static void test_Poly1305()
        {
            string msg;
            string msgHex;
            string keyHex;
            string tagHex;
            string okhex;

            // ***********************************
            // POLY1305 AUTHENTICATION ALGORITHM *
            // ***********************************
            Console.WriteLine("\nPOLY1305 AUTHENTICATION ALGORITHM:");
            // Ref: Test vector from `draft-irtf-cfrg-chacha20-poly1305-06.txt`
            msg = "Cryptographic Forum Research Group";
            keyHex = "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b";
            okhex = "a8061dc1305136c6c22b8baf0c0127a9";

            msgHex = Cnv.ToHex(msg);
            Console.WriteLine("Message to be authenticated:");
            Console.WriteLine("'"+ msg + "'");
            Console.WriteLine(msgHex);

            Console.WriteLine("Key: " + keyHex);
            tagHex = Mac.HexFromHex(msgHex, keyHex, MacAlgorithm.Poly1305);
            Console.WriteLine("Tag: " + tagHex);
            Debug.Assert(String.Compare(tagHex, okhex, true) == 0, "Mac.HexFromHex(Poly1305) failed");


        }

        static void test_SHA3_obj()
        {
            int n;
            string s;
            bool isok;
            string okhex;

            //**************************
            // SHA-3 HASH DIGEST TESTS *
            //**************************
            Console.WriteLine("TESTING SHA-3 object:");
            int[] bitlengths = { 224, 256, 384, 512 };
            foreach (int nbits in bitlengths) {
                // Instantiate a new object for SHA-3
                Sha3 oSha3 = Sha3.Instance();
                isok = oSha3.Init(nbits);
                Console.WriteLine("oSha3.Init({1}) returned {0}. LengthInBytes={2}", isok, nbits, oSha3.LengthInBytes);
                Debug.Assert(isok, "Sha3.Init failed");

                n = oSha3.AddData("a");
                n = oSha3.AddData("bc");
                s = oSha3.HexDigest();
                Console.WriteLine("SHA3-{1}('abc')={0}", s, nbits);
                // Correct result
                switch (nbits) {
                    case 224:
                        okhex = "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf";
                        break;
                    case 256:
                        okhex = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532";
                        break;
                    case 384:
                        okhex = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25";
                        break;
                    case 512:
                        okhex = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0";
                        break;
                    default:
                        okhex = "";
                        break;
                }
                Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3('abc') failed");

                // Compute SHA-3(one million repetitions of 'a')
                oSha3.Init(nbits);
                byte[] a1000 = new byte[1000];
                for (int i = 0; i < 1000; i++)
                    a1000[i] = 0x61;	// 'a' in ascii form
                for (int i = 0; i < 1000; i++) {
                    n = oSha3.AddData(a1000);
                    Debug.Assert(0 == n, "Sha3.Adddata failed");
                }
                s = oSha3.HexDigest();
                Console.WriteLine("SHA3-{1}(1M x 'a')={0}", s, nbits);
                // Correct result
                switch (nbits) {
                    case 224:
                        okhex = "d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c";
                        break;
                    case 256:
                        okhex = "5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1";
                        break;
                    case 384:
                        okhex = "eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e76847aa0774ddb90a842190d2c558b4b8340";
                        break;
                    case 512:
                        okhex = "3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87";
                        break;
                    default:
                        okhex = "";
                        break;
                }
                Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3(1M x 'a') failed");

                // Compute the SHA-3 digest of the empty string
                oSha3.Init(nbits);
                s = oSha3.HexDigest();
                Console.WriteLine("SHA3-{1}('')={0}", s, nbits);
                // Correct result
                switch (nbits) {
                    case 224:
                        okhex = "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7";
                        break;
                    case 256:
                        okhex = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a";
                        break;
                    case 384:
                        okhex = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
                        break;
                    case 512:
                        okhex = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26";
                        break;
                    default:
                        okhex = "";
                        break;
                }
                Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3(empty) failed");

                oSha3.Dispose();
            }
        }

        static void test_SHA3()
        {
            string s;
            byte[] b;
            string okhex;
            string msghex;
            string keyhex;
            int bitlen;

            Console.WriteLine("TESTING SHA-3:");
            // SHA-3-256("abc")
            okhex = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532";

            // Compute digest from string
            s = Hash.HexFromString("abc", HashAlgorithm.Sha3_256);
            Console.WriteLine("SHA3-256('abc')={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3('abc') failed");

            // SHA-3-256 of "abc" as byte array
            b = new byte[] { 0x61, 0x62, 0x63 };    // "abc" in a byte array
            s = Hash.HexFromBytes(b, HashAlgorithm.Sha3_256);
            Console.WriteLine("SHA3-256('abc')={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3('abc') failed");

            // Same again bitwise
            s = Hash.HexFromBits(b, 24, HashAlgorithm.Sha3_256);
            Console.WriteLine("SHA3-256('abc')={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3('abc') failed");

            // Ref: SHAVS-SHA3 CAVS 19.0 "SHA3-256 ShortMsg" information for "SHA3AllBits1-28-16"
            b = Cnv.FromHex("2590A0");  // NIST "259028"
            bitlen = 22;
            okhex = "d5863d4b1ff41551c92a9e08c52177e32376c9bd100c611c607db840096eb22f";
            s = Hash.HexFromBits(b, bitlen, HashAlgorithm.Sha3_256);
            Console.WriteLine("SHA3-256(22bits)={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "SHA-3(22bits) failed");

            // HMAC-SHA3-256
            // Text is "Sample message for keylen<blocklen"
            msghex = "53616D706C65206D65737361676520666F72206B65796C656E3C626C6F636B6C656E";
            keyhex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
            okhex = "4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205";
            s = Mac.HexFromHex(msghex, keyhex, MacAlgorithm.HmacSha3_256);
            Console.WriteLine("HMAC-SHA3-256()={0}", s);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "HMAC-SHA3-256() failed");

        }

        static void test_KMAC()
        {
            byte[] b;
            string s;
            string okhex;
            string msghex;
            string keyhex;
            int noutbits;

            Console.WriteLine("TESTING KMAC:");
            // Ref: `KMAC_samples.pdf` "Secure Hashing - KMAC-Samples" 2017-02-27
            // Sample #1
            keyhex = "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F";
            msghex = "00010203";
            noutbits = 256;
            okhex = "E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E";

            // Compute MAC from hex-encoded strings, fixed "standard" size
            s = Mac.HexFromHex(msghex, keyhex, MacAlgorithm.Kmac128);
            Console.WriteLine("KMAC128={0}", s);
            Console.WriteLine("OK     ={0}", okhex);
            Debug.Assert(String.Compare(okhex, s, true) == 0, "KMAC failed");
            
            // Compute MAC using Prf class, explicitly specifying size
            b = Prf.Bytes(noutbits / 8, Cnv.FromHex(msghex), Cnv.FromHex(keyhex), "", PrfAlgorithm.Kmac128);
            Console.WriteLine("KMAC128={0}", Cnv.ToHex(b));
            Console.WriteLine("OK     ={0}", okhex);
            Debug.Assert(String.Compare(okhex, Cnv.ToHex(b), true) == 0, "KMAC failed");

            // Request a lot of output (> single KECCAK block)
            okhex = "38158A1CAE4E1A25D85F2031246ADE697B3292FEF88B0923A59A02D1D53B704653EE7242662A10796BA20779D300D52D7432018741233D587252D31DC48BDB8233285D4A4ACD65848509B051A448D873649228B6626E5EF817C7AF2DEDC91F120F8CA535A1EE301FAE8186FDEDE5A76181A472A32CFAD1DDD1391E162F124D4A7572AD8A20076601BCF81E4B0391F3E95AEFFA708C33C1217C96BE6A4F02FBBC2D3B3B6FFAEB5BFD3BE4A2E02B75993FCC04DA6FAC4BFCB2A9F05792A1A5CC80CA34186243EFDB31";
            noutbits = 1600;
            b = Prf.Bytes(noutbits / 8, Cnv.FromHex(msghex), Cnv.FromHex(keyhex), "", PrfAlgorithm.Kmac128);
            Console.WriteLine("KMAC128={0}", Cnv.ToHex(b));
            Console.WriteLine("OK     ={0}", okhex);
            Debug.Assert(String.Compare(okhex, Cnv.ToHex(b), true) == 0, "KMAC failed");
        }

        static void test_XOF()
        {
            byte[] b;
            string okhex;
            string msghex;
            int noutbits;

            Console.WriteLine("TESTING XOF:");
            // Ref: "SHA-3 XOF Test Vectors for Byte-Oriented Output"
            // File `SHAKE256VariableOut.rsp` COUNT = 1244
            msghex = "6ae23f058f0f2264a18cd609acc26dd4dbc00f5c3ee9e13ecaea2bb5a2f0bb6b";
            noutbits = 2000;
            okhex = "b9b92544fb25cfe4ec6fe437d8da2bbe00f7bdaface3de97b8775a44d753c3adca3f7c6f183cc8647e229070439aa9539ae1f8f13470c9d3527fffdeef6c94f9f0520ff0c1ba8b16e16014e1af43ac6d94cb7929188cce9d7b02f81a2746f52ba16988e5f6d93298d778dfe05ea0ef256ae3728643ce3e29c794a0370e9ca6a8bf3e7a41e86770676ac106f7ae79e67027ce7b7b38efe27d253a52b5cb54d6eb4367a87736ed48cb45ef27f42683da140ed3295dfc575d3ea38cfc2a3697cc92864305407369b4abac054e497378dd9fd0c4b352ea3185ce1178b3dc1599df69db29259d4735320c8e7d33e8226620c9a1d22761f1d35bdff79a";

            b = Xof.Bytes(noutbits / 8, Cnv.FromHex(msghex), XofAlgorithm.Shake256);
            Console.WriteLine("SHAKE256={0}", Cnv.ToHex(b));
            Console.WriteLine("OK      ={0}", okhex);
            Debug.Assert(String.Compare(okhex, Cnv.ToHex(b), true) == 0, "XOF failed");
        }

		//*****************
		// FILE UTILITIES *
		//*****************

        static string GetFileAsHex(string fileName)
        {
            byte[] b = File.ReadAllBytes(fileName);
            string s = Cnv.ToHex(b);
            return s;
        }

		static bool FileExists(string filePath)
		{
			FileInfo fi = new FileInfo(filePath);
			return fi.Exists;
		}

        static int FileLength(string filePath)
        {   // Assuming size less than 2 GB
            FileInfo fi = new FileInfo(filePath);
            return (int)fi.Length;
        }

        static bool FilesAreIdentical(string file1, string file2)
        // Returns true if two binary files are identical, false if they are not
        // Ref: http://support.microsoft.com/kb/320348
        {
            int file1byte;
            int file2byte;
            FileStream fs1;
            FileStream fs2;

            // Open the two files.
            fs1 = new FileStream(file1, FileMode.Open);
            fs2 = new FileStream(file2, FileMode.Open);

            // Check the file sizes. If they are not the same, the files 
            // are not the same.
            if (fs1.Length != fs2.Length)
            {
                // Close the files
                fs1.Close();
                fs2.Close();

                // Return false to indicate files are different
                return false;
            }
            do
            {
                // Read one byte from each file.
                file1byte = fs1.ReadByte();
                file2byte = fs2.ReadByte();
            }
            while ((file1byte == file2byte) && (file1byte != -1));

            // Close the files.
            fs1.Close();
            fs2.Close();
            // Return the success of the comparison. "file1byte" is 
            // equal to "file2byte" at this point only if the files are 
            // the same.
            return ((file1byte - file2byte) == 0);
        }


        // Incredibly, there isn't a byte compare function in .NET
        static bool ByteArraysEqual(byte[] data1, byte[] data2)
        {	// Thanks to Jon Skeet http://www.pobox.com/~skeet
            // If both are null, they're equal
            if (data1 == null && data2 == null)
            {
                return true;
            }
            // If either but not both are null, they're not equal
            if (data1 == null || data2 == null)
            {
                return false;
            }
            if (data1.Length != data2.Length)
            {
                return false;
            }
            for (int i = 0; i < data1.Length; i++)
            {
                if (data1[i] != data2[i])
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Concatenate byte arrays a and b
        /// </summary>
        /// <param name="a">Array a</param>
        /// <param name="b">Array b</param>
        /// <returns>a concat b</returns>
        static byte[] ByteArraysConcat(byte[] a, byte[] b)
        {
            int len = a.Length + b.Length;
            byte[] c = new byte[len];
            a.CopyTo(c, 0);
            b.CopyTo(c, a.Length);
            return c;
        }

        //**********************
        // HOUSEKEEPING STUFF...
        //**********************

        static string SetupTestDirectory()
        {
            string subdir;
            //**************************************************
            // Check we have required files in local directory *
            //**************************************************
            string assemblyFile = Assembly.GetExecutingAssembly().Location;
            string assemblyDir = Path.GetDirectoryName(assemblyFile);
            Console.WriteLine("Local directory is '{0}'.", assemblyDir);

            //*************************************************
            // Create a test sub-directory with a random name, 
            // copy these test files to it, and work in that sub-directory
            //*************************************************
            subdir = "apitest." + Cnv.ToHex(Rng.NonceBytes(4));
            Console.WriteLine("Creating test sub-directory '{0}'", subdir);
            System.IO.Directory.CreateDirectory(subdir);
            // Change current working directory to sub-dir
            System.IO.Directory.SetCurrentDirectory(subdir);
            Console.WriteLine("CWD is " + System.IO.Directory.GetCurrentDirectory());

            return subdir;
        }

        //*********************************************************
        // Put CWD back to parent and offer to remove the test dir
        //*********************************************************
        static void RestoreDirectory(string subdir, bool askDelete)
        {
            string s;

            System.IO.Directory.SetCurrentDirectory("..");
            Console.WriteLine("\nCWD reset to " + System.IO.Directory.GetCurrentDirectory());
            if (askDelete)
            {
                Console.Write("The temp test directory '{0}' was created by this program.\nDo you want to remove it? ([Y]/N) ", subdir);
                s = Console.ReadLine();
                if ("N" != s && "n" != s)
                {
                    // Remove directory
                    Console.WriteLine("Removing test directory...");
                    System.IO.Directory.Delete(subdir, true);
                }
                else
                {
                    Console.WriteLine("Temp directory '{0}' left in place.", subdir);
                }
            }
            else
            {
                // Remove directory regardless
                Console.WriteLine("Removing test directory '{0}'", subdir);
                System.IO.Directory.Delete(subdir, true);
            }
        }

	}
}