1

I am developing a class project in C# that encrypts the users and admins passwords. To encrypt I'm using the TripleDESCryptoServiceProvider.

In the configuration app the user enters the key to be used for encryption and decryption of the passwords. I want to have a button to generate a key to help the user but I'm at a loss as to how I generate the 128 bits randomly. How a generate a key with 128-bits?

halfer
  • 19,824
  • 17
  • 99
  • 186
Hugao
  • 40
  • 1
  • 1
  • 7
  • The immediate answer is `RNGCryptoServiceProvider`. But you're probably doing something wrong. Perhaps you need hashing, perhaps you want AES and most likely you're using a bad encryption mode. – CodesInChaos May 15 '13 at 20:47
  • 1
    One method is not to encrypt passwords, but to hash them instead. The good theory behind this is that they are never "decrypted", but instead you compare the hashes without actually revealing the password. – Moo-Juice May 15 '13 at 20:49
  • One thing you could do is use the current date and time and feed that in as a seed into the random number generator. Then generate a number between some range like 1000,2500 and loop that random number of times until you get to the end of the loop. The last random number generated will then be what you convert to a byte array. Just make certain you limit the second number you generate to ensure it creates 128 bits when converted from a number to a byte array. – SASS_Shooter May 15 '13 at 21:11
  • 1
    @SASS_Shooter Sounds like a terrible idea. The current time doesn't have enough entropy and writing a crypto strength PRNG is non trivial. – CodesInChaos May 15 '13 at 21:14
  • @SASS_Shooter [Don't roll your own crypto](http://security.stackexchange.com/questions/2202/lessons-learned-and-misconceptions-regarding-encryption-and-cryptology), use the correct tools in the correct way. The way you are recommending is very poor crypto, someone could easily figure out what the random number was just by knowing about what time of day the number was generated then trying all the combinations near that time till you find the key that decrypts the message. – Scott Chamberlain May 15 '13 at 21:14

5 Answers5

10

To generate a random value for crypto use, you should use RNGCryptoServiceProvider:

byte[] bytes = new byte[16];
var rng = new RNGCryptoServiceProvider();
rng.GetBytes(bytes);

To turn this sequence of bytes into a string you could use hex (BitConverter.ToString) or Base64 (Convert.ToBase64String).


But there are some strange points here:

  • 3DES uses a 168 bit key
  • If you want to use symmetric encryption, you should probably use AES. 3DES isn't totally broken, but it's pretty much for legacy use only.
  • Be careful about the Block cipher mode of operation you're choosing. You typically need a proper IV, a MAC and a secure chaining mode
  • Often you actually should hash passwords instead of encrypting them. See How to securely hash passwords? on security.SE for details.
Community
  • 1
  • 1
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Thanks for the answer and I'm using your recommendation of hashing the passwords. Thanks for the quick answer – Hugao May 15 '13 at 22:00
1

I understand perfectly what you want Instead of passing urls with htttp: //mydomain.com? Id = 123, you want to pass with an encrypted value. And when someone clicks on this url with encrypted id, you want to decrypt the value of the url.

There are 2 procedures for this:

In encryption: 1 - Convert the "ID" (usually an integer) to a string. Example var NewId = Convert.ToString ((ID); 2 - Use a phrase to shuffle the encryption. Example: "I love chocolate" (this phrase can be fished from your parameter database if you have one ...)

In decryption: 1 - Use the same blocking phrase to unscramble. 2 - Convert what was decrypted to an integer again, using Convert.ToInt32 (Shuffled Variable Above)

You will have to implement 2 functions:

Function for encrypt:

private string Encrypt(string clearText)
    {
        string EncryptionKey = "I love chocolate";
        byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = Convert.ToBase64String(ms.ToArray());
            }
        }
        return clearText;
    }

Function for Decryption:

private string Decrypt(string cipherText)
    {
        string EncryptionKey = "I love chocolate";
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = System.Text.Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }

When encrypting an ID as ID = "123", you will have a value for the ID as ID = "B8 + iXv5 / 8BUQEbHt8 // fGA ==".

When you decrypt the ID value "B8 + iXv5 / 8BUQEbHt8 // fGA ==" you will get "123" again.

A sample in C#:

  var OriginalId = 123;
          var EncrypetedId = Encrypt(Convert.ToString(OriginalId));
          //for recovering original value
          var OriginalID = Convert.ToInt32(Decrypt(EncrypetedId));

I hope this can help you.

0

Take a look at the RNGCryptoServiceProvider class, specifically the GetNonZeroBytes method. You could run that string of bytes though a base64 encoding to make it human readable, perhaps.

object88
  • 720
  • 1
  • 7
  • 20
0

RNGCryptoServiceProvider is obsolete:

RNGCryptoServiceProvider is obsolete. To generate a random number, use one of the RandomNumberGenerator static methods instead.

This will generate 128 and 256 bits keys:

private void PrintBase64Hex(byte[] bytes)
{
    var base64String = Convert.ToBase64String(bytes);
    var hexString = Convert.ToHexString(bytes);
    Console.WriteLine(base64String);
    Console.WriteLine(hexString);
}

[TestMethod]
[DataRow(16)]
[DataRow(32)]
public void GenerateKeyTest(int n)
{
    byte[] bytes = new byte[n];
    var rng = RandomNumberGenerator.Create();
    rng.GetBytes(bytes);

    PrintBase64Hex(bytes);
    Assert.AreEqual(n, bytes.Length);
}

16 bytes (128 bits):

sHG3x5uO2gkx6AkLT5AVSA==
B071B7C79B8EDA0931E8090B4F901548

32 bytes (256 bits):

VXlFUX/OnJmHk7UWogFZZ494oISoTSm5Kvqz+4EXue4=
557945517FCE9C998793B516A20159678F78A084A84D29B92AFAB3FB8117B9EE

An "alternative" is to use Aes abstract class from System.Security.Cryptography, but that's for a larger context than just creating a 256 bits key.

[TestMethod]
public void AESTest()
{
    var sut = Aes.Create();

    PrintBase64Hex(sut.Key);
    Assert.AreEqual(32, sut.Key.Length);
}

I add that AES is stronger and recommended over triple DES. And to date AES is accelerated since many years in CPUs, so there is no reason to privilege it.

Even Triple DES is not enough protection

Triple DES (3DES) – also known as Triple Data Encryption Algorithm (TDEA) – is a way of using DES encryption three times. But even Triple DES was proven ineffective against brute force attacks (in addition to slowing down the process substantially).

According to draft guidance published by NIST on July 19, 2018, TDEA/3DES is officially being retired. The guidelines propose that Triple DES be deprecated for all new applications and disallowed after 2023.

Soleil
  • 6,404
  • 5
  • 41
  • 61
0

Just use Guid.NewGuid(). It creates a RFC 4122 v4 (random) UUID. See RFC 4122 § 4.4 for details.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135