Beispiel #1
0
        /// <summary>
        /// Tries to read the crypt header from a stream
        /// </summary>
        /// <param name="Input">Input stream</param>
        /// <returns>Crypt header.</returns>
        /// <remarks>This will leave the stream as-is</remarks>
        public static CryptHeader GetHeader(Stream Input)
        {
            var H = new CryptHeader();

            try
            {
                H.ReadFrom(Input);
            }
            catch
            {
                return(new CryptHeader());
            }
            return(H);
        }
Beispiel #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);
        }