2

I am implementing a shared-secret encryption scheme for moderately secure data transfer. When the server is provisioning a client, I can generate one or more strings representing the secret. The client will then use this secret information to encrypt data before sending it to the server. I want ensure the shared secret is as strong as practicable and sufficient to guarantee interoperability.

Algorithm/class selection: It seems one should "stick to AES unless you have a good reason not to." Is AesManaged a good choice for this? Difference between symmetric crypto algorithms

Settings and default object: I am using .NET 4.0 and .NET 4.5 in different parts of the system, and may upgrade over time. I cannot find documentation for the default properties of KeySize and BlockSize, nor the default length for IV. In .NET 4.0 it appears the default key size is 32 (bytes, 256-bit) and the default IV size is 16 (bytes). BlockSize and FeedbackSize are 128 (bits). Mode is CBC and Padding is PKCS7. Which properties should I set explicitly, and should I regenerate the key and IV afterwards?

[Edits: Fixed 256-bit above and below. Added questions.]

Is a 256-bit key and a 16-byte IV strong enough for "non-government work?"

I have read that 256-bit keys are vulnerable to a certain kind of attack (which I don't think applies in my case). Is there any reason to use a 128-bit key instead? What is the performance differential?

Is it normal that the default key size is larger than the block size?

[Edits: Done.]

Strength of default key and IV: Is there any reason to use RNGCryptoServiceProvider.GetBytes() or is that what AesManaged is doing already?

Interoperability: I am assuming the shared secret consists of they key and the IV (encoded to Base64 strings). Will setting the Key and IV properties from the recovered byte arrays be sufficient to set the related properties (e.g. KeySize)?

Can any other properties be inferred and guaranteed to agree, or should I set them explicitly for key generation, encryption, and decryption?

Key generation code:

AesManaged myAes = new AesManaged(); // use defaults
string keyString = Convert.ToBase64String(myAes.Key);
string ivString = Convert.ToBase64String(myAes.IV);

Code and context: I borrowed heavily from here: http://msdn.microsoft.com/en-us/library/vstudio/system.security.cryptography.aesmanaged%28v=vs.100%29

Community
  • 1
  • 1
verbamour
  • 945
  • 9
  • 16
  • `32 (bytes, 128-bit)` This is wrong. 32 bytes = 256 bits. 16 bytes = 128 bits. I imagine the confusion comes from the fact that 128 bits is represented in 32 hexadecimal characters. – Spencer D Sep 14 '14 at 02:47
  • Oops. Sorry about that. Fixed. – verbamour Sep 16 '14 at 00:19

1 Answers1

2

AES (or Rijndael) are pretty much standards, on Linux blowfish comes to my mind but in C# you want to stick with what you have for free.

I'd advise to set the values instead of leaving them at their defaults. This guarantees that silent malfunctioning is less probable. Of course, you'll have to know exactly what you are doing. But security is all about knowing what you do.

For the rest I can only say this. Increasing a key size from 128 to 192 or 256 bits (or other settings without actually changing the algorithm) is relatively easy, so start with common values and make it work. But if you can have better encryption with the same code base why settle for less? On the other hand, security is a compromise. Nothing is totally secure and it all depends on how much you are willing to spend.

What I say now won't please you. The shared secret renders ALL your efforts useless. If an eavesdropper can grab the secret, the encryption is completely useless.

For stored data that choice might be ok, as long as you ask for the key every time you want to decrypt the block and never store the secret on disk (much like KeePassX asks for a password to open a key file).

For data on the move (sent over a network) asymmetric encryption is indispensable unless you have alternative ways to communicate the secret. That is, NEVER send the secret over Internet but use out-of-Internet ways (plain old mail, maybe telephone or face-to-face).

As you can see, sharing the secret is the true problem here. The obvious solution is SSL but it's asymmetric and the C# implementation is highly unstable, especially for multi-platform applications that may run on mono/Linux/OpenSSL. Be ready for a hell of a nightmare if you go that way.

True feasible security over the Internet without SSL or external communication channels? No dice.

Depending on your use case you may want to avoid storing the secret in a string.

If there are lives or good money involved you want to do even more than that. Consider that users might install the client on a public computer such as an Internet cafe. Look into SecureString and algorithms that hash characters incrementally and never actually store the string in memory.

EDIT:

Because of how the VM manages memory and garbage collection, and how virtual memory works, you risk that unused sectors on a public PC might contain passwords in plain text. This happens when the OS swaps out virtual memory to disk. There is no programmatic way in C# to be absolutely sure it didn't occur. In these scenarios SecureString and memory pinning help you securing .NET clients (C# and VB).

pid
  • 11,472
  • 6
  • 34
  • 63
  • Correct me if I'm wrong, @pid, but you can send the secret over the internet if you use the diffie-hellman key exchange. It will prevent the attacker from determining the secret without reversing the discrete logarithm problem. Which is infeasible to do if the prime modulus is large. – Spencer D Sep 14 '14 at 02:57
  • Oh and AES does not accept a 1024 bit key. Acceptable AES key sizes are 128 bits, 192 bits, and 256 bits. – Spencer D Sep 14 '14 at 03:45
  • @SpencerGrantDoak Yes, you're right. I've never used an ECDH [ECDiffieHellmanCng](http://msdn.microsoft.com/en-us/library/system.security.cryptography.ecdiffiehellmancng(v=vs.110).aspx) so I must agree with you if not suggest you to give an alternative answer, which would be great. About AES: Yes again, there are those specific key size constraints, but I intended to convey a general way of thinking instead of a precise implementation. As always, all help is welcome and thanks for contributing :) – pid Sep 14 '14 at 08:03
  • Ahh okay. I was concerned that you were attempting to suggest to the user that AES 1024 and AES 2048 existed. – Spencer D Sep 15 '14 at 02:28
  • 1
    You're right it was confusing. I've corrected the answer, I don't want to confuse anybody. – pid Sep 15 '14 at 07:21
  • Great, I'm glad my suggestion could be of use. Also, thank you for the link to the MSDN ECDiffieHellmanCng. I've been looking for a way to do this in .NET. I'd post an alternative answer, but if my answer included ECDH, it would be psuedo-code. Anyway, great answer! Very well written and helpful. – Spencer D Sep 16 '14 at 21:09