1

I am fairly new to this, so I'm sure it has been asked and answered but I cannot find a clear answer. If this has already been addressed, please point me in the right direction and I will remove this question.

I have a program which will need to accept a username and password from the user. This username and password is for another server, but the information will need to be passed around a few DLLs before sending the final request to the other server. My concern is with passing usernames and passwords between DLLs without encryption, so I have made a simple Encrypt and Decrypt method set using Microsoft's System.Security.Cryptography.CryptoStream class.

Essentially, the following operations are performed.

A plain string is entered into the encryption method along with the encryption key. This method then generates a random IV (8 byte), random array (8 bytes) and the byte array encryption. The IV, random array, and encryption are then put into a single byte array and passed around between DLLS.

The byte array is received by a DLL and passed through the decryption method with the encryption key. This method grabs the IV part of the array and the encryption part of the array, and ignores the random 8 bytes added (these are added simply for totally arbitrary reasons). The string is then decrypted.

Have I accidentally broken the whole security of using an encryption by appending the IVs to the encrypted byte array?

Should I be using the random 8 bytes as salt (just, since I have them anyway) and passing them through with the encryption? Or would that just break it even further?

Note that I have no direct access to a list of usernames or passwords, this is an entirely external application. I just want to ensure that the request and movement of username and password pairs are secure on my end.

  • IVs are not secret, and it is expected that they are transmitted alongside their corresponding ciphertext. Just don't ever reuse an IV alongside a given key. – Stephen Touset Apr 19 '17 at 20:40
  • @StephenTouset OK, so in that case the only item that I really need to worry about keeping hidden is the key used with the encryption, if I am understanding you correctly. Thanks! – Mikey Awbrey Apr 19 '17 at 20:43
  • Yes, the key is the only part you need to keep secret. – Stephen Touset Apr 19 '17 at 20:56
  • Note that while cipher IVs are never required to be secret, the exact requirements for them depend on the exact cipher you pick. Some ciphers require IVs to be chosen randomly, while others allow deterministic IVs as long as they never to repeat for the same key. If unsure, random IVs (with a cryptographic random number generator) are generally a safe choice. – Luis Casillas Apr 19 '17 at 22:16
  • *Why* is there a "totally arbitrary" extra 8 random bytes? Generally speaking, everything a crypto function does is done for a reason. With that said, 8 bytes isn't a very long IV; 16 bytes (128 bits) is slightly more secure (greatly reduces the risk of a birthday attack on the IV) and much more common. – CBHacking Apr 19 '17 at 23:49
  • @CBHacking the reason will make you laugh. That was added because during my unit tests I noticed the IV and encryption I was using was 24 bytes. I wanted to make it 32 bytes so it was a power of 2. Yep. That is my totally arbitrary reason. I was going to take the random bytes out once I had completed testing, but wrote this question off the unit tests. – Mikey Awbrey Apr 20 '17 at 12:45

1 Answers1

0

IVs are not secret and it is common to pass them along with ciphertext. That part is not a problem. Since you didn't say what threat you are defending against, I will assume you worry about reading the password from memory directly or from memory dumps. In that case you might have a different problem with your approach: strings.

Strings in .NET are immutable and you cannot clear it after you are done with it. If you assign an empty string to a variable, the old value will remain in memory and you will get new empty string object in its place. Even if you create a byte array and encrypt it like you proposed, the left over string will remain in memory and will wait there until Garbage Collector clears it.

If you don't control the way passwords are received, this might be impossible to solve. You need to make sure password is never stored in a string. Let's assume you can solve this part. Your options then would be:

  1. You can either always use byte arrays and do encryption like you described (salt is not required, just make sure you never reuse key/IV pair and generate random IVs with strong CSPRNG) or
  2. Use SecureString.

SecureString is designed to solve exactly the problem you describe without the need to "roll your own".

Introducing cryptography primitives into a solution and believing it will make the solution more secure is deceptive. Sometimes the scope of the problem is much larger than you realize.

Marko Vodopija
  • 1,062
  • 1
  • 8
  • 19
  • I thought I had eliminated strings from my password collection, but I double checked and just realized one of my collection methods was with command line arguments (string[])...... You pretty much nailed my security concerns on the head. After going over the MSDN pages you linked, I'm not sure that a SecureString is quite what I am looking for either, though it is better than my custom implementation. I'll have to rethink my password collection from the user first. Thank you! – Mikey Awbrey Apr 20 '17 at 12:34
  • 1
    So I've gone through my code and looked at the real situations I am interested in defending against. The final product is an internal client server relationship. The most important point of defense is the data transfer across the internal network, or a VPN depending on the user. After looking at securestring I believe the method I already have implemented is sufficient as a securestring can not be easily sent through an open socket, but a byte array can. Once an attacker has the ability to perform memory dumps, the information in this program is the least of our concerns. – Mikey Awbrey Apr 20 '17 at 14:27