Reader that won't close the stream when disposed
상속: System.IO.BinaryReader
예제 #1
0
        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;
            }
        }
예제 #2
0
        /// <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!");

            }
        }