Сила на базирания на PBKDF AES ключ

Ето част от система, която ще генерира двойка ключове, използвайки AES 256 CBC в OpenSSL. Целта на кода по-долу е да генерира два произволни ключа за достъп, AES ключ и някои други публични данни. AES ключът ще се използва за обмен на споделени тайни.

Отказ от отговорност: НЕ съм експерт по криптография или системи за сигурност. Осъзнавам опасностите, но смисълът на това упражнение е академичен интерес. Ако има начинаещи грешки или нещо изцяло и опасно неправилно, моля, посочете го, за да ми помогнете в обучението.

// The key_generator() will produce the following public keys in addition
// to a couple of other private keys.
// public_identifier
// public_salt
// public_composite_identifier
// public_aes_key

int key_generator(/*some args*/)
{
    // Step 1
    //Obtain public_identifier. Possibly a hashed value of an unique ASCII string.
    unsigned char *public_identifier;


    // Step 2
    //Generate 256 bit private_primary_random_passkey which is secret. 
    //This random key is generated once and reused later.
    unsigned char *private_primary_random_passkey;

    if(RAND_bytes(private_primary_random_passkey, 256) == 0)     
        return FAILURE;


    // Step 3
    //Generate private_composite_identifier using public_identifier
    //and private_primary_random_passkey.
    //IMPORTANT - The method to obtain private_composite_identifier 
    //may be publicly known.  
    //The public_identifier is also publicly known but the 
    //private_primary_random_passkey is secret.
    unsigned char *private_composite_identifier;

    //<Some code for generating private_composite_identifier>
    //.....
    //</code>


    // Step 4     
    //Generate temporary temp_private_aes_key and temp_private_aes_IV;
    //NOTE - Used dummy vars wherever key length is required. 
    //Assume correct length is passed in.

    int aes_rounds = 25000;

    unsigned char *temp_private_aes_key;
    unsigned char *temp_private_aes_IV;

    if(EVP_BytesToKey(EVP_aes_256_cbc(), 
                      EVP_sha512(), 
                      private_composite_identifier, 
                      private_primary_random_passkey, 
                      private_composite_identifier_length/8, 
                      aes_rounds, 
                      temp_private_aes_key, 
                      temp_private_aes_IV) == 0)     
        return FAILURE;    


    // Step 5
    //Generate 128 bit random salt which is public.
    unsigned char *public_salt;

    if(RAND_bytes(public_salt, 128) == 0)     
        return FAILURE;


    // Step 6
    //Generate private_composite_identifier and public_composite_identifier 
    //using temp_private_aes_key and public_salt.
    unsigned char *public_composite_identifier;
    unsigned char *private_composite_identifier;

    if(EVP_BytesToKey(EVP_aes_256_cbc(), 
                      EVP_sha512(), 
                      temp_private_aes_key,
                      public_salt,
                      temp_private_aes_key_length/8, 
                      aes_rounds, 
                      private_composite_identifier, 
                      public_composite_identifier) == 0)     
        return FAILURE;    


    // Step 7
    //Generate 128 bit private_secondary_random_passkey which is secret. 
    //This random key is generated once and reused later.
    unsigned char *private_secondary_random_passkey;

    if(RAND_bytes(private_secondary_random_passkey, 128) == 0)     
        return FAILURE;

    unsigned char *private_aes_key;
    unsigned char *public_aes_key;

    if(EVP_BytesToKey(EVP_aes_256_cbc(), 
                      EVP_sha512(), 
                      private_composite_identifier,
                      private_secondary_random_passkey,
                      private_composite_identifier_length/8, 
                      aes_rounds, 
                      private_aes_key, 
                     public_aes_key) == 0)     
        return FAILURE
}

Ето моите въпроси:

  • Трябва ли да се използва двойка ключове RSA вместо AES ключа? Защо едното би било предпочитано пред другото?
  • Тъй като ключовете, използвани за създаване на двойката ключове, са дълги, произволно генерирани и солирани, безопасно ли е да използвате същата двойка ключове AES/RSA по-късно? Разбирам рисковете от таблиците на Rainbow и други мерки, но не се ли облекчават тези опасения с произволните соли и ключове, последвани от три нива на генериране на ключове?
  • Какви са начините, по които злонамерен нападател може да пресъздаде двойката ключове или да разбие тази система, използвайки публично достъпните данни?
  • Всякакви други точки, за които можете да се сетите, за да осуетите или подобрите тази система.

Благодаря за отделеното време.


person Nilesh Karia    schedule 10.01.2014    source източник
comment
AES е симетричен. RSA е асиметрична.   -  person Jonathon Reinhart    schedule 10.01.2014
comment
@JonathonReinhart - Благодаря, че посочихте грешката n00b. :) Бихте ли преразгледали въпросите, ако в стъпка 7 генерираме двойка ключове RSA от наличната до този момент информация и използваме тази двойка ключове за бъдещо криптиране?   -  person Nilesh Karia    schedule 10.01.2014


Отговори (1)


Вие наистина се занимавате с криптографско инженерство и хората от Crypto Stack Exchange вероятно биха били по-подходящи за този вид въпроси относно дизайна.

Освен това ви липсват много подробности за каквито и да било полезни отговори. (Върнете се, когато въпросът е по-ориентиран към изпълнението и специфичен).


Сила на базирания на PBKDF AES ключ

Първо, заглавието.

Този проблем е толкова труден, колкото отгатването на паролата, и вероятно е по-лесен с неща като многомилионни списъци с думи от минали пробиви на данни. Тоест вашият нападател няма да се опита да разбие AES ключа - той или тя ще се опита да отгатне паролата, която сте използвали, за да извлечете ключа.

За да въведете ключ AES-128 със 128-битова сигурност, имате нужда от 128-битова ентропия в паролата. Паролите не са произволни и английският има около 1,3 бита ентропия на буква, така че очаквайте да използвате около 14+ символна парола за AES-128. Използвайте парола от 28+ знака, ако въвеждате AES-256.


Целта на кода по-долу е да генерира два произволни ключа за достъп, AES ключ и някои други публични данни. AES ключът ще се използва за обмен на споделени тайни.

Каква е целта тук? За да създадете защитен канал? Или просто размяна на ключове?

Обикновено използвате публичен ключ за транспортиране или споразумение за транспортиране на симетрични или сесийни ключове. Това е: (1) използвайте Diffie-Hellman за генериране на споделена тайна („ключово споразумение“, тъй като и двете страни добавят към процеса), след това транспортирайте симетрични сесийни ключове под споделената тайна; или (2) използвайте RSA за транспортиране на „главен“ симетричен сесиен ключ („пренос на ключ“, тъй като едната страна генерира тайната, криптира я под RSA ключа на партньора и след това го изпраща на партньора).

Има автентифициран обмен на ключове, базиран на споделени тайни и пароли. SSL/TLS има два от тях - Preshared Key (PSK) и Secure Remote Password (SRP). PSK използва AES като примитив, а SRP използва Diffie-Hellman.

PSK и SRP обикновено са по-добри от DH и RSA, защото осигуряват (1) взаимно удостоверяване и (2) обвързване на канали. Въз основа на вашето изявление „AES ключът ще се използва за обмен на споделени тайни“, PSK може да е идеален за вас. Но не е ясно дали са добър избор, защото не знаем какво се опитвате да постигнете.


Трябва ли да се използва двойка ключове RSA вместо AES ключа? Защо едното би било предпочитано пред другото?

Зависи от вашия проблемен домейн и това, което се опитвате да направите.

Ако сървърът има публичен RSA ключ, тогава ще използвате Diffie-Hellman или RSA. Ако вие и сървърът споделяте тайна, тогава избягвайте нещата с публичния ключ и използвайте PSK или SRP.

Diffie-Hellman и RSA са скъпи по отношение на изчисленията. Те обикновено се използват за обмен или транспортиране на ключ за симетричен шифър. RSA-2048 може да приеме 4 или 5 милиона инструкции и осакатява производителността.

Симетричните шифри са бързи по отношение на изчисленията. Те се използват за по-голямата част от трафика, след като Diffie-Hellman или RSA са завършени. Ние го наричаме масово криптиране и те са дебели. Ако имате хардуер Ivy Bridge, тогава AES-NI може да се доближи до 1 цикъл/байт за криптирани данни.

Когато четете, че уеб сървъри като nginx могат да обработват само 1000 SSL/TLS връзки, виждате ефектите на Diffie-Hellman и RSA. След като тези канали са настроени и зададени за групово криптиране, той може да обработва хиляди криптирани потоци от трафик.

безопасно ли е да използвате същата двойка ключове AES/RSA по-късно?

Това са ябълки и портокали. Обикновено използвате двойка ключове RSA за дългосрочен план, докато AES ключовете са ограничени до сесия.

Като цяло всяко изпълнение на протокол трябва да използва различни параметри. Протоколът също трябва да липсва симетрия, така че нападателят да не може да стартира втори екземпляр на вашия протокол и след това вашият сървър да отговаря на въпроси, присъстващи в първия екземпляр с втория екземпляр.


Разбирам рисковете от таблиците на Rainbow и други мерки, но не се ли облекчават тези опасения с произволните соли и ключове, последвани от три нива на генериране на ключове?

Зависи от вашия проблемен домейн и това, което се опитвате да направите. Не можем наистина да отговорим, защото не знаем какво се опитвате да постигнете.

Вижте Cheat Sheet на John Steven в OWASP. Той ви превежда през моделите на заплахи и обяснява частите на системата. Подробното лечение е достъпно на адрес Сигурно съхранение на пароли.


Какви са начините, по които злонамерен нападател може да пресъздаде двойката ключове или да разбие тази система, използвайки публично достъпните данни?

Зависи от вашия проблемен домейн и това, което се опитвате да направите. Не можем наистина да отговорим, защото не знаем какво се опитвате да постигнете.

Управлението на ключовете е най-трудната част от криптографията и всичко, което виждаме, е вакуум:

int key_generator(/*some args*/)

Ще трябва да описвате напълно всички параметри, как ги управлявате и как ги използвате.


Всякакви други точки, за които можете да се сетите, за да осуетите или подобрите тази система.

Това изскача: три обаждания до RAND_byes и EVP_BytesToKey. Обикновено правите това:

byte[] master = Random(16) // or 32, or however many you need
byte[] key1 = Derive(master, "<some usage>", <other distinguishing information>)
byte[] key2 = Derive(master, "<some usage>", <other distinguishing information>)
byte[] key3 = Derive(master, "<some usage>", <other distinguishing information>)

master може да идва от обмен на ключове или споразумение за ключове.

key1, key2 и key3 биха били различни, защото (1) използването е различно при извикванията и (2) допълнителната отличителна информация е различна при равностойните.

Derive може да бъде HMAC или CMAC и включва елементите на KDF. Също така погледнете HKDF, който е най-модерният за алгоритмите „разгъване и след това извличане“.

person jww    schedule 11.01.2014
comment
Благодаря за много подробния отговор! Първо целта: Това е да се изгради система, в която клиентите могат детерминирано (ре)генерират двойки публични ключове, които ще се използват за обмен на данни, използвайки съществуващите двойки ключове. Не е задължително паролите да са на английски. Шестнадесетичните ключове ще бъдат въведени отново, за да се генерират отново двойките ключове, когато клиентите искат да обменят данни. Ето защо паролите се генерират произволно в мънича и се представят на регистриращ се клиент. След първоначалното генериране на ключове всеки клиент ще има някакъв уникален идентификатор, свързан с публичен ключ и публична сол. - person Nilesh Karia; 14.01.2014
comment
Разбирам мнението ви относно използването на производни методи, вместо да използвате отделни извиквания към EVP_BytesToKey (Извикването RAND_bytes е само за първоначалната регистрация на клиента). Ще работя върху разработена тестова реализация, като имам предвид точките, които посочихте, и ще се върна. Като се има предвид това, не успях да намеря добър пример за създаване на двойка ключове RSA (или всяка друга асиметрична двойка ключове) детерминистично от дадено семе (256-битово произволно семе, в този случай) в OpenSSL за C/C++. Би било изключително полезно, ако вие или някой друг тук можете да ми посочите такъв пример. - person Nilesh Karia; 14.01.2014