Подтвердить что ты не робот

Детерминированно Генерирование криптографически защищенных ключей и IVEC

Фон

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

Проблема

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

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

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

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

ripemd160 (RandomPreGeneratedFixedNonce: Passphrase: UInt64SinceEpoch: 128BitBlockIndexNumber);

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

Является ли это разумным подходом (-, то есть криптографически безопасным)?

- изменить: отправить комментарий -

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

Ну, я думаю, что часть решения - использовать генератор, не основанный на времени. Таким образом, если обе стороны начинаются с одного и того же семени, то они оба производят один и тот же случайный поток. Вы можете сложить свои "недели с первой недели" 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.

Также см. раздел Reproducibility для класса RandomNumberGenerator в вики Crypto ++.