A simple block cipher based on the SHA-256 hash function I've come up with this little routine for doing encryption using the SHA-2 (in this case SHA-256) hash function. As such it is a block cipher with a 256 bit (32 byte) block size and an arbitrary key length. It's easy to see that you could replace the hash function and get an entirely new type of algorithm.

I want to know if there are any problems, especially flaws, in this construction, and whether algorithms of this type have been studied.

Initialization with key:

$$ S_0 = H(k) $$

Encryption for plaintext blocks $P_1, \dots P_n$:

$$ S_i = H(S_{i-1})$$
  $$ C_i = P_i \oplus S_i $$

Decryption for ciphertext blocks $C_1 \dots C_n$:

$$ S_i = H(S_{i-1})$$
  $$ P_i = C_i \oplus S_i $$

Here is some sample C source code using SSL:

#include &lt;openssl/sha.h&gt;

struct sha_crypt_state {
    unsigned char digest[SHA256_DIGEST_LENGTH];
};

void sha_crypt_set_key( sha_crypt_state *state, unsigned char *key, int key_length )
{
    SHA256( key, key_length, state-&gt;digest );
}

void sha_crypt( sha_crypt_state *state, unsigned char *block )
{
    sha_crypt_state temp;
    SHA256( state-&gt;digest, sizeof(state-&gt;digest), temp.digest );
    memcpy( state-&gt;digest, temp.digest, sizeof(temp.digest) );

    for ( int i = 0; i &lt; sizeof(state-&gt;digest); ++i ) {
        block[i] ^= state-&gt;digest[i];
    }
}

void sha_crypt_test()
{
    const char *key = "secret";

    // prepare a test block
    char block[SHA256_DIGEST_LENGTH];
    memset( block, 0, sizeof(block) );
    strcpy( block, "Hello, testing encryption!" );

    // test encrypt
    sha_crypt_state state;
    set_key( &amp;state, (unsigned char *)key, strlen(key) );
    sha_crypt( &amp;state, (unsigned char *)block );

    // test decrypt
    set_key( &amp;state, (unsigned char *)key, strlen(key) );
    sha_crypt( &amp;state, (unsigned char *)block );
}
First of all, this no block-cipher at all. It's a stream-cipher. Thus you can use every key only once, and you can't use any cipher modes built on block-ciphers.

Your scheme is vulnerable to a known plaintext attack. If the attacker knows 32 aligned(or 63 unaligned) bytes of plaintext, he can calculate the state of your cipher:

$ S_i = P_i \oplus C_i $

The later $ S_j (j&gt;i) $ only depend on the $ S_i $ the attacker recovered, i.e. he can calculate all of them. And thus he can decrypt everything that comes after that known plaintext.

Such a plain text attack is often possible in practice. Files often start with known magic bytes, network protocols often contain known sequences in headers (http headers should be long enough),...