es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo firmar datos utilizando el algoritmo ECDSA, en C++ con OPENSSL?

Tengo un resumen SHA256 de 32 bytes y necesito firmarlo con ECDSA. La clave privada está en un archivo .pem. Ya lo hice en la consola utilizando el comando: openssl.exe dgst -sha256 -sign ecc.pem -out %archivo_firma% %archivo_datos%. Ahora necesito hacerlo en c++ y los resultados que he obtenido no son los mismos que en la consola.

¿Qué hay de malo en el siguiente código, considerando el comando que utilicé en la consola?

bool firmar(unsigned char *digest) {

BIO *b_pem;
EVP_PKEY* pkey2 = nullptr;
const char * nombreArchivo = "ecc.pem";
pkey2 = EVP_PKEY_new();
b_pem = BIO_new_file(nombreArchivo, "rb");

PEM_read_bio_PrivateKey(b_pem, &pkey, NULL, NULL))

unsigned char firma[200] = {0};
EVP_MD_CTX *mctx;
const EVP_MD *md = EVP_get_digestbyname("SHA256");
size_t longitudFirma = 0;

mctx = EVP_MD_CTX_new();

if (EVP_DigestSignInit(mctx, NULL, md, NULL, pkey)<=0) {
    return false;
}
if (EVP_DigestSignUpdate(mctx, digest, 32) <= 0) {
    return false;
}
if (EVP_DigestSignFinal(mctx, firma, &longitudFirma) <=0) {
    return false;
}

EVP_MD_CTX_free(mctx);
return true;
}
Tags:  ,

Answer

  1. Avatar for davy.ai

    Hay algunas cosas incorrectas en el código:

    1. fileName se declara pero luego se usa ecFileName en BIO_new_file, el cual no está definido. Debe ser fileName.
    2. Se crea la variable pkey2 pero luego PEM_read_bio_PrivateKey lee en pkey, el cual no está definido. Debe ser pkey2.

    3. El búfer sign se crea con un tamaño de 200, pero el tamaño de la firma no está garantizado de ser menor o igual a 200 bytes. Sería mejor asignar este búfer dinámicamente según el tamaño de EVP_PKEY_size de la clave.

    4. La función EVP_DigestSignInit no está recibiendo el objeto EVP_PKEY como clave de firma. Debe ser llamada con pkey2 en lugar de pkey.

    5. La función no devuelve la firma generada. Debe devolver sign y su longitud en lugar de solo devolver true.

    Aquí está el código corregido:

    bool sign(unsigned char *digest, unsigned char **sig, size_t *siglen) {
    
        const char *fileName = "ecc.pem";
        BIO *b_pem = BIO_new_file(fileName, "rb");
        if (!b_pem) {
            return false;
        }
    
        EVP_PKEY *pkey2 = PEM_read_bio_PrivateKey(b_pem, NULL, NULL, NULL);
        if (!pkey2) {
            BIO_free(b_pem);
            return false;
        }
    
        const EVP_MD *md = EVP_get_digestbyname("SHA256");
        if (!md) {
            EVP_PKEY_free(pkey2);
            BIO_free(b_pem);
            return false;
        }
    
        size_t sigsize = EVP_PKEY_size(pkey2);
        *sig = (unsigned char*)OPENSSL_malloc(sigsize);
        if (!*sig) {
            EVP_PKEY_free(pkey2);
            BIO_free(b_pem);
            return false;
        }
    
        EVP_MD_CTX *mctx = EVP_MD_CTX_new();
        if (!mctx) {
            OPENSSL_free(*sig);
            EVP_PKEY_free(pkey2);
            BIO_free(b_pem);
            return false;
        }
    
        if (EVP_DigestSignInit(mctx, NULL, md, NULL, pkey2) <= 0) {
            goto error;
        }
        if (EVP_DigestSignUpdate(mctx, digest, 32) <= 0) {
            goto error;
        }
        if (EVP_DigestSignFinal(mctx, *sig, siglen) <= 0) {
            goto error;
        }
    
        EVP_MD_CTX_free(mctx);
        EVP_PKEY_free(pkey2);
        BIO_free(b_pem);
        return true;
    
    error:
        EVP_MD_CTX_free(mctx);
        EVP_PKEY_free(pkey2);
        BIO_free(b_pem);
        OPENSSL_free(*sig);
        return false;
    }
    

    Esta función toma una entrada digest y devuelve la firma generada en sig junto con su longitud en siglen. Si ocurre un error, devuelve false y libera los recursos asignados.

Comments are closed.