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