tags:

views:

262

answers:

1

I generated an RSA private key using openssl.

I need to use the HMAC_*() functions of the OpenSSL library in plain C to hash/sign data, but I'm unsure on how to correctly extract the private key data from that file.

From what I know, that file is B64 encoded, so I uncoded it and stored it in a buffer. However, it seems to me that the HMAC_*() functions, although hashing and signing do not use the actual key since the result is not what I expect.

I assume I should discard the header ? Or user functions to read the keys instead of doing it by myself ?

I came accross PEM_read_PrivateKey() but that one creates an EVP_PKEY struct which is unusable directly by HMAC*() functions.

Any hint ? Thanks !

+1  A: 

You misunderstand HMAC. HMAC uses a shared (symmetric) key to create a secure keyed hash of the data. It requires the same key to verify it as produced it (this is not a signature). The key is just a sequence of random bits with no particular structure.

A RSA signature is based on a normal, unkeyed hash. You should use the EVP_SignInit() / EVP_SignUpdate() / EVP_SignFinal() functions to create RSA signatures. For example, to intialise an EVP context for RSA-with-SHA256 signatures, you'd do:

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

(If your version of OpenSSL doesn't include SHA256, you can use EVP_sha1() for RSA-with-SHA1 signatures).

To obtain the EVP_PKEY * needed by EVP_SignFinal(), you'll initialise it from your RSA key:

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

The base64-encoded RSA keys created by the openssl commandline utility are in PEM format, so you can just use PEM_read_RSAPrivateKey() to read it directly from the file into an RSA * handle.

Here's an example of reading an RSA private key file and using it to generate a signature of another file:

#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;
}
caf