diff options
Diffstat (limited to 'src/rexmpp_digest.c')
-rw-r--r-- | src/rexmpp_digest.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/rexmpp_digest.c b/src/rexmpp_digest.c new file mode 100644 index 0000000..c1dd436 --- /dev/null +++ b/src/rexmpp_digest.c @@ -0,0 +1,125 @@ +/** + @file rexmpp_digest.c + @brief Cryptographic functions + @author defanor <defanor@uberspace.net> + @date 2023 + @copyright MIT license. +*/ + +#include "config.h" +#include "rexmpp_digest.h" + +#if defined(HAVE_GCRYPT) +#include <gcrypt.h> +#elif defined(HAVE_NETTLE) +#include <nettle/nettle-meta.h> +#include <stdlib.h> +#elif defined(HAVE_OPENSSL) +#include <openssl/evp.h> +#endif + +size_t rexmpp_digest_len (rexmpp_digest_algorithm algo) { + switch (algo) { + case REXMPP_DIGEST_SHA1: return 20; + case REXMPP_DIGEST_SHA256: return 32; + case REXMPP_DIGEST_SHA3_256: return 32; + default: return 0; + } +} + +int rexmpp_digest_buffer (rexmpp_digest_algorithm algo, + const void *in, + size_t in_len, + void *out, + size_t out_len) +{ + rexmpp_digest_t ctx; + int err = rexmpp_digest_init(&ctx, algo); + if (err) { + return err; + } + err = rexmpp_digest_update(&ctx, in, in_len); + if (err) { + return err; + } + return rexmpp_digest_finish(&ctx, out, out_len); +} + +int rexmpp_digest_init (rexmpp_digest_t *ctx, rexmpp_digest_algorithm algo) { +#if defined(HAVE_GCRYPT) + int gcry_algo = GCRY_MD_NONE; + switch (algo) { + case REXMPP_DIGEST_SHA1: gcry_algo = GCRY_MD_SHA1; break; + case REXMPP_DIGEST_SHA256: gcry_algo = GCRY_MD_SHA256; break; + case REXMPP_DIGEST_SHA3_256: gcry_algo = GCRY_MD_SHA3_256; break; + default: return -1; + } + gcry_error_t err = gcry_md_open(ctx, gcry_algo, 0); + if (err != GPG_ERR_NO_ERROR) { + return -1; + } +#elif defined(HAVE_NETTLE) + ctx->nh = NULL; + switch (algo) { + case REXMPP_DIGEST_SHA1: ctx->nh = &nettle_sha1; break; + case REXMPP_DIGEST_SHA256: ctx->nh = &nettle_sha256; break; + case REXMPP_DIGEST_SHA3_256: ctx->nh = &nettle_sha3_256; break; + default: return -1; + } + ctx->nh_ctx = malloc(ctx->nh->context_size); + ctx->nh->init(ctx->nh_ctx); +#elif defined(HAVE_OPENSSL) + const EVP_MD *md = NULL; + switch (algo) { + case REXMPP_DIGEST_SHA1: md = EVP_sha1(); break; + case REXMPP_DIGEST_SHA256: md = EVP_sha256(); break; + case REXMPP_DIGEST_SHA3_256: md = EVP_sha3_256(); break; + default: return -1; + } + *ctx = EVP_MD_CTX_new(); + if (! EVP_DigestInit(*ctx, md)) { + EVP_MD_CTX_free(*ctx); + return -1; + } +#endif + return 0; +} + +int rexmpp_digest_update (rexmpp_digest_t *ctx, const void *in, size_t len) { +#if defined(HAVE_GCRYPT) + gcry_md_write(*ctx, in, len); +#elif defined(HAVE_NETTLE) + ctx->nh->update(ctx->nh_ctx, len, in); +#elif defined(HAVE_OPENSSL) + if (! EVP_DigestUpdate(*ctx, in, len)) { + return -1; + } +#endif + return 0; +} + +int rexmpp_digest_finish (rexmpp_digest_t *ctx, void *out, size_t len) { + int ret = 0; +#if defined(HAVE_GCRYPT) + if (out != NULL) { + unsigned char *result = gcry_md_read(*ctx, 0); + if (result != NULL) { + memcpy(out, result, len); + } else { + ret = -1; + } + } + gcry_md_close(*ctx); +#elif defined(HAVE_NETTLE) + ctx->nh->digest(ctx->nh_ctx, len, out); + free(ctx->nh_ctx); +#elif defined(HAVE_OPENSSL) + (void)len; + if (! EVP_DigestFinal_ex(*ctx, out, NULL)) { + ret = -1; + } + EVP_MD_CTX_free(*ctx); + *ctx = NULL; +#endif + return ret; +} |