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.
#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 );
}
One obvious weakness is that if I can guess the plaintext of any block – for example if you are encrypting a Word document, which has a static header – I can decrypt all of the following blocks (just xor the plaintext with the ciphertext to yield the state).
Block ciphers based on hash functions usually uses just the compression function of the hash algorithm. One example is SHACAL-2 which is based on SHA-256 like your algorithm.