-1

I know there are way better and more tested encryption methods, but I was wondering if the following code could be use for symmetric encryption?

var text = "hello";
var password = "mypass";
var message = hash(text) + encrypt(text, password);

function encrypt(text, password){
    var key = hash(hash(text) XOR hash(password));
    var passphrase = key;
    while(passphrase.length < text.length){
        key = hash(key);
        passphrase += key;
    }
    passphrase = passphrase.substring(0, text.length);
    return text XOR passphrase;
}

It can easily be decrypted if you know the password.

Is there any flaw to this simple algorithm?

N.B.: A similar question was asked here but the algorithm doesn't work...

Gudradain
  • 121
  • 1
  • 4

3 Answers3

3

The basic flaw is the same as indentified in this answer I linked in comments:

If you know the plaintext for block $i$, you can derive the key for that block and then derive the rest of the keystream from that key. Thus, an attacker can simply make guesses on the message until they find one that allows them to decrypt the rest of the message.


A better way to build a stream cipher from a hash function would be to hash a key and a counter and a unique nonce so two messages always get different keystreams and knowing a keystream block will not help in calculating the later blocks.

For example: $k_i = H(K||N||i)$

Better yet, use an existing stream cipher, or the stream cipher mode of a hash function that has one, like Skein (or IIRC SHA-3).

otus
  • 32,462
  • 5
  • 75
  • 167
2

Depends on your security requirements. Basically it is OK to create a (slow!) stream cipher using a secure hash method, given that the password has a large enough security margin.

But your code has at least the following issues:

  • you leak enough information in the first block to regenerate the key stream from a known plaintext (thanks otus);
  • you have to leak hash(text) to an attacker, otherwise you cannot decrypt;
  • you can distinguish if the same text has been encrypted twice with the same password (the encryption is deterministic as it misses an IV);
  • you don't deploy a password based key derivation funcation instead of a cryptographic hash over the password to generate the initial key.

The first one completely breaks your cipher. #2 and #3 are enough to consider the cipher broken, but may allow you to use a cipher (if it weren't for #1). #4 will make it easy for an attacker to brute-force your password, or perform a dictionary attack.

Not all hash algorithm implementations are protected against side channel attacks (less so than block ciphers anyway). And block ciphers are designed for this purpose and much faster. Stream ciphers such as Salsa20 will completely blow this implementation out of the water with regards to speed.

Maarten Bodewes
  • 96,351
  • 14
  • 169
  • 323
2

Here is my take on your algorithm. I'll try to perform the known plaintext attack.

  • Knowing the plaintext allows to recover the keystream (passphrase) by simply XORing it.
  • This in turn reveals the value of hash(hash(text) XOR hash(password)) -- simply the first hash block, and the value of hash(text) is known (by virtue of KPA plus it is leaked by your message construction).
  • So the attack boils down to finding a preimage for the value hash(hash(text) XOR hash(password)). It may be computationally feasible to utilise rainbow tables for that as you do not use any kind of salt for this hash. I think there should be precomputed tables for this sort of attack as they are useful in unwinding the hash(hash(hash(hash(...)))) construct as well.
  • If finding the preimage is successful, the attacker would know hash(text) XOR hash(password) candidate(s), where recovering hash(password) is trivial. Which one is the correct one can be verified by encrypting the test data.
  • At this point, the attacker would be able at least to forge arbitrary messages, as the plaintext of password is not required, only its hash.