diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-11-15 12:28:07 +0200 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2013-11-16 12:52:17 +0200 |
commit | fcd6da37d55f248d3558ee0ff385b41b866e7ded (patch) | |
tree | b942fea4e29d43427b4e5c221d8c40455e6b8cfe /cipher | |
parent | b95a557a43aeed68ea5e5ce02aca42ee97bfdb3b (diff) | |
download | libgcrypt-fcd6da37d55f248d3558ee0ff385b41b866e7ded.tar.gz |
Add new MAC API, initially with HMAC
* cipher/Makefile.am: Add 'mac.c', 'mac-internal.h' and 'mac-hmac.c'.
* cipher/bufhelp.h (buf_eq_const): New.
* cipher/cipher-ccm.c (_gcry_cipher_ccm_tag): Use 'buf_eq_const' for
constant-time compare.
* cipher/mac-hmac.c: New.
* cipher/mac-internal.h: New.
* cipher/mac.c: New.
* doc/gcrypt.texi: Add documentation for MAC API.
* src/gcrypt-int.h [GPG_ERROR_VERSION_NUMBER < 1.13]
(GPG_ERR_MAC_ALGO): New.
* src/gcrypt.h.in (gcry_mac_handle, gcry_mac_hd_t, gcry_mac_algos)
(gcry_mac_flags, gcry_mac_open, gcry_mac_close, gcry_mac_ctl)
(gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write)
(gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen)
(gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name)
(gcry_mac_reset, gcry_mac_test_algo): New.
* src/libgcrypt.def (gcry_mac_open, gcry_mac_close, gcry_mac_ctl)
(gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write)
(gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen)
(gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New.
* src/libgcrypt.vers (gcry_mac_open, gcry_mac_close, gcry_mac_ctl)
(gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write)
(gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen)
(gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New.
* src/visibility.c (gcry_mac_open, gcry_mac_close, gcry_mac_ctl)
(gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write)
(gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen)
(gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New.
* src/visibility.h (gcry_mac_open, gcry_mac_close, gcry_mac_ctl)
(gcry_mac_algo_info, gcry_mac_setkey, gcry_mac_setiv, gcry_mac_write)
(gcry_mac_read, gcry_mac_verify, gcry_mac_get_algo_maclen)
(gcry_mac_get_algo_keylen, gcry_mac_algo_name, gcry_mac_map_name): New.
* tests/basic.c (check_one_mac, check_mac): New.
(main): Call 'check_mac'.
* tests/bench-slope.c (bench_print_header, bench_print_footer): Allow
variable algorithm name width.
(_cipher_bench, hash_bench): Update to above change.
(bench_hash_do_bench): Add 'gcry_md_reset'.
(bench_mac_mode, bench_mac_init, bench_mac_free, bench_mac_do_bench)
(mac_ops, mac_modes, mac_bench_one, _mac_bench, mac_bench): New.
(main): Add 'mac' benchmark options.
* tests/benchmark.c (mac_repetitions, mac_bench): New.
(main): Add 'mac' benchmark options.
--
Add MAC API, with HMAC algorithms. Internally uses HMAC functionality of the
MD module.
[v2]:
- Add documentation for MAC API.
- Change length argument for gcry_mac_read from size_t to size_t* for
returning number of written bytes.
[v3]:
- HMAC algorithm ids start from 101.
- Fix coding style for new files.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/Makefile.am | 2 | ||||
-rw-r--r-- | cipher/bufhelp.h | 17 | ||||
-rw-r--r-- | cipher/cipher-ccm.c | 13 | ||||
-rw-r--r-- | cipher/mac-hmac.c | 272 | ||||
-rw-r--r-- | cipher/mac-internal.h | 140 | ||||
-rw-r--r-- | cipher/mac.c | 447 |
6 files changed, 882 insertions, 9 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 95d484e6..1d54b078 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -44,6 +44,8 @@ cipher-ccm.c \ cipher-selftest.c cipher-selftest.h \ pubkey.c pubkey-internal.h pubkey-util.c \ md.c \ +mac.c mac-internal.h \ +mac-hmac.c \ kdf.c kdf-internal.h \ hmac-tests.c \ bithelp.h \ diff --git a/cipher/bufhelp.h b/cipher/bufhelp.h index dc39b46d..45a72094 100644 --- a/cipher/bufhelp.h +++ b/cipher/bufhelp.h @@ -220,6 +220,23 @@ buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len) } +/* Constant-time compare of two buffers. Returns 1 if buffers are equal, + and 0 if buffers differ. */ +static inline int +buf_eq_const(const void *_a, const void *_b, size_t len) +{ + const byte *a = _a; + const byte *b = _b; + size_t diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < len; i++) + diff -= !!(a[i] - b[i]); + + return !diff; +} + + #ifndef BUFHELP_FAST_UNALIGNED_ACCESS /* Functions for loading and storing unaligned u32 values of different diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c index 2a1fc74a..1eba7f0f 100644 --- a/cipher/cipher-ccm.c +++ b/cipher/cipher-ccm.c @@ -289,13 +289,8 @@ _gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, } else { - int diff, i; - - /* Constant-time compare. */ - for (i = 0, diff = 0; i < outbuflen; i++) - diff -= !!(outbuf[i] - c->u_iv.iv[i]); - - return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; } } @@ -304,7 +299,7 @@ gcry_err_code_t _gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, size_t taglen) { - return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); } @@ -312,7 +307,7 @@ gcry_err_code_t _gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, size_t taglen) { - return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); } diff --git a/cipher/mac-hmac.c b/cipher/mac-hmac.c new file mode 100644 index 00000000..46b21b15 --- /dev/null +++ b/cipher/mac-hmac.c @@ -0,0 +1,272 @@ +/* mac-hmac.c - HMAC glue for MAC API + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "./mac-internal.h" +#include "bufhelp.h" + + +static int +map_mac_algo_to_md (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_MD_NONE; + case GCRY_MAC_HMAC_MD4: + return GCRY_MD_MD4; + case GCRY_MAC_HMAC_MD5: + return GCRY_MD_MD5; + case GCRY_MAC_HMAC_SHA1: + return GCRY_MD_SHA1; + case GCRY_MAC_HMAC_SHA224: + return GCRY_MD_SHA224; + case GCRY_MAC_HMAC_SHA256: + return GCRY_MD_SHA256; + case GCRY_MAC_HMAC_SHA384: + return GCRY_MD_SHA384; + case GCRY_MAC_HMAC_SHA512: + return GCRY_MD_SHA512; + case GCRY_MAC_HMAC_RMD160: + return GCRY_MD_RMD160; + case GCRY_MAC_HMAC_TIGER1: + return GCRY_MD_TIGER1; + case GCRY_MAC_HMAC_WHIRLPOOL: + return GCRY_MD_WHIRLPOOL; + case GCRY_MAC_HMAC_GOSTR3411_94: + return GCRY_MD_GOSTR3411_94; + case GCRY_MAC_HMAC_STRIBOG256: + return GCRY_MD_STRIBOG256; + case GCRY_MAC_HMAC_STRIBOG512: + return GCRY_MD_STRIBOG512; + } +} + + +static gcry_err_code_t +hmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_md_hd_t hd; + int secure = (h->magic == CTX_MAGIC_SECURE); + unsigned int flags; + int md_algo; + + md_algo = map_mac_algo_to_md (h->spec->algo); + + flags = GCRY_MD_FLAG_HMAC; + flags |= (secure ? GCRY_MD_FLAG_SECURE : 0); + + err = gcry_md_open (&hd, md_algo, flags); + if (err) + return err; + + h->u.hmac.md_algo = md_algo; + h->u.hmac.md_ctx = hd; + return 0; +} + + +static void +hmac_close (gcry_mac_hd_t h) +{ + gcry_md_close (h->u.hmac.md_ctx); + h->u.hmac.md_ctx = NULL; +} + + +static gcry_err_code_t +hmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return gcry_md_setkey (h->u.hmac.md_ctx, key, keylen); +} + + +static gcry_err_code_t +hmac_reset (gcry_mac_hd_t h) +{ + gcry_md_reset (h->u.hmac.md_ctx); + return 0; +} + + +static gcry_err_code_t +hmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + gcry_md_write (h->u.hmac.md_ctx, buf, buflen); + return 0; +} + + +static gcry_err_code_t +hmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + unsigned int dlen; + const unsigned char *digest; + + dlen = gcry_md_get_algo_dlen (h->u.hmac.md_algo); + digest = gcry_md_read (h->u.hmac.md_ctx, h->u.hmac.md_algo); + + if (*outlen <= dlen) + buf_cpy (outbuf, digest, *outlen); + else + { + buf_cpy (outbuf, digest, dlen); + *outlen = dlen; + } + + return 0; +} + + +static gcry_err_code_t +hmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + unsigned int dlen; + const unsigned char *digest; + + dlen = gcry_md_get_algo_dlen (h->u.hmac.md_algo); + digest = gcry_md_read (h->u.hmac.md_ctx, h->u.hmac.md_algo); + + if (buflen > dlen) + return GPG_ERR_INV_LENGTH; + + return buf_eq_const (buf, digest, buflen) ? 0 : GPG_ERR_CHECKSUM; +} + + +static unsigned int +hmac_get_maclen (int algo) +{ + return gcry_md_get_algo_dlen (map_mac_algo_to_md (algo)); +} + + +static unsigned int +hmac_get_keylen (int algo) +{ + /* Return blocksize for default key length. */ + switch (algo) + { + case GCRY_MAC_HMAC_SHA384: + case GCRY_MAC_HMAC_SHA512: + return 128; + case GCRY_MAC_HMAC_GOSTR3411_94: + return 32; + default: + return 64; + } +} + + +static const gcry_mac_spec_ops_t hmac_ops = { + hmac_open, + hmac_close, + hmac_setkey, + NULL, + hmac_reset, + hmac_write, + hmac_read, + hmac_verify, + hmac_get_maclen, + hmac_get_keylen +}; + + +#if USE_SHA1 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha1 = { + GCRY_MAC_HMAC_SHA1, {0, 1}, "HMAC_SHA1", + &hmac_ops +}; +#endif +#if USE_SHA256 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha256 = { + GCRY_MAC_HMAC_SHA256, {0, 1}, "HMAC_SHA256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha224 = { + GCRY_MAC_HMAC_SHA224, {0, 1}, "HMAC_SHA224", + &hmac_ops +}; +#endif +#if USE_SHA512 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512 = { + GCRY_MAC_HMAC_SHA512, {0, 1}, "HMAC_SHA512", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha384 = { + GCRY_MAC_HMAC_SHA384, {0, 1}, "HMAC_SHA384", + &hmac_ops +}; +#endif +#ifdef USE_GOST_R_3411_94 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_94 = { + GCRY_MAC_HMAC_GOSTR3411_94, {0, 0}, "HMAC_GOSTR3411_94", + &hmac_ops +}; +#endif +#ifdef USE_GOST_R_3411_12 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog256 = { + GCRY_MAC_HMAC_STRIBOG256, {0, 0}, "HMAC_STRIBOG256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog512 = { + GCRY_MAC_HMAC_STRIBOG512, {0, 0}, "HMAC_STRIBOG512", + &hmac_ops +}; +#endif +#if USE_WHIRLPOOL +gcry_mac_spec_t _gcry_mac_type_spec_hmac_whirlpool = { + GCRY_MAC_HMAC_WHIRLPOOL, {0, 0}, "HMAC_WHIRLPOOL", + &hmac_ops +}; +#endif +#if USE_RMD160 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_rmd160 = { + GCRY_MAC_HMAC_RMD160, {0, 0}, "HMAC_RIPEMD160", + &hmac_ops +}; +#endif +#if USE_TIGER +gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1 = { + GCRY_MAC_HMAC_TIGER1, {0, 0}, "HMAC_TIGER", + &hmac_ops +}; +#endif +#if USE_MD5 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5 = { + GCRY_MAC_HMAC_MD5, {0, 0}, "HMAC_MD5", + &hmac_ops +}; +#endif +#if USE_MD4 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md4 = { + GCRY_MAC_HMAC_MD4, {0, 0}, "HMAC_MD4", + &hmac_ops +}; +#endif diff --git a/cipher/mac-internal.h b/cipher/mac-internal.h new file mode 100644 index 00000000..9ebc0357 --- /dev/null +++ b/cipher/mac-internal.h @@ -0,0 +1,140 @@ +/* mac-internal.h - Internal defs for mac.c + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* The data object used to hold a handle to an encryption object. */ +struct gcry_mac_handle; +typedef struct gcry_mac_handle *gcry_mac_hd_t; + + +/* + * + * Message authentication code related definitions. + * + */ + + +/* Magic values for the context structure. */ +#define CTX_MAGIC_NORMAL 0x59d9b8af +#define CTX_MAGIC_SECURE 0x12c27cd0 + + +/* MAC module functions. */ +typedef gcry_err_code_t (*gcry_mac_open_func_t)(gcry_mac_hd_t h); +typedef void (*gcry_mac_close_func_t)(gcry_mac_hd_t h); +typedef gcry_err_code_t (*gcry_mac_setkey_func_t)(gcry_mac_hd_t h, + const unsigned char *key, + size_t keylen); +typedef gcry_err_code_t (*gcry_mac_setiv_func_t)(gcry_mac_hd_t h, + const unsigned char *iv, + size_t ivlen); +typedef gcry_err_code_t (*gcry_mac_reset_func_t)(gcry_mac_hd_t h); +typedef gcry_err_code_t (*gcry_mac_write_func_t)(gcry_mac_hd_t h, + const unsigned char *inbuf, + size_t inlen); +typedef gcry_err_code_t (*gcry_mac_read_func_t)(gcry_mac_hd_t h, + unsigned char *outbuf, + size_t *outlen); +typedef gcry_err_code_t (*gcry_mac_verify_func_t)(gcry_mac_hd_t h, + const unsigned char *inbuf, + size_t inlen); +typedef unsigned int (*gcry_mac_get_maclen_func_t)(int algo); +typedef unsigned int (*gcry_mac_get_keylen_func_t)(int algo); + + +typedef struct gcry_mac_spec_ops +{ + gcry_mac_open_func_t open; + gcry_mac_close_func_t close; + gcry_mac_setkey_func_t setkey; + gcry_mac_setiv_func_t setiv; + gcry_mac_reset_func_t reset; + gcry_mac_write_func_t write; + gcry_mac_read_func_t read; + gcry_mac_verify_func_t verify; + gcry_mac_get_maclen_func_t get_maclen; + gcry_mac_get_keylen_func_t get_keylen; +} gcry_mac_spec_ops_t; + + +/* Module specification structure for message authentication codes. */ +typedef struct gcry_mac_spec +{ + int algo; + struct { + unsigned int disabled:1; + unsigned int fips:1; + } flags; + const char *name; + const gcry_mac_spec_ops_t *ops; +} gcry_mac_spec_t; + + + +/* The handle structure. */ +struct gcry_mac_handle +{ + int magic; + int algo; + const gcry_mac_spec_t *spec; + gcry_ctx_t gcry_ctx; + union { + struct { + gcry_md_hd_t md_ctx; + int md_algo; + } hmac; + } u; +}; + + +/* + * The HMAC algorithm specifications (mac-hmac.c). + */ +#if USE_SHA1 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha1; +#endif +#if USE_SHA256 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha224; +#endif +#if USE_SHA512 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha384; +#endif +#ifdef USE_GOST_R_3411_94 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_94; +#endif +#ifdef USE_GOST_R_3411_12 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog512; +#endif +#if USE_WHIRLPOOL +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_whirlpool; +#endif +#if USE_RMD160 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_rmd160; +#endif +#if USE_TIGER +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1; +#endif +#if USE_MD5 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5; +#endif +#if USE_MD4 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_md4; +#endif diff --git a/cipher/mac.c b/cipher/mac.c new file mode 100644 index 00000000..9708b3a6 --- /dev/null +++ b/cipher/mac.c @@ -0,0 +1,447 @@ +/* mac.c - message authentication code dispatcher + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mac-internal.h" + + +/* This is the list of the digest implementations included in + libgcrypt. */ +static gcry_mac_spec_t *mac_list[] = { +#if USE_SHA1 + &_gcry_mac_type_spec_hmac_sha1, +#endif +#if USE_SHA256 + &_gcry_mac_type_spec_hmac_sha256, + &_gcry_mac_type_spec_hmac_sha224, +#endif +#if USE_SHA512 + &_gcry_mac_type_spec_hmac_sha512, + &_gcry_mac_type_spec_hmac_sha384, +#endif +#ifdef USE_GOST_R_3411_94 + &_gcry_mac_type_spec_hmac_gost3411_94, +#endif +#ifdef USE_GOST_R_3411_12 + &_gcry_mac_type_spec_hmac_stribog256, + &_gcry_mac_type_spec_hmac_stribog512, +#endif +#if USE_WHIRLPOOL + &_gcry_mac_type_spec_hmac_whirlpool, +#endif +#if USE_RMD160 + &_gcry_mac_type_spec_hmac_rmd160, +#endif +#if USE_TIGER + &_gcry_mac_type_spec_hmac_tiger1, +#endif +#if USE_MD5 + &_gcry_mac_type_spec_hmac_md5, +#endif +#if USE_MD4 + &_gcry_mac_type_spec_hmac_md4, +#endif + NULL, +}; + + + +/* Return the spec structure for the MAC algorithm ALGO. For an + unknown algorithm NULL is returned. */ +static gcry_mac_spec_t * +spec_from_algo (int algo) +{ + gcry_mac_spec_t *spec; + int idx; + + for (idx = 0; (spec = mac_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; +} + + +/* Lookup a mac's spec by its name. */ +static gcry_mac_spec_t * +spec_from_name (const char *name) +{ + gcry_mac_spec_t *spec; + int idx; + + for (idx = 0; (spec = mac_list[idx]); idx++) + if (!stricmp (name, spec->name)) + return spec; + + return NULL; +} + + +/**************** + * Map a string to the mac algo + */ +int +gcry_mac_map_name (const char *string) +{ + gcry_mac_spec_t *spec; + + if (!string) + return 0; + + /* Not found, search a matching mac name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; + + return 0; +} + + +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + * Use the macro gcry_mac_test_algo() to check whether the algorithm + * is valid. + */ +const char * +gcry_mac_algo_name (int algorithm) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec ? spec->name : "?"; +} + + +static gcry_err_code_t +check_mac_algo (int algorithm) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; + + return GPG_ERR_MAC_ALGO; +} + + +/**************** + * Open a message digest handle for use with algorithm ALGO. + */ +static gcry_err_code_t +mac_open (gcry_mac_hd_t * hd, int algo, int secure, gcry_ctx_t ctx) +{ + gcry_mac_spec_t *spec; + gcry_err_code_t err; + gcry_mac_hd_t h; + + spec = spec_from_algo (algo); + if (!spec) + return GPG_ERR_MAC_ALGO; + else if (spec->flags.disabled) + return GPG_ERR_MAC_ALGO; + else if (!spec->ops) + return GPG_ERR_MAC_ALGO; + else if (!spec->ops->open || !spec->ops->write || !spec->ops->setkey || + !spec->ops->read || !spec->ops->verify || !spec->ops->reset) + return GPG_ERR_MAC_ALGO; + + if (secure) + h = gcry_calloc_secure (1, sizeof (*h)); + else + h = gcry_calloc (1, sizeof (*h)); + + if (!h) + return gpg_err_code_from_syserror (); + + h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + h->spec = spec; + h->algo = algo; + h->gcry_ctx = ctx; + + err = h->spec->ops->open (h); + if (err) + gcry_free (h); + else + *hd = h; + + return err; +} + + +static gcry_error_t +mac_reset (gcry_mac_hd_t hd) +{ + if (hd->spec->ops->reset) + return hd->spec->ops->reset (hd); + + return 0; +} + + +static void +mac_close (gcry_mac_hd_t hd) +{ + if (hd->spec->ops->close) + hd->spec->ops->close (hd); + + wipememory (hd, sizeof (*hd)); + + gcry_free (hd); +} + + +static gcry_error_t +mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) +{ + if (!hd->spec->ops->setkey) + return GPG_ERR_INV_ARG; + if (keylen > 0 && !key) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->setkey (hd, key, keylen); +} + + +static gcry_error_t +mac_setiv (gcry_mac_hd_t hd, const void *iv, size_t ivlen) +{ + if (!hd->spec->ops->setiv) + return GPG_ERR_INV_ARG; + if (ivlen > 0 && !iv) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->setiv (hd, iv, ivlen); +} + + +static gcry_error_t +mac_write (gcry_mac_hd_t hd, const void *inbuf, size_t inlen) +{ + if (!hd->spec->ops->write) + return GPG_ERR_INV_ARG; + if (inlen > 0 && !inbuf) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->write (hd, inbuf, inlen); +} + + +static gcry_error_t +mac_read (gcry_mac_hd_t hd, void *outbuf, size_t * outlen) +{ + if (!outbuf || !outlen || *outlen == 0 || !hd->spec->ops->read) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->read (hd, outbuf, outlen); +} + + +static gcry_error_t +mac_verify (gcry_mac_hd_t hd, const void *buf, size_t buflen) +{ + if (!buf || buflen == 0 || !hd->spec->ops->verify) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->verify (hd, buf, buflen); +} + + +/* Create a MAC object for algorithm ALGO. FLAGS may be + given as an bitwise OR of the gcry_mac_flags values. + H is guaranteed to be a valid handle or NULL on error. */ +gcry_error_t +gcry_mac_open (gcry_mac_hd_t * h, int algo, unsigned int flags, + gcry_ctx_t ctx) +{ + gcry_err_code_t err; + gcry_mac_hd_t hd = NULL; + + if ((flags & ~GCRY_MAC_FLAG_SECURE)) + err = GPG_ERR_INV_ARG; + else + err = mac_open (&hd, algo, !!(flags & GCRY_MAC_FLAG_SECURE), ctx); + + *h = err ? NULL : hd; + return gpg_error (err); +} + + +void +gcry_mac_close (gcry_mac_hd_t hd) +{ + mac_close (hd); +} + + +gcry_error_t +gcry_mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) +{ + gcry_error_t err; + + err = mac_setkey (hd, key, keylen); + + return gpg_error (err); +} + + +gcry_error_t +gcry_mac_setiv (gcry_mac_hd_t hd, const void *iv, size_t ivlen) +{ + gcry_error_t err; + + err = mac_setiv (hd, iv, ivlen); + + return gpg_error (err); +} + + +gcry_error_t +gcry_mac_write (gcry_mac_hd_t hd, const void *inbuf, size_t inlen) +{ + gcry_err_code_t err; + + err = mac_write (hd, inbuf, inlen); + + return gpg_error (err); +} + + +gcry_error_t +gcry_mac_read (gcry_mac_hd_t hd, void *outbuf, size_t * outlen) +{ + gcry_error_t err; + + err = mac_read (hd, outbuf, outlen); + + return gpg_error (err); +} + + +gcry_error_t +gcry_mac_verify (gcry_mac_hd_t hd, const void *buf, size_t buflen) +{ + gcry_err_code_t err; + + err = mac_verify (hd, buf, buflen); + + return gpg_error (err); +} + + +unsigned int +gcry_mac_get_algo_maclen (int algo) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec || !spec->ops || !spec->ops->get_maclen) + return 0; + + return spec->ops->get_maclen (algo); +} + + +unsigned int +gcry_mac_get_algo_keylen (int algo) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec || !spec->ops || !spec->ops->get_keylen) + return 0; + + return spec->ops->get_keylen (algo); +} + + +gcry_error_t +gcry_mac_ctl (gcry_mac_hd_t hd, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = GPG_ERR_NO_ERROR; + + /* Currently not used. */ + (void) hd; + (void) buffer; + (void) buflen; + + switch (cmd) + { + case GCRYCTL_RESET: + rc = mac_reset (hd); + break; + default: + rc = GPG_ERR_INV_OP; + } + return gcry_error (rc); +} + + +/* Return information about the given MAC algorithm ALGO. + + GCRYCTL_TEST_ALGO: + Returns 0 if the specified algorithm ALGO is available for use. + BUFFER and NBYTES must be zero. + + Note: Because this function is in most cases used to return an + integer value, we can make it easier for the caller to just look at + the return value. The caller will in all cases consult the value + and thereby detecting whether a error occurred or not (i.e. while + checking the block size) + */ +gcry_error_t +gcry_mac_algo_info (int algo, int what, void *buffer, size_t * nbytes) +{ + gcry_err_code_t err = GPG_ERR_NO_ERROR; + unsigned int ui; + + switch (what) + { + case GCRYCTL_GET_KEYLEN: + if (buffer || (!nbytes)) + err = GPG_ERR_INV_ARG; + else + { + ui = gcry_mac_get_algo_keylen (algo); + if (ui > 0) + *nbytes = (size_t) ui; + else + /* The only reason for an error is an invalid algo. */ + err = GPG_ERR_MAC_ALGO; + } + break; + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + err = GPG_ERR_INV_ARG; + else + err = check_mac_algo (algo); + break; + + default: + err = GPG_ERR_INV_OP; + } + + return gcry_error (err); +} |