5

I've written my own encryption method using AES in a project I've been working on lately using PyCrypto. I use a hash to generate a 32-byte password and feed that to AES-256bit encryption using CBC. The file input is padding using PKCS#7 padding to conform to be divisible by 16.

I can encrypt and decrypt the file without incident and the input file originally encrypted along with the output file have the same SHA-256 hash.

The only problem I'm finding is that if I supply the wrong passphrase, decryption still happens. This is a problem for what I'm doing, as I need to have decryption fail fast if the passphrase is wrong.

How can I make this happen? I've heard of other methods of AES encryption, but it seems that PyCrypto only supports ECB, CBC, CFB, OFB, CTR, and OpenPGP. How can I implement cryptographically strong AES which will fail decryption without the right passphrase?

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
Naftuli Kay
  • 87,710
  • 93
  • 269
  • 411
  • 1
    `I've written my own encryption method` -- Well there's your problem. –  Feb 20 '13 at 20:11
  • 1
    I didn't write my own encryption method. I wrote a program which uses AES as an encryption method. I'm not _that_ daft. – Naftuli Kay Feb 20 '13 at 20:24
  • AES is just a primitive (a block cipher). I get that my "encryption method" you mean a way to use this primitive (and others) for a higher-level purpose (password-based encryption of arbitrary amounts of data). That's what I meant: This is still something you probably shouldn't do yourself. –  Feb 20 '13 at 20:28
  • Can you recommend a secure encryption method which offers 256-bit encryption, uses a strong and slow hash method as its key, and can encrypt without knowing the full length of the file? If there were a drop-in solution which met all of my requirements, that would be _awesome_. – Naftuli Kay Feb 20 '13 at 20:34
  • I'm pretty sure there are existing solutions, but I'm no expert. At least for the hashing part, there's PBKDF2. Applying a stream cipher to arbitrary-length plaintexts is also done on a regular basis by expert-written and -reviewed software (and on the other side, crypto people come up with more sophisticated attacks every other month). As for combining the two, I'm stumped but presume there are existing standards, though perhaps no open source implementations. –  Feb 20 '13 at 20:39
  • The hash method I'm using is bcrypt but can be easily replaced by PBKDF2. That, combined with AES-256 bit encryption would seem to indicate high security. Of course, before doing anything super important with it, I'd probably hire a cryptographer to analyze my methods. – Naftuli Kay Feb 20 '13 at 20:41

3 Answers3

5

The best way of making sure that your ciphertext won't decrypt when it has been changed is to add an authentication tag. An authentication tag is used to provide authentication and integrity of the ciphertext.

This tag may consist of a MAC (e.g. AES-CMAC or HMAC using SHA-256) over the ciphertext. This however requires a second key to be secure.

Another method is to use authenticated encryption such as GCM. GCM uses a single key and generates an authentication tag (the size can be configured).

Make sure you use a correctly generated IV. The IV could be prefixed to the ciphertext, and should be included when calculating the authentication tag), and don't forget that the size of your plain text may not be hidden.

You should verify the correctness of the tag before decryption of the ciphertext.

Note that in general, you should not encrypt passwords, unless you require access to the precise password at a later date. For verification of passwords, use PBKDF2 instead.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • I'm using a hash method for passwords, bcrypt right now, though I may use PBKDF2. Unfortunately, there is virtually no support for authenticated AES modes in Python. I know virtually nothing of MACing ciphertext, any ideas on where to start there? I'd like to use something that does it for me so I have less of a chance of messing it up and compromising security. – Naftuli Kay Feb 20 '13 at 21:14
  • [This article](http://code.activestate.com/recipes/576980-authenticated-encryption-with-pycrypto/) seems to do a lot of things right. HMAC with SHA256, two keys, IV in HMAC. Cannot vouch for it fully, but it certainly looks ok... – Maarten Bodewes Feb 20 '13 at 22:01
3

There is nothing about AES (or any other encryption algorithm for that matter) that could allow you to know whether you have the correct key. That said, it's a very useful feature when you actually want to use cryptography outside of the realm of mathematics.

What you need to do is add a block with a known value at the start of your message, that way after decrypting the first block you can compare it against the known value and know whether you have the wrong key. If the data you're encrypting has a known header you could use this instead.

Alternatively you could send a cryptographic hash (for example SHA-256) of the key along with the message, an attacker would only be able to recover the key if they could break the hash.

jleahy
  • 16,149
  • 6
  • 47
  • 66
  • 1
    I'm no crypto expert, but if the first block of the plaintext is a know value, can't an attacker easily get the key from looking at the first block of the ciphertext (and the IV, if applicable, but that's included in plain text)? –  Feb 20 '13 at 20:15
  • I'd hope not, that would be a [known-plaintext attack](http://en.wikipedia.org/wiki/Known-plaintext_attack). If you were very paranoid you could make the first block the key, or some irreversible hash of the key. – jleahy Feb 20 '13 at 20:20
  • Would storing a hash of the IV in the first block be cryptographically insecure? It's a known value and has to be. – Naftuli Kay Feb 20 '13 at 20:28
  • @jleahy I don't *think* my concern is as weak as a known-plaintext attack, but I lack insight to discuss this further. RE Encrypting the key with itself (e.g. as the first block): That's at least theoretically interesting, and IIUC dangerous with many ciphers that don't have a certain property whose name escapes me (I'd have to do some research). –  Feb 20 '13 at 20:33
  • This is perfectly sufficient. Having a known header isn't a problem, otherwise encrypting something like a Microsoft Word document (that also has a known header) would be insecure. If you want a third solution you can just send the SHA-256 hash of the key along with the message. You'd only be able to recover the key if you can break SHA-256. – jleahy Feb 20 '13 at 20:45
  • @jleahy A hash by itself would be rather vulnerable to attack by means of precomputed tables. Also, due to the rising popularity of Bitcoin, there is a growing interest in ASIC designed to brute-force SHA-256 (since this is the basis of Bitcoin's proof-of-work scheme). – Jeffrey Hantin Feb 21 '13 at 01:33
  • 1
    @JeffreyHantin this is not an issue if the key has sufficient entropy, e.g. if it was randomly generated. Note that this is about encrypting the password, not encrypting something *with* the password. – Maarten Bodewes Feb 21 '13 at 02:02
  • 1
    **WARNING**: accepted answer uses non-standard cryptographic practices. A MAC over the ciphertext or authenticated encryption is the way to accept or reject a ciphertext. – Maarten Bodewes Feb 21 '13 at 02:04
  • @owlstead The whole question seems rather fuzzy to me in the first place, so I may have gone off the rails. Also, if this is about encrypting the password, there are an entirely different set of standard practices for that. – Jeffrey Hantin Feb 21 '13 at 02:20
  • 2
    @JeffreyHantin this was more or less cross posted to [crypto](http://crypto.stackexchange.com/questions/6411/validating-successful-decryption-in-aes), without so much of a hint, discussion continues there. – Maarten Bodewes Feb 21 '13 at 02:22
  • I have run some experiments using `gpg -c --cipher-algo aes256`, trying to decrypt a file protected by a single-letter password, but contrary to this answer, I could *not* decrypt with any of the randomly guessed millions of passwords. How do you encrypt s.t. encryption succeeds (producing meaningless data) even with an incorrect key (which *is* desirable in my case)? – eold Sep 25 '14 at 21:27
0

To provide the desired fail-fast property, you'll need to prepend a header to the data being enciphered. I suggest using a random "confounder" nonce (similar to a cryptographic salt) concatenated with a known constant "magic number"; the presence of a confounder will, much like a salt, provide a measure of defense against attacks based on precomputed tables.

With such a header present, you need only decipher the header and validate the magic number field; if it does not match the known constant, the key is no good. If it does match, discard the header and process the remainder of the input.

Jeffrey Hantin
  • 35,734
  • 7
  • 75
  • 94