Stream Cipher

Stream ciphers are an extremely versatile and secure form of cipher.

All stream ciphers can be represented by the following algorithm

#![allow(unused)]
fn main() {
let state = init(key, iv);
for block in message {
    // determine the block key from the state
    let block_key = hash(state);
    // progress the state forward
    state = forward(state);
    // apply the key to the block by xor
    block ^= block_key
}
}

Stream ciphers allow for encrypting data that can be streamed (hence the name). This allows you to decrypt data without first having decrypted the block before.

The enigma machine is a famous example of a stream cipher, however instead of XOR it used substitution.

Theory

If the hash function is a strong pseudo random number generator, then the key stream will be a high entropy random key. Since a one-time-pad (OTP) is provably secure with a perfectly random key, then the stream cipher key stream will imitate that.

Insecurities lie in the deterministic factor of the key stream. Given a known block plaintext, the block key is easily determined. If there's a way to reverse the let block_key = hash(state) step, then an attacker can decrypt all following blocks. This was the failure of the enigma machine. The state was directly related to the substitutions. If the substitutions could be determined, then the state was trivially brute-forcable.