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...
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.