# Review of AES encryption concept for an open source project

i'm working on an opensource project, A generator for static (html/js), password protected photo galleries. The generator AES 256 encrypts many images with the same key in PyCrypto, and decrypt them with CryptoJS. That's what my prototype does so far:

## General

• Encrypt many images with the same salted password
• an unique iv for every image
• store the unencrypted salt and the unencrypted iv with every encrypted image
• store the plain sha1 of the unencrypted image with the encrypted image

• salt = 16 random bytes from Random()
• aes_key = PBKDF2(dkLen=32, count=1000, salt=salt) of the user selected password
• The user can select the password. ATM the only requirement is: min 8 chars.

## IV

iv = 16 random bytes from Random()

Do you think this procedure is ok for my use case? If so, can someone review my python code to encrypt the images? (I'll provide the code on github if general procedure is ok)

Thank you very much for help and have a nice day, Boerni

-
"Do you think this procedure is ok for my use case?" You haven't said what your use case is. Why do you want to encrypt the images? What attacks or attackers do you have in mind? – user7576 Jul 12 '13 at 10:06
Please post your use case. Do you want to achieve just confidentiality or also integrity and authenticity? Who do you expect to attack your system and which attack vectors are available? Note that this question is better suited for security.stackexchange.com as it does not seem to be about cryptography in itself. – Maarten Bodewes Jul 12 '13 at 13:17
Although the algorithm is suitable for attaining confidentiality you may want to diversify your keys. If a password is changed you may have to re-encrypt all images for that password. Again, is it a use that that you can change the password? We don't know... – Maarten Bodewes Jul 12 '13 at 13:19
You should use a proper MAC in an encrypt-then-mac scheme, or standard authenticated encryption like AES-GCM. – CodesInChaos Jul 12 '13 at 14:38
And 1,000 rounds is not nearly enough for PBKDF2. The best number of rounds is "as many as possible without impacting users", but you should aim for a minimum of around 100,000 for now. If your library can't do 100,000 iterations in well under a second, find another library. – Stephen Touset Jul 12 '13 at 18:56

You're pretty much on the right track, I've got a few comments/suggestions though:

store the plain sha1 of the unencrypted image with the encrypted image

I'm assuming the sha1 hash is to ensure the integrity of the data being encrypted? If that's the case, you should have a read through this answer.

Assuming you're limited to non-authenticated modes (I don't see GCM, EAX or otherwise) as options in CryptoJS, then you'd probably do best to encrypt-then-MAC:

• InitialKey = PBKDF2(dkLen=32, count=100000, salt=salt, password=password) — where dkLen is the native block size of the underlying hash algorithm, in this case, sha256 = 32 bytes. Note: 1000 rounds of PBKDF2 is considered weak in 2013, if you must use PBKDF2 (as opposed to something stronger like Scrypt), then aim for as many rounds as is tolerable by the user
• SecondaryKey = PBKDF2(dkLen=64, count=1, salt=salt, password=InitialKey) — Note; just one round here. If you're wondering about this two-step PBKDF2 process, check out this excellent answer by D.W.
• AES_key = SecondaryKey:0-32
• HMAC_key = SecondaryKey:32-64
• HMAC = HMAC_SHA256((cipherText || iv || salt), HMAC_key) — where || denotes concatenation
• cipherText = cipherText || HMAC

I'd be inclined to use CTR mode (and no padding) instead of CBC, but that's just a preference - CBC is perfectly fine. Also, as @owlstead pointed out, you need to consider the implications of a user updating their password, and having to decrypt/re-encrypt all of their images, but that's beyond the scope of my answer.

-
@owlstead only works on comments, but thanks for the attribution :) – Maarten Bodewes Jul 12 '13 at 16:51