Как прочитать файл ключа для использования с HMAC_Init_ex () - PullRequest
2 голосов
/ 12 января 2010

Я сгенерировал закрытый ключ RSA, используя openssl.

Мне нужно использовать функции HMAC _ * () библиотеки OpenSSL в простом C для хеширования / подписывания данных, но я не уверен, как правильно извлечь данные закрытого ключа из этого файла.

Из того, что я знаю, этот файл закодирован в B64, поэтому я расшифровал его и сохранил в буфере. Однако мне кажется, что функции HMAC _ * (), хотя хеширование и подпись не используют фактический ключ, так как результат не тот, который я ожидаю.

Я полагаю, мне следует отказаться от заголовка? Или пользовательские функции читают ключи вместо того, чтобы делать это самостоятельно?

Я наткнулся на PEM_read_PrivateKey (), но он создает структуру EVP_PKEY, которую нельзя использовать напрямую функциями HMAC * ().

Любой намек? Спасибо!

1 Ответ

4 голосов
/ 13 января 2010

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

Подпись RSA основана на обычном хеше без ключа. Вы должны использовать функции EVP_SignInit() / EVP_SignUpdate() / EVP_SignFinal() для создания подписей RSA. Например, чтобы инициализировать контекст EVP для подписей RSA-with-SHA256, вы должны сделать:

EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
EVP_SignInit(&ctx, EVP_sha256());

(Если ваша версия OpenSSL не включает SHA256, вы можете использовать EVP_sha1() для подписей RSA-with-SHA1).

Чтобы получить EVP_PKEY *, необходимый для EVP_SignFinal(), вы инициализируете его с помощью ключа RSA:

EVP_PKEY *pkey = EVP_PKEY_new();
EVP_PKEY_set1_RSA(pkey, rsakey);

Ключи RSA в кодировке base64, созданные утилитой командной строки openssl, имеют формат PEM, поэтому вы можете просто использовать PEM_read_RSAPrivateKey() для чтения его непосредственно из файла в дескриптор RSA *.

Вот пример чтения файла закрытого ключа RSA и использования его для генерации подписи другого файла:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>

int do_evp_sign(FILE *rsa_pkey_file, FILE *in_file)
{
    RSA *rsa_pkey = NULL;
    EVP_PKEY *pkey = EVP_PKEY_new();
    EVP_MD_CTX ctx;
    unsigned char buffer[4096];
    size_t len;
    unsigned char *sig;
    unsigned int siglen;
    int i;

    if (!PEM_read_RSAPrivateKey(rsa_pkey_file, &rsa_pkey, NULL, NULL))
    {
        fprintf(stderr, "Error loading RSA Private Key File.\n");
        return 2;
    }

    if (!EVP_PKEY_assign_RSA(pkey, rsa_pkey))
    {
        fprintf(stderr, "EVP_PKEY_assign_RSA: failed.\n");
        return 3;
    }

    EVP_MD_CTX_init(&ctx);

    if (!EVP_SignInit(&ctx, EVP_sha1()))
    {
        fprintf(stderr, "EVP_SignInit: failed.\n");
        EVP_PKEY_free(pkey);
        return 3;
    }

    while ((len = fread(buffer, 1, sizeof buffer, in_file)) > 0)
    {
        if (!EVP_SignUpdate(&ctx, buffer, len))
        {
            fprintf(stderr, "EVP_SignUpdate: failed.\n");
            EVP_PKEY_free(pkey);
            return 3;
        }
    }

    if (ferror(in_file))
    {
        perror("input file");
        EVP_PKEY_free(pkey);
        return 4;
    }

    sig = malloc(EVP_PKEY_size(pkey));
    if (!EVP_SignFinal(&ctx, sig, &siglen, pkey))
    {
        fprintf(stderr, "EVP_SignFinal: failed.\n");
        free(sig);
        EVP_PKEY_free(pkey);
        return 3;
    }

    printf("Signature: \n");
    for (i = 0; i < siglen; i++)
    {
        printf("%02x", sig[i]);
        if (i % 16 == 15)
            printf("\n");
    }
    printf("\n");

    free(sig);
    EVP_PKEY_free(pkey);
    return 0;
}
...