024d802014-04-21Henrik Grubbström (Grubba) /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */ #include "global.h" #include "interpret.h" #include "svalue.h" #include "threads.h" /* For this_object() */ #include "object.h" #include "module_support.h" #include "pike_memory.h" #include "nettle_config.h" #ifdef HAVE_LIBNETTLE DECLARATIONS #include "nettle.h" #ifdef HAVE_NETTLE_POLY1305_H #include <nettle/poly1305.h> #endif #ifdef HAVE_NETTLE_UMAC_H #include <nettle/umac.h> #endif #include <stdarg.h> #include "fdlib.h" /*! @module Nettle */ struct pike_mac { const char *name;
13670c2015-05-25Martin Nilsson 
024d802014-04-21Henrik Grubbström (Grubba)  unsigned context_size; unsigned digest_size; unsigned block_size; /* Suggested key size; other sizes are sometimes possible. */ unsigned key_size; unsigned iv_size;
8ea45f2014-04-22Henrik Grubbström (Grubba)  /* NB: Use nettle_hash_update_func here to get both a length field, * and a const uint8_t source. */
fd073e2014-06-23Henrik Grubbström (Grubba)  pike_nettle_hash_update_func set_key; pike_nettle_hash_update_func set_iv;
024d802014-04-21Henrik Grubbström (Grubba) 
fd073e2014-06-23Henrik Grubbström (Grubba)  pike_nettle_hash_update_func update; pike_nettle_hash_digest_func digest;
024d802014-04-21Henrik Grubbström (Grubba) };
d61b142014-10-24Henrik Grubbström (Grubba) #define _PIKE_MAC(name, NAME) { \ #name, \ sizeof(struct name##_ctx), \ NAME##_DIGEST_SIZE, \ NAME##_BLOCK_SIZE, \ NAME##_KEY_SIZE, \ NAME##_IV_SIZE, \ (pike_nettle_hash_update_func)pike_##name##_set_key, \ (pike_nettle_hash_update_func)pike_##name##_set_iv, \ (pike_nettle_hash_update_func)name##_update, \ (pike_nettle_hash_digest_func)name##_digest, \ }
024d802014-04-21Henrik Grubbström (Grubba)  /*! @class MAC *! *! Represents information about a MAC algorithm, such as *! name, key size, digest size, and internal block size. */ PIKECLASS MAC { /*! @decl inherit __builtin.Nettle.MAC */ INHERIT "__builtin.Nettle.MAC"; CVAR const struct pike_mac *meta; /*! @decl string(0..255) name(void) *! *! Returns a human readable name for the algorithm. */ PIKEFUN string(0..255) name() optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("MAC not properly initialized.\n"); push_text(THIS->meta->name); } /*! @decl int(0..) digest_size(void) *! *! Returns the size of a MAC digest. */ PIKEFUN int(0..) digest_size() optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("MAC not properly initialized.\n"); push_int(THIS->meta->digest_size); } /*! @decl int(0..) block_size(void) *! *! Returns the internal block size of the MAC algorithm. */ PIKEFUN int(0..) block_size() optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("MAC not properly initialized.\n"); push_int(THIS->meta->block_size); } /*! @decl int(0..) key_size(void) *! *! Returns the recommended size for the secret key for the MAC algorithm. */ PIKEFUN int(0..) key_size() optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("MAC not properly initialized.\n"); push_int(THIS->meta->key_size); } /*! @decl int(0..) iv_size(void) *! *! Returns the size of the iv/nonce of the MAC algorithm (if any). *! *! Returns @expr{0@} (zero) if there is no configurable iv/nonce. */ PIKEFUN int(0..) iv_size() optflags OPT_TRY_OPTIMIZE; { if (!THIS->meta) Pike_error("MAC not properly initialized.\n"); push_int(THIS->meta->iv_size); } INIT { THIS->meta = NULL; } /*! @class State *! *! Base class for MAC contexts. */ PIKECLASS State
9e336b2014-06-19Henrik Grubbström (Grubba)  program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE;
024d802014-04-21Henrik Grubbström (Grubba)  { DOCSTART() @decl inherit MAC::State DOCEND() EXTRA { /* Perform an inherit of the State class (if any) that our parent * may contain via its inherit of __builtin.Nettle.MAC. */ struct program *parent_prog = Pike_compiler->previous->new_program; struct object *parent_obj = Pike_compiler->previous->fake_object; int parent_State_fun_num = really_low_find_shared_string_identifier(MK_STRING("State"), parent_prog, SEE_PROTECTED|SEE_PRIVATE); if (parent_State_fun_num >= 0) { struct program *parent_State_prog = low_program_from_function(parent_obj, parent_State_fun_num); if (parent_State_prog) {
27b78a2014-10-06Henrik Grubbström (Grubba)  parent_State_fun_num = really_low_reference_inherited_identifier(Pike_compiler->previous, 0, parent_State_fun_num);
024d802014-04-21Henrik Grubbström (Grubba)  low_inherit(parent_State_prog, 0,
27b78a2014-10-06Henrik Grubbström (Grubba)  parent_State_fun_num,
024d802014-04-21Henrik Grubbström (Grubba)  1 + 42, 0, NULL); } } } #define GET_META(o) \
13e2ba2014-04-26Henrik Grubbström (Grubba)  ( ((struct Nettle_MAC_struct *)parent_storage(1, Nettle_MAC_program))->meta )
024d802014-04-21Henrik Grubbström (Grubba)  CVAR void *ctx; /*! @decl void create(string(8bit) key) *! *! Initialize the MAC with a password. *! *! It also resets any iv/nonce to it's default. */ PIKEFUN void create(string(8bit) key) flags ID_PROTECTED; { void *ctx = THIS->ctx; const struct pike_mac *meta = GET_META(Pike_fp->current_object); key->flags |= STRING_CLEAR_ON_EXIT; NO_WIDE_STRING(key); meta->set_key(ctx, key->len, STR0(key)); pop_n_elems(args); } /*! @decl State set_iv(string(0..255) iv) *! *! Set the iv/nonce (if supported) for the MAC. *! *! @returns *! Returns @expr{this@} in order to simplify chaining *! of function calls. */ PIKEFUN object set_iv(string(0..255) iv) optflags OPT_SIDE_EFFECT; rawtype tFunc(tStr8, tObjImpl_NETTLE_MAC_STATE); { void *ctx = THIS->ctx; const struct pike_mac *meta = GET_META(Pike_fp->current_object); if (!ctx || !meta) Pike_error("State not properly initialized.\n"); iv->flags |= STRING_CLEAR_ON_EXIT; NO_WIDE_STRING(iv);
4607cf2014-05-10Henrik Grubbström (Grubba)  /* NB: Check iv length here so that we can use the * Nettle implementation straight in meta->set_iv. */
0695b42014-11-05Martin Nilsson  if (((unsigned)iv->len > meta->iv_size) || !meta->iv_size) {
024d802014-04-21Henrik Grubbström (Grubba)  Pike_error("Invalid iv/nonce.\n"); } meta->set_iv(ctx, iv->len, STR0(iv)); push_object(this_object()); } /*! @decl State update(string(0..255) data) *! *! Hashes more data. *! *! @returns *! Returns @expr{this@} in order to simplify chaining *! of function calls. */ PIKEFUN object update(string(0..255) data) optflags OPT_SIDE_EFFECT; rawtype tFunc(tStr8, tObjImpl_NETTLE_MAC_STATE); { void *ctx = THIS->ctx; const struct pike_mac *meta = GET_META(Pike_fp->current_object); if (!ctx || !meta) Pike_error("State not properly initialized.\n"); NO_WIDE_STRING(data);
13670c2015-05-25Martin Nilsson 
024d802014-04-21Henrik Grubbström (Grubba)  /* Only thread this block for significant data size */
0473d52014-05-11Henrik Grubbström (Grubba)  if (data->len > HASH_THREADS_ALLOW_THRESHOLD) {
024d802014-04-21Henrik Grubbström (Grubba)  THREADS_ALLOW(); meta->update(ctx, data->len, (const uint8_t *)data->str); THREADS_DISALLOW(); } else { meta->update(ctx, data->len, (const uint8_t *)data->str); } push_object(this_object()); } /*! @decl string(0..255) digest(int|void length) *! *! Generates a digest, and resets the MAC contents. *! *! Also updates the iv/nonce (if any). *! *! @param length *! If the length argument is provided, the digest is truncated *! to the given length. *! *! @returns *! The digest. */ PIKEFUN string(0..255) digest(int|void arg) { const struct pike_mac *meta; struct pike_string *digest; unsigned length; meta = GET_META(Pike_fp->current_object); if (!THIS->ctx || !meta) Pike_error("State not properly initialized.\n"); if (!arg) length = meta->digest_size; else { if (TYPEOF(*arg) != PIKE_T_INT) Pike_error("Bad argument type.\n"); if (arg->u.integer < 0) Pike_error("Invalid length, must be positive.\n"); if ((unsigned)arg->u.integer > meta->digest_size) Pike_error("Unsupported digest length.\n"); length = arg->u.integer; }
13670c2015-05-25Martin Nilsson 
024d802014-04-21Henrik Grubbström (Grubba)  digest = begin_shared_string(length); meta->digest(THIS->ctx, length, (uint8_t *)digest->str); push_string(end_shared_string(digest)); } /*! @decl string(8bit) `()(string(8bit) data) *! Acts as the combination of @[update()] followed by @[digest()]. *! *! @note *! Also updates the iv/nonce (if any). */ PIKEFUN string(8bit) `()(string(8bit) data) { const struct pike_mac *meta; struct pike_string *digest; meta = GET_META(Pike_fp->current_object); if (!THIS->ctx || !meta) Pike_error("State not properly initialized.\n"); NO_WIDE_STRING(data); meta->update(&THIS->ctx, data->len, STR0(data)); digest = begin_shared_string(meta->digest_size); meta->digest(&THIS->ctx, meta->digest_size, STR0(digest)); push_string(end_shared_string(digest)); } INIT { THIS->ctx = NULL; } EXIT { if (THIS->ctx) { const struct pike_mac *meta = GET_META(Pike_fp->current_object); if (meta) { memset(THIS->ctx, 0, meta->context_size); } } } } /*! @endclass State */ } /*! @endclass MAC */ /* The algorithm objects can be overloaded in pike. */ #cmod_define TOSTR(DEF) #DEF #ifdef HAVE_NETTLE_POLY1305_H #define poly1305_aes_set_iv poly1305_aes_set_nonce #define POLY1305_AES_BLOCK_SIZE POLY1305_BLOCK_SIZE #define POLY1305_AES_IV_SIZE POLY1305_AES_NONCE_SIZE
8ea45f2014-04-22Henrik Grubbström (Grubba) static void pike_poly1305_aes_set_key(void *ctx, pike_nettle_size_t len,
024d802014-04-21Henrik Grubbström (Grubba)  const uint8_t *key) { if (len != POLY1305_AES_KEY_SIZE) { Pike_error("Invalid key length.\n"); } poly1305_aes_set_key(ctx, key); }
8ea45f2014-04-22Henrik Grubbström (Grubba) static void pike_poly1305_aes_set_iv(void *ctx, pike_nettle_size_t len,
024d802014-04-21Henrik Grubbström (Grubba)  const uint8_t *key) { if (len != POLY1305_AES_IV_SIZE) {
ba2d672014-04-21Henrik Grubbström (Grubba)  Pike_error("Invalid iv length.\n");
024d802014-04-21Henrik Grubbström (Grubba)  }
ba2d672014-04-21Henrik Grubbström (Grubba)  poly1305_aes_set_nonce(ctx, key);
024d802014-04-21Henrik Grubbström (Grubba) } #cmod_define PIKE_NAME POLY1305_AES #cmod_define NETTLE_NAME poly1305_aes #cmod_include "mac.H" #cmod_undef PIKE_NAME #cmod_undef NETTLE_NAME #endif
cf1d762014-04-22Henrik Grubbström (Grubba) #ifdef HAVE_NETTLE_UMAC_H
7505312014-04-26Henrik Grubbström (Grubba) /* These really ought to be in the <nettle/umac.h> header file, but... * * They are now in the upcoming Nettle 3.0. */
cf1d762014-04-22Henrik Grubbström (Grubba) #ifndef UMAC_BLOCK_SIZE #define UMAC_BLOCK_SIZE UMAC_DATA_SIZE #endif
7505312014-04-26Henrik Grubbström (Grubba) #ifndef UMAC_MAX_NONCE_SIZE #define UMAC_MAX_NONCE_SIZE 16 #endif
cf1d762014-04-22Henrik Grubbström (Grubba) #ifndef UMAC_NONCE_SIZE
7505312014-04-26Henrik Grubbström (Grubba) #define UMAC_NONCE_SIZE UMAC_MAX_NONCE_SIZE
cf1d762014-04-22Henrik Grubbström (Grubba) #endif
4607cf2014-05-10Henrik Grubbström (Grubba) #define UMAC32_AES_BLOCK_SIZE UMAC_BLOCK_SIZE #define UMAC32_AES_KEY_SIZE UMAC_KEY_SIZE #define UMAC32_AES_IV_SIZE UMAC_NONCE_SIZE #define UMAC32_AES_DIGEST_SIZE UMAC32_DIGEST_SIZE
cf1d762014-04-22Henrik Grubbström (Grubba) #define pike_umac32_set_iv umac32_set_nonce static void pike_umac32_set_key(void *ctx, pike_nettle_size_t len, const uint8_t *key) { if (len != UMAC_KEY_SIZE) { Pike_error("Invalid key length.\n"); } umac32_set_key(ctx, key); }
4607cf2014-05-10Henrik Grubbström (Grubba) #cmod_define PIKE_NAME UMAC32_AES
cf1d762014-04-22Henrik Grubbström (Grubba) #cmod_define NETTLE_NAME umac32 #cmod_include "mac.H" #cmod_undef PIKE_NAME #cmod_undef NETTLE_NAME
4607cf2014-05-10Henrik Grubbström (Grubba) #define UMAC64_AES_BLOCK_SIZE UMAC_BLOCK_SIZE #define UMAC64_AES_KEY_SIZE UMAC_KEY_SIZE #define UMAC64_AES_IV_SIZE UMAC_NONCE_SIZE #define UMAC64_AES_DIGEST_SIZE UMAC64_DIGEST_SIZE
cf1d762014-04-22Henrik Grubbström (Grubba) #define pike_umac64_set_iv umac64_set_nonce static void pike_umac64_set_key(void *ctx, pike_nettle_size_t len, const uint8_t *key) { if (len != UMAC_KEY_SIZE) { Pike_error("Invalid key length.\n"); } umac64_set_key(ctx, key); }
4607cf2014-05-10Henrik Grubbström (Grubba) #cmod_define PIKE_NAME UMAC64_AES
cf1d762014-04-22Henrik Grubbström (Grubba) #cmod_define NETTLE_NAME umac64 #cmod_include "mac.H" #cmod_undef PIKE_NAME #cmod_undef NETTLE_NAME
4607cf2014-05-10Henrik Grubbström (Grubba) #define UMAC96_AES_BLOCK_SIZE UMAC_BLOCK_SIZE #define UMAC96_AES_KEY_SIZE UMAC_KEY_SIZE #define UMAC96_AES_IV_SIZE UMAC_NONCE_SIZE #define UMAC96_AES_DIGEST_SIZE UMAC96_DIGEST_SIZE
cf1d762014-04-22Henrik Grubbström (Grubba) #define pike_umac96_set_iv umac96_set_nonce static void pike_umac96_set_key(void *ctx, pike_nettle_size_t len, const uint8_t *key) { if (len != UMAC_KEY_SIZE) { Pike_error("Invalid key length.\n"); } umac96_set_key(ctx, key); }
4607cf2014-05-10Henrik Grubbström (Grubba) #cmod_define PIKE_NAME UMAC96_AES
cf1d762014-04-22Henrik Grubbström (Grubba) #cmod_define NETTLE_NAME umac96 #cmod_include "mac.H" #cmod_undef PIKE_NAME #cmod_undef NETTLE_NAME
4607cf2014-05-10Henrik Grubbström (Grubba) #define UMAC128_AES_BLOCK_SIZE UMAC_BLOCK_SIZE #define UMAC128_AES_KEY_SIZE UMAC_KEY_SIZE #define UMAC128_AES_IV_SIZE UMAC_NONCE_SIZE #define UMAC128_AES_DIGEST_SIZE UMAC128_DIGEST_SIZE
cf1d762014-04-22Henrik Grubbström (Grubba) #define pike_umac128_set_iv umac128_set_nonce static void pike_umac128_set_key(void *ctx, pike_nettle_size_t len, const uint8_t *key) { if (len != UMAC_KEY_SIZE) { Pike_error("Invalid key length.\n"); } umac128_set_key(ctx, key); }
4607cf2014-05-10Henrik Grubbström (Grubba) #cmod_define PIKE_NAME UMAC128_AES
cf1d762014-04-22Henrik Grubbström (Grubba) #cmod_define NETTLE_NAME umac128 #cmod_include "mac.H" #cmod_undef PIKE_NAME #cmod_undef NETTLE_NAME #endif
024d802014-04-21Henrik Grubbström (Grubba) /*! @endmodule Nettle */ void mac_init(void) { werror("Nettle, mac init\n"); INIT; } void mac_exit(void) { werror("Nettle, mac exit\n"); EXIT; } #endif /* HAVE_LIBNETTLE */