Exemple #1
0
        /// <summary>
        /// Get a stream as the result of the specified stream being compressed using the specified method. Optionally specify a length
        /// for the number of bytes to read.
        /// </summary>
        public static MemoryStream Compress(System.Net.DecompressionMethods method, CompressionLevel level, Stream source, int length = -1)
        {
            // create a new memory stream to receive the compressed stream
            MemoryStream memStream = new MemoryStream(Global.BufferSizeLocal);

            // resolve the compression stream
            Stream compressionStream;

            switch (method)
            {
            case System.Net.DecompressionMethods.Deflate:
                compressionStream = new GZipStream(memStream, level, true);
                break;

            case System.Net.DecompressionMethods.GZip:
                compressionStream = new DeflateStream(memStream, level, true);
                break;

            default:
                // no compression - return uncompressed
                source.CopyTo(memStream);
                return(memStream);
            }

            // was the length specifed?
            if (length == -1)
            {
                // no, write the buffer to the compression
                source.CopyTo(compressionStream, Global.BufferSizeLocal);
            }
            else
            {
                // yes, create a buffer for the copy
                byte[] buffer = BufferCache.Get();
                int    count  = Global.BufferSizeLocal;

                // while the buffer is filled by reading from the stream
                while (count == Global.BufferSizeLocal)
                {
                    // read from the stream
                    count = length < Global.BufferSizeLocal ?
                            source.Read(buffer, 0, length) :
                            source.Read(buffer, 0, Global.BufferSizeLocal);

                    // write to the compression stream
                    compressionStream.Write(buffer, 0, count);
                    // decrement the remaining bytes
                    length -= count;
                }

                BufferCache.Set(buffer);
            }

            // close the compression stream
            compressionStream.Close();

            // return the memory stream
            return(memStream);
        }
Exemple #2
0
        /// <summary>
        /// Inner method compress stream method.
        /// </summary>
        private static void Compress(IRun callback, Stream result, Stream destination, Stream source,
                                     int length, bool dispose)
        {
            // reset the buffer
            byte[] buffer = BufferCache.Get();

            int count;

            if (length == -1)
            {
                // read from the stream
                count = source.Read(buffer, 0, Global.BufferSizeLocal);
            }
            else
            {
                // read from the stream
                count = length < Global.BufferSizeLocal ?
                        source.Read(buffer, 0, length) :
                        source.Read(buffer, 0, Global.BufferSizeLocal);

                // decrement the remaining bytes
                length -= count;
            }

            // write to the compression stream
            destination.Write(buffer, 0, count);

            // reset the buffer
            BufferCache.Set(buffer);

            // has the compression been completed?
            if (count == Global.BufferSizeLocal)
            {
                // no, run a new compression iteration
                ManagerUpdate.Control.AddSingle(Compress, callback, result, destination, source, length, dispose);
            }
            else
            {
                // yes, dispose of the compression stream
                destination.Dispose();

                // should the source be disposed? yes
                if (dispose)
                {
                    source.Dispose();
                }

                // reset the memory stream position
                result.Position = 0L;

                // yes, run the callback
                callback.Run();
            }
        }
Exemple #3
0
        /// <summary>
        /// Continuing compute of a hash of the specified stream.
        /// </summary>
        protected void ComputeHashInner(Stream stream, IAction <byte[]> onComplete, byte[] buffer, int index)
        {
            if (buffer == null)
            {
                buffer = BufferCache.Get();
                index  = 0;
            }
            int  count = stream.Read(buffer, index, Global.BufferSizeLocal);
            bool last  = count != Global.BufferSizeLocal;

            _h1     = _seed;
            _length = 0;

            // read 128 bits, 16 bytes, 2 longs in eacy cycle
            while (index + 16 <= count)
            {
                ulong k1 = GetUInt64(buffer, index);
                ulong k2 = GetUInt64(buffer, index + 8);

                _length += ReadSize;
                MixBody(k1, k2);

                index += 16;
            }

            if (index + 16 == count)
            {
                BufferCache.Set(buffer);
                buffer = null;
            }
            else
            {
                if (last)
                {
                    // if the input MOD 16 != 0
                    if (index < count)
                    {
                        ProcessBytesRemaining(buffer, count - index, index);
                    }
                    onComplete.ArgA = Hash;
                    onComplete.Run();
                    return;
                }
                Micron.CopyMemory(buffer, index, buffer, 0, count - index);
                index -= count;
            }

            ManagerUpdate.Control.AddSingle(ComputeHashInner, stream, onComplete, buffer, index);
        }
Exemple #4
0
        /// <summary>
        /// Compress the specified byte buffer.
        /// </summary>
        public static Stream Decompress(System.Net.DecompressionMethods method, Stream source, ref int count)
        {
            // create a new memory stream to receive the compressed stream
            MemoryStream memStream = new MemoryStream();

            // resolve the compression stream
            Stream compressionStream;

            switch (method)
            {
            case System.Net.DecompressionMethods.Deflate:
                compressionStream = new DeflateStream(memStream, CompressionMode.Decompress, true);
                break;

            case System.Net.DecompressionMethods.GZip:
                compressionStream = new GZipStream(memStream, CompressionMode.Decompress, true);
                break;

            default:
                // no compression - return uncompressed
                return(source);
            }

            // write the buffer to the compression
            var buffer      = BufferCache.Get();
            int bufferCount = Global.BufferSizeLocal;

            while (bufferCount == Global.BufferSizeLocal)
            {
                bufferCount = source.Read(buffer, 0, count > Global.BufferSizeLocal ? Global.BufferSizeLocal : count);
                count      -= bufferCount;
                compressionStream.Write(buffer, 0, bufferCount);
            }

            // pass the buffer back to the cache
            BufferCache.Set(buffer);

            // close the stream
            compressionStream.Dispose();

            // get the count
            memStream.Position = 0L;
            count = (int)memStream.Length;

            // get the bytes from the memory stream
            return(memStream);
        }
Exemple #5
0
        /// <summary>
        /// Copy the content of a stream to another over a series of async tasks.
        /// </summary>
        public static void BufferedCopy(this Stream inStream, Stream outStream, IAction onComplete = null)
        {
            var buffer = BufferCache.Get();
            int count  = inStream.Read(buffer, 0, Global.BufferSizeLocal);

            if (count == 0)
            {
                outStream.Flush();
                BufferCache.Set(buffer);
                if (onComplete != null)
                {
                    onComplete.Run();
                }
            }
            else
            {
                outStream.Write(buffer, 0, count);
                BufferCache.Set(buffer);
                ManagerUpdate.Control.AddSingle(BufferedCopy, inStream, outStream, onComplete);
            }
        }
Exemple #6
0
        /// <summary>
        /// Decrypt with password. The stream must be navigatable.
        /// </summary>
        public static Stream DecryptWithPassword(Stream stream, string password, int nonSecretPayloadLength = 0)
        {
            const int ivLength = BlockBitSize / 8;

            var cryptSalt = new byte[SaltBitSize];
            var authSalt  = new byte[SaltBitSize];

            var streamStartPosition = stream.Position;

            // grab Salt from Non-Secret Payload
            if (nonSecretPayloadLength != 0)
            {
                stream.Position = streamStartPosition + nonSecretPayloadLength;
            }
            stream.Read(cryptSalt, 0, SaltBitSize);
            stream.Read(authSalt, 0, SaltBitSize);

            // grab IV from message
            var iv = new byte[ivLength];

            stream.Read(iv, 0, ivLength);


            byte[] cryptKey;
            byte[] authKey;

            // generate crypt key
            using (var generator = new Rfc2898DeriveBytes(password, cryptSalt, Iterations)) {
                cryptKey = generator.GetBytes(KeyBitSize);
            }
            // generate auth key
            using (var generator = new Rfc2898DeriveBytes(password, authSalt, Iterations)) {
                authKey = generator.GetBytes(KeyBitSize);
            }

            using (var hmac = new HMACSHA256(authKey)) {
                int sentTagLength = hmac.HashSize / 8;

                // if message length is to small just return null
                if (stream.Length - streamStartPosition < sentTagLength + nonSecretPayloadLength + ivLength)
                {
                    throw new CryptographicException("Insufficient bytes in stream.");
                }

                // get the number of encrypted bytes that constitute the message
                int count = (int)(stream.Length -
                                  streamStartPosition -
                                  sentTagLength -
                                  nonSecretPayloadLength -
                                  ivLength -
                                  SaltBitSize - SaltBitSize);

                byte[] tagContent = BufferCache.Get(count);

                // read the bytes required for the tag hash
                count = stream.Read(tagContent, 0, count);

                // calculate the tag hash
                byte[] calcTag = hmac.ComputeHash(tagContent, 0, count);

                // read sent tag
                stream.Read(tagContent, 0, sentTagLength);

                // compare tag with constant time comparison
                var compare = 0;
                for (var i = 0; i < sentTagLength; ++i)
                {
                    compare |= tagContent[i] ^ calcTag[i];
                }

                BufferCache.Set(tagContent);

                // if message doesn't authenticate, throw
                if (compare != 0)
                {
                    throw new CryptographicException("Data hash was not correct.");
                }

                using (var aes = new AesManaged {
                    Key = cryptKey,
                    IV = iv,
                    BlockSize = BlockBitSize,
                    Mode = CipherMode.CBC,
                    Padding = PaddingMode.Zeros
                }) {
                    // create a memory stream for the decrypted bytes
                    var decrypted = new MemoryStream();

                    using (var decrypter = aes.CreateDecryptor()) {
                        var decrypterStream = new CryptoStream(decrypted, decrypter, CryptoStreamMode.Write);

                        byte[] buffer = BufferCache.Get();

                        // move to the start of the encrypted data
                        stream.Position = streamStartPosition +
                                          nonSecretPayloadLength +
                                          SaltBitSize + SaltBitSize +
                                          ivLength;

                        // determine the bytes to be written to the decrypter stream
                        int remaining = (int)(stream.Length - stream.Position - sentTagLength);

                        // read the first buffer from the stream
                        count = stream.Read(buffer, 0, remaining > Global.BufferSizeLocal ? Global.BufferSizeLocal : remaining);

                        // while the buffer is full
                        while (count == Global.BufferSizeLocal)
                        {
                            // decrement the remaining bytes
                            remaining -= count;

                            // write the buffer
                            decrypterStream.Write(buffer, 0, count);

                            // read a new buffer
                            count = stream.Read(buffer, 0, Global.BufferSizeLocal);
                        }

                        // if the stream ended prematurely, throw
                        if (count != remaining)
                        {
                            throw new EndOfStreamException();
                        }

                        // write final buffer
                        decrypterStream.Write(buffer, 0, count);

                        BufferCache.Set(buffer);

                        // flush the decryption stream
                        decrypterStream.FlushFinalBlock();

                        // set the decrpted memory stream position
                        decrypted.Position = 0;

                        // return the decrypted stream
                        return(decrypted);
                    }
                }
            }
        }
Exemple #7
0
        /// <summary>
        /// Encrypt bytes from the stream using a string password.
        /// </summary>
        public static MemoryStream EncryptWithPassword(Stream stream, string password, byte[] nonSecretPayload = null)
        {
            byte[] payload;
            int    payloadIndex;

            if (nonSecretPayload == null)
            {
                payload = BufferCache.Get(SaltBitSize * 2);

                payloadIndex = 0;
            }
            else
            {
                payload = BufferCache.Get((SaltBitSize * 2) + nonSecretPayload.Length);

                Array.Copy(nonSecretPayload, payload, nonSecretPayload.Length);
                payloadIndex = nonSecretPayload.Length;
            }

            byte[] cryptKey;
            byte[] authKey;
            //Use Random Salt to prevent pre-generated weak password attacks.
            using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize, Iterations)) {
                var salt = generator.Salt;

                // generate the cryptography key
                cryptKey = generator.GetBytes(KeyBitSize);

                // copy the salt
                Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
                payloadIndex += salt.Length;
            }

            //Deriving separate key, might be less efficient than using HKDF,
            //but now compatible with RNEncryptor which had a very similar wireformat and requires less code than HKDF.
            using (var generator = new Rfc2898DeriveBytes(password, SaltBitSize, Iterations)) {
                var salt = generator.Salt;

                // generate the auth key
                authKey = generator.GetBytes(KeyBitSize);

                // create the rest of the non-secret payload
                Array.Copy(salt, 0, payload, payloadIndex, salt.Length);
                payloadIndex += salt.Length;
            }

            byte[] iv;
            byte[] buffer = BufferCache.Get();

            using (var aes = new AesManaged {
                Key = cryptKey,
                BlockSize = BlockBitSize,
                Mode = CipherMode.CBC,
                Padding = PaddingMode.Zeros
            }) {
                // use random IV
                aes.GenerateIV();
                iv = aes.IV;

                using (var encrypter = aes.CreateEncryptor())
                    using (var cipherStream = new MemoryStream())
                        using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write)) {
                            // read from the stream
                            int count = stream.Read(buffer, 0, Global.BufferSizeLocal);

                            // while the buffer is filled
                            while (count == Global.BufferSizeLocal)
                            {
                                // write to the crypto stream
                                cryptoStream.Write(buffer, 0, count);

                                // read from the stream
                                count = stream.Read(buffer, 0, Global.BufferSizeLocal);
                            }

                            // write the final buffer
                            cryptoStream.Write(buffer, 0, count);

                            // flush the encryped stream
                            cryptoStream.Flush();

                            cipherStream.Position = 0;

                            // assemble encrypted message and add authentication
                            var encryptedStream = new MemoryStream();

                            // prepend payload
                            encryptedStream.Write(payload, 0, payloadIndex);
                            // prepend IV
                            encryptedStream.Write(iv, 0, iv.Length);

                            // read from the stream
                            count = cipherStream.Read(buffer, 0, Global.BufferSizeLocal);

                            while (count == Global.BufferSizeLocal)
                            {
                                // write to the crypto stream
                                encryptedStream.Write(buffer, 0, count);

                                // read from the stream
                                count = cipherStream.Read(buffer, 0, Global.BufferSizeLocal);
                            }

                            // write the final buffer
                            encryptedStream.Write(buffer, 0, count);

                            BufferCache.Set(buffer);


                            // authenticate all data by postpending a hash of all data
                            encryptedStream.Position = payloadIndex + iv.Length;

                            using (var hmac = new HMACSHA256(authKey)) {
                                // calculate a hash of the entire stream excluding the payload and iv
                                // that can be used to authenticate the received data
                                byte[] tag = hmac.ComputeHash(encryptedStream);

                                // write the tag to the end of the encrypted stream
                                encryptedStream.Write(tag, 0, tag.Length);
                            }

                            // reset the stream position
                            encryptedStream.Position = 0;

                            // return the complete, encrypted stream
                            return(encryptedStream);
                        }
            }
        }