Использование PBKDF2 с библиотекой OpenSSL

Я хочу использовать алгоритм PBKDF2 с SHA1 HMAC (основываясь на этом ответе).

Как я могу использовать это через библиотеку шифрования?

Я начал с того, что посмотрел на man openssl, но openssl passwd Команда ( страница man) поддерживает только небольшое количество алгоритмов. Глядя на крипто- документацию, модуль evp имеет метод EVP_BytesToKey.

Тщательный выбор параметров обеспечит реализацию, совместимую с PKCS#5 PBKDF1. Однако новые приложения обычно не должны использовать это (предпочитая, например, PBKDF2 из PCKS#5).

Что возвращает меня к моему первоначальному вопросу, как я могу использовать PBKDF2 через криптографию? Нужно ли копаться в коде и вызывать метод без использования API (например, PKCS5_PBKDF2_HMAC)? (и если так, что мешает этому быть разоблаченным?)

1 ответ

У меня есть работающий, но плохой пример C PBKDF2 через библиотеки OpenSSL в моем репозитории github, включая сценарии для компиляции под Linux и Windows (через MinGW). Исходный код, расположенный в разделе "Релизы", известен как хороший; Исходный код в ветке master - это WIP. Этот вариант лицензируется под тем же BSD с 4 пунктами в дополнение к лицензии SSLeay OpenSSL.

Я все еще работаю над добавлением нескольких функций, затем я вернусь к отличным данным, полученным на сайте StackExchange для Code Review, и обновлю их до синтаксиса C99 и так далее.

Базовый код очень примитивен и может содержать недостатки, несмотря на прохождение очень обширных тестовых векторов на основе строк. Он не был (пока) проверен на чистый двоичный ввод.

#include <openssl/evp.h>
#include <openssl/sha.h>
// crypto.h used for the version
#include <openssl/crypto.h>

void PBKDF2_HMAC_SHA_1nat_string(const char* pass, const unsigned char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
{
    unsigned int i;
    unsigned char digest[outputBytes];
    PKCS5_PBKDF2_HMAC_SHA1(pass, strlen(pass), salt, strlen(salt), iterations, outputBytes, digest);
    for (i = 0; i < sizeof(digest); i++)
        sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
}

Если у вас есть 64-битная система, я бы настоятельно рекомендовал перейти на PBKDF2-HMAC-SHA-512 или PBKDF2-HMAC-SHA-384:

#include <openssl/evp.h>
#include <openssl/sha.h>
// crypto.h used for the version
#include <openssl/crypto.h>


void PBKDF2_HMAC_SHA_384_string(const char* pass, const unsigned char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
{
    unsigned int i;
    unsigned char digest[outputBytes];
    PKCS5_PBKDF2_HMAC(pass, strlen(pass), salt, strlen(salt), iterations, EVP_sha384(), outputBytes, digest);
    for (i = 0; i < sizeof(digest); i++)
        sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
}

void PBKDF2_HMAC_SHA_512_string(const char* pass, const unsigned char* salt, int32_t iterations, uint32_t outputBytes, char* hexResult)
 {
     unsigned int i;
     unsigned char digest[outputBytes];
     PKCS5_PBKDF2_HMAC(pass, strlen(pass), salt, strlen(salt), iterations, EVP_sha512(), outputBytes, digest);
     for (i = 0; i < sizeof(digest); i++)
         sprintf(hexResult + (i * 2), "%02x", 255 & digest[i]);
 }    

Пример использования будет:

// 2*outputBytes+1 is 2 hex bytes per binary byte, 
// and one character at the end for the string-terminating \0
char hexResult[2*outputBytes+1];
memset(hexResult,0,sizeof(hexResult));
PBKDF2_HMAC_SHA_1nat_string(pass, salt, iterations, outputBytes, hexResult);
printf("%s\n", hexResult);

или же

// 2*outputBytes+1 is 2 hex bytes per binary byte, 
// and one character at the end for the string-terminating \0
char hexResult[2*outputBytes+1];
memset(hexResult,0,sizeof(hexResult));
PBKDF2_HMAC_SHA_512_string(pass, salt, iterations, outputBytes, hexResult);
printf("%s\n", hexResult);

Используйте случайную соль для каждого пользователя от 8 до 16 двоичных байтов, то есть от 16 до 32 шестнадцатеричных цифр - мой код пока не имеет примеров генерации этого

Независимо от того, что вы выберете, не забудьте проверить его по тестовым векторам (некоторые из них находятся в pbkdf2_test.bat/sh в моем репозитории).

Кроме того, в вашей системе проведите некоторое тестирование - конечно, в вариантах PBKDF2-HMAC-SHA-384 и PBKDF2-HMAC-SHA-512, компиляция в 64-битной системе дает значительно лучшие результаты. Сравните это с моими одинаково плохими C++ Crypto++ и / или моими плохими примерами C PolarSSL или примером реализации Jither C#, в зависимости от того, какая у вас целевая система.

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

Злоумышленники будут использовать что-то вроде oclHashcat, который на одном ПК с 8-кратным ядром AMD R9 290Xstock может пытаться угадать 3.4E12 (2^41) каждые 30 дней против PBKDF2-HMAC-SHA-1(SSID как соль, пароль Длина вывода 32 байта, 4096 итераций, или WPA/WPA2), что более или менее эквивалентно PBKDF2-HMAC-SHA-1 (соль, pw, длина вывода 20 байтов, 8192 итерации).

  • если вы используете 65536 итераций, злоумышленник сможет проверять предположения 8.5E11 (~2^39) каждые 30 дней.
  • если вы используете 1024 итерации, злоумышленник сможет вместо этого пробовать догадки 2.7E13 (~2^44) каждые 30 дней.

Разница становится важной, когда атакующий начинает выбирать свои атаки.

  • В обоих случаях злоумышленник собирается грубо взломать очень маленькие ключи; нет причин не тратить несколько минут или даже несколько часов на низко висящие фрукты.
    • Это все шестнадцатеричные символы для длины 1-n, а затем все печатные символы от длины n+1 до n+m, и затем, продолжающиеся вниз по линии, пока они не будут в n+y с жестко закодированными! в конце:).
  • В обоих случаях злоумышленник собирается использовать крошечные словари и крошечные наборы правил; скажем, словарь phpbb из 184389 слов и набор правил Best64
    • Если у вас было 1000 пользователей с 1000 различными случайными солями и вы использовали PBKDF2-HMAC-SHA-1 с 65536 итерациями, то для нашего единственного ПК потребуется 8 атакующих GPU (184389*64*1000)/(8.5E11/30) дней = 0,41 дней. Это того стоит!
  • Теперь, что насчет того же словаря phpbb и среднего размера T0X1C набора правил из 4089 правил?
    • Если у вас было 1000 пользователей с 1000 различными случайными солями и вы использовали PBKDF2-HMAC-SHA-1 с 65536 итерациями, то для нашего единственного ПК потребуется 8 атакующих GPU (184389*4089*1000)/(8.5E11/30) дней = 26,61 дней.
      • Все еще стоит, но это почти 4 недели, чтобы эта машина потратила на одну атаку!
    • Если у вас было 1000 пользователей с 1000 различными случайными солями и вы использовали PBKDF2-HMAC-SHA-1 с 65536 итерациями, то для нашего единственного ПК потребуется 8 атакующих GPU (184389*4089*1000)/(2.7E13/30) дней = 0,83 дня.
      • Оно того стоит!
  • А как насчет того же словаря phpbb и превосходного набора правил d3ead0ne из 35404 правил?
    • Если у вас было 1000 пользователей с 1000 различными случайными солями и вы использовали PBKDF2-HMAC-SHA-1 с 65536 итерациями, то для нашего единственного ПК потребуется 8 атакующих GPU (184389*35404*1000)/(8.5E11/30) дней = 230,39 дней.
      • Правильно, время покупать больше машин или работать над этим в нерабочее время.
    • Если у вас было 1000 пользователей с 1000 различными случайными солями и вы использовали PBKDF2-HMAC-SHA-1 с 65536 итерациями, то для нашего единственного ПК потребуется 8 атакующих GPU (184389*4089*1000)/(2.7E13/30) дней = 7,18 дней.
      • Стоило того! Это всего лишь неделя и еда.

Теперь для PBKDF2 есть еще несколько вещей, которые нужно знать:

  • Для хэширования пароля никогда не выбирайте двоичный выходной размер больше, чем собственный размер хэша. Лично я бы не рекомендовал двоичный размер вывода менее 20 байт независимо, так что это немного ограничивает SHA-1.
    • SHA-1 имеет размер 20 байт
    • SHA-224 имеет размер 20 <= размер <= 28 байт
    • SHA-256 имеет размер 20 <= размер <= 32 байта
    • SHA-384 имеет размер 20 <= размер <= 48 байтов
    • SHA-512 имеет размер 20 <= размер <= 64 байта
    • отрегулируйте, как вы храните хеш, если он, конечно, не в двоичном виде.
    • Причина: PBKDF2 сначала запускает количество итераций, запрошенных для одного собственного выходного размера (число справа, выше). Если вам нужно больше, он снова запускает весь счетчик итераций. Если вы хотели меньше, он усекается.
    • Атакующий будет только соответствовать первому собственному размеру - если первые байты совпадают, да, это пароль, так что вам лучше увеличить количество итераций.
Другие вопросы по тегам