1

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

  • 2
    It is rare that an error message tells you what you are doing wrong so very accurately. What about the message don't you understand? – President James K. Polk Jul 05 '10 at 12:21
  • You should not be using a string to initialise the IV (or the key) here - lots of problems - including this problem (although in your case it's because as other people have said you're providing too many characters). – Andras Zoltan Jul 05 '10 at 12:27

6 Answers6

10

MSDN explicitly states that:

...The size of the IV property must be the same as the BlockSize property.

For Triple DES it is 64 bits.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
6

The size of the initialization vector must match the block size - 64 bit in case of TripleDES. Your initialization vector is much longer than eight bytes.

Further you should really use a key derivation function like PBKDF2 to create strong keys and initialization vectors from password phrases.

Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
5

The IV must be the same length (in bits) as tripDES.BlockSize. This will be 8 bytes (64 bits) for TripleDES.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
5

Key should be 24 bytes and IV should be 8 bytes.

tripDES.Key = Encoding.ASCII.GetBytes("123456789012345678901234");
tripDES.IV = Encoding.ASCII.GetBytes("12345678");
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
4

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.

Andras Zoltan
  • 41,961
  • 13
  • 104
  • 160
0

I do it like this:

var derivedForIv = new Rfc2898DeriveBytes(passwordBytes, _saltBytes, 3);
_encryptionAlgorithm.IV = derivedForIv.GetBytes(_encryptionAlgorithm.LegalBlockSizes[0].MaxSize / 8);

The IV gets bytes from the derive bytes 'smusher' using the block size as described by the algorithm itself via the LegalBlockSizes property.

Luke Puplett
  • 42,091
  • 47
  • 181
  • 266