summaryrefslogtreecommitdiff
path: root/src/rexmpp_digest.c
blob: c1dd436a26de29d7474470f1c7adbb4e49912f5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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;
}