public static bool TryDecrypt(byte[] Source, byte[] Passphrase, out byte[] Result) { if (Source == null || Source.Length == 0) { throw new ArgumentOutOfRangeException("Cannot decrypt an empty payload!"); } if (Source.Length < CIPHERTEXT_START) { Result = null; return(false); // not a complete header, nothing to decrypt } //test: is this the correct version and is this a TripleSec payload to begin with? byte[] buffer = new byte[4 + 4]; Buffer.BlockCopy(Source, 0, buffer, 0, buffer.Length); if (buffer.ToHexString() != TRIPLESEC_MAGICPLUSVERSION4_HEXBYTES) { throw new ArgumentException("Not a TripleSec v3 encrypted payload!"); } byte[] theSalt = new byte[SALT_LEN]; Buffer.BlockCopy(Source, SALT_START, theSalt, 0, SALT_LEN); // need the keys to verify the signatures #if DEBUG #pragma warning disable 618 // we know in DEBUG mode this will throw an Obsolete warning; this is a legitimate use of this function, so supress it #endif KeysV4 keys = new KeysV4(Passphrase, theSalt); #if DEBUG #pragma warning restore 618 #endif // VERIFY SIGNATURES HERE // get existing signatures byte[] SENT_HMACSHA512 = new byte[HMACSHA512_LEN]; Buffer.BlockCopy(Source, HMACSHA512_START, SENT_HMACSHA512, 0, HMACSHA512_LEN); byte[] SENT_HMACSHA3_512 = new byte[HMACSHA3_512_LEN]; Buffer.BlockCopy(Source, HMACSHA3_512_START, SENT_HMACSHA3_512, 0, HMACSHA3_512_LEN); string SENT_SIGNATURE = Utilities.BytesToHexString(SENT_HMACSHA512) + Utilities.BytesToHexString(SENT_HMACSHA3_512); //calculate hash on sent data before decryption int sourceLength = Source.Length - CIPHERTEXT_START; // the AES_IV isn't counted here byte[] AES_IV = new byte[AES_IV_LEN]; // we need the AES_IV as part of the hmac calculations Buffer.BlockCopy(Source, AES_IV_START, AES_IV, 0, AES_IV_LEN); HMACSHA512 sha512 = new HMACSHA512(keys.HMACSHA512_KEY); SHA3Managed.HMACSHA3_512 sha3_512 = new SHA3Managed.HMACSHA3_512(keys.HMACSHA3_512_KEY); sha512.TransformBlock(TRIPLESEC_MAGICPLUSVERSION4_BYTES, 0, TRIPLESEC_MAGICPLUSVERSION4_BYTELENGTH, TRIPLESEC_MAGICPLUSVERSION4_BYTES, 0); sha3_512.HashCore(TRIPLESEC_MAGICPLUSVERSION4_BYTES, 0, TRIPLESEC_MAGICPLUSVERSION4_BYTELENGTH); sha512.TransformBlock(theSalt, 0, theSalt.Length, theSalt, 0); sha3_512.HashCore(theSalt, 0, theSalt.Length); sha512.TransformBlock(AES_IV, 0, AES_IV.Length, AES_IV, 0); sha3_512.HashCore(AES_IV, 0, AES_IV.Length); sha512.TransformBlock(Source, CIPHERTEXT_START, sourceLength, Source, CIPHERTEXT_START); sha3_512.HashCore(Source, CIPHERTEXT_START, sourceLength); sha512.TransformFinalBlock(Source, 0, 0); sha3_512.HashFinal(Source, 0, 0); //#if DEBUG // System.Diagnostics.Debug.Print("DECRYPT SIGNATURES:"); // System.Diagnostics.Debug.Print(BitConverter.ToString(sha512.Hash).Replace("-", "")); // System.Diagnostics.Debug.Print(BitConverter.ToString(sha3_512.Hash).Replace("-", "")); //#endif string CALCULATED_SIGNATURE = Utilities.BytesToHexString(sha512.Hash) + Utilities.BytesToHexString(sha3_512.Hash); if (CALCULATED_SIGNATURE != SENT_SIGNATURE) { Result = null; return(false); } //================================================================================== byte[] OUTPUT = new byte[sourceLength]; // AES is first (outermost) BC.Crypto.Modes.SicBlockCipher mySIC_AES = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.AesEngine()); mySIC_AES.Init(true, new BC.Crypto.Parameters.ParametersWithIV( new BC.Crypto.Parameters.KeyParameter(keys.AES_KEY), AES_IV)); ProcessArray(mySIC_AES, Source, CIPHERTEXT_START, OUTPUT, 0, sourceLength); //Twofish is REMOVED IN V4 // prepare for next byte[] IV_XSALSA20 = new byte[24]; Buffer.BlockCopy(OUTPUT, 0, IV_XSALSA20, 0, IV_XSALSA20.Length); byte[] INPUT = new byte[OUTPUT.Length - IV_XSALSA20.Length]; Buffer.BlockCopy(OUTPUT, IV_XSALSA20.Length, INPUT, 0, INPUT.Length); OUTPUT.Wipe(); // DON'T LEAK! //XSalsa20 is last OUTPUT = Chaos.NaCl.XSalsa20.Process(INPUT, keys.XSalsa20_KEY, IV_XSALSA20); INPUT.Wipe(); // DON'T LEAK! Result = OUTPUT; return(true); }
/// <summary> /// Encrypt an array of bytes using the TripleSec protocol with the supplied passphrase. Internal function, not intended for use by an end coder. /// </summary> /// <param name="Source">Source array of bytes to process.</param> /// <param name="Keys">The KeysV3 object initialized with the proper keys.</param> /// <param name="IVs">The RNGV3 object initialized with the proper initialization arrays.</param> /// <returns>The encrypted array.</returns> internal static byte[] Encrypt(byte[] Source, KeysV4 Keys, RNGV4 IVs) #endif { if (Source == null || Source.Length == 0) { throw new ArgumentNullException("Source"); } if (Keys == null || !Keys.IsInitialized || IVs == null || !IVs.IsInitialized) { throw new InvalidOperationException("Keys and IVs objects must not be null (and both must be initialized)"); } // the added IV's and the signatures and the header always add up to the same length added to the original message length // if we're going to run out of memory, it will be here, or shortly thereafter byte[] OUT_BUFFER = new byte[Source.Length + 192]; //standard header stuff // All the header pieces are now copied by the built-in SHA512 method TransformBlock //XSalsa20 is up first byte[] interim = Chaos.NaCl.XSalsa20.Process(Source, Keys.XSalsa20_KEY, IVs.XSalsa20_IV); byte[] interim2 = new byte[interim.Length + IVs.XSalsa20_IV.Length]; // IV included here as it is part of the input to the next process Buffer.BlockCopy(IVs.XSalsa20_IV, 0, interim2, 0, IVs.XSalsa20_IV.Length); Buffer.BlockCopy(interim, 0, interim2, IVs.XSalsa20_IV.Length, interim.Length); ////Twofish is REMOVED FROM V4 //AES is last interim.Wipe(); // DON'T LEAK! BC.Crypto.Modes.SicBlockCipher aes = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.AesEngine()); aes.Init(true, new BC.Crypto.Parameters.ParametersWithIV(new BC.Crypto.Parameters.KeyParameter(Keys.AES_KEY), IVs.AES_IV)); ProcessArray(aes, interim2, interim2); // process array in-place // buffer is copied to output by built-in HMACSHA512 TransFormBlock aes.Reset(); aes = null; HMACSHA512 sha512 = new HMACSHA512(Keys.HMACSHA512_KEY); sha512.TransformBlock(TRIPLESEC_MAGICPLUSVERSION4_BYTES, 0, TRIPLESEC_MAGICPLUSVERSION4_BYTELENGTH, OUT_BUFFER, 0); sha512.TransformBlock(Keys.Salt, 0, Keys.Salt.Length, OUT_BUFFER, SALT_START); sha512.TransformBlock(IVs.AES_IV, 0, IVs.AES_IV.Length, OUT_BUFFER, AES_IV_START); sha512.TransformBlock(interim2, 0, interim2.Length, OUT_BUFFER, CIPHERTEXT_START); sha512.TransformFinalBlock(interim2, 0, 0); // transform final block doesn't copy the output Buffer.BlockCopy(sha512.Hash, 0, OUT_BUFFER, HMACSHA512_START, sha512.Hash.Length); SHA3Managed.HMACSHA3_512 sha3_512 = new SHA3Managed.HMACSHA3_512(Keys.HMACSHA3_512_KEY); sha3_512.HashCore(TRIPLESEC_MAGICPLUSVERSION4_BYTES, 0, TRIPLESEC_MAGICPLUSVERSION4_BYTELENGTH); sha3_512.HashCore(Keys.Salt, 0, Keys.Salt.Length); sha3_512.HashCore(IVs.AES_IV, 0, IVs.AES_IV.Length); sha3_512.HashCore(interim2, 0, interim2.Length); sha3_512.HashFinal(interim2, 0, 0); // transform final block doesn't copy the output Buffer.BlockCopy(sha3_512.Hash, 0, OUT_BUFFER, HMACSHA3_512_START, sha3_512.Hash.Length); //#if DEBUG // System.Diagnostics.Debug.Print("ENCRYPT SIGNATURES: HMACSHA512, HMACSHA3_512, CipherText"); // System.Diagnostics.Debug.Print(BitConverter.ToString(sha512.Hash).Replace("-", "").ToLowerInvariant()); // System.Diagnostics.Debug.Print(BitConverter.ToString(sha3_512.Hash).Replace("-", "").ToLowerInvariant()); // System.Diagnostics.Debug.Print(BitConverter.ToString(OUT_BUFFER).Replace("-","").ToLowerInvariant()); //#endif // HASHLIB REMOVED -------- ! return(OUT_BUFFER); }
/// <summary> /// Encrypt an array of bytes using the TripleSec protocol with the supplied passphrase. Internal function, not intended for use by an end coder. /// </summary> /// <param name="Source">Source array of bytes to process.</param> /// <param name="Keys">The KeysV3 object initialized with the proper keys.</param> /// <param name="IVs">The RNGV3 object initialized with the proper initialization arrays.</param> /// <returns>The encrypted array.</returns> internal static byte[] Encrypt(byte[] Source, KeysV3 Keys, RNGV3 IVs) #endif { if (Source == null || Source.Length == 0) throw new ArgumentNullException("Source"); if (Keys == null || !Keys.IsInitialized || IVs == null || !IVs.IsInitialized) throw new InvalidOperationException("Keys and IVs objects must not be null (and both must be initialized)"); // the added IV's and the signatures and the header always add up to the same length added to the original message length // if we're going to run out of memory, it will be here, or shortly thereafter byte[] OUT_BUFFER = new byte[Source.Length + 208]; //standard header stuff Buffer.BlockCopy(Utilities.HexStringToBytes(TRIPLESEC_MAGICPLUSVERSION3_HEXBYTES), 0, OUT_BUFFER, 0, 8); // The SALT and AES IV are public in the final construction, so putting them here is a minimal risk. // At worst, it leaks RNG material on abort. //salt Buffer.BlockCopy(IVs.Salt, 0, OUT_BUFFER, SALT_START, SALT_LEN); //AES IV Buffer.BlockCopy(IVs.AES_IV, 0, OUT_BUFFER, AES_IV_START, AES_IV_LEN); //XSalsa20 is up first byte[] interim = Chaos.NaCl.XSalsa20.Process(Source, Keys.XSalsa20_KEY, IVs.XSalsa20_IV); byte[] interim2 = new byte[interim.Length + IVs.XSalsa20_IV.Length]; // IV included here as it is part of the input to the next process Buffer.BlockCopy(IVs.XSalsa20_IV, 0, interim2, 0, IVs.XSalsa20_IV.Length); Buffer.BlockCopy(interim, 0, interim2, IVs.XSalsa20_IV.Length, interim.Length); //Twofish is up next interim.Wipe(); // DON'T LEAK! interim = new byte[interim2.Length + IVs.Twofish_IV.Length]; // IV included here as it is part of the input to the next process Buffer.BlockCopy(IVs.Twofish_IV, 0, interim, 0, IVs.Twofish_IV.Length); BC.Crypto.Modes.SicBlockCipher tf = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.TwofishEngine()); tf.Init(true, new BC.Crypto.Parameters.ParametersWithIV(new BC.Crypto.Parameters.KeyParameter(Keys.Twofish_KEY), IVs.Twofish_IV)); ProcessArray(tf, interim2, interim2); // process array in-place Buffer.BlockCopy(interim2, 0, interim, IVs.Twofish_IV.Length, interim2.Length); tf.Reset(); tf = null; //AES is last interim2.Wipe(); // DON'T LEAK! BC.Crypto.Modes.SicBlockCipher aes = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.AesEngine()); aes.Init(true, new BC.Crypto.Parameters.ParametersWithIV(new BC.Crypto.Parameters.KeyParameter(Keys.AES_KEY), IVs.AES_IV)); ProcessArray(aes, interim, interim); // process array in-place Buffer.BlockCopy(interim, 0, OUT_BUFFER, CIPHERTEXT_START, interim.Length); aes.Reset(); aes = null; HashLib.IHMAC h512 = CreateSHA512MacObject(Keys.HMACSHA512_KEY); h512.TransformBytes(Utilities.HexStringToBytes(TRIPLESEC_MAGICPLUSVERSION3_HEXBYTES)); //header h512.TransformBytes(IVs.Salt); //salt h512.TransformBytes(IVs.AES_IV); // IV for AES h512.TransformBytes(interim); // ciphertext HashLib.HashResult sig1 = h512.TransformFinal(); // get the result Buffer.BlockCopy(sig1.GetBytes(), 0, OUT_BUFFER, HMACSHA512_START, HMACSHA512_LEN); // store it HashLib.IHMAC keccak = CreateKeccak512MacObject(Keys.HMACKeccak512_KEY); keccak.TransformBytes(Utilities.HexStringToBytes(TRIPLESEC_MAGICPLUSVERSION3_HEXBYTES)); //header keccak.TransformBytes(IVs.Salt); //salt keccak.TransformBytes(IVs.AES_IV); // IV for AES keccak.TransformBytes(interim); // ciphertext HashLib.HashResult sig2 = keccak.TransformFinal(); // get the result Buffer.BlockCopy(sig2.GetBytes(), 0, OUT_BUFFER, HMACKECCAK512_START, HMACKECCAK512_LEN); //store it interim.Wipe(); // this isn't really leaking since it's encrypted AND copied to the output buffer, but clean house all the same. return OUT_BUFFER; }
public static bool TryDecrypt(byte[] Source, byte[] Passphrase, out byte[] Result) { //is this the correct version and is this a TripleSec payload to begin with byte[] buffer = new byte[4 + 4]; Buffer.BlockCopy(Source, 0, buffer, 0, buffer.Length); if (buffer.ToHexString() != TRIPLESEC_MAGICPLUSVERSION3_HEXBYTES) throw new ArgumentException("Not a TripleSec encrypted payload!"); byte[] theSalt = new byte[SALT_LEN]; Buffer.BlockCopy(Source, SALT_START, theSalt, 0, SALT_LEN); // need the keys to verify the signatures #pragma warning disable 618 // we know in DEBUG mode this will throw an Obsolete warning, this is a legitimate use of this function, so supress it KeysV3 keys = new KeysV3(Passphrase, theSalt); #pragma warning restore 618 // VERIFY SIGNATURES HERE // get existing signatures byte[] SENT_HMACSHA512 = new byte[HMACSHA512_LEN]; Buffer.BlockCopy(Source, HMACSHA512_START, SENT_HMACSHA512, 0, HMACSHA512_LEN); byte[] SENT_HMACKECCAK512 = new byte[HMACKECCAK512_LEN]; Buffer.BlockCopy(Source, HMACKECCAK512_START, SENT_HMACKECCAK512, 0, HMACKECCAK512_LEN); string SENT_SIGNATURE = Utilities.BytesToHexString(SENT_HMACSHA512) + Utilities.BytesToHexString(SENT_HMACKECCAK512); //calculate hash on sent data before decryption int sourceLength = Source.Length - CIPHERTEXT_START; // the AES_IV isn't counted here byte[] AES_IV = new byte[AES_IV_LEN]; Buffer.BlockCopy(Source, AES_IV_START, AES_IV, 0, AES_IV_LEN); HashLib.IHMAC hsha512 = CreateSHA512MacObject(keys.HMACSHA512_KEY); hsha512.TransformBytes(Utilities.HexStringToBytes(TRIPLESEC_MAGICPLUSVERSION3_HEXBYTES)); //header hsha512.TransformBytes(theSalt); //salt hsha512.TransformBytes(AES_IV); // IV for AES hsha512.TransformBytes(Source, CIPHERTEXT_START, sourceLength); HashLib.HashResult sig1 = hsha512.TransformFinal(); HashLib.IHMAC hkeccak512 = CreateKeccak512MacObject(keys.HMACKeccak512_KEY); hkeccak512.TransformBytes(Utilities.HexStringToBytes(TRIPLESEC_MAGICPLUSVERSION3_HEXBYTES)); //header hkeccak512.TransformBytes(theSalt); //salt hkeccak512.TransformBytes(AES_IV); // IV for AES hkeccak512.TransformBytes(Source, CIPHERTEXT_START, sourceLength); HashLib.HashResult sig2 = hkeccak512.TransformFinal(); string CALCULATED_SIGNATURE = Utilities.BytesToHexString(sig1.GetBytes()) + Utilities.BytesToHexString(sig2.GetBytes()); if (CALCULATED_SIGNATURE != SENT_SIGNATURE) { Result = null; return false; } //================================================================================== byte[] OUTPUT = new byte[sourceLength]; // AES is first (outermost) BC.Crypto.Modes.SicBlockCipher mySIC_AES = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.AesEngine()); mySIC_AES.Init(true, new BC.Crypto.Parameters.ParametersWithIV( new BC.Crypto.Parameters.KeyParameter(keys.AES_KEY), AES_IV)); ProcessArray(mySIC_AES, Source, CIPHERTEXT_START, OUTPUT, 0, sourceLength); // prepare for next byte[] IV_TWOFISH = new byte[16]; Buffer.BlockCopy(OUTPUT, 0, IV_TWOFISH, 0, IV_TWOFISH.Length); byte[] INPUT = new byte[OUTPUT.Length - IV_TWOFISH.Length]; Buffer.BlockCopy(OUTPUT, IV_TWOFISH.Length, INPUT, 0, INPUT.Length); OUTPUT.Wipe(); // DON'T LEAK! OUTPUT = new byte[INPUT.Length]; //Twofish is next BC.Crypto.Modes.SicBlockCipher mySIC_TF = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.TwofishEngine()); mySIC_TF.Init(true, new BC.Crypto.Parameters.ParametersWithIV( new BC.Crypto.Parameters.KeyParameter(keys.Twofish_KEY), IV_TWOFISH)); ProcessArray(mySIC_TF, INPUT, OUTPUT); INPUT.Wipe(); // DON'T LEAK! // prepare for next byte[] IV_XSALSA20 = new byte[24]; Buffer.BlockCopy(OUTPUT, 0, IV_XSALSA20, 0, IV_XSALSA20.Length); INPUT = new byte[OUTPUT.Length - IV_XSALSA20.Length]; Buffer.BlockCopy(OUTPUT, IV_XSALSA20.Length, INPUT, 0, INPUT.Length); OUTPUT.Wipe(); // DON'T LEAK! //XSalsa20 is last OUTPUT = Chaos.NaCl.XSalsa20.Process(INPUT, keys.XSalsa20_KEY, IV_XSALSA20); INPUT.Wipe(); // DON'T LEAK! Result = OUTPUT; return true; }
/// <summary> /// Encrypt an array of bytes using the TripleSec protocol with the supplied passphrase. Internal function, not intended for use by an end coder. /// </summary> /// <param name="Source">Source array of bytes to process.</param> /// <param name="Keys">The KeysV3 object initialized with the proper keys.</param> /// <param name="IVs">The RNGV3 object initialized with the proper initialization arrays.</param> /// <returns>The encrypted array.</returns> internal static byte[] Encrypt(byte[] Source, KeysV3 Keys, RNGV3 IVs) #endif { if (Source == null || Source.Length == 0) { throw new ArgumentNullException("Source"); } if (Keys == null || !Keys.IsInitialized || IVs == null || !IVs.IsInitialized) { throw new InvalidOperationException("Keys and IVs objects must not be null (and both must be initialized)"); } // the added IV's and the signatures and the header always add up to the same length added to the original message length // if we're going to run out of memory, it will be here, or shortly thereafter byte[] OUT_BUFFER = new byte[Source.Length + 208]; //standard header stuff // All the header pieces are now copied by the built-in SHA512 method TransformBlock //XSalsa20 is up first byte[] interim = Chaos.NaCl.XSalsa20.Process(Source, Keys.XSalsa20_KEY, IVs.XSalsa20_IV); byte[] interim2 = new byte[interim.Length + IVs.XSalsa20_IV.Length]; // IV included here as it is part of the input to the next process Buffer.BlockCopy(IVs.XSalsa20_IV, 0, interim2, 0, IVs.XSalsa20_IV.Length); Buffer.BlockCopy(interim, 0, interim2, IVs.XSalsa20_IV.Length, interim.Length); //Twofish is up next interim.Wipe(); // DON'T LEAK! interim = new byte[interim2.Length + IVs.Twofish_IV.Length]; // IV included here as it is part of the input to the next process Buffer.BlockCopy(IVs.Twofish_IV, 0, interim, 0, IVs.Twofish_IV.Length); BC.Crypto.Modes.SicBlockCipher tf = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.TwofishEngine()); tf.Init(true, new BC.Crypto.Parameters.ParametersWithIV(new BC.Crypto.Parameters.KeyParameter(Keys.Twofish_KEY), IVs.Twofish_IV)); ProcessArray(tf, interim2, interim2); // process array in-place Buffer.BlockCopy(interim2, 0, interim, IVs.Twofish_IV.Length, interim2.Length); tf.Reset(); tf = null; //AES is last interim2.Wipe(); // DON'T LEAK! BC.Crypto.Modes.SicBlockCipher aes = new BC.Crypto.Modes.SicBlockCipher(new BC.Crypto.Engines.AesEngine()); aes.Init(true, new BC.Crypto.Parameters.ParametersWithIV(new BC.Crypto.Parameters.KeyParameter(Keys.AES_KEY), IVs.AES_IV)); ProcessArray(aes, interim, interim); // process array in-place //the HMACSHA512 process will copy the data to the output as it hashes aes.Reset(); aes = null; HMACSHA512 sha512 = new HMACSHA512(Keys.HMACSHA512_KEY); sha512.TransformBlock(TRIPLESEC_MAGICPLUSVERSION3_BYTES, 0, TRIPLESEC_MAGICPLUSVERSION3_BYTELENGTH, OUT_BUFFER, 0); sha512.TransformBlock(Keys.Salt, 0, Keys.Salt.Length, OUT_BUFFER, SALT_START); sha512.TransformBlock(IVs.AES_IV, 0, IVs.AES_IV.Length, OUT_BUFFER, AES_IV_START); sha512.TransformBlock(interim, 0, interim.Length, OUT_BUFFER, CIPHERTEXT_START); sha512.TransformFinalBlock(interim, 0, 0); // transform final block doesn't copy the output Buffer.BlockCopy(sha512.Hash, 0, OUT_BUFFER, HMACSHA512_START, sha512.Hash.Length); // Proposed SHA3 uses a delimiter/padding byte of 0x01 intead of 0x06 or 0x1f (SHAKE128/256), that's the only difference // This is IMPORTANT for V3, as it used a pre-release version of the proposed SHA3 standard. NIST changed SHA3 well after // TripleSec was released and had been used in the wild. SHA3Managed.HMAC_Proposed_SHA3_512 sha3_512 = new SHA3Managed.HMAC_Proposed_SHA3_512(Keys.HMACKeccak512_KEY); sha3_512.HashCore(TRIPLESEC_MAGICPLUSVERSION3_BYTES, 0, TRIPLESEC_MAGICPLUSVERSION3_BYTELENGTH); sha3_512.HashCore(Keys.Salt, 0, Keys.Salt.Length); sha3_512.HashCore(IVs.AES_IV, 0, IVs.AES_IV.Length); sha3_512.HashCore(interim, 0, interim.Length); sha3_512.HashFinal(interim, 0, 0); // transform final block doesn't copy the output Buffer.BlockCopy(sha3_512.Hash, 0, OUT_BUFFER, HMACKECCAK512_START, sha3_512.Hash.Length); //#if DEBUG // System.Diagnostics.Debug.Print("ENCRYPT SIGNATURES:"); // System.Diagnostics.Debug.Print(BitConverter.ToString(sha512.Hash).Replace("-", "")); // System.Diagnostics.Debug.Print(BitConverter.ToString(sha3_512.Hash).Replace("-", "")); // System.Diagnostics.Debug.Print(BitConverter.ToString(OUT_BUFFER).Replace("-","")); //#endif // HASHLIB REMOVED -----------! interim.Wipe(); // this isn't really leaking since it's encrypted AND copied to the output buffer, but clean house all the same. return(OUT_BUFFER); }