private void ReadFrom(Stream s, string password)
        {
            byte[] format = new byte[2];
            s.Read(format, 0, 2);

            if (Encoding.ASCII.GetString(format) != "CC")
            {
                throw new InvalidCryptoContainerException("Invalid CryptoContainer format.");
            }

            switch (s.ReadByte()) //version
            {
            case 0:
                ReadPlainTextFrom(s);
                break;

            case 1:     //depricated version
            {
                if (password == null)
                {
                    throw new InvalidCryptoContainerException("Password required.");
                }

                //CryptoAlgo
                SymmetricEncryptionAlgorithm cryptoAlgo = (SymmetricEncryptionAlgorithm)s.ReadByte();

                //KeySizeBytes
                int keySizeBytes = s.ReadByte();

                byte[] IV = new byte[s.ReadByte()];
                s.Read(IV, 0, IV.Length);

                byte[] key;

                switch (keySizeBytes)
                {
                case 16:
                    key = HashAlgorithm.Create("MD5").ComputeHash(Encoding.UTF8.GetBytes(password));
                    break;

                case 32:
                    key = HashAlgorithm.Create("SHA256").ComputeHash(Encoding.UTF8.GetBytes(password));
                    break;

                default:
                    throw new CryptoException("CryptoContainer key size not supported.");
                }

                _containerKey = new SymmetricCryptoKey(cryptoAlgo, key, IV);
                ReadPlainTextFrom(_containerKey.GetCryptoStreamReader(s));

                //auto upgrade to version 2 with PBKDF2-HMAC-SHA256 when calling WriteTo
                _kdf          = PBKDF2.CreateHMACSHA256(password, keySizeBytes, PBKDF2_ITERATION_COUNT);
                key           = _kdf.GetBytes(keySizeBytes);
                _containerKey = new SymmetricCryptoKey(cryptoAlgo, key, IV);
                _hmac         = new HMACSHA256(key);
            }
            break;

            case 2:     //using PBKDF2-HMAC-SHA256
            {
                if (password == null)
                {
                    throw new InvalidCryptoContainerException("Password required.");
                }

                //CryptoAlgo
                SymmetricEncryptionAlgorithm cryptoAlgo = (SymmetricEncryptionAlgorithm)s.ReadByte();

                //KeySizeBytes
                int keySizeBytes = s.ReadByte();

                byte[] IV = new byte[s.ReadByte()];
                s.Read(IV, 0, IV.Length);

                byte[] salt = new byte[s.ReadByte()];
                s.Read(salt, 0, salt.Length);

                byte[] HMAC = new byte[s.ReadByte()];
                s.Read(HMAC, 0, HMAC.Length);

                _kdf = PBKDF2.CreateHMACSHA256(password, salt, PBKDF2_ITERATION_COUNT);
                byte[] key = _kdf.GetBytes(keySizeBytes);

                //authenticate data
                _hmac = new HMACSHA256(key);
                long   startPosition = s.Position;
                byte[] computedHMAC  = _hmac.ComputeHash(s);
                s.Position = startPosition;

                //verify hmac
                for (int i = 0; i < HMAC.Length; i++)
                {
                    if (HMAC[i] != computedHMAC[i])
                    {
                        throw new CryptoException("Invalid password or data tampered.");
                    }
                }

                //decrypt data
                _containerKey = new SymmetricCryptoKey(cryptoAlgo, key, IV);
                ReadPlainTextFrom(_containerKey.GetCryptoStreamReader(s));
            }
            break;

            case -1:
                throw new EndOfStreamException();

            default:
                throw new InvalidCryptoContainerException("CryptoContainer format version not supported.");
            }
        }