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

version» Context lines:

pike.git/src/post_modules/Nettle/hash.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 "global.h" + #include "module.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 "pike_compiler.h"      #include "nettle_config.h"      #ifdef HAVE_LIBNETTLE      DECLARATIONS      #include "nettle.h"      #include <nettle/md5.h> - #ifdef HAVE_NETTLE_MD4_INIT +    #include <nettle/md4.h>   #include <nettle/md2.h> - #endif +    #include <nettle/sha.h>   #ifdef HAVE_NETTLE_SHA3_H   #include <nettle/sha3.h>   #endif   #ifdef HAVE_NETTLE_RIPEMD160_H   #include <nettle/ripemd160.h>   #endif   #ifdef HAVE_NETTLE_GOSTHASH94_H   #include <nettle/gosthash94.h>   #endif - #include <nettle/nettle-meta.h> + #ifdef HAVE_NETTLE_PBKDF2_H + #include <nettle/pbkdf2.h> + #endif + #ifdef HAVE_NETTLE_HMAC_H + #include <nettle/hmac.h> + #endif    - #include <stdio.h> - #include <stdarg.h> +    #include "fdlib.h"    - #if 0 - static void - werror(const char *format, ...) - { -  va_list args; -  -  va_start(args, format); -  vfprintf(stderr, format, args); -  va_end(args); - } - #else - #define werror(x) - #endif -  +    /*! @module Nettle */      /*! @class Hash    *!    *! Represents information about a hash algorithm, such as    *! name, digest size, and internal block size.    */   PIKECLASS Hash   {    /*! @decl inherit __builtin.Nettle.Hash    */    INHERIT "__builtin.Nettle.Hash";       CVAR const struct nettle_hash *meta;    -  /*! @decl string(0..255) name(void) +  /*! @decl string(0..255) name()    *!    *! Returns a human readable name for the algorithm.    */    PIKEFUN string(0..255) name()    optflags OPT_TRY_OPTIMIZE;    {    if (!THIS->meta)    Pike_error("Hash not properly initialized.\n");       push_text(THIS->meta->name);    }    -  /*! @decl int(0..) digest_size(void) +  /*! @decl int(0..) digest_size()    *! -  *! Returns the size of a hash digests. +  *! Returns the size of a hash digest.    */    PIKEFUN int(0..) digest_size()    optflags OPT_TRY_OPTIMIZE;    {    if (!THIS->meta)    Pike_error("Hash not properly initialized.\n");       push_int(THIS->meta->digest_size);    }    -  /*! @decl int(0..) block_size(void) +  /*! @decl int(0..) block_size()    *!    *! Returns the internal block size of the hash algorithm.    */    PIKEFUN int(0..) block_size()    optflags OPT_TRY_OPTIMIZE;    {    if (!THIS->meta)    Pike_error("Hash not properly initialized.\n");       push_int(THIS->meta->block_size);
pike.git/src/post_modules/Nettle/hash.cmod:126:    {    void *ctx;    struct pike_string *out;    unsigned digest_length;    const struct nettle_hash *meta = THIS->meta;       if (!meta)    Pike_error("Hash not properly initialized.\n");    NO_WIDE_STRING(in);    -  ctx = (void *)alloca(meta->context_size); +  ctx = alloca(meta->context_size);    if(!ctx)    SIMPLE_OUT_OF_MEMORY_ERROR("hash", meta->context_size);       /* Only thread this block for significant data size */ -  if (in->len > THREADS_ALLOW_THRESHOLD) { +  if (in->len > HASH_THREADS_ALLOW_THRESHOLD) {    THREADS_ALLOW();    meta->init(ctx);    meta->update(ctx, in->len, (const uint8_t *)in->str);    THREADS_DISALLOW();    } else {    meta->init(ctx);    meta->update(ctx, in->len, (const uint8_t *)in->str);    }       digest_length = meta->digest_size;    out = begin_shared_string(digest_length);    meta->digest(ctx, digest_length, (uint8_t *)out->str);       pop_n_elems(args);    push_string(end_shared_string(out));    }    -  int is_stdio_file(struct object *o) +  static int is_stdio_file(struct object *o)    {    struct program *p = o->prog;    INT32 i = p->num_inherits;    while( i-- )    {    if( p->inherits[i].prog->id == PROG_STDIO_FD_ID ||    p->inherits[i].prog->id == PROG_STDIO_FD_REF_ID )    return 1;    }    return 0;    }    -  /*! @decl string(0..255) hash(Stdio.File file, void|int bytes) +  /*! @decl string(0..255) hash(Stdio.File|Stdio.Buffer|String.Buffer|System.Memory source, void|int(0..) bytes)    *! -  *! Works as a (faster) shortcut for +  *! Works as a (faster) shortcut for e.g.    *! @expr{State()->update(Stdio.read_file(file))->digest()@},    *! where State is the hash state class corresponding to this    *! Hash.    *!    *! @param bytes    *! The number of bytes of the file object @[file] that should be    *! hashed. Negative numbers are ignored and the whole file is    *! hashed.    *!    *! @seealso    *! @[Stdio.File], @[State()->update()] and    *! @[State()->digest()].    */ -  PIKEFUN string(0..255) hash(object in, void|int bytes) +  PIKEFUN string(0..255) hash(object in, void|int(0..) bytes)    optflags OPT_EXTERNAL_DEPEND;    {    void *ctx; -  int len, fd; +  size_t len; +  int fd;    char *read_buffer;    PIKE_STAT_T st;    struct pike_string *out;    const struct nettle_hash *meta = THIS->meta;       if (!meta)    Pike_error("HashInfo not properly initialized.\n");    -  +  ctx = alloca(meta->context_size); +  if (!ctx) +  SIMPLE_OUT_OF_MEMORY_ERROR("hash", meta->context_size); +  meta->init(ctx); +  +  if( get_memory_object_memory(in, (void **)&read_buffer, &len, NULL) ) +  { +  if( bytes ) +  len = MINIMUM(len, (size_t)MAXIMUM(bytes->u.integer,0) ); +  meta->update( ctx, len, (const uint8_t*)read_buffer); +  goto ret_meta; +  } +     if (!is_stdio_file(in)) -  Pike_error("Object not Fd or Fd_ref, or subclass.\n"); +  Pike_error("Object not Fd or Fd_ref, or subclass or 8bit buffer.\n");       apply(in, "query_fd", 0);    fd = Pike_sp[-1].u.integer;    pop_stack();       if (fd_fstat(fd, &st)<0)    Pike_error("File not found!\n");       if (!S_ISREG(st.st_mode))    Pike_error("Non-regular file.\n");    -  ctx = (void *)alloca(meta->context_size); -  if (!ctx) -  SIMPLE_OUT_OF_MEMORY_ERROR("hash", meta->context_size); +  read_buffer=xalloc(8192);    -  read_buffer=(char *)malloc(8192); -  if (!read_buffer) -  SIMPLE_OUT_OF_MEMORY_ERROR("hash", 8192); -  +     THREADS_ALLOW(); -  meta->init(ctx); -  if(args==2 && bytes->u.integer>-1) { +  if(bytes && bytes->u.integer>-1) {    int bytes_left = bytes->u.integer;    int read_bytes = MINIMUM(8192, bytes_left);    while(read_bytes>0 && (len=fd_read(fd, read_buffer, read_bytes))>0) {    meta->update(ctx, len, (const uint8_t *)read_buffer);    bytes_left -= read_bytes;    read_bytes = MINIMUM(8192, bytes_left);    }    }    else    while((len=fd_read(fd, read_buffer, 8192))>0)    meta->update(ctx, len, (const uint8_t *)read_buffer);       free(read_buffer);       THREADS_DISALLOW(); -  +  ret_meta:    out = begin_shared_string(meta->digest_size);    meta->digest(ctx, meta->digest_size, (uint8_t *)out->str);       pop_n_elems(args);    push_string(end_shared_string(out));    }       /* NOTE: This is NOT the MIME base64 table! */    static const char b64tab[64] =    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
pike.git/src/post_modules/Nettle/hash.cmod:263:    *! Password hashing function in @[crypt_md5()]-style.    *!    *! Implements the algorithm described in    *! @url{http://www.akkadia.org/drepper/SHA-crypt.txt@}.    *!    *! This is the algorithm used by @tt{crypt(2)@} in    *! methods @tt{$5$@} (SHA256) and @tt{$6$@} (SHA512).    *!    *! The @[password] memory will be cleared before released.    *! +  *! Rounds will never be set to less than 1000. If @[rounds] is 0 +  *! it will be set to 5000. +  *!    *! @seealso    *! @[crypt_md5()]    */ -  PIKEFUN string(0..127) crypt_hash(string(0..255) password, -  string(0..255) salt, int rounds) +  PIKEFUN string(0..127) crypt_hash(string password, +  string salt, int rounds) +  /* NB: We use a weaker type above to allow us to delay +  * throwing errors on wide strings until we've had +  * time to censor the password string. +  */ +  rawtype tFunc(tStr8 tStr8 tInt, tStr7);    {    struct pike_string *res;    const struct nettle_hash *meta = THIS->meta;    void *ctx;    uint8_t *abcbuf;    uint8_t *dpbuf;    uint8_t *dsbuf;       unsigned char *p;    unsigned char *s;    int plen;    int slen; -  int dsz = meta->digest_size; +  int dsz;       int i;    int r;       int a, b, c;    -  +  if (!meta) +  Pike_error("HashInfo not properly initialized.\n"); +     if (!rounds) rounds = 5000;    if (rounds < 1000) rounds = 1000;    if (rounds > 999999999) rounds = 999999999;    -  +  /* Censor the password. */ +  push_string(password); +  args++; +  add_ref(Pike_sp[-args].u.string = MK_STRING("censored")); +     NO_WIDE_STRING(password);    NO_WIDE_STRING(salt);       password->flags |= STRING_CLEAR_ON_EXIT;    -  ctx = (void *)alloca(meta->context_size); +  ctx = alloca(meta->context_size);    if (!ctx)    SIMPLE_OUT_OF_MEMORY_ERROR("crypt_hash", meta->context_size);    -  abcbuf = (uint8_t *)alloca(meta->digest_size * 3); +  abcbuf = alloca(meta->digest_size * 3);    if (!abcbuf)    SIMPLE_OUT_OF_MEMORY_ERROR("crypt_hash", meta->digest_size * 3);       dpbuf = abcbuf + meta->digest_size;    dsbuf = dpbuf + meta->digest_size;       /* NB: We use these to allow the compiler to    * avoid dereferencing at every step.    */    p = (unsigned char*)password->str;
pike.git/src/post_modules/Nettle/hash.cmod:340:       THREADS_ALLOW();       /* NB: Comments refer to http://www.akkadia.org/drepper/SHA-crypt.txt */    meta->init(ctx); /* 4 */    meta->update(ctx, plen, p); /* 5 */    meta->update(ctx, slen, s); /* 6 */    meta->update(ctx, plen, p); /* 7 */    meta->digest(ctx, dsz, abcbuf); /* 8 */    -  meta->init(ctx); /* 1 */ +  /* 1 */    meta->update(ctx, plen, p); /* 2 */    meta->update(ctx, slen, s); /* 3 */       for (i = 0; i + dsz < plen; i += dsz) { /* 9 */    meta->update(ctx, dsz, abcbuf);    }       meta->update(ctx, plen - i, abcbuf); /* 10 */       for (i = 1; i < plen; i <<= 1) { /* 11 */    if (plen & i) {    meta->update(ctx, dsz, abcbuf);    } else {    meta->update(ctx, plen, p);    }    }       meta->digest(ctx, dsz, abcbuf); /* 12 */    -  meta->init(ctx); /* 13 */ +  /* 13 */    for (i = 0; i < plen; i++) { /* 14 */    meta->update(ctx, plen, p);    }    meta->digest(ctx, dsz, dpbuf); /* 15 */       /* Sequence P is implicit. */ /* 16 */    -  meta->init(ctx); /* 17 */ +  /* 17 */    for(i = 0; i < 16 + abcbuf[0]; i++) { /* 18 */    meta->update(ctx, slen, s);    }    meta->digest(ctx, dsz, dsbuf); /* 19 */       /* Sequence S is implicit. */ /* 20 */       for (r = 0; r < rounds; r++) { /* 21 */ -  meta->init(ctx); /* a */ +  /* a */    if (r & 1) { /* b */    for (i = 0; i + dsz < plen; i += dsz) {    meta->update(ctx, dsz, dpbuf);    }    meta->update(ctx, plen - i, dpbuf);    } else {    meta->update(ctx, dsz, abcbuf); /* c */    } -  if (r % 3) { /* d */ -  for (i = 0; i + dsz < slen; i += dsz) { -  meta->update(ctx, dsz, dsbuf); -  } -  meta->update(ctx, slen - i, dsbuf); -  } +  if (r % 3) /* d */ +  meta->update(ctx, slen, dsbuf);    if (r % 7) { /* e */    for (i = 0; i + dsz < plen; i += dsz) {    meta->update(ctx, dsz, dpbuf);    }    meta->update(ctx, plen - i, dpbuf);    }    if (r & 1) { /* f */    meta->update(ctx, dsz, abcbuf);    } else { /* g */    for (i = 0; i + dsz < plen; i += dsz) {
pike.git/src/post_modules/Nettle/hash.cmod:446:    a = c+1;    c = b+1;    b = t;    }    b64enc(res->str + r, abcbuf[63], 0, 0, 2);    }       push_string(end_shared_string(res)); /* 22e */       /* Clean intermediate values. */ -  MEMSET(ctx, 0, meta->context_size); -  MEMSET(abcbuf, 0, 3*dsz); +  memset(ctx, 0, meta->context_size); +  memset(abcbuf, 0, 3*dsz);    }    -  + #ifdef PIKE_NULL_IS_SPECIAL    INIT    {    werror("Hash->INIT\n");    THIS->meta = NULL;    } -  + #endif       /*! @class State    *!    *! Base class for hashing contexts.    */    PIKECLASS State -  program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT; +  program_flags PROGRAM_USES_PARENT|PROGRAM_NEEDS_PARENT|PROGRAM_CLEAR_STORAGE;    {    DOCSTART() @decl inherit Hash::State    DOCEND()       EXTRA    {    /* Perform an inherit of the State class (if any) that our parent    * may contain via its inherit of __builtin.Nettle.Hash.    */ -  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) { -  low_inherit(parent_State_prog, 0, -  parent_State_fun_num + -  parent_prog->inherits[1].identifier_level, -  1 + 42, 0, NULL); +  lexical_inherit(1, MK_STRING("State"), 0, REPORT_WARNING);    } -  } -  } +       #define GET_META(o) \ -  ( ((struct Hash_struct *)parent_storage(1))->meta ) +  ( ((struct Nettle_Hash_struct *)parent_storage(1, Nettle_Hash_program))->meta )       CVAR void *ctx;       /* FIXME: Create should copy state from the other object, if    * provided. */       /*! @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_HASH_STATE); +  rawtype tFunc(tStr8, tObjImpl_NETTLE_HASH_STATE);    {    void *ctx = THIS->ctx;    const struct nettle_hash *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 > THREADS_ALLOW_THRESHOLD) { +  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) +  /*! @decl string(0..255) digest(int(0..)|void length)    *!    *! Generates a digest, and resets the hashing contents.    *!    *! @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) +  PIKEFUN string(0..255) digest(int(0..)|void arg)    {    const struct nettle_hash *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));    }    -  + #ifdef PIKE_NULL_IS_SPECIAL    INIT    {    werror("State->INIT\n");    THIS->ctx = NULL;    } -  + #endif       EXIT    {    werror("State->EXIT\n");    if (THIS->ctx)    {    const struct nettle_hash *meta =    GET_META(Pike_fp->current_object);    if (meta) {    memset(THIS->ctx, 0, meta->context_size);
pike.git/src/post_modules/Nettle/hash.cmod:600:       /*! @endclass State */      }      /*! @endclass Hash */      /* The algorithm objects can be overloaded in pike. */      #cmod_define TOSTR(DEF) #DEF + #undef SPECIAL_PBKDF2    -  +    #cmod_define PIKE_NAME MD5   #cmod_define NETTLE_NAME md5   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME    - #ifdef HAVE_NETTLE_MD4_INIT -  +    #cmod_define PIKE_NAME MD4   #cmod_define NETTLE_NAME md4   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #cmod_define PIKE_NAME MD2   #cmod_define NETTLE_NAME md2   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME    - #endif /* HAVE_NETTLE_MD4_INIT */ -  +    #cmod_define PIKE_NAME SHA1   #cmod_define NETTLE_NAME sha1 -  + #define SPECIAL_PBKDF2   #cmod_include "hash.H" -  + #undef SPECIAL_PBKDF2   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #ifdef HAVE_NETTLE_SHA224_INIT      #cmod_define PIKE_NAME SHA224   #cmod_define NETTLE_NAME sha224   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #endif      #cmod_define PIKE_NAME SHA256   #cmod_define NETTLE_NAME sha256 -  + #define SPECIAL_PBKDF2   #cmod_include "hash.H" -  + #undef SPECIAL_PBKDF2   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #ifdef SHA384_DIGEST_SIZE      #cmod_define PIKE_NAME SHA384   #cmod_define NETTLE_NAME sha384   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME
pike.git/src/post_modules/Nettle/hash.cmod:665:   #ifdef SHA512_DIGEST_SIZE      #cmod_define PIKE_NAME SHA512   #cmod_define NETTLE_NAME sha512   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #endif /* SHA512_DIGEST_SIZE */    - #ifdef HAVE_NETTLE_SHA3_H + #ifdef SHA512_224_DIGEST_SIZE    -  + #cmod_define PIKE_NAME SHA512_224 + #cmod_define NETTLE_NAME sha512_224 + #cmod_include "hash.H" + #cmod_undef PIKE_NAME + #cmod_undef NETTLE_NAME +  + #endif /* SHA512_224_DIGEST_SIZE */ +  + #ifdef SHA512_256_DIGEST_SIZE +  + #cmod_define PIKE_NAME SHA512_256 + #cmod_define NETTLE_NAME sha512_256 + #cmod_include "hash.H" + #cmod_undef PIKE_NAME + #cmod_undef NETTLE_NAME +  + #endif /* SHA512_256_DIGEST_SIZE */ +  + /* NB: SHA3 in Nettle 3.2 and later does not interoperate +  * with earlier versions of Nettle. +  */ + #ifdef NETTLE_SHA3_FIPS202 +    #cmod_define PIKE_NAME SHA3_224   #cmod_define NETTLE_NAME sha3_224   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #cmod_define PIKE_NAME SHA3_256   #cmod_define NETTLE_NAME sha3_256   #cmod_include "hash.H"   #cmod_undef PIKE_NAME
pike.git/src/post_modules/Nettle/hash.cmod:691:   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #cmod_define PIKE_NAME SHA3_512   #cmod_define NETTLE_NAME sha3_512   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME    - #endif /* HAVE_NETTLE_SHA3_H */ + #endif /* NETTLE_SHA3_FIPS202 */      #ifdef HAVE_NETTLE_RIPEMD160_H      #cmod_define PIKE_NAME RIPEMD160   #cmod_define NETTLE_NAME ripemd160   #cmod_include "hash.H"   #cmod_undef PIKE_NAME   #cmod_undef NETTLE_NAME      #endif