patterncMinor
Using SHA-512 for encryption/decryption
Viewed 0 times
encryptionshadecryptionforusing512
Problem
It occurred to me that if SHA2 can be used to derive keys from passwords, then it might as well be good enough to generate random data that can be xored with a plaintext to encrypt and the other way around.
These are my assumptions:
If those assumptions hold, then it should provide privacy. It's much faster than AES-256-CBC.
At first I thought there must be something I'm missing, but no one has pointed out an attack that can be carried out against this construction. So what I would like to know is how secure this algorithm is and specific ways to break it.
Here's the code:
mad.h
mad.c
```
#include "mad.h"
#include
#include
#include
#include
// Private
static void _xor64(uint64_t dest, uint64_t const a, uint64_t* b)
{
for(int i = 0; i state, iv, 64);
memcpy(mad->key, key, 32);
}
void mad_encrypt(MadCtx mad, unsigned char const in, unsigned int in_size,
unsigned char* out)
{
assert(0 == in_size % 64);
int n = in_size >> 6; // in_size / 64
while(n){
uint64_t x[8];
SHA512((unsigned char const)mad, 96, (unsigned char)x);
_xor64((uint64_t)out, (uint64_t const)in, x);
memcpy(mad->state, out, 64);
in += 64;
out += 64;
--n;
}
}
void mad_decrypt(MadCtx mad, unsigned char const in, unsigned int in_size,
unsign
These are my assumptions:
- SHA-512 produces a random-looking output that is impossible to guess
- The result of SHA-512 can be fed back into it appended to a 256-bit key and produce an output with the same quality as given for a random input
If those assumptions hold, then it should provide privacy. It's much faster than AES-256-CBC.
At first I thought there must be something I'm missing, but no one has pointed out an attack that can be carried out against this construction. So what I would like to know is how secure this algorithm is and specific ways to break it.
Here's the code:
mad.h
#ifndef _MAD_H_
#define _MAD_H_
typedef struct {
unsigned char state[64];
unsigned char key[32];
} MadCtx;
void mad_ctx_init(MadCtx* mad, unsigned char const* key,
unsigned char const* iv);
void mad_encrypt(MadCtx* mad, unsigned char const* in, unsigned int in_size,
unsigned char* out);
void mad_decrypt(MadCtx* mad, unsigned char const* in, unsigned int in_size,
unsigned char* out);
#endifmad.c
```
#include "mad.h"
#include
#include
#include
#include
// Private
static void _xor64(uint64_t dest, uint64_t const a, uint64_t* b)
{
for(int i = 0; i state, iv, 64);
memcpy(mad->key, key, 32);
}
void mad_encrypt(MadCtx mad, unsigned char const in, unsigned int in_size,
unsigned char* out)
{
assert(0 == in_size % 64);
int n = in_size >> 6; // in_size / 64
while(n){
uint64_t x[8];
SHA512((unsigned char const)mad, 96, (unsigned char)x);
_xor64((uint64_t)out, (uint64_t const)in, x);
memcpy(mad->state, out, 64);
in += 64;
out += 64;
--n;
}
}
void mad_decrypt(MadCtx mad, unsigned char const in, unsigned int in_size,
unsign
Solution
The above encrypt/decrypt functions can be summarized as follows:
This is basically the CFB mode. Note that the two functions are almost identical, except a small difference in
AES in CFB mode is done in much the same way, except of course it uses AES block cipher instead of
To compare the performance you can simply compare 4 rounds of AES to 1 round of SHA512. Watch out for compiler optimizations which may skew the result. Many tests have already been done for this, it shows AES is faster.
AES also uses key expansion which makes it more secure. Key expansion is relatively slow but it's done only once per file/data. This may skew the performance test depending on how the test is done.
For improvement, don't let the
Example:
void mad_encrypt(...)
{
while(n)
{
SHA512(mad, 96, x);
XOR(out, in, x);
memcpy(mad->state, out, 64);
...
}
}
void mad_decrypt(...)
{
while(n)
{
SHA512(mad, 96, x);
XOR(out, in, x);
memcpy(mad->state, in, 64);
...
}
}This is basically the CFB mode. Note that the two functions are almost identical, except a small difference in
memcpy. AES in CFB mode is done in much the same way, except of course it uses AES block cipher instead of
SHA512(...) function above. Also AES uses blocks of 16 bytes, so AES has to run 4 rounds to catch up with a single SHA512 round. Overall, AES is faster. To compare the performance you can simply compare 4 rounds of AES to 1 round of SHA512. Watch out for compiler optimizations which may skew the result. Many tests have already been done for this, it shows AES is faster.
AES also uses key expansion which makes it more secure. Key expansion is relatively slow but it's done only once per file/data. This may skew the performance test depending on how the test is done.
typedef struct {
unsigned char state[64];
unsigned char key[32];
} MadCtx;For improvement, don't let the
key linger on in MadCtx::key. For example, you can use SHA512 to combine the key with IV (or state as you call it) so it becomes hidden during the operation, then you can drop key out of the structure.Example:
unsigned char mad_IV[64];
void mad_init(const unsigned char *key, const unsigned char* iv)
{
unsigned char buf[96];
memcpy(buf, iv, 64);
memcpy(buf + 64, key, 32);
SHA512(buf, 96, mad_IV);
}
void mad_crypt(char const* in, int in_size, char* out, int encrypt)
{
assert(0 == in_size % 64);
int n = in_size >> 6; // in_size / 64
while (n)
{
SHA512(mad_IV, 64, mad_IV);
_xor64((uint64_t*)out, (uint64_t*)in, (uint64_t*)mad_IV);
if (encrypt)
memcpy(mad_IV, out, 64);
else
memcpy(mad_IV, in, 64);
in += 64;
out += 64;
--n;
}
}
int main()
{
unsigned char iv[64] = { 0 };
unsigned char key[32] = { 0 };
memcpy(iv, "iv", 2);
memcpy(key, "key", 3);
int size = 640;
char *plaintext = malloc(size);
char *decrypted = malloc(size);
char *encrypted = malloc(size);
memset(plaintext, 0, size);
memset(encrypted, 0, size);
memset(decrypted, 0, size);
strcpy_s(plaintext, size, "plainxxxxxx.");
mad_init(key, iv);
mad_crypt(plaintext, size, encrypted, 1);
mad_init(key, iv);
mad_crypt(encrypted, size, decrypted, 0);
phex(encrypted, 64);
printf("\n\n");
printf("plaintext: %s\n", plaintext);
printf("decrypted: %s\n", decrypted);
putchar('\n');
return 0;
}Code Snippets
void mad_encrypt(...)
{
while(n)
{
SHA512(mad, 96, x);
XOR(out, in, x);
memcpy(mad->state, out, 64);
...
}
}
void mad_decrypt(...)
{
while(n)
{
SHA512(mad, 96, x);
XOR(out, in, x);
memcpy(mad->state, in, 64);
...
}
}typedef struct {
unsigned char state[64];
unsigned char key[32];
} MadCtx;unsigned char mad_IV[64];
void mad_init(const unsigned char *key, const unsigned char* iv)
{
unsigned char buf[96];
memcpy(buf, iv, 64);
memcpy(buf + 64, key, 32);
SHA512(buf, 96, mad_IV);
}
void mad_crypt(char const* in, int in_size, char* out, int encrypt)
{
assert(0 == in_size % 64);
int n = in_size >> 6; // in_size / 64
while (n)
{
SHA512(mad_IV, 64, mad_IV);
_xor64((uint64_t*)out, (uint64_t*)in, (uint64_t*)mad_IV);
if (encrypt)
memcpy(mad_IV, out, 64);
else
memcpy(mad_IV, in, 64);
in += 64;
out += 64;
--n;
}
}
int main()
{
unsigned char iv[64] = { 0 };
unsigned char key[32] = { 0 };
memcpy(iv, "iv", 2);
memcpy(key, "key", 3);
int size = 640;
char *plaintext = malloc(size);
char *decrypted = malloc(size);
char *encrypted = malloc(size);
memset(plaintext, 0, size);
memset(encrypted, 0, size);
memset(decrypted, 0, size);
strcpy_s(plaintext, size, "plainxxxxxx.");
mad_init(key, iv);
mad_crypt(plaintext, size, encrypted, 1);
mad_init(key, iv);
mad_crypt(encrypted, size, decrypted, 0);
phex(encrypted, 64);
printf("\n\n");
printf("plaintext: %s\n", plaintext);
printf("decrypted: %s\n", decrypted);
putchar('\n');
return 0;
}Context
StackExchange Code Review Q#142355, answer score: 3
Revisions (0)
No revisions yet.