Example devcrypto plugin: openssl_digest.c

This example illustrates how to implement a devcrypto plugin.

For more information, see “The devcrypto plugin API (devcrypto_plugin.h) and the entry for devcrypto in the Utilities Reference.

/*
 * $QNXLicenseC:
 * Copyright 2018, QNX Software Systems. All Rights Reserved.
 *
 * You must obtain a written license from and pay applicable license fees to QNX
 * Software Systems before you may reproduce, modify or distribute this software,
 * or any work that includes all or part of this software.   Free development
 * licenses are available for evaluation and non-commercial purposes.  For more
 * information visit http://licensing.qnx.com or email licensing@qnx.com.
 *
 * This file may contain contributions from others.  Please review this entire
 * file for other proprietary rights or license notices, as well as the QNX
 * Development Suite License Guide at http://licensing.qnx.com/license-guide/
 * for other information.
 * $
 */

#include <errno.h>
#include <stdlib.h>

#include <crypto/devcrypto_plugin.h>

#include <openssl/evp.h>

#include "openssl.h"

/*
 * Openssl digest context
 */
typedef struct _digest_ctx
{
    const EVP_MD    *md;       /* digest algorithm */
    EVP_MD_CTX      *mdctx;    /* digest context */
} digest_ctx;

/*
 * Openssl digest algorithm initialization
 *
 * @sctx: state context object
 * @alg: algorithm object
 *
 * Return:
 * - EOK on success
 * - errno on failure
 */
static int devcrypto_openssl_digest_alg_init(devcrypto_state_ctx_t *sctx)
{
	int ret = EOK;
	digest_ctx *ctx;

	ctx = calloc(1, sizeof(*ctx));
	if (!ctx) {
		ret = ENOMEM;
		goto done;
	}

	ctx->md = EVP_get_digestbyname(sctx->alg->name);
	if (!ctx->md) {
		ret = ELIBBAD;
		goto err;
	}

	ctx->mdctx = EVP_MD_CTX_create();
	if (!ctx->mdctx) {
		ret = ENOMEM;
		goto err;
	}

	sctx->data = ctx;
	ret = EOK;

	goto done;

err:
	free(ctx);

done:
	return ret;
}

/*
 * Openssl digest algorithm un-initialization
 *
 * @sctx: state context object
 *
 * Return:
 * - EOK on success
 */
static void devcrypto_openssl_digest_alg_uninit(devcrypto_state_ctx_t *sctx)
{
	digest_ctx *ctx = sctx->data;

	EVP_MD_CTX_destroy(ctx->mdctx);
	free(ctx);
}

/*
 * Openssl Digest Init
 *
 * @sctx: state context object
 *
 * Return:
 * - EOK on success
 * - errno on failure
 */
static int devcrypto_openssl_digest_init(devcrypto_state_ctx_t *sctx)
{
	int ret;
	digest_ctx *ctx = sctx->data;

	ret = EVP_DigestInit(ctx->mdctx, ctx->md);
	if (ret <= 0) {
		return ELIBBAD;
	}
	return EOK;
}

/*
 * Openssl Digest Update
 *
 * @sctx: state context object
 * @data: binary data to hash in digest
 * @size: size of @data
 *
 * Return:
 * - EOK on success
 * - errno on failure
 */
static int devcrypto_openssl_digest_update(devcrypto_state_ctx_t *sctx, const uint8_t *data, uint32_t size)
{
	int ret;
	digest_ctx *ctx = sctx->data;

	ret = EVP_DigestUpdate(ctx->mdctx, data, size);
	if (ret <= 0) {
		return ELIBBAD;
	}
	return EOK;
}

/*
 * Openssl Digest Init
 *
 * @sctx: state context object
 * @digest: buffer to store digest value
 * @size: pointer to store digest size
 *
 * Return:
 * - EOK on success
 * - errno on failure
 */
static int devcrypto_openssl_digest_final(devcrypto_state_ctx_t *sctx, uint8_t *digest, uint32_t *size)
{
	int ret;
	digest_ctx *ctx = sctx->data;
	unsigned int dsize;

	ret = EVP_DigestFinal(ctx->mdctx, digest, &dsize);
	if (ret <= 0) {
		return ELIBBAD;
	}

	if (size) {
		*size = (uint32_t)dsize;
	}

	return EOK;
}

/* Algorithms */

/*
 * Digests
 */
#define OPENSSL_DIGEST_ALG(dgstname, dgst, DGST)        \
static const devcrypto_algorithm_t dgst = {             \
    .name =    dgstname,                                \
    .type =    CRYPTO_ ## DGST,                         \
    .init =    devcrypto_openssl_digest_alg_init,       \
    .uninit =  devcrypto_openssl_digest_alg_uninit,     \
    .digest = {                                         \
        .params = {                                     \
            .digestsize =   DGST ## _DIGEST_SIZE,       \
            .blocksize =    DGST ## _BLOCK_SIZE,        \
        },                                              \
        .ops = {                                        \
            .init =     devcrypto_openssl_digest_init,  \
            .update =   devcrypto_openssl_digest_update,\
            .final =    devcrypto_openssl_digest_final, \
        },                                              \
    },                                                  \
};

/* Define algorithms */
OPENSSL_DIGEST_ALG("md5",md5,MD5)
OPENSSL_DIGEST_ALG("sha1",sha1,SHA1)
OPENSSL_DIGEST_ALG("sha224",sha224,SHA224)
OPENSSL_DIGEST_ALG("sha256",sha256,SHA256)
OPENSSL_DIGEST_ALG("sha384",sha384,SHA384)
OPENSSL_DIGEST_ALG("sha512",sha512,SHA512)
OPENSSL_DIGEST_ALG("sha512-224",sha512_224,SHA512_224)
OPENSSL_DIGEST_ALG("sha512-256",sha512_256,SHA512_256)

/*
 * TODO
 */
void devcrypto_openssl_digest_register(void)
{
	devcrypto_plugin_register_algorithm(&md5);
	devcrypto_plugin_register_algorithm(&sha1);
	devcrypto_plugin_register_algorithm(&sha224);
	devcrypto_plugin_register_algorithm(&sha256);
	devcrypto_plugin_register_algorithm(&sha384);
	devcrypto_plugin_register_algorithm(&sha512);
	devcrypto_plugin_register_algorithm(&sha512_224);
	devcrypto_plugin_register_algorithm(&sha512_256);
}