It's as true in life as it is in client-server programming: the only secret that can't be compromised is the one you never revealed.
But sometimes, it's unavoidable. If you must send a secret down to the client, you can encrypt it. The most common form of encryption is symmetric encryption, where the same key is used to both encrypt and decrypt. Most languages have relatively easy to use libraries in place for symmetric encryption. Here's how we were doing it in .NET:
public static string Encrypt(string toEncrypt, string key, bool useHashing)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
if (useHashing)
keyArray = new MD5CryptoServiceProvider().ComputeHash(keyArray);
var tdes = new TripleDESCryptoServiceProvider()
{ Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
This is how our symmetric encryption function works:
We'd call the function like so:
Encrypt("NaCl" + "password123", "key-m4ast3r", true);
The output is a base64 encoded string of the TripleDES encrypted byte data. This encrypted data can now be sent to the client without any reasonable risk that the secret string will be revealed. There's always unreasonable risk, of the silent black government helicopter sort, but for all practical purposes there's no way someone could discover that your password is "password123" unless your key is revealed.
In our case, we were using this Encrypt() method to experiment with storing some state data in web pages related to the login process. We thought it was secure, because the data was encrypted. Sure it's encrypted! It says Encrypt() right there in the method name, right?
Wrong.
There's a bug in that code. A bug that makes our encrypted state data vulnerable. Do you see it? My coding mistakes, let me show you them!
string key = "SuperSecretKey";
Debug.WriteLine(
Encrypt("try some different" +
"00000000000000000000000000000000",
key, true).Base64ToHex());
Debug.WriteLine(
Encrypt("salts" +
"00000000000000000000000000000000",
key, true).Base64ToHex());
3908024fc33b55c3
4e885c8946b80735
704cbe2a41d25f21
81bb6d726bd35152
81bb6d726bd35152
81bb6d726bd35152
1367f10f2584ace3
4ae7661295a98e46
81bb6d726bd35152
81bb6d726bd35152
81bb6d726bd35152
4ee5d23b3b5e3eb4
(I'm using strings with multiples of 8 here to make the Base64 conversions easier.)
Do you see the mistake now? It's a short trip from here to unlimited data tampering, particularly since the state data from the login process contained user entered strings. An attacker could simply submit the form as many times as she likes, chop out the encrypted attack values from the middle, and insert them into the next encrypted request -- which will happily decrypt and be processed as if our code had sent it down!
The culprit is this line of code:
{ Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 }
Which, much to our embarrassment, is an incredibly stupid parameter to use in symmetric encryption:
The Electronic Codebook (ECB) mode encrypts each block individually. This means that any blocks of plain text that are identical and are in the same message, or in a different message encrypted with the same key, will be transformed into identical cipher text blocks. If the plain text to be encrypted contains substantial repetition, it is feasible for the cipher text to be broken one block at a time. Also, it is possible for an active adversary to substitute and exchange individual blocks without detection.
It's fairly standard for symmetric encryption algorithms to use feedback from the previous block to seed the next block. I honestly did not realize that it was possible to pick a cipher mode that did not do some kind of block chaining! CipherMode.ECB? More like CipherMode.Fail!
So, what have we learned?
CipherMode that allowed block level substitution of the encrypted data.
Luckily, this was a somewhat experimental page on the site, so we were able to revert back to our standard server-side approach rather quickly once the exploit was discovered. I'm no Bruce Schneier, but I have a reasonable grasp of encryption concepts. And I still completely missed this problem.
So the next time you sit down to write some encryption code, consider the above two points carefully. Otherwise, like us, you'll be left wondering why your encryption isn't... encrypting.
(Thanks to Daniel LeCheminant for his assistance in discovering this issue.)
I made this mistake, too!
Josh Stodola on May 18, 2009 7:33 AMThat's why you don't override defaults if you don't know what they are.
Also, TripleDES? Why not AES?
Wyatt on May 18, 2009 7:35 AMAlso keep in mind that even if you do use a good algorithm (3DES? ugh!) and sensible block-chaining mode, that just might not be enough.
Like, replay attacks.
f0dder on May 18, 2009 7:38 AMMaybe this is just simplified sample code for the blog, but both MD5CryptoServiceProvider and TripleDESCryptoServiceProvider are IDisposable objects that wrap underlying Win32 CryptoAPI components; they should be disposed so that the native objects are freed when no longer in use.
Bradley Grainger on May 18, 2009 7:42 AMJust curious... what's your decryption code look like?
Keltex on May 18, 2009 7:43 AMYou have another problem, although it's not as serious. The salt shouldn't be fixed.
It should change every time, so you can't tell if the same plaintext was encrypted. More seriously, they don't have to be exactly identical. You can tell if two plaintexts' share a common prefix (in block sizes).
Strilanc on May 18, 2009 7:56 AMTripleDES shouldn't really be relied on anymore these days, anyhow. As others have asked, why not something like AES?
Kevin Fairchild on May 18, 2009 7:58 AM"More like CipherMode.Fail!"
Hilarious!
ah encryption, what a fickle and fatal mistress...
Keven Sutton on May 18, 2009 8:05 AMIn its defense, ECB does have valid uses: Whole disk encryption, for example.
Nick Johnson on May 18, 2009 8:10 AMForgot about MAC? You should have sign the message.
signit on May 18, 2009 8:19 AMSo now you are using CipherMode.CBC ??
"The Cipher Block Chaining (CBC) mode introduces feedback. Before each plain text block is encrypted, it is combined with the cipher text of the previous block by a bitwise exclusive OR operation. This ensures that even if the plain text contains many identical blocks, they will each encrypt to a different cipher text block. The initialization vector is combined with the first plain text block by a bitwise exclusive OR operation before the block is encrypted. If a single bit of the cipher text block is mangled, the corresponding plain text block will also be mangled. In addition, a bit in the subsequent block, in the same position as the original mangled bit, will be mangled. "
Antonio on May 18, 2009 8:20 AMWhy isn't 3-des considered secure? From what I've seen the best known attack is the mitm, which takes years and requires large amounts of memory memory.
al on May 18, 2009 8:29 AMGiven that not everyone can (or should be) an encryption expert, I'd argue that the key issue here is too many options. For experts, certainly options for special cases are fine - but for the average user, why isn't there an Encrypt(key, plaintext) function built into the API - with all the options fixed by someone who *has* taken the time to become an expert, so that the rest of us don't have to?
Or if there is such a function, why didn't you use it?
(Even your code has one too many options - as a naive user, I've no idea whether I should set useHashing to true or false, and why it would matter!)
Paul Moore on May 18, 2009 8:29 AMOh, where to begin. 3DES is OK, especially since the items you're encrypting are of only short-term value. But MD5 for hashing? There are enough attacks against MD5 now that its inadvisable to use it for anything new. Try the SHA-256.
I hope you're generating a new salt each time... that's kind of the point of a nonce, that it's different for each operation. It doesn't matter if people know the nonce, then. If you use the same nonce, and it's discovered, then it makes a brute-force or rainbow-table attack a lot more likely.
Also, I find it incredibly hard to believe that you need anything more than session management - if you're encrypting stuff to be stored in an HTML page, you're probably doing it wrong.
Darren on May 18, 2009 8:38 AMEncryption is hard to understand. When I first started having to deal with encryption I researched, mostly on the web, but I looked around a lot. I took the "lazy" route and looked for examples of what I was trying to do. This lead me to a lot of articles and discussion forums on wrong ways to encrypt. These wrong ways were really helpful as I was able to take my encrypting solutions and use the wrong way examples as test cases.
My advice, if you need to add an encryption scheme to your app look for on how to do it, it's all out there somewhere. Then test, test, and test some more.
Sean on May 18, 2009 8:44 AMWhy does the useHashing parameter control hashing of the key, rather than hashing of the plaintext? Hashing the key seems rather stupid, as you could just use hash("key-m4st3r") at the same point you're now setting "key-m4st3r". I'm not a crypto geek, but I don't think this gains you any additional entropy or anything (the hashed key is vulnerable to the same attacks the unhashed key is, I think). OTOH, encrypting a hashed plaintext is very useful, as that's the whole basis behind digitial signatures.
John on May 18, 2009 8:46 AMPassword123 - that's not your real password is it Jeff? I wouldn't normally ask, but you know, recent events and all that...
Schmoo on May 18, 2009 8:49 AMI've got a big blind spot in my skill set when it comes to encryption. Keep on sharing, Jeff! These posts help me a lot.
Charles on May 18, 2009 8:55 AMHi, this is tux:
http://upload.wikimedia.org/wikipedia/commons/5/56/Tux.jpg
and this is tux encrypted with a block cypher in ECB mode:
http://upload.wikimedia.org/wikipedia/commons/f/f0/Tux_ecb.jpg
regardless of the type of block cypher (3DES, AES ...) ECB is a bad choice for an encryption mode; unless you are showing someone this kind of blunder.
Mario.
Mario on May 18, 2009 9:03 AMActually, scratch my earlier - even for whole disk encryption you should be using CTR instead of ECB. :)
Nick Johnson on May 18, 2009 9:11 AMI don't think the API's so great, since it allows you to shoot yourself in the foot so easily. When you first use an API you are completely ignorant, and you want the API designer to have made some good choices for you for default parameters.
The DOCS are rarely much help either, since they fail to provide any judgement about the encryption scheme. Wouldn't it be good if they said something like "if your doing this, then use this encryption, and make sure these options are set, and here's a real example too." And then have an example with all the right stuff like salting put in and done properly.
Anyway, good post.
Mat Roberts on May 18, 2009 9:11 AMECB has its uses, but one of its big uses was to allow blazing fast (for the time) hardware implementations. CBC makes each block dependent upon the previous blocks, meaning hardware has to be one great big pipelined unit. ECB allowed hardware to consist of a large number of smaller, independent encryption engines. It was only safe to use ECB when replay was not a concern and where you can change the key frequently enough that repeated identical ciphertext doesn't give an attacker much leverege.
Denton Gentry on May 18, 2009 9:17 AMam i the only person that thinks using NaCl for the salt is crypto-comedy-gold?
...
uhhh...crypto-comedy-Au?
daniel on May 18, 2009 9:31 AMYou might want to take a read over the encryption posts on Good Math-Bad Math as they go over this kind of material: http://scienceblogs.com/goodmath/goodmath/encryption/
Keith Gaughan on May 18, 2009 9:35 AMNaCL is the new orange imo
fschwiet on May 18, 2009 9:40 AMthis guy knows his chemistry. NaCl. wow.
Ironically, C2H5OH would have been a better salt. Even methane would have salted this better.
securityhorror on May 18, 2009 9:45 AMSo.
MD5 *is* a bad choice but not for the reasons Darren suggests; the published attacks on MD5 render it unsuitable for message digests and digital signatures, but it's fine for entropy mixing purposes. The *real* reason you wouldn't want to use MD5 is because MD5's digest length of 128 bits is far short of 3DES's strongest key size of 168 bits. You've dropped about 50 orders of magnitude of cryptographic strength without even realizing it. (Well, not exactly -- 3key-3DES has a meet-in-the-middle attack which reduces the work order of a brute force attack to 2^112, but even that is predicated on a high-entropy 168-bit key, which you'll not get out of MD5.)
You *don't* need a salt. A salt is a unique value which is combined with a password before hashing it and storing it for later password authentication. You're not hashing passwords and then storing them here, so attempting to defeat a rainbow attack doesn't make sense -- it's not an attack vector for what you're doing. Adding a salt is cargo culting. Best case scenario, it adds nothing. Worse case scenario, it reduces the strength of the system.
You *do* need an initialization vector, which is a unique, non-zero parameter used as the first feedback block in block cipher chaining algorithms like CBC and CFB. It doesn't need to be high-entropy, but it *does* need to be unique. If you reuse an IV for different plaintexts, an attacker knows that (C1 XOR C2 = P1 XOR P2) and can recover the plaintexts with a small amount of guessing. This is why WEP is no longer considered secure.
Your encryption algorithm should look something like this:
1. Generate a random IV of a length equal to the encryption algorithm's block size (for 3DES, that's 64 bits).
2. Run the user's password through a hash algorithm with a digest size equal to or greater than the key size of the encryption algorithm. SHA-256 is a fine choice; just drop the unused bits off the end. Your aim here is simply to diffuse the entropy in the user's password across the entire key (otherwise big chunks of the key are predictable).
3. Initialize the encryptor with the key and the initialization vector.
4. Encrypt your data.
5. Prepend the initialization vector to the encrypted data.
That said, the only kind of people who should be writing code like that are people who understand *why* they should be writing code like that. I'm not seeing that here, so a better description of what your algorithm should look like is:
1. Pick a reputable cryptographic library, like Bouncy Castle.
2. Pick a high-level abstraction from the library which matches what you want to do (e.g., "send a confidential message").
3. Do what it says.
Seriously. Don't play with cryptographic primitives in production code.
Coda Hale on May 18, 2009 9:46 AMYou guys asking for the API designers to magically make the right choices for you are children. Crypto is complicated. For any given set of defaults, there are simple situations where those defaults are unsatisfactory. If you actually need encryption, take the time to read up on the concepts so that you know what you're doing - or hire someone who already does.
ben on May 18, 2009 9:58 AMWhat really struck me about this post was not the technical bit but the honesty that someone actually admits his mistake (undermining their reputation?). I believe there are maaany other people out there who don't understand the concepts and do a very bad job at security (as I have to confess myself) - the only reason so little happens is that people don't know about the many security holes?
thosteg on May 18, 2009 10:04 AMAm I missing something? Isn't it worth noting how you planed on sharing the key?
ian on May 18, 2009 10:20 AMThe irony in this is that someone will inevitably end up here for sample encryption code and blindly copy/paste your flawed code.
Geoff Weinhold on May 18, 2009 10:25 AMi agree with you @jeff when you say "the only secret that can't be compromised is the one you never revealed" and also that "If it doesn't have to be sent to the client, then don't!".
Back in the day when i was freelance, a client called in some friends of mine because he had forgotten the password to the company pop mail account. Do you know what these "clever so and so"s did? They went and installed packet sniffer on the company network and snatched the password (among many other things) right out of the ether when one of the other company computers tried to pop the company email.
Lesson here, please don't send sensitive information over the ether. What i usually do here is use a one way hash on the client app that compares this hash with a stored hash of the password in the database. This is the reason the more reputable (and several less reputable) sites instead of sending you your password, simply assign you a new temporary one. Not because they couldn't be bothered (which could be), but rather because they most often never knew your password to begin with. This makes also the same password reusable(now if only they could register somewhere what algorithms they all use to ease the choice).
The catch here would be what salt to use in order to have the salt unique to each and every password that is hashed. my suggestion would be a certain portion of the users password. where by the fore mentioned portion would be known only to the programmer who implemented the algorithm yet still of little use to him. I welcome better suggestions for a method to choose the salt and a better algorithm.
"I have a reasonable grasp of encryption concepts"
I am sorry Jeff, but you have just shown that you know bugger all about cryptography! Seriously consider reading some Bruce Schneier books and then re-evaluate all the places you use any form of cryptography.
Jeff -
ECB does have it's uses, especially when errors in transmission are possible. A single bit error will corrupt only the received vector with ECB, but with CBC all following vectors will also be corrupt.
The main problem was best described by Stevie Wonder: "when you believe in things you don't understand...Superstition is the word."
- Lepto (nambla)
Lepto Spirosis on May 18, 2009 10:48 AMWow... This is scary...
I think my advice would be: describe the functionality of the system and then hire someone who knows how to implement it properly.
To illustrate the point: your GP doctor does not do heart surgeries. And there is a reason for that...
Boy, what sites do you guys work on?
Honestly, if I just used rot13, that would probably be enough to keep anyone interested in snooping out of most of my sites. All you have to do is make it more of a pain to read than the information is worth.
Heck, with most of my websites, I could even email you the information, and it still wouldn't be worth your effort to double click on the message to read it.
If I really have to encrypt, I use SSL certificates on my server. Then, the encryption is handled by the webserver, and I don't have to worry about a programmer making a dumb mistake. Let the professionals handle the problem, and try not to reinvent the wheel.
David W. on May 18, 2009 11:15 AMTheir seem to be all kinds of reasons that MD5 is a bad idea. What about gzip? Gzip the data before the crypto and any changes in the input will get spread across the whole message. This might be improved by ordering data in the message to place changing data at the start or end.
BCS on May 18, 2009 11:22 AMPlease do not use the advice given in the comments here. Most of it is VERY wrong.
argh on May 18, 2009 11:58 AMWhen I have to do symmetric encryption in .NET I always rely on ASP.NET FormsAuthentication provider do that. It is used to encrypt cookies in all ASP.NET applications (using forms authentication) so it should be strong enough. Here's the code:
class Program
{
static void Main(string[] args)
{
var encrypted = EncryptUsingMachineKey("value to encrypt");
var decrypted = DecryptUsingMachineKey(encrypted);
Console.WriteLine(encrypted);
Console.WriteLine(decrypted);
}
public static string EncryptUsingMachineKey(string value)
{
var ticket = new FormsAuthenticationTicket(
2, "", DateTime.Now, DateTime.Now.AddMinutes(10), false, value);
return FormsAuthentication.Encrypt(ticket);
}
public static string DecryptUsingMachineKey(string cipherText)
{
return FormsAuthentication.Decrypt(cipherText).UserData.ToString();
}
}
This uses the following section in machine/web/app.config:
<machineKey
validationKey="3DC93913A3E7998AE43...C519574359262"
decryptionKey="9470AD8F914387CBE0...ABA8A0DB762"
validation="SHA1" decryption="AES" />
This means that AES is used to encrypt and HMACSHA1 to tamper proof the encrypted string.
Whats with the sudden influx on 4chan memes?
dude on May 18, 2009 12:17 PMReason for ECB -- can seek.
Joshua on May 18, 2009 12:32 PMOff-topic.
"An attacker could simply submit the form as many times as _she_ likes"
Why "she"? I fail to understand this bit of English usage.
Can someone explain?
AndrÈ on May 18, 2009 1:07 PM"Why "she"? I fail to understand this bit of English usage."
Thank you AndrÈ for raising this question! I think he is referring to Eve, the evil eavesdropper. But it's so biblical, patriarchal, typical and annoying.
http://xkcd.com/177/
http://en.wikipedia.org/wiki/Alice_and_Bob
Salt????? This isn't a hash--this is a cipher.
Assuming you're changing the value of this "salt" each time, I think the phrase you're looking for in this context is an initialization vector: http://en.wikipedia.org/wiki/Initialization_vector
TorgoGuy on May 18, 2009 1:21 PMMy favorite is when people want to "encrypt" things by XORing against a fixed string: perl -le 'print for map ord, split //, "secret" ^ "foobar"' looks pretty random, but if the plaintext has a bunch of spaces (as they often do): perl -le 'print "secret" ^ " "', oops, there is they key (uppercased, but still).
Chas. Owens on May 18, 2009 1:39 PMSo, you mean it's just in order not to look sexist?
AndrÈ on May 18, 2009 1:55 PMIn the name of not being sexist writers are committing errors to the English language. He is either masculine or neuter. She is always feminine.
In the name of political correctness we are slowly destroying our language. Bah!!
Mark on May 18, 2009 2:26 PMFun fun fun, this is the stuff I love.
Coda Hale's advice is pretty good, but I understand entropy to be something different. If there are 40 bits of entropy in the world "hello" (there aren't but for example's sake) then md5("hello") doesn't suddenly give me 128 bits of entropy. You don't get entropy by passing it through functions, you can only get it from randomness. Which is why your key shouldn't be any sort of string at all, but rather a completely random byte array (from some secure source of randomness - just ask Debian).
Don't feel bad Jeff, that's not nearly as bad as the multi-million dollar blunder I found last week (linked in my name) - you were just protecting our precious Rep ;)
Tom Ritter on May 18, 2009 2:30 PM@jake
Why would you use part of the password as a salt? I'm no crypto expert but that sounds like a complete WTF to me.
What's wrong with just using a random number?
Looks like CBC is going to need some explaining as well.
CBC combines the output of the previous cipher block with the current plain text block before encrypting. An IV is required for encrypting the initial block.
CBC is actually quite robust for errors during transmission. A 1 bit error in one block will result in that block decrypting to garbage, and the same bit flipped in the subsequent block.
Because of this property, it is possible to change the plaintext without knowing the key. CBC+block wide salt = particularly bad news. Since you don't validate the salt, an attacker can modify the first 8 characters of the string. More advanced attacks are possible if the user collects a sufficient amount of cipher text blocks with known plaintext.
In general the following rules should be followed when using a cipher in CBC mode:
1) Use a randomly choosen unique salt
2) Sign both the salt and the message with a good HMAC
3) Use strong validation of the decrypted input
Also, for disk encryption use a cipher mode meant for it, like XTS.
Charles on May 18, 2009 2:47 PM@Joshua
CBC and CTR can seek as well.
Charles on May 18, 2009 2:50 PM@Mark "She is always feminine."
Except when she is a ship, boat, or other vessel. Or sometimes a gun, cannon, or other weapon. Or the sea. Or nature.
http://en.wikipedia.org/wiki/She
Ed on May 18, 2009 2:58 PMI have purchased a number of books over the years, but none come close to my first purchase "Applied Cryptography" by Bruce Schneier
http://www.schneier.com/book-applied.html
The best part about the book is that it is 90% processes and 10% code.
That is - Encryption is NOT a computer task, it is a process in which computers play a role.
It describes how people could/can hack your communication, and therefore how to best stop it. I've never made the mistake you outlined only because I read this book cover to cover before writing a single line of security code.
It also introduces concepts such as "how secret" you need something to be. If you use standard technologies for encryption, then you can expect the data will be cracked quite easily in about 5 years (computers doubling in speed at approx. 18 months). Using moderately advanced encryption techniques, and you are looking at 10-15 years.
Using very time consuming methods, you might get decades (depending on when quantum computing comes out). The point is - if you don't want people to know about it, don't store it!
But most encryption that people deal with is "in the moment", were the details of a login, transaction, etc. are needed to be kept secret. This is easily handled.
BUT - just remember, security on a computer is like physical security. Even if you implement the best security available, if someone wants it enough and has the resources, they will get what they are after. It's just a matter of making it so difficult and time consuming that it isn't worth their while.
Honestly, I'm getting very uninterested in your blog.
The last couple blog are abundantly obvious to anyone with a modicum of computer science education. I mean basic things like formal logic, discrete math, algorithmic thinking/analysis, and cryptography.
Why is it again that you don't seem to support the need for basic computer science education for programmers?
Mark on May 18, 2009 4:01 PMThis is like one of the softball easy questions that shows up on the first midterm of a Computer Security or Cryptography course.
Charles on May 18, 2009 4:17 PMSorry to say this Jeff, but if you don't know what ECB is, and if you use 3DES in new code, then you don't have a reasonable grasp of encryption concepts.
This is literally first-week material in any Cryptography course.
Can Berk G¸der on May 18, 2009 5:11 PMYou have no idea what you're talking about, do you, Jeff.
dsdz on May 18, 2009 5:40 PMBuy and read a good cryptography book... instead of reinvent the wheel.
Band5 on May 18, 2009 6:22 PMYet again, Jeff Atwood demonstrates how incredibly ill-informed he is. First it's NP-completeness, then it's using a English dictionary word as a password, now it's using 3DES in ECB mode. This guy is a clown.
Jebus on May 18, 2009 6:59 PMChrist, you guys are a bit harsh. Sure, he didnt know that you're not supposed to use 3DES in ECB mode.
Guess what, neither did I until I read this. Probably because I never took a crypto elective, and to date have not yet had to implement any crypto at lower than library level. Id say my ignorance is forgivable.
All of you experts that know everything about everything perhaps shouldnt read a blog pitched at the rest of us?
At the very least its taught a bunch of mortals like me(well at least one :p) that we should be very cautious about doing any lower-level crypto, which is a good thing.
Dave on May 18, 2009 7:08 PMYeah - a lot of the posts have been harsh - but aren't the consequences of this type of naive mistake also harsh?
Yes he made simple mistakes ñ but thatís why I pointed out a specific book (above) that would have stopped that mistake.
I have to agree with the harshness of others (but not the bluntness), if you havenít done a cryptography course, then you better dam well read a book on it because itís not something you want to get wrong.
The problem is that a post like this strikes us as ìif you didnít know that, stop what you are doing and go and learn about it NOW!!!î
Itís like seeing an army soldier playing with a gun and then pointing out to those around them ìhey look ñ it didnít shoot because of this little lever. It must be some type of safety latch.î If they donít know about the safety lever ñ chances are they shouldnít have the gun in their hand.
So the advice would be, go get a cryptography book, read AND understand before writing a single line of code using cryptography. Otherwise there is probably little point in even using cryptography.
Philip on May 18, 2009 8:35 PMBah! I'm rather sure none of those issues would ever happen with on oldskool C/C++ encryption lib.
You MSIL freaks! ;)
Base 64 conversion is not encryption, It is encoding!!
Please correct me if i am wrong.
Its like converting a decimal to hexa....
@AndrÈ:
Well, I think he was being passively sexist rather than actively sexist. Whoever chose to call Eve Eve in the fist place is to blame. Why to choose that very telling name that relates to the story that is the bane of our existence? And by us I mean us women.
Programming community at large is pretty happy to sustain these stereotypes, though.
Joy on May 19, 2009 12:23 AMbasically everytime you made a choice you got it wrong.
-md5 should not be used anymore
-3des should not be used anymore
-ecb should not be used anymore
just leave it with the default: passwordderivebytes class and dont set any parameters you dont understand.
tobi on May 19, 2009 1:35 AM> I'm no Bruce Schneier, but I have a reasonable grasp of encryption concepts.
MWAHAHAHAHAHAHAHAAAAAA
You so do not have a reasonable grasp of encryption concepts.
Anon on May 19, 2009 1:57 AMOf the comments so far, I think Coda Hale makes the best point. You don't need a salt; you should be using CBC with a good, random initialization vector (which is transmitted along in plain-text). This acts like a salt in that it guarantees encrypted messages are unique even if their plain-text contents aren't. Together with CBC it's practically impossible to deduce information about the message contents from the encrypted data.
However, nothing so far prevents tampering with messages (which seemed to be the main concern in this post). A simple and secure solution is to add an HMAC of the plain-text data (or even the encrypted data). It would probably also suffice to insert a (cryptographic) hash code of the plain text in the plain text data somewhere, but HMAC is better established, so probably a better choice.
Note that at this point replay attacks are still possible. This may or may not be a problem depending on the application.
Maks Verver on May 19, 2009 2:35 AM@Joy:
She's called "Eve" because she's the eavesdropper. If you still don't get it (highly probable), try pronouncing the words out loud (you may have to repeat this several times).
> am i the only person that thinks using NaCl for the salt is crypto-comedy-gold?
> uhhh...crypto-comedy-Au?
> daniel on May 18, 2009 09:31 AM
Kr-comedy-Au?
Sure ECB has its uses. You use it in whenever you don't need encryption.
Unless you are a crypto expert, if you use it anywhere else I'm 100% sure you did it wrong and your "encryption" is only wasting CPU cycles but not protecting anything.
About 3DES: I disagree with those claiming it is insecure or anything, I really don't think there is any reason to avoid it at all.
Except that it is stupid in this case, for software implementations 3DES is (a lot) _slower_ than AES. DES (and thus 3DES) was designed with hardware implementations in mind and no regard to software. AES was designed to work well in a software implementation (but is harder to do in hardware, thus hardware often continues to prefer 3DES).
Apart from this, you absolutely need a truly random IV, not just the normal "salt", and encrypted data is still trivial to manipulate (even if you can't predict the results), so you still need a way to verify it.
A HMAC definitely is the "right" way to do it, but if you absolutely can't afford it, at least (in CBC mode) add a "magic" last block that you verify after decoding - note that with a block size of only 64 bit that generally is in the area of "brute-forceable".
I think the main point here is that you didn't need any encryption in the first place. As a rule, you can't trust anything you receive from the client to be in any way valid.
For me the problem is most apparent in Flash. For example, any high scores system that receives scores from a Flash-based game is hackable, and the only thing we can do is to make hacking our game a bit more difficult. Likewise, if you send any information to a Flash you have to treat it like the user saw it the moment you sent it, even if it's not actually shown on the client.
Pies on May 19, 2009 7:37 AMGreat post Jeff. Ignore those who happen to specialize in this area.
Practicality on May 19, 2009 7:59 AMWell, I should amend that. Learn from them, but ignore the criticism :)
Practicality on May 19, 2009 8:00 AMCue a whole slew of stupid, ill-informed questions on Stack Overflow. I pity the hapless fuckers who read the shit you post, and then use it as an authoritative source of information.
It seems to me that this entire blog is basically Jeff revealing his complete and utter lack of knowledge regarding the web, programming, or just computers in general.
Rob on May 19, 2009 8:31 AM>What really struck me about this post was not the technical bit but the honesty that someone actually admits his mistake (undermining their reputation?)
Jeff seems to be going for a clown of software development sort of image, so this just furthers that goal.
And I marvel that Jeff still gets comments like "Great post jeff". Great post? What is great about it? Aside from the incorrect terminology, that sample is such a complete FUBAR that I don't even want to make sense of it, as it risks corrupting my brain.
Dennis Forbes on May 19, 2009 8:33 AMI've been playing with encryption and found that HMAC is a great way to mix up any hashing/encryption algorithm
Brig Lamoreaux on May 19, 2009 8:38 AMHaha, these cryptography trollers are just like the database administrator trollers!
cbp on May 19, 2009 11:18 PM"cryptography trollers are just like the database administrator trollers!"
No cryptography trollers, they prevent people asking questron which prevents people learning how to do things correctly (or showing the traps) which then leads to weaker easy to break encription.
>>Why is it again that you don't seem to support the need for basic computer science education for programmers?
Jeff never had a basic computer science education. Or, well, actually he did. He started with BASIC, and never learned C, which basically means he has a giant fscking gap in his education.
I enjoy the blog, but I don't think he's a CS expert - more like one of those self-taught CS people you work with in an office, and get amused by the mistakes they make because they had no formal education in computer science.
That sounded a bit harsh... but accurate enough I guess.
Bill on May 20, 2009 4:37 AMRight from the MS Press MCTS Exam 70-536 "Microsoft .NET Framework - Application Development Foundation, 2nd ed." book, page 568:
"Mode - A property set to one of the CipherMode enumeration values that determines one aspect of the encryption algorithm's behavior. This property is usually set to Cipher Block Chaining (CBC), the default. You usually should leave this set to CBC. If you do change this value, you must change it at both the encryptor and decryptor."
And sure enough, the MSDN doco for that property says, "The default is CipherMode.CBC."
Perhaps the REAL lesson here is don't change default parameters in APIs unless you know what you're doing, and why. I think that's a common sin among many programmers (myself included, especially when I am learning a new API), to specify unnecessary parameters or override default property values just because we're trying to figure out what the API does, and how.
Jim on May 20, 2009 4:56 AMI am surprised you didn't find this example:
http://support.microsoft.com/kb/317535
Paul Moore has great point, there should be a simple API for most of that want to secure a string. Implement override functions if you want more control, or go with a basic, common-sense group of defaults.
I created one here that uses a default Key, I also have an override that allows:
Private Shared Function AESEncrypt(ByVal plainText As String) As String
Dim msEncrypt As MemoryStream
Dim csEncrypt As CryptoStream
Dim swEncrypt As StreamWriter
Dim aesAlg As RijndaelManaged
Dim returnVal As String
Dim ReturnByteArray() As Byte
Try
aesAlg = New RijndaelManaged
aesAlg.Key = _AES_Key_Default
aesAlg.IV = _AES_IV_Default
' Create a decrytor to perform the stream transform.
Dim encryptor As ICryptoTransform = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV)
' Create the streams used for encryption.
msEncrypt = New MemoryStream
csEncrypt = New CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)
swEncrypt = New StreamWriter(csEncrypt)
'Write all data to the stream.
swEncrypt.Write(plainText)
Finally
' Close the streams.
If Not (swEncrypt Is Nothing) Then
swEncrypt.Close()
End If
If Not (csEncrypt Is Nothing) Then
csEncrypt.Close()
End If
If Not (msEncrypt Is Nothing) Then
msEncrypt.Close()
End If
' Clear the RijndaelManaged object.
If Not (aesAlg Is Nothing) Then
aesAlg.Clear()
End If
End Try
'Return the encrypted bytes from the memory stream.
ReturnByteArray = msEncrypt.ToArray()
'Convert to Base64 Encoded String
returnVal = Convert.ToBase64String(ReturnByteArray, 0, ReturnByteArray.Length)
Return returnVal
End Function
TripleDES is fun to think about in Japanese.
Anil on May 20, 2009 12:50 PMI did 4 years CS at the best university in the state and we never did cryptography.
Sorry, but those saying that doing a CS degree is the answer are wrong on so many levels.
cbp on May 20, 2009 4:57 PM@cdp - and??? I know developers who have computer science degrees who did no accounting. I know developers who didn't study statistics.
When I was at Uni one lecturer said "We aren't teaching you everything you will ever need to know, because we can't know what you will need to know. Instead we give you the understanding and processes needed to understand and develop your skills and knowledge further during your career."
In essence University is teaching a way of thinking as much as it is the fundamentals of the topic of study.
For instance, a Lawyer may be trained as a generalist, then undertake Bar exams for specific localities, and/or undertake further narrowed research/education in specific areas of Law. The initial degree gave them the tools to do everything else, but you still wouldn't expect a lawyer to take on a Environmental pollution case without having researched that area or represent clients in a state without knowing the state laws and being accredited by their bar association.
Similarly for computer scientists, University provides you with the minimum information that peers agree is necessary to operate in the field, but further education or research should be undertaken when working in specific fields. A security programmer should study security BEFORE programming. A business programmer should study accounting BEFORE programming.
You get my point... this "learn on the fly" stuff is crud and the "cowboy" practitioners are bringing our industry into disrepute. Computer Scientists need to stay scientific about what they are doing, which includes researching and analysing.
@Philip - What you say is true. I was referring to a couple of comments in this thread and in the follow up article that implied that issues like this are 'abundantly obvious to anyone with a modicum of computer science education'.
I think the harshness of some of the comments here are indicators of a borderline psychopathic lack of empathy with the variance in knowledge and ability that the average computer programmer has had the opportunity to attain.
We all know that Jeff is not a computer programming genius and that he is the first to admit that. We also know that he is one of the better communicators in the programming-blog community and that he has used his position to create an important, ground-breaking programming website. Varying degrees of knowledge and ability - no need to be rude about it.
cbp on May 20, 2009 6:33 PMHundreds of eBooks full and free, requires no registration.
Books for Java,. NET, among others.
Link: http://www.ebook-here.com
@Philip - this "learn on the fly" stuff is crud
Boy, I take it every project you've worked on has been well-funded and given plenty of time to do their job.
Honestly, doing the job as best one can and learning frantically is pretty much par for the course at most places. Generally I have a few days to become a de-facto 'expert' in whatever field I'm needed next. (Usually it's a week if it's not a language I've ever seen before.)
CodingHorror is not first in my list of authoritative sites, but it and it's commentators often provide useful bits of information or references, which is why I find those making dismissive and yet completely unhelpful comments so contemptible.
Of course, if you're at the bottom of the heap most of the time, it's not uncommon to happily heap scorn on everyone else in the one field in which you are knowledgeable and on top. Sad, but true.
Jeff, I would recommend buying 2 books by (or co-authored by) Bruce Schneier:
- Secrets and Lies
- Practical Cryptography
Read them in that order. The first is a really fun read.
Then revisit your security design, and then revisit your encryption and authentication code.
Once you have done that, go buy "Security Engineering, 2nd Ed" by Ross Anderson, digest it at whatever pace you can handle, and then go look at your security again.
Eli on June 15, 2009 1:24 PMA lot of people here have given intelligent advice. However, that doesn't help. The big problem is that the first hit by Google when searching for ".NET cryptography" already suggests completely brain-damaged code: It derives both the key and the IV from a passphrase using SHA-384, destroying the purpose of using a chaining mode with an IV.
However, it may seem perfectly reasonable to a newbie, because he doesn't have the expertise to reason about cryptographic methods properly. Unfortunately those newbies are the ones using search engines and amateur tutorials to learn stuff, as well as people who need to get the job done fast. They don't have the patience or time to read dozens of papers.
Ertugrul Söylemez on June 23, 2009 7:37 AM@Joy:
For heavens' sake, it's a pun. The name "Eve" is chosen to symbolise the role of the eavesdropper, because it's mnemonic of the word "eavesdropper".
If you can think of a synonym for "eavesdropper" that can be shortened to a male name - one that's in as common use by ordinary people as "eavesdropper" itself - then there's a 50% chance that you have a point (even then, they could have just flipped a coin). But I can't think of one at all, so it seems to me you are making much ado about nothing.
You also have no evidence, BTW, for your suspicion that Jeff was even referring to the character of "Eve" in the first place.
The annoying thing is that I see this sort of argument from feminists all the time. It ignores all possible motivations for the situation in order to pick out the offensive aspect, and also ignores errors introduced by small sample size. The irony here is that all of this was motivated by an apparent attempt of Jeff's part to "do the right thing" by using 'she' as a pronoun instead of just 'he' all the time.
Karl Knechtel on June 24, 2009 11:43 AM@Practicality
" Great post Jeff. Ignore those who happen to specialize in this area. "
Taking one class called "Introduction to Cryptography" in a computer science course does *not* count as specialization, but that's all it takes to see the mistake(s) in Jeff's example (hell, even if you dropped out of the class after finding the first couple of weeks boring you'd probably still know enough to recognise that ECB is a dangerous mode to use).
This is why real CS courses are worth the money you pay for them, and why programmers who don't bother to properly investigate an area before jumping into code (*particularly* an area that is quite obviously tricky to get right, like security) are highly dangerous and should be restricted to programming things that don't actually matter to anyone.
If you can think of a synonym for "eavesdropper" that can be shortened to a male name - one that's in as common use by ordinary people
links of london on August 26, 2009 12:41 AMTiffany Jewellery barely 2-year-old result called Iridesse is set to the more Tiffany Key Rings South Coast Plaza setting was the jeweler’s supreme tome branch stockTiffany Bracelets diamonds are about more than absolute condition, cut and beauty - they are one of our diamonds underscores.Tiffany Sets reputation as a world premier jeweler synonymous with diamonds of the finest feature,” added Bennett.
tiffany jewellery on August 28, 2009 2:14 AMnow is the second,i can't longin the web.
http://www.christianlouboutins.de
Tripledes is fun to think about in japanese...
sevgiliye hediye on October 13, 2009 12:26 AMIf you can think of a synonym for "eavesdropper" that can be shortened to a male name - one that's in as common use by ordinary people
tiny on October 18, 2009 6:14 PMThanks for your information, i have read it, very good!
ed hardy shirts on October 23, 2009 7:23 PMVery interesting article. Encryption plays a very important role in so many places and we often forget about it. But it's part of the game that we don't ear about it i guess. I really liked the article, lot of great information.
Strategy games on November 13, 2009 3:49 PMThis article takes me way back. I wish it could say it seems like just last year that I was writing my own encryption software as part of my graduate studies, but in reality...it was way longer ago than I care to imagine. Great article and a very cool site you have here. I will keep an eye out for your updates.
Mike on November 16, 2009 9:27 AM| Content (c) 2009 Jeff Atwood. Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved. |