Детерминированная генерация криптографически защищенных ключей и IVEC - PullRequest
12 голосов
/ 29 ноября 2010

Фон

Я проектирую систему, которая позволяет разрабатывать схемы динамической аутентификации для пользователя статического веб-контента. Мотивация состоит в том, чтобы предварительно генерировать большие объемы сложного для создания, но все же конфиденциального веб-контента, а затем обрабатывать его статически с помощью аутентификации на основе файлов cookie (встраивание обратимо зашифрованной информации), принудительно применяемой веб-сервером. Использование примитива шифрования в режиме AEAD.

Проблема

Мне нужно сгенерировать IVEC и ключи, которые действительны в течение определенного периода времени, скажем, одной недели (текущая действующая пара). и что предыдущие IVEC / ключи также действительны, скажем, в течение 2 недель (исторически действительные), и любые данные, зашифрованные с помощью исторически действительных секретов, будут просто повторно зашифрованы с помощью действующего на текущий момент IVEC / KEY.

Что мне нужно, так это детерминированный CSPRNG, который порождает случайное число и парольную фразу и который может индексировать 64-битные или 128-битные блоки чисел. Если в качестве одного из элементов индекса моего гипотетического CSPRNG я использую недели с 1 января 1970 года, я смогу построить систему, которая автоматически меняет ключи автоматически с течением времени.

Подход, который я рассматриваю

Сейчас я не вижу такой функциональности в cryptopp, или я знаю достаточно хорошо терминологию, и поскольку cryptopp является самой продвинутой из существующих библиотек шифрования, я не уверен, что найду другую. Так что, если я не могу найти реализацию там, я должен свернуть свою собственную. Будет ли создание статической строковой структуры из конкатенированных данных с последующим хешированием (показанной ниже) работать?

ripemd160 (RandomPreGeneratedFixedNonce: Passphrase: UInt64SinceEpoch: 128BitBlockIndexNumber); * +1021 *

Примечание. Блочные номера будут назначаться и иметь регулярную структуру, поэтому, например, для 128-битного дайджеста, первые 64-битные блоки 0 будут для ivec, а весь элемент 1 для 128-битного. ключ.

Это разумный подход (т. Е. Криптографически безопасный)?

- редактировать: опубликовать, принять комментарий -

После некоторого размышления я решил объединить то, что первоначально рассматривал парольную фразу и одноразовый номер / соль, в 16-байтовый (криптографически сильный) ключ и использовать методы, описанные в PKCS # 5, для получения нескольких основанных на времени ключи. В соли нет необходимости, так как парольные фразы не используются.

Ответы [ 2 ]

4 голосов
/ 01 декабря 2010

Интересный вопрос.

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

Ключи, конечно, должны быть настолько сильными, насколько вы можете их практически изготовить..

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

Выможет также захотеть взглянуть на схему генерации ключей, изложенную в PKCS # 5 (например, на http://www.faqs.org/rfcs/rfc2898.html), которая реализована в cryptopp как PasswordBasedKeyDerivationFunction. Этот механизм уже широко используется и известен как достаточно безопасный (примечаниечто PKCS # 5 рекомендует хэшировать данные парольной фразы не менее 1000 раз.) Вы можете просто добавить свой срок действия и индексные данные к парольной фразе и использовать PasswordBasedKeyDerivationFunction в ее нынешнем виде.

Вы не говорите, какой алгоритм шифрования вы используетеПредлагаю использовать для шифрования данных, но я бы предложил, чтобы вы выбрали что-то широко используемое и, как известно, безопасное ... и, в частности, я бы предложил использовать AES. Я бы также предложил использовать один из SHAфункции дайджеста (возможно, в качестве входных данных для PasswordBasedKeyDerivationFunction).SHA-2 является текущим, но SHA-1 достаточно для целей генерации ключей.

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

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

1 голос
/ 16 февраля 2015

Что мне нужно, так это детерминированный CSPRNG, который порождает случайное число и парольную фразу и может индексированно генерировать 64-битные или 128-битные блоки чисел. Если я использую неделю с 1 января 1970 года в качестве одного из элементов индекса моего гипотетического CSPRNG, я смогу построить систему, которая автоматически меняет ключи автоматически с течением времени.

Ну, я думаю, что часть решения заключается в использовании генератора, не основанного на времени. Таким образом, если обе стороны начинают с одного и того же начального числа, то обе они создают один и тот же случайный поток. Вы можете поместить свою логику «недели с 1-й недели 1970 года» поверх этого.

Для этого вы должны использовать OFB_mode<T>::Encryption. Он может использоваться в качестве генератора, поскольку в режиме OFB используется AdditiveCipherTemplate<T>, который происходит от RandomNumberGenerator.

Фактически, Crpyto ++ использует генератор в test.cpp, так что результаты могут быть воспроизведены в случае сбоя. Вот как бы вы использовали OFB_mode<T>::Encryption. Это также относится к CTR_Mode<T>::Encryption:

SecByteBlock seed(32 + 16);
OS_GenerateRandomBlock(false, seed, seed.size());

for(unsigned int i = 0; i < 10; i++)
{
    OFB_Mode<AES>::Encryption prng;
    prng.SetKeyWithIV(seed, 32, seed + 32, 16);

    SecByteBlock t(16);
    prng.GenerateBlock(t, t.size());

    string s;
    HexEncoder hex(new StringSink(s));

    hex.Put(t, t.size());
    hex.MessageEnd();

    cout << "Random: " << s << endl;
}

Вызов OS_GenerateRandomBlock извлекает байты из /dev/{u|s}random и затем использует его в качестве имитированного общего начального числа. Каждый запуск программы будет отличаться. При каждом запуске программы она печатает примерно так:

$ ./cryptopp-test.exe
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD

Есть еще один генератор, который делает то же самое, но не является частью библиотеки Crypto ++. Его называют AES_RNG, и он основан на AES-256. Это реализация только для заголовков, и вы можете найти ее в вики Crypto ++ под RandomNumberGenerator .

Также см. Тему Воспроизводимость для RandomNumberGenerator класса в вики Crypto ++.

...