开发者

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:

TripleDESCrypto开发者_如何学编程ServiceProvider 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


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.


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.


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

tripDES.Key = Encoding.ASCII.GetBytes("123456789012345678901234");
tripDES.IV = Encoding.ASCII.GetBytes("12345678");


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜