Генерация ключа CMAC с OpenSSL EVP_DigestSign* завершается неудачно

Я пытаюсь сгенерировать ключ для вычисления CMAC с OpenSSL.

Однако, похоже, что они не работают с сообщением об ошибке, скопированным ниже. Может кто-то указать, где проблема? Кто-нибудь сделал CMAC с EVP_DigestSign* звонки?

Вот часть кода, которая была построена из примера на https://wiki.openssl.org/index.php/EVP_Key_and_Parameter_Generation:

BIO *out = NULL;   
out = BIO_new(BIO_s_file());

if (out == NULL)
        return -1;
BIO_set_fp(out, stdout, BIO_NOCLOSE);

EVP_MD_CTX* rctx = NULL;
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *kctx = NULL;

rctx = EVP_MD_CTX_create();
if(rctx == NULL) {
    printf("EVP_MD_CTX_create failed\n");
}
 if(!EVP_PKEY_keygen_init(kctx)){
     printf("EVP_PKEY_keygen_init failed\n");
}

if (EVP_PKEY_CTX_ctrl(kctx, -1, EVP_PKEY_OP_KEYGEN,EVP_PKEY_CTRL_CIPHER,0, (void *)EVP_aes_256_ecb()) <= 0)
    printf("EVP_PKEY_CTX_ctrl 1  failed\n");

if (EVP_PKEY_CTX_ctrl(kctx, -1, EVP_PKEY_OP_KEYGEN,EVP_PKEY_CTRL_SET_MAC_KEY,/*key length*/32, "01234567890123456789012345678901") <= 0)
    printf("Set the key data failed 1\n");

Здесь ошибка:

EVP_PKEY_CTX_ctrl failed
3073898120:error:06093096:lib(6):func(147):reason(150):pmeth_gn.c:122:
3073898120:error:06089093:lib(6):func(137):reason(147):pmeth_lib.c:390:

И в строке 390 в pmeth_lib.c:

EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);

Я использую OpenSSL 1.0.1e.

См. Также Как рассчитать AES CMAC с использованием функций CMAC_xxx OpenSSL?

2 ответа

Мне удалось заставить CMAC работать, используя интерфейсы EVP. Часть генерации ключа, которая потерпела неудачу ранее, также работает. Вот код Как видите, я воспользовался приведенным здесь примером: Как рассчитать AES CMAC с использованием OpenSSL? который использует интерфейсы CMAC_Init/Update/Final OpenSSL и пробовал различные значения NIST, чтобы проверить, работают ли интерфейсы EVP для CMAC: Вот фрагмент кода. Генерация ключей также работает сейчас. Пожалуйста, дайте мне знать, если я что-то упустил. У меня есть замечание при использовании EVP. Пожалуйста, смотрите раздел замечаний ниже.

/*
 * CMACSiging.c
 */

#include <stdio.h>
#include <openssl/cmac.h>
#include <openssl/err.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <string.h>

typedef signed char       int8_t;
typedef signed short      int16_t;
typedef signed int        int32_t;
typedef unsigned char     uint8_t;
typedef unsigned short    uint16_t;
typedef unsigned int      uint32_t;

void printBytes(unsigned char *buf, size_t len) {
    int i;
    for(i=0; i<len; i++) {
        printf("%02x", buf[i]);
    }
    printf("\n");
}
EVP_PKEY *generate_key(int type)
{
    EVP_PKEY_CTX *pctx = NULL, *kctx = NULL;
    EVP_PKEY *params = NULL, *key = NULL;

    unsigned char k[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4};
    /* Create context for the key generation */
    if(!(kctx = EVP_PKEY_CTX_new_id(type, NULL))) goto err;

    /* Generate the key */

    if(!EVP_PKEY_keygen_init(kctx)) goto err;

    if(type == EVP_PKEY_CMAC)
    {
        if (EVP_PKEY_CTX_ctrl(kctx, -1, EVP_PKEY_OP_KEYGEN,
            EVP_PKEY_CTRL_CIPHER,
            0, (void *)EVP_aes_256_cbc()) <= 0)
            goto err;

        if (EVP_PKEY_CTX_ctrl(kctx, -1, EVP_PKEY_OP_KEYGEN,
            EVP_PKEY_CTRL_SET_MAC_KEY, sizeof(k), k) <= 0)
            goto err;
    }

    if (!EVP_PKEY_keygen(kctx, &key)) goto err;

   goto end;
err:

end:

    if(pctx) EVP_PKEY_CTX_free(pctx);
    if(params) EVP_PKEY_free(params);
    if(kctx) EVP_PKEY_CTX_free(kctx);

    return key;
}

void trial(uint8_t *msg, uint8_t mlen, uint8_t *key, uint8_t keylen, uint8_t **sig, uint8_t *slen)
{
//16 byte msg with 32 byte key with aes 256 cbc based CMAC
    if(!msg || !mlen || !key) {
        //handleError
    }

    if(*sig)
        OPENSSL_free(*sig);

    *sig = NULL;
    *slen = 0;

    EVP_MD_CTX* ctx = NULL;
    EVP_PKEY *pkey = NULL;
    const EVP_MD* md = NULL;
    OpenSSL_add_all_digests();

    do
    {
        ctx = EVP_MD_CTX_create();
        if(ctx == NULL) {
            printf("EVP_MD_CTX_create failed\n");
            break; // failed
        }
        if(!(md = EVP_get_digestbyname("SHA256")))
                printf("EVP_get_digestbyname failed\n");

        printf("Over to EVP calls \n");
        if(!(pkey = generate_key(EVP_PKEY_CMAC))) printf("Error 5 \n");
        int rc ;
        rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey);
        if(rc != 1) {
            printf("EVP_DigestSignInit failed\n");
            ERR_print_errors_fp(stdout);
            break;
        }

        rc = EVP_DigestSignUpdate(ctx, msg, mlen);
        if(rc != 1) {
            printf("EVP_DigestSignUpdate failed\n");
            ERR_print_errors_fp(stdout);
            break;
        }

        size_t req = 0;
        rc = EVP_DigestSignFinal(ctx, NULL, &req);

        if(rc != 1) {
            printf("EVP_DigestSignFinal failed\n");
            ERR_print_errors_fp(stdout);
            break;
        }

        if(!(req > 0)) {
            printf("EVP_DigestSignFinal failed (2)\n");
            break;
        }

        *sig = OPENSSL_malloc(req);
        if(*sig == NULL) {
            printf("OPENSSL_malloc failed, error \n");
            break;
        }

        *slen = req;
        rc = EVP_DigestSignFinal(ctx, *sig, slen);
        if(rc != 1) {
            printf("EVP_DigestSignFinal failed (3)\n");
            ERR_print_errors_fp(stdout);
            break;
        }

    } while(0);

    if(ctx) {
        EVP_MD_CTX_destroy(ctx);
        ctx = NULL;
    }
}

int main(int argc, char *argv[])
{
    // https://tools.ietf.org/html/rfc4493

    // K, M and T from
    // http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf
    // D.1 AES-128

    // K: 2b7e1516 28aed2a6 abf71588 09cf4f3c

    unsigned char key[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4};

    // M: 6bc1bee2 2e409f96 e93d7e11 7393172a Mlen: 128
    unsigned char message[] = { 0x6b,0xc1,0xbe,0xe2,
            0x2e,0x40,0x9f,0x96,
            0xe9,0x3d,0x7e,0x11,
            0x73,0x93,0x17,0x2a };

    unsigned char mact[16] = {0};
    size_t mactlen;

    CMAC_CTX *ctx = CMAC_CTX_new();
    CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL);
    printf("message length = %lu bytes (%lu bits)\n",sizeof(message), sizeof(message)*8);

    CMAC_Update(ctx, message, sizeof(message));
    CMAC_Final(ctx, mact, &mactlen);

    printBytes(mact, mactlen);
    //expected result T = 070a16b4 6b4d4144 f79bdd9d d04a287c

    CMAC_CTX_free(ctx);


    uint8_t key_len = sizeof(key);
    uint8_t mlen = sizeof(message);
    uint8_t *dgst = NULL;
    size_t dlen;
    trial( message, mlen, key, key_len, &dgst, &dlen);
    printf("length of sig = %d\n", dlen);
    printf("CMAC returned from trial is: ");
    int i;
    for(i = 0; i < dlen; i++)
        printf("%02x", dgst[i]);
    printf("\n");

    return 0;
}

Замечание:

Как видно из кода, важно отметить, что при использовании EVP_DigestSignInit структура конверта дайджеста сообщения (EVP_MD) не должна восприниматься как NULL, как упомянуто в OpenSSL Wiki (ATLEAST для OpenSSL 1.0.2e, где я тестировал):

Примечание. В API нет разницы между подписанием с использованием асимметричного алгоритма и генерацией кода MAC. В случае CMAC не требуется функция дайджеста сообщения (может быть передано значение NULL). Подписывание с использованием функций EVP_Sign* очень похоже на приведенный выше пример, за исключением того, что не поддерживается код MAC. Обратите внимание, что CMAC поддерживается только в (пока не выпущенной) версии 1.1.0 OpenSSL.

Если NULL пропущен, я получаю ошибку, что дайджест NULL. Кажется, что то, что передано, не влияет на генерацию CMAC, так как эта структура в основном игнорируется. Я надеюсь, что ребята из OpenSSL здесь могут уточнить. Спасибо!!

В настоящее время это невозможно, потому что это не поддерживается.

Единственное, что вы можете попробовать - это использовать последнюю версию OpenSSL и попробовать то же самое, но я сомневаюсь, что это сработает. Попробуй без EVP.

Другие вопросы по тегам