Why is crypto with .Net Framework so complicated? - c#

In most cases I need to encrypt a string with a password and then send/save it somewhere. Later I want do decrypt it with the password. I am not encrypting nuclear missile codes or medical patient data! The ideal would be 2 functions:
string Encrypt(string plainText, string password);
string Decrypt(string cipherText, string password);
I had a look at the crypto documentation... Oh boy! So I try to code the above calls myself (see a proof of concept using AES Managed and Base64 encoded payload). I am no crypto expert, why do I have to code that? I probably did somethings wrong...
To derive the key from the password the interface requires a salt. Can I use the password as salt? Can I re-use the IV as salt? Maybe not, but I don't want to add another parameter.
Can I use a fixed IV? Same plaintext and password should result in different cipher text, so I have to supply the IV for decryption in the payload.
Can I use a salt for the key and keep the IV constant instead? Feels wrong.
Creating a nonce and deriving IV and key salt from it is a valid approach?
If .Net would support the GCM mode would I still have this problems?

The .NET crypto API exposes a general purpose encryption library, containing object oriented approaches to implement cryptographic algorithms. Of course, to use these algorithms and algorithm implementations you need to have a good grasp on cryptography, which you currently lack.
This general purpose library is required to implement the various protocols that exist out there. Usually a single algorithm doesn't fulfill a specific use case (encrypt a string using a password, returning a different string, in your case). So a protocol needs to be chosen or devised that does fulfill that use case. This protocol may e.g. define a container format such as CMS or PGP, which can for instance be used to encrypt emails (the use case).
You're directly trying to apply cryptographic algorithms to solve your use case. That's not going to work. You need a pre-made protocol, preferably with a pre-made API.
Note that there are many different use cases, many different protocols and even more opinions on how to create and implement those correctly. Libsodium / NaCl for instance defines a small container format called SecretBox that does take some of the work from you.
However, it would of course be rather impossible to implement TLS on top of NaCl, as the functionality / algorithms are just not there. Again, .NET needs a generic crypto library like the .NET API for others to implement their protocols.
So either you'll have to byte the bullet and try to create your own protocol or you take an existing one and take an educated guess if it is secure (hopefully the protocol has been reviewed / updated a few times). Stay away from single person projects without additional contributors (like the many sample codes out there without review).
For your own protocol, yes, there are mistakes such as not storing the salt with the ciphertext. You need a random - or at least unique - salt to be secure, reusing the password for that is certainly not secure. Don't let it become a single person project itself and either borrow a protocol or have it reviewed.
OK, quickly then:
To derive the key from the password the interface requires a salt. Can I use the password as salt? Can I re-use the IV as salt? Maybe not, but I don't want to add another parameter.
No, the salt needs to be unique and preferably random; the password / salt combination should be unique (it should not repeat, not even in time, or over different domains).
Can I use a fixed IV? Same plaintext and password should result in different cipher text, so I have to supply the IV for decryption in the payload.
No, unless the key changes value each time (see above). For CBC the IV should be unpredictable unless you use a fresh key each time.
Can I use a salt for the key and keep the IV constant instead? Feels wrong.
That's possible, as long as you don't repeat the salt.
Creating a nonce and deriving IV and key salt from it is a valid approach?
That depends on very specific details. In other words, I would not try it if you don't exactly know what you're doing.
If .Net would support the GCM mode would I still have this problems?
Absolutely, and in a sense your problems would be worse if you'd use GCM, as using GCM with the same key and IV is completely broken.
Remember, GCM is just an algorithm, not a protocol, it cannot solve your use case by itself.

Related

Security of AES encryption with constant salt

I have an encoding application written in C# where users can optionally encrypt messages. I had been using the class in this answer, and it turns out I'm in good company because I found several places online that use the exact same code (one of which is Netflix's Open Source Platform).
However, comments to that answer (as well as later edits to that answer) led me to believe that this method was insecure. I opted to use the class in this answer to the same question instead.
How secure is AES encryption if you use a constant salt? How easily can this method be broken? I admit that I have very little experience in this area.
AES is a block cipher. A block cipher's input is a key and a block of plaintext. A block cipher is usually used in a block cipher mode of operation. All secure modes of operation use an Initialization Vector or IV. Otherwise identical plaintext would encrypt to identical ciphertext (for the same key), and this is leaking information.
Salt is not used by AES or modes of operation. It's usually used as input for Key Derivation Functions (KDFs), especially Password Based Key Derivation Functions (PBKDFs). Dot NET's Rfc2898DeriveBytes implements the PBKDF2 function as defined in - you'd guess it - RFC 2898: "PKCS #5: Password-Based Cryptography Specification Version 2.0".
If you use a static salt in a PBKDF2 then you would get the same key as output (for the same number of iterations). Now if you would ever leak the resulting key then all your ciphertext would be vulnerable. And if you would use multiple passwords then an attacker would be able to build a rainbow table; the PBKDF2 work factor would become less important; the attacker can simply build one table and then try all the resulting keys on all possible ciphertexts.
So, as the salt is not actually used for AES it doesn't make much of a difference for the security. It is however still a horrible sin, even worse than using the default iteration count for PBKDF2 / Rfc2898DeriveBytes.
Note that horrible security sins are committed by a large number of people on a daily basis. That there are many many many persons that get it wrong doesn't tell you that you are in "good company". That there are 289 upvotes just tells you that SO answers about cryptography should not be trusted based on vote count.
Salt is there for a reason.
This enables same input to be encrypted differently.
If an attacker would really insist, he can find some patterns that repeat themselves in encryption without salt, and eventually can get to your key more easily.
Still the attcker would have to work very hard.
Using constant salt equals to not using salt at all.
And it is highly recommended to use it, as it has no effect on the decryption process.

Best practices for (symmetric) encryption in .Net?

What is considered "best practice" for encrypting certain sensitive or personally identifiable data in a SQL database (under PCI, HIPAA, or other applicable compliance standards)?
There are many questions here regarding individual aspects of a solution, but I have not seen any that discuss the approach at a high level.
After looking around for quite some time, I came up with the following:
Use CryptoAPI and Rijndael
Generate IV and store it with the encrypted data
Use DPAPI (Machine scope) to "protect" the symmetric key
Store the symmetric key in the registry or a file or the database, split the key and store parts in multiple places for added protection
do not decrypt the data unless it is really needed, i.e. not upon read from the database. Instead, hold cipher text in memory.
Is this adequate? Outdated? Audit-safe? Reckless?
Your approach is good, with a few adjustments in my eyes (I code for PCI compliance generally):
Use CryptoAPI and Rijndael
Use Rijndael/AES256 at a minimum, regardless of other APIs
Generate IV and store it with the encrypted data
Good
Use DPAPI (Machine scope) to "protect" the symmetric key
Not sure if it matters. I'd just keep the IV next to the data that's encrypted, or if you're really paranoid on some other medium. Ensure that the IV is not accessible to the public.
Store the symmetric key in the registry or a file or the database, split the key and store parts in multiple places for added protection
Storing in multiple places will not help you if someone steals your media. It's a bit overkill to split the key up all over heck, but definitely do NOT store it with your IV and/or ciphertext. That'd be bad.
do not decrypt the data unless it is really needed, i.e. not upon read from the database. Instead, hold cipher text in memory.
Definitely. Holding cipher text in memory in fine, but don't pass it around anywhere, and don't decrypt except when you absolutely must, and even then don't EXPOSE the entire unencrypted dataset - only what is needed from it at the minimum. Also, do not hold the key in memory if possible - a memory dump could expose it.
Additions:
Whatever database you store your cipher text in, restrict read access entirely to the proc(s) that select for a given identifier. Do not allow read access to the tables that store this data to ANYONE, even the SA account. This way, a person who breaks into your system will have a hard time pulling down your cipher texts without knowing what IDs to look for. Do the same for any table(s) referencing the identifier on the ciphertext table. DO NOT ALLOW BLANKET READS OF THESE TABLES!
Restrict database access by IP
Never persist any unencrypted plaintext in memory over state. Allow it to be dereferenced/garbage collected as soon as the request is completed.
Restrict the server(s) running this code to as few users as possible.
Possibly combine encryption methods for a stronger ciphertext (AES + Blowfish for example)
Hope these help. Some of them are my personal opinions but remain PCI compliant to the best of my knowledge.
I saw that one of the previous comments mentioned that it doesn't matter if you use CryptoAPI. I just wanted to point out that CryptoAPI is FIPS 140-2 compliant, while Bouncy Castle and the built-in managed classes (all the ones with "Managed" at the end of their names in the System.Security.Cryptography namespace) are not. If you have a requirement for FIPS compliance, it's probably easiest to for you to use CryptoAPI.
I would add:
Keeping the IV hidden is not important. It's OK if the IV is public. Just use good IVs, which means, use a cryptographic-strong random number generator so that your IVs are indistinguishable from random.
Storing the encryption key separate from the data that it encrypts.
Add authentication to your encryption. For example, add an HMAC keyed with a second symmetric encryption key, covering the ciphertext. If you don't use some form of authenticated encryption, then your ciphertext could be modified, and you have no way of knowing (AES will decrypt garbage just fine.) You want any tampering of the ciphertext to be noticed.
Taken more generic list of best practices, from OWASP (Cryptographic Storage Cheat Sheet):
Use strong approved cryptographic algorithms
Do not implement an existing cryptographic algorithm on your own
Only use approved public algorithms such as AES, RSA public key cryptography, and SHA-256 or better for hashing
Do not use weak algorithms, such as MD5 or SHA1
Avoid hashing for password storage, instead use Argon2, PBKDF2, bcrypt or scrypt
Use approved cryptographic modes
In general, you should not use AES, DES or other symmetric cipher primitives directly. NIST approved modes should be used instead. Quote from Nist: "The approved algorithms for encryption/decryption are symmetric key algorithms: AES and TDEA."
Use strong random numbers
Ensure that any secret key is protected from unauthorized access
Also, according to this Cisco article:
DES is to be avoided and so is RSA-768, -1024
RSA-2048 and RSA-3072 are acceptable
AES-CBC mode is acceptable, while
AES-GCM mode is part of the Next Generation Encription.

Decrypting string with Microsoft Crypto API with C#

So at my workplace, I have a .NET based web application, that has to pick up an encrypted parameter in a querystring.
Those supplying the encrypted string is an external contractor and they prefer (almost demand. cant change contractors though, the higher ups decide that stuff...), to use Microsoft's Crypto API to encrypt the string.
Well, fair enough, AFAIK I can decrypt that with C#, but after endless searching I am still at a loss on how it works.
That means I cant even supply example code, and I am stuck in this bind until I can decrypt this string.
What I have is:
I have the common password they encrypt with and I have to use to decrypt it with.
Encryption settings are: "CALC_AES_128" hash: "CALC_MD5". The string is encrypted, then hashed.
So I want to unhash it, and decrypt it.
I know its a lot to ask but how do I go about it?
Your external contractor doesn't know what he is talking about.
Hashes are used as a trap door function, a way to recognize something without been told what that thing IS. It is a digital fingerprint. The way a CRYPTOGRAPHICALLY SECURE hash is made, means even given the hash and the algorithm it is difficult to create an object that matches the fingerprint.
AES is a non-deterministic cypher. The non-determinisism comes from the Initialization Vector, which is meant to be a random number each time (not hard coded from a die roll, ahem Sony). This means for all intents and purposes, the output of AES is pure random (unless you have the key). Good cyphers are all designed to produce data that is statistically random (thus there is little data to form an attack from).
So by feeding data into a function that creates random data, then putting it into a trap door function, you have produce something that is truly difficult to decode (difficult in this sense is mathematically, you actually need more energy than exist in the universe to compute this).
As for how to send data across in a secure manner (secure as in against prying eyes on an unsecure network) in the query string? There is a well known protocol that .net supports that does this very well. Its called HTTPS.

.net Cryptography - is there a way to tell that something has been decrypted wrong?

See the title for question.
In a nut shell, what I am trying to do is encrypt some data with the seed (keyword) provided by the user. Is there a way to know that the data has been decrypted wrong, or in other words that the seed is wrong?
Using .net 2.0, C#
Thanks!
It's quite normal to make a hash part of the encrypted data. Say, you have some data you want to encrypt. You then create an MD5 hash of this and add this to the end of the data. Then, when you decrypt it, you take the hash of the end of the encrypted data and verify that the hash hasn't changed.
Depends on your algorithm specifics. stream ciphers (like RC4) will not by themselves be able to detect any tampering. Block ciphers (AES) may detect some tampering because of the block padding algorithms (PKCS#5). This padding check is what causes ICryptoTransform.TransformFinalBlock` to throw exception that the decryption failed, but this detection is not cryptographically secure (in the worst case is 1/256 chances of not detecting tampering, if padding is one byte). This is not an omission of the .Net implementation, is a fundamental problem with using all encryption algorithms.
So given that the decryption operation itself basically cannot detect tampering (or the use of a bad key/IV) the solution is to add a digest of the message in the message. The industry standard is to use an HMAC digest, and have the key derivation process produce enough key material for the key/IV and HMAC secret (this is how TLS/SSL do it, which is pretty much 'industry standard', see 6.3 Key calculation of the RFC linked). The decryption step decrypts the message and then computes the HMAC of the message, comparing it with the original digest. If they match, the decryption was successful (correct key/IV used) and the message was not tampered with.
If you want to prevent tampering of the message use a HMAC.
Regular encryption doesn't tamper proofs messages. Learn from asp.net's team mistake, and put the extra validation in place - see how the asp.net padding oracle vulnerability related to getting different levels of access.
If you don't put the extra validation, it's likely you'll expose information that an attacker may use to try to game the system.
The formal way to resolve that issue is to use a key wrap around the key (which would itself be encrypted). This is because you should only trust entirely private keys, not keys which are given to you. If you were to use an invalid key for encrypting data, then things go bad.
There are no built in routines (that I know of) that perform key wrapping in .NET, but in essence you can achieve the same thing by prefixing and postfixing the actual key with a string of 16 (or whatever your blocksize is) 'A' characters. When you decrypt the key you ensure that it is pre & postfixed with 'A' and flag it as an error if not.
If you have less formal requirements then another option is to use the key to decrypt a string which is known to be encrypted with the correct key. If once you've decrypted that string you get an unexpected result, then flag it as an error.
One brute force way - depending of what are you doing with your data... Push it to any algorithm that expects it and see if it crashes. I have encrypted binary serialized data that I deserialize that way. Binary formatter throws an exception if data is decrypted wrongly and turned to noise.

Encryption algorithms that don't use a key

I need a simple encryption algorithm that doesn't use a key.
Which ones do you guys recommend?
How about if I use the built in encryption method that forms authentication has? (I forget the method/namespace for it).
Every symmetrical encryption scheme has a key. If you're looking for an encryption scheme where you don't manage the key, you might look into the Data Protection API, exposed in .NET (2.0 and above) as the System.Security.Cryptography.ProtectedData class. It provides symmetric encryption of arbitrary data, using the credentials of the machine or (better) the user, as the encryption key.
byte[] plaintextBytes = GetDataToProtect();
byte[] encodedBytes = ProtectedData.Protect(plaintextBytes
, null
, DataProtectionScope.CurrentUser);
See my other answer here for more detail.
Something outside of the thing being encrypted needs to be used to do encryption, if only because you need that thing to decrypt it later. This external thing is a key. There is no useful encryption without a key. There is only hashing.
What you are calling encryption is simply obfuscation. Even then its going to be encryption where the key is embedded in the algorithm. You'll have to provide at least a simple use case for this before you're going to get any kind of reasonable answer.
rot13 uses a key that's already in the algorithm. That's the closest I think you're going to get.
As an aside to the talks about no key = no encryption...
Maybe what you're really after is automatic and safe key creation and exchange with no user interaction. This can be done by the use of asymmetric encryption, and it works like this:
Scenario: A needs to send a message to B, and wants to make sure no man-in-the middle can read the message.
A and B initiate a conversation like this:
A asks B for B's public key.
B generates a public/private key pair, and sends the public key to A.
A uses the public key to encrypt the message, and sends the message.
B receives the message, and decrypts it with its private key.
This works since the message is encrypted with a public key, can only be decrypted with the corresponding private key. So the public key doesn't have to be secret. If man-in-the-middle picks up the public key, he can't use it to decrypt the message.
You'll probably find tons of information about this if you google for asymmetric encryption...
Fundamentally, ciphers are a way to let Alice tell something to Bob that Eve can't figure out even if she overhears.
This means that there has to be some way for the ciphertext to distinguish Bob from Eve.
Usually, this is a key. Nowadays, it can be a symmetric cipher key that Alice gives to Bob and not Eve somehow, or an asymmetric cipher key that Bob broadcasts so that anybody can encrypt a message for him that only he can read (often used as a way to transmit a symmetric cipher key).
An algorithm can serve as a key, but algorithms are really inconvenient to distribute and keep secret. It's better just to use a standard key.
You could simply obfuscate the plaintext, if you're willing to count on Bob being motivated to read the message and Eve not be. You could do that by zipping a file, for example. Eve couldn't just read it, she'd have to unzip it. This is usually done to prevent Eve from accidentally reading something meant for Bob, on the assumption that Eve is honorable but may make occasional mistakes. The example popping into my mind is the CVS password file; it will prevent a sysadmin from seeing the password at a glance, but it's "the moral equivalent of rot13" if somebody actually wants to read it.
So, to give you a useful answer, we need to know what you want to use this for. How sensitive is the data? How likely is it to fall into unfriendly hands? Who do you want to be able to read it?
BTW, never roll your own cryptography. It's real easy to get something wrong and real hard to notice it. Use standard implementations of standard algorithms.
The problem with keyless encryption is that once it's broken, it's broken for everyone. Take MicroSoft Script Encoder as an example. Once one person figured out how to reverse the encryption and published it, the encryption was broken for everyone (see comments for details on how this isn't as bad as it sounds in this case).
That being said, you can use any keyed algorithm and keep the key a secret and you'll get the same (bad) effect.
If you're really after obfuscation, you can use the PasswordDeriveBytes class to create a key from a password. Then use the key in e.g. AES.

Categories