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 <openssl/sha.h>
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->digest );
}
void sha_crypt( sha_crypt_state *state, unsigned char *block )
{
sha_crypt_state temp;
SHA256( state->digest, sizeof(state->digest), temp.digest );
memcpy( state->digest, temp.digest, sizeof(temp.digest) );
for ( int i = 0; i < sizeof(state->digest); ++i ) {
block[i] ^= state->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( &state, (unsigned char *)key, strlen(key) );
sha_crypt( &state, (unsigned char *)block );
// test decrypt
set_key( &state, (unsigned char *)key, strlen(key) );
sha_crypt( &state, (unsigned char *)block );
}