Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I would like to store encrypted backup of text files on my computer. I'm developing a python script using Pycrypto to achieve that, based on this code to use the library. (current code)

The basic idea is :

  1. Generate new/Read existing AES + signature keys
  2. Encrypt the data using the first key (AES 256-CBC)
  3. Sign the encrypted data using the second key with HMAC-SHA256

The generation of bytes for the keys is simply the result of Random.get_random_bytes(KEY_SIZE + SIG_SIZE), so 64 bytes in my case.

Now, to improve the security, I would like to add a password protection to the key (if somebody find the keys file). My initial idea is to hash salt+password and XOR the result with the random bytes in the key-file.

If I use SHA256 (to be consistent), it means I output 32 bytes and should XOR twice (for each 32 bytes key) and I don't like that (not sure but sounds like a potential attack). Using a different salt for each key ?

Finally, is there a standard way to store the salt and keys ? I don't like the idea of inventing my own scheme (usually a bad idea in cryptography). Is there some good practices ?

Update: thanks to the answer of Polynomial, I got the following code :

from Crypto import Random
from Crypto.Protocol.KDF import PBKDF2

def generate_new_keys(password, enc_key_size=32, sig_key_size=32):
    rand_bytes = Random.get_random_bytes(enc_key_size + sig_key_size)
    # save the salt
    with open('keys.salt','w') as f:
        f.write(rand_bytes.encode("base64").replace("\n",""))
    # derive the two keys using PBKDF2
    enc_key = PBKDF2(password, rand_bytes[:enc_key_size], dkLen=enc_key_size)
    sig_key = PBKDF2(password, rand_bytes[enc_key_size:], dkLen=sig_key_size)
    return (ency_key, sig_key)
share|improve this question

1 Answer 1

up vote 5 down vote accepted

Don't try to come up with your own encryption scheme. The one you propose is vulnerable to a known plaintext attack, which makes key material trivial to recover if any bits of the original file are known.

For example, if I know that the first byte of plaintext is always 0x4B, and I can see that the first byte of ciphertext is 0xC7, I can compute 0x4B ^ 0xC7 and get the first byte of the key, which would be 0x8C. From there I can skip ahead 32 bytes and decrypt that byte of ciphertext, and again, and again. Using that information I might discover more information about your plaintext, and use that to decrypt more of the data.

Encrypt your key file with a block cipher (e.g. AES) using an appropriate mode of operation (e.g. CBC), with a key derived using a proper key derivation algorithm, such as PBKDF2. Using a plain hash function for key derivation is a bad idea, as it's extremely fast and allows an attacker to crack the password efficiently. If your mode of operation requires an initialization vector (IV) it should be random and unique, but is not secret information.

share|improve this answer
    
Thank you for the attack explanations, as I thought, not good to use own scheme. So to sum up, I should use my two block of random bytes as salt ? –  Martin Trigaux Dec 17 '12 at 11:23
    
Also, is it better to store sha256(salt+password) to check if the entered password is correct or let the program fail if the entered password is incorrect ? –  Martin Trigaux Dec 17 '12 at 11:44
2  
The salt for the key should be a random value stored in plaintext in the file, along with the IV for AES. Don't bother storing the hash, just make the first 4 bytes of the encrypted data static (e.g. "MTKF") so you can check that the decryption produced a correct output. –  Polynomial Dec 17 '12 at 11:51
    
Wouldn't first X bytes plaintext (4 for 'MTKF') + first X bytes of ciphertext + first X bytes of IV still produce the first X bytes of the key (P ^ C ^ I = K)? If anything of the plaintext is to be static as a "checksum", I would suggest it be the last X bytes; in CBC mode any error in ciphering is compounded with each block, so if the last block is what you expect then you know the message wasn't tampered with. CBC-MAC creates checksums using this exact property of CBC block mode. –  KeithS Dec 19 '12 at 22:22
    
@KeithS Not if you're using a proper cipher like AES, rather than a home-brew one. –  Polynomial Dec 19 '12 at 23:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.