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."); } }