Рекомендации, необходимые для переноса низкоуровневого OpenSSL API на высокоуровневый OpenSSL API

#encryption #hash #openssl #md5

Вопрос:

Я новичок в OpenSSL и в настоящее время работаю над проектом на C , который зависит от OpenSSL. Недавно я начал использовать машину, на которой был установлен OpenSSL 3.0, но не смог создать проект, потому что я получаю ошибки компилятора, как показано ниже (обратите внимание, что предупреждения рассматриваются как ошибка в проекте)

 error: 'MD5' is deprecated
    if (!MD5((uint8_t*)key.data(), key.size(), hashOutput)) {
         ^
/usr/local/Cellar/openssl@3/3.0.0_1/include/openssl/md5.h:52:1: note: 'MD5' has been explicitly marked deprecated here
OSSL_DEPRECATEDIN_3_0 unsigned char *MD5(const unsigned char *d, size_t n,
^
/usr/local/Cellar/openssl@3/3.0.0_1/include/openssl/macros.h:182:49: note: expanded from macro 'OSSL_DEPRECATEDIN_3_0'
#   define OSSL_DEPRECATEDIN_3_0                OSSL_DEPRECATED(3.0)
                                                ^
/usr/local/Cellar/openssl@3/3.0.0_1/include/openssl/macros.h:62:52: note: expanded from macro 'OSSL_DEPRECATED'
#     define OSSL_DEPRECATED(since) __attribute__((deprecated))
                                                   ^
1 error generated.
 

Проведя некоторое расследование, я обнаружил, что эти API устарели в OpenSSL 3.0.0, и теперь у меня есть три варианта

  1. Игнорируйте предупреждения. Это просто предупреждения. Устаревшие функции все еще присутствуют, и вы все равно можете их использовать. Однако имейте в виду, что они могут быть удалены из будущей версии OpenSSL.
  2. Подавите предупреждения. Обратитесь к документации вашего компилятора о том, как это сделать.
  3. Удалите использование низкоуровневых API. В этом случае вам нужно будет переписать свой код, чтобы вместо него использовать API высокого уровня.

Я выбираю третий вариант, но даже после прочтения документации, связанной с OpenSSL, я все еще не уверен, какой EVP API эквивалентен методу MD5, который устарел в OpenSSL 3.0.0. Если вы проверите ссылку https://www.openssl.org/docs/manmaster/man3/MD5.html в нем говорится , что

Все функции, описанные на этой странице, устарели. Приложения должны вместо этого использовать EVP_DigestInit_ex(3), EVP_DigestUpdate(3) и EVP_DigestFinal_ex(3).

Было бы здорово, если бы кто-нибудь мог предоставить мне некоторую обратную связь / помощь или дополнительные ресурсы / ссылки, которые могли бы помочь мне понять использование высокоуровневого OpenSSL API в целом, чтобы я мог заставить его работать для моего варианта использования, например, шифрования MD5.

Я должен также упомянуть, что я загрузил OpenSSL repo с github и обнаружил, что реализация метода md5 выглядит следующим образом

     unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)
{
    MD5_CTX c;
    static unsigned char m[MD5_DIGEST_LENGTH];

    if (md == NULL)
        md = m;
    if (!MD5_Init(amp;c))
        return NULL;
#ifndef CHARSET_EBCDIC
    MD5_Update(amp;c, d, n);
#else
    {
        char temp[1024];
        unsigned long chunk;

        while (n > 0) {
            chunk = (n > sizeof(temp)) ? sizeof(temp) : n;
            ebcdic2ascii(temp, d, chunk);
            MD5_Update(amp;c, temp, chunk);
            n -= chunk;
            d  = chunk;
        }
    }
#endif
    MD5_Final(md, amp;c);
    OPENSSL_cleanse(amp;c, sizeof(c)); /* security consideration */
    return md;
}
 

Комментарии:

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

2. если я правильно понимаю, это означает, что мне нужно реализовать подобный метод void digest_message(const unsigned char *message, size_t message_len, unsigned char **digest, unsigned int *digest_len) , и нет доступного EVP_ эквивалента MD5, правильно ли я понимаю.

3. Afaik, OpenSSL не предоставляет метод, который уже выполняет это, т. Е. Вы должны реализовать его самостоятельно: скопируйте метод из документации и замените два EVP_sha256() вызова EVP_md5() вызовами.

Ответ №1:

Я надеюсь, что этот пример поможет (я не проверяю ошибки и исключения в моем примере, поэтому имейте это в виду):

Устаревшая реализация

 #include <openssl/md5.h>

static void calculate_md5(unsigned char* buf, unsigned int buf_size)
{
    unsigned char md5_digest[MD5_DIGEST_LENGTH];
    MD5_CTX md5ctx;

    MD5_Init(amp;md5ctx);
    MD5_Update(amp;md5ctx, buf, buf_size);
    MD5_Final(md5_digest, amp;md5ctx);
}
 

Новая реализация:

 #include <openssl/evp.h>

static void calculate_md5(unsigned char* buf, unsigned int buf_size)
{
    EVP_MD_CTX *mdctx;
    unsigned char *md5_digest;
    unsigned int md5_digest_len = EVP_MD_size(EVP_md5());
    
    // MD5_Init
    mdctx = EVP_MD_CTX_new();
    EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);

    // MD5_Update
    EVP_DigestUpdate(mdctx, buf, buf_size);

    // MD5_Final
    md5_digest = (unsigned char *)OPENSSL_malloc(md5_digest_len);
    EVP_DigestFinal_ex(mdctx, md5_digest, amp;md5_digest_len);
    EVP_MD_CTX_free(mdctx);
}