C # Не могу сгенерировать вектор инициализации IV - PullRequest
1 голос
/ 05 июля 2010

Я получаю следующую ошибку при попытке создать вектор инициализации IV для шифратора TripleDES.

См. Пример кода:

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;

Это исключение, которое я получаю от VS.

Указанный вектор инициализации (IV) не соответствует размеру блока для этого алгоритма.

Куда я иду не так?

Спасибо

Ответы [ 6 ]

10 голосов
/ 05 июля 2010

MSDN явно заявляет , что:

... Размер свойства IV должен совпадать со свойством BlockSize.

Для Triple DES это 64 бита.

6 голосов
/ 05 июля 2010

Размер вектора инициализации должен соответствовать размеру блока - 64 бита в случае TripleDES.Ваш вектор инициализации намного длиннее, чем восемь байтов.

Кроме того, вам действительно следует использовать функцию вывода ключей, такую ​​как PBKDF2 , для создания сильных ключей и векторов инициализации из фраз пароля.

5 голосов
/ 05 июля 2010

Ключ должен быть 24 байта, а IV должен быть 8 байтов.

tripDES.Key = Encoding.ASCII.GetBytes("123456789012345678901234");
tripDES.IV = Encoding.ASCII.GetBytes("12345678");
5 голосов
/ 05 июля 2010

Длина IV должна быть такой же длины (в битах), что и tripDES.BlockSize. Это будет 8 байтов (64 бита) для TripleDES.

4 голосов
/ 05 июля 2010

Я проголосовал за каждый ответ (ну, те, что здесь до моего!) Здесь, так как они все правильные.

Однако есть большая ошибка, которую вы совершаете (одну, которую я тоже сделал раньше) - НЕ ИСПОЛЬЗУЙТЕ СТРОКУ, ЧТОБЫ ЗАВЕРШИТЬ IV ИЛИ КЛЮЧ !!!

Строковый литерал времени компиляции является строкой Unicode и, несмотря на то, что вы не получите ни случайного, ни достаточно широкого разброса значений байтов (потому что даже случайная строка содержит много повторяющихся байтов из-за узкого диапазон байтов печатаемых символов), очень легко получить символ, который на самом деле требует 2 байта вместо 1 - попробуйте использовать 8 из более экзотических символов на клавиатуре, и вы поймете, что я имею в виду - при преобразовании в байты вы может содержать более 8 байтов.

Хорошо - значит, вы используете кодировку ASCII - но это не решает неслучайную проблему.

Вместо этого вы должны использовать RNGCryptoServiceProvider для инициализации вашего IV и ключа и, если вам нужно захватить постоянное значение для этого для будущего использования, тогда вы все равно должны использовать этот класс - но захватить результат как hex string или Base-64 закодированное значение (хотя я предпочитаю hex).

Чтобы достичь этого просто, я написал макрос, который я использую в VS (привязан к сочетанию клавиш CTRL + SHIFT + G, CTRL + SHIFT + H ), который использует .Net PRNG для произвести шестнадцатеричную строку:

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

Теперь все, что вам нужно сделать, это превратить ваш шестнадцатеричный строковый литерал в байтовый массив - я делаю это с помощью полезного метода расширения:

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;
}

Возможно, есть лучшие способы сделать это, но у меня это работает.

0 голосов
/ 23 марта 2012

Я делаю это так:

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

IV получает байты из производных байтов 'smusher', используя размер блока, как описано самим алгоритмом, через свойство LegalBlockSizes.

...