Example #1
0
        /// <summary>
        /// Decrypts a stream
        /// </summary>
        /// <param name="Input">Input stream</param>
        /// <param name="Output">Output stream</param>
        /// <returns>true, if successfull</returns>
        public CryptResult Decrypt(Stream Input, Stream Output, string Password)
        {
            if (!Input.CanRead)
            {
                return(CryptResult.StreamCantRead);
            }
            if (!Output.CanWrite)
            {
                return(CryptResult.StreamCantWrite);
            }
            var Header = GetHeader(Input);

            if (!Header.Valid)
            {
                return(CryptResult.InvalidFileState);
            }
            using (Rijndael R = Rijndael.Create())
            {
                NotClosingCryptoStream CS;

                byte[] Key = DeriveBytes(Password, MaxKeySize, Header.Salt, Header.Cycles);

                if (!CheckPasswordBytes(Key, Header.KeyHash))
                {
                    return(CryptResult.PasswordInvalid);
                }

                try
                {
                    CS = new NotClosingCryptoStream(Input, R.CreateDecryptor(Key, Header.IV), CryptoStreamMode.Read);
                }
                catch
                {
                    return(CryptResult.CryptoStreamError);
                }
                using (CS)
                {
                    using (var Hasher = (SHA256)HashAlgorithm.Create(HASHALG))
                    {
                        byte[] Data   = new byte[R.BlockSize * 100];
                        int    readed = 0;
                        do
                        {
                            try
                            {
                                readed = CS.Read(Data, 0, Data.Length);
                            }
                            catch (IOException)
                            {
                                return(CryptResult.IOError);
                            }
                            catch
                            {
                                return(CryptResult.CryptoStreamError);
                            }
                            if (readed > 0)
                            {
                                try
                                {
                                    Output.Write(Data, 0, readed);
                                }
                                catch
                                {
                                    return(CryptResult.IOError);
                                }
                                //Always read a multiple of the supported blocksize to avoid problems with readahead
                                if (Input.Position == Input.Length)
                                {
                                    Hasher.TransformFinalBlock(Data, 0, readed);
                                }
                                else
                                {
                                    Hasher.TransformBlock(Data, 0, readed, Data, 0);
                                }
                            }
                        } while (readed > 0);
                        if (!VerifyHMAC(Key, Header.FileHash, Hasher.Hash))
                        {
                            return(CryptResult.FileHashInvalid);
                        }
                    }
                }
            }
            return(CryptResult.Success);
        }
Example #2
0
        /// <summary>
        /// Encrypts a stream
        /// </summary>
        /// <param name="Input">Source stream</param>
        /// <param name="Output">Output stream</param>
        /// <returns>true, if successfull</returns>
        /// <remarks>Output stream must be seekable</remarks>
        public CryptResult Encrypt(Stream Input, Stream Output)
        {
            if (Key == null || Salt == null)
            {
                return(CryptResult.PasswordInvalid);
            }
            if (!Input.CanRead)
            {
                return(CryptResult.StreamCantRead);
            }
            if (!Output.CanWrite)
            {
                return(CryptResult.StreamCantWrite);
            }
            if (!Output.CanSeek)
            {
                return(CryptResult.IOError);
            }
            else
            {
                using (Rijndael R = Rijndael.Create())
                {
                    var Header = new CryptHeader();
                    Header.Valid  = true;
                    Header.Cycles = Difficulty;
                    R.GenerateIV();
                    Header.IV = R.IV;
                    //Randomly generate a salt for each encryption task.
                    //This makes the password different for each file even if the source file and password are identical.
                    Header.Salt = Salt;
                    //Get Hash for password verification.
                    //This hash allows us to check if a user supplied the correct password for decryption.
                    //This should not be insecure as it still goes through the password generator and thus is very slow.
                    Header.KeyHash = GetPasswordByteHash(Key);
                    //Placeholder for the File hash. When decrypting, this is used to verify integrity.
                    Header.FileHash = new byte[256 / 8];
                    long HashPos = 0;
                    NotClosingCryptoStream CS;

                    Header.WriteTo(Output);
                    HashPos = Output.Position - Header.FileHash.Length - sizeof(int) /*Header.Cycles*/;

                    try
                    {
                        CS = new NotClosingCryptoStream(Output, R.CreateEncryptor(Key, R.IV), CryptoStreamMode.Write);
                    }
                    catch
                    {
                        return(CryptResult.CryptoStreamError);
                    }

                    using (CS)
                    {
                        using (var Hasher = (SHA256)HashAlgorithm.Create(HASHALG))
                        {
                            int    readed = 0;
                            byte[] Buffer = new byte[R.BlockSize * 10];
                            do
                            {
                                try
                                {
                                    readed = Input.Read(Buffer, 0, Buffer.Length);
                                }
                                catch
                                {
                                    return(CryptResult.IOError);
                                }
                                if (readed > 0)
                                {
                                    try
                                    {
                                        CS.Write(Buffer, 0, readed);
                                    }
                                    catch (IOException)
                                    {
                                        return(CryptResult.IOError);
                                    }
                                    catch
                                    {
                                        return(CryptResult.CryptoStreamError);
                                    }

                                    if (Input.Position == Input.Length)
                                    {
                                        var temp = Hasher.TransformFinalBlock(Buffer, 0, readed);
                                    }
                                    else
                                    {
                                        Hasher.TransformBlock(Buffer, 0, readed, Buffer, 0);
                                    }
                                }
                            } while (readed > 0);
                            Header.FileHash = CreateHMAC(Key, (byte[])Hasher.Hash.Clone());
                        }
                        try
                        {
                            CS.FlushFinalBlock();
                        }
                        catch (IOException)
                        {
                            return(CryptResult.IOError);
                        }
                        catch
                        {
                            return(CryptResult.CryptoStreamError);
                        }
                        //Store File hash and seek back to the end
                        try
                        {
                            Output.Flush();
                            long CurrentPos = Output.Position;
                            Output.Seek(HashPos, SeekOrigin.Begin);
                            Output.Write(Header.FileHash, 0, Header.FileHash.Length);
                            Output.Flush();
                            Output.Seek(Output.Position, SeekOrigin.Begin);
                        }
                        catch
                        {
                            return(CryptResult.IOError);
                        }
                    }
                }
            }
            return(CryptResult.Success);
        }