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); } } } }