6d1a542003-03-13Niels Möller /* hash.cmod -*- c -*- */ #include "global.h"
7a38822004-04-30Martin Nilsson RCSID("$Id: hash.cmod,v 1.23 2004/04/30 20:19:53 nilsson Exp $");
6d1a542003-03-13Niels Möller #include "interpret.h" #include "svalue.h"
602fe62004-02-21Martin Nilsson #include "threads.h"
6d1a542003-03-13Niels Möller  /* For this_object() */ #include "object.h" #include "module_support.h" #include "nettle_config.h" #ifdef HAVE_LIBNETTLE #include "nettle.h" #include <nettle/md5.h>
5c36c82003-08-26Martin Nilsson #ifdef HAVE_NETTLE_MD4_INIT
40f88a2003-08-01Martin Nilsson #include <nettle/md4.h>
5c36c82003-08-26Martin Nilsson #include <nettle/md2.h>
40f88a2003-08-01Martin Nilsson #endif
6d1a542003-03-13Niels Möller #include <nettle/sha.h> #include <nettle/nettle-meta.h> #include <assert.h> #include <stdio.h> #include <stdarg.h>
5a20f92004-04-28Martin Nilsson #include "fdlib.h"
7a38822004-04-30Martin Nilsson 
6d1a542003-03-13Niels Möller #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
5a20f92004-04-28Martin Nilsson static struct program *Fd_ref_program = NULL;
411a282003-03-18Niels Möller /*! @module Nettle */
cd26482003-03-18Niels Möller /*! @class HashInfo *! *! Represents information about a hash algorithm, such as *! name, digest size, and internal block size. */ PIKECLASS HashInfo
6d1a542003-03-13Niels Möller { CVAR const struct nettle_hash *meta;
cd26482003-03-18Niels Möller  /*! @decl string name(void) *! *! Returns a human readable name for the algorithm. */
6d1a542003-03-13Niels Möller  PIKEFUN string name()
1a2b712004-02-14Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
6d1a542003-03-13Niels Möller  { if (!THIS->meta)
f1c9f42003-08-05Martin Nilsson  Pike_error("HashInfo not properly initialized.\n");
6d1a542003-03-13Niels Möller 
3f286d2003-11-29Martin Nilsson  push_text(THIS->meta->name);
6d1a542003-03-13Niels Möller  }
cd26482003-03-18Niels Möller  /*! @decl string digest_size(void) *! *! Returns the size of a hash digests. */
6d1a542003-03-13Niels Möller  PIKEFUN int digest_size()
1a2b712004-02-14Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
6d1a542003-03-13Niels Möller  { if (!THIS->meta)
f1c9f42003-08-05Martin Nilsson  Pike_error("HashInfo not properly initialized.\n");
6d1a542003-03-13Niels Möller  push_int(THIS->meta->digest_size); }
cd26482003-03-18Niels Möller  /*! @decl string block_size(void) *!
f1c9f42003-08-05Martin Nilsson  *! Returns the internal block size of the hash algorithm.
cd26482003-03-18Niels Möller  */
6d1a542003-03-13Niels Möller  PIKEFUN int block_size()
1a2b712004-02-14Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
6d1a542003-03-13Niels Möller  { if (!THIS->meta)
f1c9f42003-08-05Martin Nilsson  Pike_error("HashInfo not properly initialized.\n");
6d1a542003-03-13Niels Möller  push_int(THIS->meta->block_size); }
9512252004-04-28Martin Nilsson  /*! @decl string hash(string data) *! *! Works as a (faster) shortcut for *! @expr{obj->update(data)->digest()@}. *! *! @seealso *! @[HashState()->update()] and @[HashState()->digest()]. */ PIKEFUN string hash(string in) optflags OPT_TRY_OPTIMIZE; { void *ctx; struct pike_string *out; unsigned digest_length;
5a20f92004-04-28Martin Nilsson  const struct nettle_hash *meta = THIS->meta;
9512252004-04-28Martin Nilsson 
5a20f92004-04-28Martin Nilsson  if (!meta)
9512252004-04-28Martin Nilsson  Pike_error("HashInfo not properly initialized.\n"); NO_WIDE_STRING(in);
5a20f92004-04-28Martin Nilsson  ctx = (void *)alloca(meta->context_size);
9512252004-04-28Martin Nilsson  if(!ctx) Pike_error("Out of memory or karma.\n"); THREADS_ALLOW();
5a20f92004-04-28Martin Nilsson  meta->init(ctx); meta->update(ctx, in->len, in->str);
9512252004-04-28Martin Nilsson 
5a20f92004-04-28Martin Nilsson  digest_length = meta->digest_size;
9512252004-04-28Martin Nilsson  out = begin_shared_string(digest_length);
5a20f92004-04-28Martin Nilsson  meta->digest(ctx, digest_length, out->str); THREADS_DISALLOW(); pop_n_elems(args); push_string(end_shared_string(out)); }
7a38822004-04-30Martin Nilsson  /*! @decl string hash(Stdio.File file, void|int bytes)
5a20f92004-04-28Martin Nilsson  *! *! Works as a (faster) shortcut for *! @expr{obj->update(Stdio.read_file(file))->digest()@}. *!
7a38822004-04-30Martin Nilsson  *! @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. *!
5a20f92004-04-28Martin Nilsson  *! @seealso *! @[Stdio.File], @[HashState()->update()] and *! @[HashState()->digest()]. */
7a38822004-04-30Martin Nilsson  PIKEFUN string hash(object in, void|int bytes)
5a20f92004-04-28Martin Nilsson  optflags OPT_EXTERNAL_DEPEND; { void *ctx;
fe11b92004-04-29Martin Nilsson  int len, fd;
5a20f92004-04-28Martin Nilsson  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"); /* Verify that the input is a Stdio.Fd_ref */ if (!Fd_ref_program) { push_text("files.Fd_ref"); SAFE_APPLY_MASTER("resolv",1); Fd_ref_program = program_from_svalue(Pike_sp-1); if (!Fd_ref_program) { pop_stack(); Pike_error("Unable to resolv files.Fd_ref.\n"); } add_ref(Fd_ref_program); pop_stack( ); } if (!get_storage(in, Fd_ref_program ) ) Pike_error("Object not Fd_ref or subclass.\n"); safe_apply(in, "query_fd", 0);
fe11b92004-04-29Martin Nilsson  fd = Pike_sp[-1].u.integer;
5a20f92004-04-28Martin Nilsson  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) Pike_error("Out of memory.\n");
337f332004-04-28Martin Nilsson  read_buffer=(char *)malloc(8192); if (!read_buffer) Pike_error("Out of memory.\n");
5a20f92004-04-28Martin Nilsson  THREADS_ALLOW(); meta->init(ctx);
7a38822004-04-30Martin Nilsson  if(args==2 && 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, 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, read_buffer);
337f332004-04-28Martin Nilsson  free(read_buffer);
5a20f92004-04-28Martin Nilsson  out = begin_shared_string(meta->digest_size); meta->digest(ctx, meta->digest_size, out->str);
9512252004-04-28Martin Nilsson  THREADS_DISALLOW(); pop_n_elems(args); push_string(end_shared_string(out)); }
6d1a542003-03-13Niels Möller  INIT {
cd26482003-03-18Niels Möller  werror("HashInfo->INIT\n");
6d1a542003-03-13Niels Möller  THIS->meta = NULL; } }
411a282003-03-18Niels Möller /*! @endclass HashInfo */
6d1a542003-03-13Niels Möller #define GET_META(o) \
cd26482003-03-18Niels Möller ( ((struct HashInfo_struct *) get_storage((o), HashInfo_program)) \
6d1a542003-03-13Niels Möller  ->meta) /* The algorithm objects have to be implemented in pike. */
cd26482003-03-18Niels Möller /*! @class HashState *! *! Base class for hashing contexts. */ PIKECLASS HashState
6d1a542003-03-13Niels Möller {
cd26482003-03-18Niels Möller  INHERIT HashInfo;
6d1a542003-03-13Niels Möller  CVAR void *ctx; /* FIXME: Create should copy state from the other object, if * provided. */
4a63d42003-03-18Martin Nilsson  /*! @decl HashState update(string data)
cd26482003-03-18Niels Möller  *! *! Hashes more data. */
6d1a542003-03-13Niels Möller  PIKEFUN object update(string data)
1a2b712004-02-14Martin Nilsson  optflags OPT_SIDE_EFFECT;
6d1a542003-03-13Niels Möller  {
03123d2004-02-21Martin Nilsson  const void *ctx = THIS->ctx;
9119632003-05-07Henrik Grubbström (Grubba)  const struct nettle_hash *meta = GET_META(Pike_fp->current_object);
6d1a542003-03-13Niels Möller 
03123d2004-02-21Martin Nilsson  if (!ctx || !meta)
f1c9f42003-08-05Martin Nilsson  Pike_error("HashState not properly initialized.\n");
6d1a542003-03-13Niels Möller  NO_WIDE_STRING(data);
602fe62004-02-21Martin Nilsson  THREADS_ALLOW();
03123d2004-02-21Martin Nilsson  meta->update(ctx, data->len, data->str);
602fe62004-02-21Martin Nilsson  THREADS_DISALLOW();
6d1a542003-03-13Niels Möller  push_object(this_object()); }
cd26482003-03-18Niels Möller  /*! @decl string digest(int|void length) *! *! Generates a digests, and resets the hashing contents. *! *! @param length *! If the length argument is provided, the digest is truncated *! to the given length. *!
4a63d42003-03-18Martin Nilsson  *! @returns *! The digest.
cd26482003-03-18Niels Möller  */
6d1a542003-03-13Niels Möller  PIKEFUN string digest(int|void arg) { const struct nettle_hash *meta; struct pike_string *digest; unsigned length; if (! THIS->ctx)
f1c9f42003-08-05Martin Nilsson  Pike_error("HashState not properly initialized.\n");
6d1a542003-03-13Niels Möller 
9119632003-05-07Henrik Grubbström (Grubba)  meta = GET_META(Pike_fp->current_object);
6d1a542003-03-13Niels Möller  assert(meta); if (!arg) length = meta->digest_size; else { if (arg->type != PIKE_T_INT)
f1c9f42003-08-05Martin Nilsson  Pike_error("Bad argument type.\n"); if (arg->u.integer < 0) Pike_error("Invalid length, must be positive.\n");
61e14b2004-01-23Martin Nilsson  if ((unsigned)arg->u.integer > meta->digest_size)
f1c9f42003-08-05Martin Nilsson  Pike_error("Unsupported digest length.\n");
6d1a542003-03-13Niels Möller  length = arg->u.integer; } digest = begin_shared_string(length); meta->digest(THIS->ctx, length, digest->str); push_string(end_shared_string(digest)); }
ac14652003-07-29Martin Nilsson 
6d1a542003-03-13Niels Möller  INIT {
cd26482003-03-18Niels Möller  werror("HashState->INIT\n");
6d1a542003-03-13Niels Möller  THIS->ctx = NULL; } EXIT {
cd26482003-03-18Niels Möller  werror("HashState->EXIT\n");
983e2d2003-05-08Henrik Grubbström (Grubba)  if (THIS->ctx && Pike_fp->current_object->prog)
6d1a542003-03-13Niels Möller  {
9119632003-05-07Henrik Grubbström (Grubba)  const struct nettle_hash *meta = GET_META(Pike_fp->current_object);
6d1a542003-03-13Niels Möller  assert(meta); memset(THIS->ctx, 0, meta->context_size); } } }
411a282003-03-18Niels Möller /*! @endclass HashState */
cd26482003-03-18Niels Möller /*! @class MD5_Info *!
6d1a542003-03-13Niels Möller  *! Internal mixin class, intended to be multiply inherited
cd26482003-03-18Niels Möller  *! together with HashInfo. */
6d1a542003-03-13Niels Möller 
cd26482003-03-18Niels Möller PIKECLASS MD5_Info
6d1a542003-03-13Niels Möller { INIT {
cd26482003-03-18Niels Möller  struct HashInfo_struct *HashInfo
9119632003-05-07Henrik Grubbström (Grubba)  = (struct HashInfo_struct *) get_storage(Pike_fp->current_object, HashInfo_program);
6d1a542003-03-13Niels Möller 
cd26482003-03-18Niels Möller  werror("MD5_Info->INIT\n");
6d1a542003-03-13Niels Möller 
411a282003-03-18Niels Möller  if (HashInfo && !HashInfo->meta)
cd26482003-03-18Niels Möller  HashInfo->meta = &nettle_md5;
ac14652003-07-29Martin Nilsson  else {
6d1a542003-03-13Niels Möller  /* Can't call Pike_error here. * Pike_error("Can't initialize this object.\n"); */
cd26482003-03-18Niels Möller  werror("MD5_Info->INIT failed\n");
ac14652003-07-29Martin Nilsson  }
6d1a542003-03-13Niels Möller  } }
411a282003-03-18Niels Möller /*! @endclass MD5_Info */
cd26482003-03-18Niels Möller /*! @class MD5_State *! *! State for MD5 hashing. */ PIKECLASS MD5_State
6d1a542003-03-13Niels Möller {
cd26482003-03-18Niels Möller  INHERIT MD5_Info; INHERIT HashState;
6d1a542003-03-13Niels Möller  CVAR struct md5_ctx md5; INIT {
cd26482003-03-18Niels Möller  struct HashState_struct *instance
9119632003-05-07Henrik Grubbström (Grubba)  = (struct HashState_struct *) get_storage(Pike_fp->current_object, HashState_program);
cd26482003-03-18Niels Möller  werror("MD5_State->INIT\n");
6d1a542003-03-13Niels Möller  assert(instance); md5_init(&THIS->md5); instance->ctx = &THIS->md5; } }
411a282003-03-18Niels Möller /*! @endclass MD5_State */
6d1a542003-03-13Niels Möller 
5c36c82003-08-26Martin Nilsson #ifdef HAVE_NETTLE_MD4_INIT
40f88a2003-08-01Martin Nilsson  /*! @class MD4_Info *! *! Internal mixin class, intended to be multiply inherited *! together with HashInfo. */ PIKECLASS MD4_Info { INIT { struct HashInfo_struct *HashInfo = (struct HashInfo_struct *) get_storage(Pike_fp->current_object, HashInfo_program); werror("MD4_Info->INIT\n"); if (HashInfo && !HashInfo->meta) HashInfo->meta = &nettle_md4; else { /* Can't call Pike_error here. * Pike_error("Can't initialize this object.\n"); */ werror("MD4_Info->INIT failed\n"); } } } /*! @endclass MD4_Info */ /*! @class MD4_State *! *! State for MD4 hashing. */ PIKECLASS MD4_State { INHERIT MD4_Info; INHERIT HashState; CVAR struct md4_ctx md4; INIT { struct HashState_struct *instance = (struct HashState_struct *) get_storage(Pike_fp->current_object, HashState_program); werror("MD4_State->INIT\n"); assert(instance);
5c36c82003-08-26Martin Nilsson  md4_init(&THIS->md4);
40f88a2003-08-01Martin Nilsson  instance->ctx = &THIS->md4; } } /*! @endclass MD4_State */
5c36c82003-08-26Martin Nilsson /*! @class MD2_Info *! *! Internal mixin class, intended to be multiply inherited *! together with HashInfo. */ PIKECLASS MD2_Info { INIT { struct HashInfo_struct *HashInfo = (struct HashInfo_struct *) get_storage(Pike_fp->current_object, HashInfo_program); werror("MD2_Info->INIT\n"); if (HashInfo && !HashInfo->meta) HashInfo->meta = &nettle_md2; else { /* Can't call Pike_error here. * Pike_error("Can't initialize this object.\n"); */ werror("MD2_Info->INIT failed\n"); } } } /*! @endclass MD2_Info */ /*! @class MD2_State *! *! State for MD2 hashing. */ PIKECLASS MD2_State { INHERIT MD2_Info; INHERIT HashState; CVAR struct md2_ctx md2; INIT { struct HashState_struct *instance = (struct HashState_struct *) get_storage(Pike_fp->current_object, HashState_program); werror("MD2_State->INIT\n"); assert(instance); md2_init(&THIS->md2); instance->ctx = &THIS->md2; } } /*! @endclass MD2_State */ #endif /* HAVE_NETTLE_MD4_INIT */
40f88a2003-08-01Martin Nilsson 
cd26482003-03-18Niels Möller /*! @class SHA1_Info *!
6d1a542003-03-13Niels Möller  *! Internal mixin class, intended to be multiply inherited
cd26482003-03-18Niels Möller  *! together with HashInfo. */
6d1a542003-03-13Niels Möller 
cd26482003-03-18Niels Möller PIKECLASS SHA1_Info
6d1a542003-03-13Niels Möller { INIT {
cd26482003-03-18Niels Möller  struct HashInfo_struct *HashInfo
9119632003-05-07Henrik Grubbström (Grubba)  = (struct HashInfo_struct *) get_storage(Pike_fp->current_object, HashInfo_program);
6d1a542003-03-13Niels Möller 
cd26482003-03-18Niels Möller  werror("SHA1_Info->INIT\n");
6d1a542003-03-13Niels Möller 
411a282003-03-18Niels Möller  if (HashInfo && !HashInfo->meta)
cd26482003-03-18Niels Möller  HashInfo->meta = &nettle_sha1;
ac14652003-07-29Martin Nilsson  else {
6d1a542003-03-13Niels Möller  /* Can't call Pike_error here. * Pike_error("Can't initialize this object.\n"); */
cd26482003-03-18Niels Möller  werror("SHA1_Info->INIT failed\n");
ac14652003-07-29Martin Nilsson  }
6d1a542003-03-13Niels Möller  } }
411a282003-03-18Niels Möller /*! @endclass SHA1_Info */
cd26482003-03-18Niels Möller /*! @class SHA1_State *! *! State for SHA1 hashing. */ PIKECLASS SHA1_State
6d1a542003-03-13Niels Möller {
cd26482003-03-18Niels Möller  INHERIT SHA1_Info; INHERIT HashState;
6d1a542003-03-13Niels Möller  CVAR struct sha1_ctx sha1; INIT {
cd26482003-03-18Niels Möller  struct HashState_struct *instance
9119632003-05-07Henrik Grubbström (Grubba)  = (struct HashState_struct *) get_storage(Pike_fp->current_object, HashState_program);
cd26482003-03-18Niels Möller  werror("SHA1_State->INIT\n");
6d1a542003-03-13Niels Möller  assert(instance); sha1_init(&THIS->sha1); instance->ctx = &THIS->sha1; } }
411a282003-03-18Niels Möller /*! @endclass SHA1_State */
6d1a542003-03-13Niels Möller 
0980772003-07-29Martin Nilsson /*! @class SHA256_Info *! *! Internal mixin class, intended to be multiply inherited *! together with HashInfo. */ PIKECLASS SHA256_Info { INIT { struct HashInfo_struct *HashInfo = (struct HashInfo_struct *) get_storage(Pike_fp->current_object, HashInfo_program); werror("SHA256_Info->INIT\n"); if (HashInfo && !HashInfo->meta) HashInfo->meta = &nettle_sha256; else { /* Can't call Pike_error here. * Pike_error("Can't initialize this object.\n"); */ werror("SHA256_Info->INIT failed\n"); } } } /*! @endclass SHA256_Info */ /*! @class SHA256_State *! *! State for SHA256 hashing. */ PIKECLASS SHA256_State { INHERIT SHA256_Info; INHERIT HashState; CVAR struct sha256_ctx sha256; INIT { struct HashState_struct *instance = (struct HashState_struct *) get_storage(Pike_fp->current_object, HashState_program); werror("SHA256_State->INIT\n"); assert(instance); sha256_init(&THIS->sha256); instance->ctx = &THIS->sha256; } } /*! @endclass SHA256_State */
411a282003-03-18Niels Möller /*! @endmodule Nettle */
6d1a542003-03-13Niels Möller  void hash_init(void) { werror("Nettle, hash init\n"); INIT; } void hash_exit(void) { werror("Nettle, hash exit\n");
5a20f92004-04-28Martin Nilsson  if (Fd_ref_program) { free_program( Fd_ref_program ); }
6d1a542003-03-13Niels Möller  EXIT; } #endif /* HAVE_LIBNETTLE */