# Vigenère cipher with sha512 and a little foresight turns to one-time pad. How safe can be?

I'm doing some exercises and of course I have read about the weaknesses of Vigenère cipher because it repeats the key. But what if I use a different hash every time? The hash of the "key + an increasing number". In this example I encode a plaintext just with a sum of every single char (text[0] + pswhash[0] and so on). blocksize is 128 because I use sha512.

    f = open(filename)
f2 = open(filename+'.encoded','w')
x = 0
while True:
if not string:
break
pswhash = sha512((psw+str(x)).encode('utf-8')).hexdigest()
f2.write(encode(string, pswhash))
x+=1
f.close
f2.close
print("File encoded.")


how safe this could be? Is this a real one-time pad?

• SHA512 produces a 64-octet result; use that (and that length) not the hex form which is hugely redundant/correlated. – dave_thompson_085 Oct 7 '16 at 3:16

Is this a real one-time pad?

No, it's not a one time pad; as the keystream is not generated from a truly random process, hence you don't get the informational security guarrantees that you'd get from a true OTP.

Instead, it's a stream cipher; in particular, counter mode (with SHA512 is the "block cipher"; in counter mode, the block cipher needn't be invertable).

It's actually decent at providing privacy (albeit not very fast at it); however, it still would need some integrity protection (unless you're absolutely positive that an attacker cannot alter the ciphertext)

• 'decent' if you use actual SHA512 (or other good hash) output, but not if you effectively use 4 bits of keystream per octet of plaintext :-{ – dave_thompson_085 Oct 7 '16 at 3:14

No, that’s not a “real one-time pad”.

As I explained in another answer of mine…

Per definition, OTP requires the “key“ to be…

1. a truly random one-time pad value,
2. generated and exchanged in a secure way.
3. at least as long as the message, and
4. only to be used once.

At the very least, your idea fails the definition in points 1 (calculated checksum != truly random) and 3 (SHA512 has a fixed length, which is bound to differ from the plaintext message length).

Besides that, I hate to disappoint you – but the idea isn’t very new either. Cryptographically secure hashes represent nice cryptographic primitives which are inviting to build upon. Yet, such hashes are also build to be rather “slow”, which raises the question why one would decide to risk security pitfalls and accept slower performance when faster, well-vetted stream and block ciphers are available (most prominent example: AES).

Nevertheless, you might be interested to check up on some related Q&As as the answers to each of these questions hold information which might help you understand things a bit better:

Last but not least, to answer your “how safe this could be?” – it could be much more secure than what you’re doing right now. Looking at your code it’s obvious you simply hash $k|m$.

pswhash = sha512((psw+str(x)).encode('utf-8')).hexdigest()


Bluntly combining and hashing both key and message is about as bad as it sounds: don’t do it! There are several issues with that approach which might not seem obvious at first sight, but those issues can and will break your neck if you let them. Instead of writing a multi-page essay about that, I’ld rather like to advise you to use a HMAC based on SHA512 (at the very least) since HMACs are made to hash things using a password. You can use HMAC to create a KDF out of SHA512 quick and easy.

Even better would be using a dedicated Key Derivation Function. Or course, a HMAC-based Extract-and-Expand Key Derivation Function (HKDF) is simple and easy to implement… but honestly – from a security point of view – I would recommend using something more dedicated like PBKDF2 (Password-Based Key Derivation Function 2). Combine that with one of the faster, well-vetted ciphers like AES and the information you plan to encrypt has a good chance to be more secure than you could wish for.