Недостатки использования одного и того же значения для ключа и IV?

Я реализую некоторые классы для .NET, которые (среди прочего) упрощают шифрование и дешифрование.

Мой текущий алгоритм создает 8-байтовую соль и использует эту соль с паролем для генерации ключа и IV. Затем я храню незашифрованную соль вместе с моими зашифрованными данными.

Это хорошо, потому что размер соли всегда составляет 8 байт, и это все накладные расходы, которые она добавляет к моим зашифрованным данным. Однако есть ли недостаток в использовании одного и того же значения как для моего ключа, так и для IV? Есть ли способ лучше?

Соответствующий код:

SymmetricAlgorithm algorithm = CreateAlgorithm();
byte[] salt = CreateSalt();
byte[] keyBytes = DeriveBytes(salt, algorithm.KeySize >> 3);
byte[] ivBytes = DeriveBytes(salt, algorithm.BlockSize >> 3);

Вспомогательный код:

private static readonly int SaltLength = 8;

internal byte[] CreateSalt()
{
    byte[] salt = new byte[SaltLength];
    using (RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider())
    {
        generator.GetBytes(salt);
    }
    return salt;
}

public byte[] DeriveBytes(byte[] salt, int bytes)
{
    Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(Password, salt, 1000);
    return derivedBytes.GetBytes(bytes);
}

person Jonathan Wood    schedule 12.08.2015    source источник
comment
Связанный: Проблемы с использованием ключа AES в качестве IV в CBC-режим   -  person Artjom B.    schedule 12.08.2015


Ответы (3)


Хорошо, пока вы используете новую, случайно созданную соль для каждого сообщения, вы близки к тому, что мог бы сделать я. Случайная соль означает, что IV будет меняться с каждым новым сообщением, а это означает, что одно и то же сообщение будет иметь разный криптотекст при каждой передаче. Все хорошо. Единственное, что я бы изменил на вашем месте, это вместо использования DeriveBytes для получения ключа, а затем для получения IV, я бы попросил DeriveBytes предоставить набор байтов, равный размеру ключа и IV, а затем разделить их и использовать. отдельно. IV не должен быть секретом ни от кого. Ключ должен быть. Таким образом, если вы один раз выберете DeriveBytes из одной и той же соли и пароля, а затем разделите эти байты на ключ и IV, злоумышленник все равно не приблизится к знанию ключа после просмотра IV, чем он был раньше.

В качестве альтернативы вы можете использовать одноразовый номер для создания известной перестановки между байтами IV и байтами ключа. Например, простите мой псевдокод:

IV = DeriveBytes(salt + password + "IV")
key = DeriveBytes(salt + password + "key")

В любом случае это безопасно. Но я бы просто использовал DeriveBytes, скажем, для 32 байтов, а затем использовал бы 16 из них для IV и 16 из них для ключа. В первых 16 байтах нет информации, которая поможет злоумышленнику вычислить следующие 16 байт.

person WDS    schedule 12.08.2015
comment
Если это безопасно, мне нравится ваше первое предложение. Его легко реализовать, и он не увеличивает объем данных, которые я должен хранить вместе с зашифрованными данными. - person Jonathan Wood; 12.08.2015
comment
Если вам не нужно/не хочется солить пароль, вы можете просто использовать режим CTR с AES. Я считаю, что в .NET не хватает реализации, но это достаточно легко сделать. Хотите верьте, хотите нет, но в Википедии есть достойное объяснение этому. И это превращает AES в потоковый шифр. При правильной реализации это устранит для вас практически все накладные расходы на передачу криптовалюты. - person WDS; 12.08.2015
comment
Просто чтобы дать вам краткое объяснение, CTR использует фиксированный одноразовый номер и счетчик для генерации открытого текста. При каждой передаче данных вы увеличиваете свой счетчик, объединяете его с одноразовым номером и шифруете его в режиме ECB. Счетчик гарантирует, что каждое шифрование будет полностью отличаться от любого предыдущего. Затем вы выполняете XOR этого вывода с блоком открытого текста, чтобы получить зашифрованный текст. Иными словами, вы пропускаете счетчик nonce plus через криптографию, чтобы получить кучу крошечных одноразовых блокнотов. Ваш открытый текст не нужно дополнять — вы просто отбрасываете столько OTP, сколько вам не нужно. - person WDS; 12.08.2015
comment
Я просто подумал, что должен прокомментировать еще раз, чтобы заверить вас, что это действительно безопасно. Учтите, что для всех простых текстов их хэши равномерно распределены по выходному пространству хэшей. Тогда, если кто-то знает первые 16 байтов 256-битного хеша, все, что он может знать о последних 16 байтах, это то, что любая возможность является допустимым результатом хеш-функции. Он просто не знает, какой из них является вашим ключом. Это похоже на проблему с одноразовыми паролями, когда злоумышленнику не хватает расшифровок; на самом деле у него их слишком много (все, что соответствует пространству сообщения), каждая так же действительна, как и следующая. - person WDS; 15.08.2015
comment
Ну, у меня есть навыки в разных областях, но понимание криптографии и безопасности не входит в их число. Так что есть части этого комментария, которые я не понимаю. Но, основываясь на всех дискуссиях, которые у меня были (с вами и другими), это кажется достаточно безопасным подходом. И все, что нужно вызывающей стороне моих классов, — это пароль, чтобы заставить ее работать, что и было моей первоначальной целью. - person Jonathan Wood; 15.08.2015

Да, это противоречит цели IV. IV используется, поэтому, если вы шифруете одно и то же сообщение одним и тем же ключом, вы не получаете тот же зашифрованный текст. С тем же успехом вы могли бы просто использовать постоянное значение 0, это добавляет такой же уровень безопасности.

person Scott Chamberlain    schedule 12.08.2015

В вашем случае здесь вы используете одно и то же значение для вашего

  • Ключ
  • IV

Концептуально это плохая идея, потому что предполагается, что IV не является секретным и отличается для каждого шифрования. Вы разобрались с "разным для каждого шифрования", но он идентичен вашему ключу.

То, от чего вы пытаетесь защититься, заключается в том, чтобы убедиться, что два шифрования с одним и тем же ключом не дадут один и тот же зашифрованный текст. В вашем случае это произойдет только в том случае, если ГСЧ сгенерирует два одинаковых 128-битных ключа AES.

Хотя шансы на это низки, у вас просто не должно быть этого.

person Ian Boyd    schedule 12.08.2015