Я хочу отправлять большие данные, зашифрованные с помощью RSA, через сокеты. Я использую openssl и c.

Поскольку расшифровка RSA довольно медленная, я использую обычный и прямой способ шифрования данных сначала с помощью AES, а затем я шифрую используемый пароль AES с помощью RSA. Затем я отправляю зашифрованные данные AES и пароль, зашифрованный RSA, через сокет и выполняю шифрование наоборот.

Я использую шифрование AES с помощью:

EVP_CIPHER_CTX en;
unsigned char password[65];
int i, x = 0;
unsigned char key[32], iv[32];
unsigned char *ciphertext;

i = dataLength + AES_BLOCK_SIZE -1;
ciphertext = (unsigned char *)malloc(i);

EVP_CIPHER_CTX_init(&en);
EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, key, iv);
EVP_EncryptUpdate(&en, ciphertext, &i, (unsigned char*)data, dataLength);
EVP_EncryptFinal_ex(&en, ciphertext+i, &x);

Но как мне безопасно создать key и iv? Прямо сейчас я использую следующую функцию:

EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, password, 64, 9, key, iv);

У меня вопрос: как правильно придумать «пароль»?

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

Есть ли в openssl функция для безопасной генерации паролей? Или EVP_BytesToKey() просто неправильный способ делать то, что я хочу делать?

1
Genius 21 Янв 2014 в 22:11
Посмотрите, как работают интегрированные системы шифрования. ECIES Шупа; или DHIES Абдаллы, Белларе и Рогавэя. Лучше использовать систему, чем изобретать ее заново. Схемы генерируют все параметры, шифруют с помощью блочного шифра, добавляют тег целостности и затем обертывают симметричные ключи, используя шифрование с открытым ключом. Система ECIES использует эллиптические кривые, а DHIES использует задачу Диффи-Хеллмана.
 – 
jww
6 Май 2014 в 08:45

1 ответ

Лучший ответ

К счастью, метод по умолчанию RAND_bytes заполняется для каждого потока и по умолчанию использует генератор случайных чисел, доступный в операционной системе. Документация OpenSSL кажется устаревшей, если речь идет о Windows, но вы можете найти дополнительную информацию об этом, просмотрев ответ достопочтенный Томас Порнин на security.stackoverflow.com.

EVP_BytesToKey используется для генерации ключей из паролей. EVP_BytesToKey - это функция вывода ключей (KDF), специфичная для OpenSSL. OpenSSL также реализует PBKDF2, который является одобренным NIST методом функции получения ключа на основе пароля (PBKDF). Но поскольку вам нужен случайный ключ, а не производный ключ, ни одна из этих функций не применима.

Поэтому используйте rand(). Если возможно, попробуйте проверить, как функция отобрана для вашей конкретной платформы.

Также обратите внимание, что OpenSSL 1.1.0c изменил алгоритм дайджеста, используемый в некоторых внутренних компонентах. Раньше использовался MD5, а 1.1.0 переключился на SHA256. Будьте осторожны, это изменение не повлияет на вас как в EVP_BytesToKey, так и в таких командах, как openssl enc.

3
Community 23 Май 2017 в 13:29
Я изменил "AESKey" на "пароль", потому что это немного вводило в заблуждение. Правильно ли я вас понял, что мне следует использовать rand() для генерации случайного символьного пароля и использовать этот пароль для генерации ключа и iv с EVP_BytesToKey?
 – 
Genius
21 Янв 2014 в 22:51
Нет, абсолютно нет. Ваш ключ AES должен состоять только из случайных байтов, сгенерированных с помощью rand(). Кажется, нет необходимости в пароле или символах в этом отношении. Если вы используете случайный ключ AES каждый раз, вы можете использовать статический IV, состоящий только из нулей, в противном случае он должен состоять из случайных байтов, как и ключ.
 – 
Maarten Bodewes
21 Янв 2014 в 23:00
2
Также обратите внимание, что пароля AES не существует. AES - это блочный шифр, и современные блочные шифры требуют ключа, а не пароля. Этот двоичный ключ должен быть неотличим от случайного. Пароль - это не случайные двоичные данные - вам нужно какое-то преобразование (PBKDF), чтобы преобразовать пароль в ключ. Даже в этом случае ключ, сгенерированный из пароля, обычно намного слабее, чем полностью случайный ключ AES.
 – 
Maarten Bodewes
21 Янв 2014 в 23:08
Да, я уже знал это, но я думал, что это обычный способ сгенерировать ключ AES с паролем, спасибо, что указали на это!
 – 
Genius
21 Янв 2014 в 23:12
1
Большинство людей так думают, но, к счастью, только относительно небольшое количество ключей AES генерируется из пароля. Они полезны, например, если вы хотите сделать закрытый ключ (например, ключ PGP) конфиденциальным. Даже в этом случае лучше хранить ключ в виде токена (например, смарт-карты). Пароли для современной криптовалюты заведомо ненадежны.
 – 
Maarten Bodewes
21 Янв 2014 в 23:20