public bool Verify(Stream input, byte[] signature, long inputLength = -1) { var milliseconds = FromDateTime(_currentDateTime()); if (!_verifier.Verify(input, signature, inputLength)) return false; using(var stream = new MemoryStream(signature)) using (var reader = new NondestructiveBinaryReader(stream)) { reader.ReadBytes(HeaderLength); var expiration =reader.ReadBytes(TimeoutLength); var expMilliseconds = Utility.ToInt64(expiration); return milliseconds < expMilliseconds; } }
/// <summary> /// Decrypts the specified input. /// </summary> /// <param name="input">The input.</param> /// <param name="output">The output.</param> /// <param name="inputLength">(optional) Length of the input.</param> /// <exception cref="InvalidCryptoDataException">Ciphertext was invalid!</exception> public void Decrypt(Stream input, Stream output, long inputLength = -1) { var fullLength = inputLength < 0 ? input.Length : inputLength + input.Position; using (var reader = new NondestructiveBinaryReader(input)) { byte[] keyHash; var resetStream = Utility.ResetStreamWhenFinished(input); var header = Utility.ReadHeader(input, out keyHash); var verify = false; foreach (var key in GetKey(keyHash)) { var cryptKey = key as ICrypterKey; resetStream.Reset(); bool ciphertextIsPreverified = false; //in case there aren't any keys that match that hash we are going to fake verify. using (var verifyStream = cryptKey.Maybe(m => m.GetAuthVerifyingStream(), () => new DummyStream())) { //If we verify in once pass like with AEAD verify stream will be null; if (verifyStream != null) { //Perform ciphertext verification ciphertextIsPreverified = true; var tagLength = verifyStream.GetTagLength(header); while (input.Position < fullLength - tagLength) { byte[] buffer = reader.ReadBytes((int)Math.Min(BufferSize, fullLength - tagLength - input.Position)); verifyStream.Write(buffer, 0, buffer.Length); } var signature = reader.ReadBytes(tagLength); try { verify = verifyStream.VerifySignature(signature); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); System.Diagnostics.Debug.WriteLine(e.StackTrace); //We don't want exceptions to keep us from trying different keys verify = false; } } } if ((!verify && ciphertextIsPreverified) || input.Length == 0) { continue; } // Stream baseStream = ciphertextIsPreverified ? output : new MemoryStream(); Stream wrapper = baseStream; bool success = false; if(Compression == CompressionType.Gzip){ wrapper = new WriteDecompressGzipStream(baseStream); }else if(Compression == CompressionType.Zlib){ wrapper = new ZlibStream(baseStream, CompressionMode.Decompress, true); } //Perform Decryption using(Compression == CompressionType.None ? null : wrapper){ FinishingStream crypterStream; resetStream.Reset(); input.Seek(HeaderLength, SeekOrigin.Current); crypterStream = cryptKey.Maybe(m => m.GetDecryptingStream(wrapper), () => new DummyStream()); try { using (crypterStream) { var tagLength = crypterStream.GetTagLength(header); while (input.Position < fullLength - tagLength) { byte[] buffer = reader.ReadBytes((int) Math.Min(BufferSize, fullLength - tagLength - input.Position)); crypterStream.Write(buffer, 0, buffer.Length); } crypterStream.Finish(); input.Seek(tagLength, SeekOrigin.Current); success = true; } } catch (Exception e) { //We don't want exceptions to keep us from trying different keys //particularly ones that aren't pre verified System.Diagnostics.Debug.WriteLine(e.Message); System.Diagnostics.Debug.WriteLine(e.StackTrace); } } if (success) { if (!ciphertextIsPreverified) { //If the ciphertext is verified in one pass, //we have to make sure that verification was successful before copying it to output. baseStream.Seek(0, SeekOrigin.Begin); baseStream.CopyTo(output); } return; } } throw new InvalidCryptoDataException("Cipher text was invalid!"); } }