views:

181

answers:

6

I'm looking for a secure way to encrypt and decrypt a string in a Visual Studio Project (in C#). I found that there is native DES classes, but it's not secure enough. Do you have any suggestions?

UPDATE : OK then, the question is : What's the most secure way to encrypt/decrypt a string without too much hassle (aka having to install external tools, etc. An external library is fine though). And where to put the secret "key" (is compiling the value inside the code secure enough?).

Update #2 If I'm using something like this code to save encrypted string in a config file :

using System.Security.Cryptography;
using System.Security;
byte[] encrypted = ProtectedData.Protect(StrToByteArray("my secret text"), null, DataProtectionScope.LocalMachine);
byte[] derypted = ProtectedData.Unprotect(encrypted , null, DataProtectionScope.LocalMachine);

Is this secure enough? I guess that with the "LocalMachine" parameter instead of "User" parameter, somebody could just write an application in .net, put it on the machine and execute it to decrypt the encrypted string. So if I want it more secure, I'll have to have a config file different for each user? Am I understanding that correctly?

+1  A: 

It also has AES.

Steven Sudit
A: 

Try using AesManaged.

Randolpho
This really isn't much worse than using http://msdn.microsoft.com/en-us/library/system.security.cryptography.aescryptoserviceprovider.aspx so I don't understand the downvote.
Steven Sudit
A: 

That depends on your definition of secure enough. You may use triple DES. .Net also has native Rijandel class. Is it secure enough? http://www.obviex.com/samples/Encryption.aspx

Alex Reitbort
As a clarification, Rijandel *is* AES.
Steven Sudit
@Steven Sudit: No. AES is Rijndael, but Rijndael is not AES. (AES is a subset in terms of operation modes.)
dtb
Does anyone really use Rijndael outside of AES?
Steven Sudit
@dtb: That wasn't a rhetorical question.
Steven Sudit
@Steven Sudit: I wouldn't have said anything if your comment had been "As a clarification, AES *is* Rijndael." :-)
dtb
@dtb: And you get full credit for getting that detail right. My only point is that, once Rijndael was accepted as the AES, people mostly just used AES. The fact that Rijndael supports a few more variations in block and key size doesn't seem very exciting.
Steven Sudit
A: 

Using a well tested and accepted library is a good idea too...

http://www.bouncycastle.org/csharp/

jayrdub
Was that a sarcastic downvote? "Yeah, like I'm going to be dumb enough use the best encryption library, I'll roll my own"
jayrdub
I disagree with the downvote, but perhaps the thought was that the built encryption classes that come with .NET are enough.
Steven Sudit
IMO a well tested and accepted library is a precondition, but not a guarantee that a resulting application is secure. Using crypto algorithms correctly is really hard to get right.
dtb
@dtb: You're not wrong. It's best to avoid trying to come up with novel solutions. If possible, avoid crpyto primitives entirely and stick to higher-level constructs.
Steven Sudit
@Steven Sudit: Those higher-level constructs are unfortunately lacking in the .NET Framework and, I believe, also in Bouncy Castle. Just look at all the horrible homegrown solutions to storing salted hashes in databases.
dtb
@dtb: Well, there are *some*. For example, instead of using SHA-1 directly and concatenating a key, you can use HMACSHA1. And, one level above this, there's PBKDF2, which uses HMACSHA1.
Steven Sudit
(I should probably mention that PBKDF2 would be a fine way to generate salted hashes that are expensive to create rainbow tables for.)
Steven Sudit
+5  A: 

To answer your second question, no, storing the encryption key in the executable, even obfuscated, is not secure at all. It'll keep casual prying eyes out, but not those with an hour to devote to walking through your decompiled source.

Think hard about where to store your encryption key - it looks like that'll be your weak point. And yes, this is a hard problem to solve. The most secure way to store encryption keys is not to - require the user to type a password, or require external hardware, like a key fob.

If you're encrypting contents intended to be read only on a single machine or by a single domain user, consider the Data Protection API (DPAPI). It takes the encryption key out of your hands - it uses the user's Windows credentials as the key.

I've got a little more detail in another answer here: Persistent storage of encrypted data using .Net

Regarding your second edit (is DataProtectionScope.LocalMachine good enough?); this MSDN blog entry summarizes it well:

Setting a scope of DataProtectionScope.CurrentUser encrypts the data so that only the currently logged on user can decrypt it. Switching to DataProtectionScope.LocalMachine allows any process running on the current machine to decrypt the data. This could be useful in a server scenario, where there are no untrusted logins to the machine, but for a general purpose workstation using LocalMachine encryption is almost equivalent to using no encryption at all (since anybody logged in can get at the data).

Michael Petrotta
that's interesting!
tink01
any thought on update #2?
tink01
@tink01: see my edit.
Michael Petrotta
I see. So basically, if I want to store a secure string in a config file, I'll have to make a different file for each user logged in or use a key from a remote service?
tink01
Indeed, the second paragraph is key. Remember: **the purpose of a cryptosystem is to leverage the security of a short secret key into the security of a long secret message.** The whole *point* of strong crypto is that your long secret message is *exactly* as secure as the effort you are willing to invest in keeping the key secret. **How you choose to keep the key secret is not a part of the cryptosystem: that's the bit you have to solve for yourself.** All crypto does is *decrease* the amount of data you have to keep hidden. It does not remove the requirement to hide *something*!
Eric Lippert
+1  A: 

If I read your update correctly, you basically want to conceal some string constant from a sysadmin snooping around your assembly.

There is no way to make it impossible that someone with too much time extracts your string constant eventually. But you can annoy them, hoping that they give up trying before they unmask your secret.

One way to achieve that are Obfuscation Tools. These obfuscate your compiled assembly as much as possible, making it much harder to follow program flow when decompiling it with Reflector. Try it. If your string constant is still not hidden enough, you can additionally invent your own scheme to make it harder to find.

If you need more security, the almost only option is to not give the relevant parts of the code to the user. Create a web service that contains the secret parts of your application and secure the connection with SSL/TLS.

dtb
I'm downvoting this because obfuscation is a much worse answer than the DPAPI.
Steven Sudit
@Steven Sudit: But how do you get the data into the DPAPI store? If you're not physically present to type in the secret, again, you have to hide the it somewhere in your code. Maybe this is not an issue for the OP, but still don't really get what his scenario is.
dtb
You do it as part of installation. The whole point is that the secret is never in your code.
Steven Sudit
@Steven Sudit: So you embed the secret in the installer executable?
dtb
*NO!* Whoever does the installation is responsible.
Steven Sudit
@Steven Sudit: So you have to be physically present and type the secret in. That works. If you can be physically present. If not, I stay with my answer that obfuscation might be good enough in some cases. (Note the lots of If's.)
dtb
The problem is that the secret is just some arbitrary bit of information shared between this app and whoever it calls, and this should be very changeable, so you don't want to ever hardcode it.
Steven Sudit
@Steven Sudit: It really depends on what the OP is trying to achieve. Or you know more about his use case than I do. :-)
dtb
My crystal ball is no more effective at reading the OP's mind than yours is. :-) Still, there are practices that cannot be secure, so they should be avoided. Hardcoding a password and counting on obfuscation to hide it is a guarantee of failure.
Steven Sudit
@Steven Sudit: It really depends. Choosing a security strategy is always the result of analysing how precious the asset is and how much protection is required. So, if obfuscation is good enough for his use case, then obfuscation is good enough. You cannot deny the truth of a tautology. :-)
dtb
Correct, I can only deny its relevance. In this case, the predicate is rarely, if ever, true.
Steven Sudit
@Steven Sudit: Aren't all software serial number mechanisms that don't use online verification based on this?
dtb
Yes, and they're all easy to crack. Google "serial number generator" and the name of any such program.
Steven Sudit
@Steven Sudit: Let's assume the OP's application is a puzzle for humans to solve. When the user solves the puzzle, the application displays the string "You won! Please send your cover letter and resume to [email protected]". Now, it's not really fun to solve the puzzle if you can cheat by opening the .exe file in notepad and see what will be displayed when you win. Then you could obfuscate the string so it takes just a bit longer to de-obfuscate the string than to solve the actual puzzle. Problem solved. Solution is good enough.
dtb
Well, in this case, the right answer would be to store a verifier, such as a hash. The hash would be enough to confirm whether the answer is correct, but not enough to yield the answer. In fact, this is the right way to go if all you want to do is have people register the program to enable full functionality. The registration key is just the name of the user and an HMAC code. This more than does its job; any additional obfuscation will yield no net benefit.
Steven Sudit