pike.git / src / post_modules / Nettle / mac.cmod

version» Context lines:

pike.git/src/post_modules/Nettle/mac.cmod:1: + /* -*- 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 "module.h" + #include "interpret.h" + #include "threads.h" + #include "module_support.h" + #include "pike_compiler.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 "fdlib.h" +  + /*! @module Nettle */ +  + struct pike_mac + { +  const char *name; +  +  unsigned context_size; +  +  unsigned digest_size; +  +  unsigned block_size; +  +  /* Suggested key size; other sizes are sometimes possible. */ +  unsigned key_size; +  +  unsigned iv_size; +  +  /* NB: Use nettle_hash_update_func here to get both a length field, +  * and a const uint8_t source. +  */ +  pike_nettle_hash_update_func set_key; +  pike_nettle_hash_update_func set_iv; +  +  pike_nettle_hash_update_func update; +  pike_nettle_hash_digest_func digest; + }; +  + #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, \ +  } +  + /*! @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); +  } +  + #ifdef PIKE_NULL_IS_SPECIAL +  INIT +  { +  THIS->meta = NULL; +  } + #endif +  +  /*! @class State +  *! +  *! Base class for MAC contexts. +  */ +  PIKECLASS State +  program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE; +  { +  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. +  */ +  lexical_inherit(1, MK_STRING("State"), 0, REPORT_WARNING); +  } +  + #define GET_META(o) \ +  ( ((struct Nettle_MAC_struct *)parent_storage(1, Nettle_MAC_program))->meta ) +  +  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_stack(); +  } +  +  /*! @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); +  +  /* NB: Check iv length here so that we can use the +  * Nettle implementation straight in meta->set_iv. +  */ +  if (((unsigned)iv->len > meta->iv_size) || !meta->iv_size) { +  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); +  +  /* Only thread this block for significant data size */ +  if (data->len > HASH_THREADS_ALLOW_THRESHOLD) { +  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; +  } +  +  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)); +  } +  + #ifdef PIKE_NULL_IS_SPECIAL +  INIT +  { +  THIS->ctx = NULL; +  } + #endif +  +  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 +  + static void pike_poly1305_aes_set_key(void *ctx, pike_nettle_size_t len, +  const uint8_t *key) + { +  if (len != POLY1305_AES_KEY_SIZE) { +  Pike_error("Invalid key length.\n"); +  } +  poly1305_aes_set_key(ctx, key); + } +  + static void pike_poly1305_aes_set_iv(void *ctx, pike_nettle_size_t len, +  const uint8_t *key) + { +  if (len != POLY1305_AES_IV_SIZE) { +  Pike_error("Invalid iv length.\n"); +  } +  poly1305_aes_set_nonce(ctx, key); + } +  + #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 +  + #ifdef HAVE_NETTLE_UMAC_H +  + /* These really ought to be in the <nettle/umac.h> header file, but... +  * +  * They are now in the upcoming Nettle 3.0. +  */ + #ifndef UMAC_BLOCK_SIZE + #define UMAC_BLOCK_SIZE UMAC_DATA_SIZE + #endif + #ifndef UMAC_MAX_NONCE_SIZE + #define UMAC_MAX_NONCE_SIZE 16 + #endif + #ifndef UMAC_NONCE_SIZE + #define UMAC_NONCE_SIZE UMAC_MAX_NONCE_SIZE + #endif +  + #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 + #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); + } +  + #cmod_define PIKE_NAME UMAC32_AES + #cmod_define NETTLE_NAME umac32 + #cmod_include "mac.H" + #cmod_undef PIKE_NAME + #cmod_undef NETTLE_NAME +  + #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 + #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); + } +  + #cmod_define PIKE_NAME UMAC64_AES + #cmod_define NETTLE_NAME umac64 + #cmod_include "mac.H" + #cmod_undef PIKE_NAME + #cmod_undef NETTLE_NAME +  + #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 + #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); + } +  + #cmod_define PIKE_NAME UMAC96_AES + #cmod_define NETTLE_NAME umac96 + #cmod_include "mac.H" + #cmod_undef PIKE_NAME + #cmod_undef NETTLE_NAME +  + #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 + #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); + } +  + #cmod_define PIKE_NAME UMAC128_AES + #cmod_define NETTLE_NAME umac128 + #cmod_include "mac.H" + #cmod_undef PIKE_NAME + #cmod_undef NETTLE_NAME +  + #endif +  + /*! @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 */   Newline at end of file added.