Search code examples
c#cryptographyencryptioninitialization-vector

C# Can't generate initialization vector IV


I get the following error when I try to create a IV initialization vector for TripleDES encryptor.

Please see the code example:

TripleDESCryptoServiceProvider tripDES = new TripleDESCryptoServiceProvider();

byte[] key = Encoding.ASCII.GetBytes("SomeKey132123ABC");
byte[] v4 = key;
byte[] connectionString = Encoding.ASCII.GetBytes("SomeConnectionStringValue");
byte[] encryptedConnectionString = Encoding.ASCII.GetBytes("");

// Read the key and convert it to byte stream
tripDES.Key = key; 
tripDES.IV = v4;

This is the exception that I get from the VS.

Specified initialization vector (IV) does not match the block size for this algorithm.

Where am I going wrong?

Thank you


Solution

  • I've upvoted every answer (well the ones that are here before mine!) here as they're all correct.

    However there's a bigger mistake you're making (one which I also made v.early on) - DO NOT USE A STRING TO SEED THE IV OR KEY!!!

    A compile-time string literal is a unicode string and, despite the fact that you will not be getting either a random or wide-enough spread of byte values (because even a random string contains lots of repeating bytes due to the narrow byte range of printable characters), it's very easy to get a character which actually requires 2 bytes instead of 1 - try using 8 of some of the more exotic characters on the keyboard and you'll see what I mean - when converted to bytes you can end up with more than 8 bytes.

    Okay - so you're using ASCII Encoding - but that doesn't solve the non-random problem.

    Instead you should use RNGCryptoServiceProvider to initialise your IV and Key and, if you need to capture a constant value for this for future use, then you should still use that class - but capture the result as a hex string or Base-64 encoded value (I prefer hex, though).

    To achieve this simply, I've written a macro that I use in VS (bound to the keyboard shortcut CTRL+SHIFT+G, CTRL+SHIFT+H) which uses the .Net PRNG to produce a hex string:

    Public Sub GenerateHexKey()
      Dim result As String = InputBox("How many bits?", "Key Generator", 128)
    
      Dim len As Int32 = 128
    
      If String.IsNullOrEmpty(result) Then Return
    
      If System.Int32.TryParse(result, len) = False Then
          Return
      End If
    
      Dim oldCursor As Cursor = Cursor.Current
    
      Cursor.Current = Cursors.WaitCursor
    
      Dim buff((len / 8) - 1) As Byte
      Dim rng As New System.Security.Cryptography.RNGCryptoServiceProvider()
    
      rng.GetBytes(buff)
    
      Dim sb As New StringBuilder(CType((len / 8) * 2, Integer))
      For Each b In buff
          sb.AppendFormat("{0:X2}", b)
      Next
    
      Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
      Dim editPoint As EnvDTE.EditPoint
    
      selection.Insert(sb.ToString())
      Cursor.Current = oldCursor
    End Sub
    

    Now all you need to do is to turn your hex string literal into a byte array - I do this with a helpful extension method:

    public static byte[] FromHexString(this string str)
    {
      //null check a good idea
      int NumberChars = str.Length;
      byte[] bytes = new byte[NumberChars / 2];
      for (int i = 0; i < NumberChars; i += 2)
        bytes[i / 2] = Convert.ToByte(str.Substring(i, 2), 16);
      return bytes;
    }
    

    There are probably better ways of doing that bit - but it works for me.