/* hash.cmod -*- c -*- */ |
|
#include "global.h" |
RCSID("$Id: hash.cmod,v 1.7 2003/07/29 03:44:39 nilsson Exp $"); |
#include "interpret.h" |
#include "svalue.h" |
|
/* For this_object() */ |
#include "object.h" |
#include "module_support.h" |
|
#include "nettle_config.h" |
|
#ifdef HAVE_LIBNETTLE |
|
#include "nettle.h" |
|
#include <nettle/md5.h> |
#include <nettle/sha.h> |
#include <nettle/nettle-meta.h> |
|
#include <assert.h> |
#include <stdio.h> |
#include <stdarg.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 HashInfo |
*! |
*! Represents information about a hash algorithm, such as |
*! name, digest size, and internal block size. |
*/ |
PIKECLASS HashInfo |
{ |
CVAR const struct nettle_hash *meta; |
|
/*! @decl string name(void) |
*! |
*! Returns a human readable name for the algorithm. |
*/ |
PIKEFUN string name() |
{ |
if (!THIS->meta) |
Pike_error("HashInfo not properly initialized."); |
|
push_string(make_shared_string(THIS->meta->name)); |
} |
|
/*! @decl string digest_size(void) |
*! |
*! Returns the size of a hash digests. |
*/ |
PIKEFUN int digest_size() |
{ |
if (!THIS->meta) |
Pike_error("HashInfo not properly initialized."); |
|
push_int(THIS->meta->digest_size); |
} |
|
/*! @decl string block_size(void) |
*! |
*! REturns the internal block size of the hash algorithm. |
*/ |
PIKEFUN int block_size() |
{ |
if (!THIS->meta) |
Pike_error("HashInfo not properly initialized."); |
|
push_int(THIS->meta->block_size); |
} |
INIT |
{ |
werror("HashInfo->INIT\n"); |
THIS->meta = NULL; |
} |
} |
|
/*! @endclass HashInfo */ |
|
#define GET_META(o) \ |
( ((struct HashInfo_struct *) get_storage((o), HashInfo_program)) \ |
->meta) |
|
/* The algorithm objects have to be implemented in pike. */ |
|
/*! @class HashState |
*! |
*! Base class for hashing contexts. |
*/ |
PIKECLASS HashState |
{ |
INHERIT HashInfo; |
CVAR void *ctx; |
|
/* FIXME: Create should copy state from the other object, if |
* provided. */ |
|
/*! @decl HashState update(string data) |
*! |
*! Hashes more data. |
*/ |
PIKEFUN object update(string data) |
{ |
const struct nettle_hash *meta = |
GET_META(Pike_fp->current_object); |
|
if (!THIS->ctx || !meta) |
Pike_error("hash_state not properly initialized."); |
|
NO_WIDE_STRING(data); |
meta->update(THIS->ctx, data->len, data->str); |
|
push_object(this_object()); |
} |
|
/*! @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. |
*! |
*! @returns |
*! The digest. |
*/ |
PIKEFUN string digest(int|void arg) |
{ |
const struct nettle_hash *meta; |
struct pike_string *digest; |
unsigned length; |
|
if (! THIS->ctx) |
Pike_error("hash_state not properly initialized."); |
|
meta = GET_META(Pike_fp->current_object); |
assert(meta); |
|
if (!arg) |
length = meta->digest_size; |
else |
{ |
if (arg->type != PIKE_T_INT) |
Pike_error("Bad argument type"); |
if (arg->u.integer <= 0) |
Pike_error("Invalid argument, must be positive.\n"); |
if (arg->u.integer > meta->digest_size) |
Pike_error("Unsupported digest length"); |
|
length = arg->u.integer; |
} |
|
digest = begin_shared_string(length); |
meta->digest(THIS->ctx, length, digest->str); |
push_string(end_shared_string(digest)); |
} |
|
/*! @decl string hash(string data) |
*! |
*! Works as a shortcut for @expr{obj->update(data)->digest()@}. |
*! |
*! @note |
*! The hash buffer will not be cleared before @[data] is added |
*! to the buffer, so data added with calls to @[update] will be |
*! prepended to the @[data]. |
*! |
*! @seealso |
*! @[update] and @[digest]. |
*/ |
PIKEFUN string hash(string data) { |
f_HashState_update(args); |
pop_stack(); |
f_HashState_digest(0); |
} |
|
INIT |
{ |
werror("HashState->INIT\n"); |
THIS->ctx = NULL; |
} |
EXIT |
{ |
werror("HashState->EXIT\n"); |
if (THIS->ctx && Pike_fp->current_object->prog) |
{ |
const struct nettle_hash *meta = |
GET_META(Pike_fp->current_object); |
assert(meta); |
memset(THIS->ctx, 0, meta->context_size); |
} |
} |
} |
|
/*! @endclass HashState */ |
|
/*! @class MD5_Info |
*! |
*! Internal mixin class, intended to be multiply inherited |
*! together with HashInfo. */ |
|
PIKECLASS MD5_Info |
{ |
INIT |
{ |
struct HashInfo_struct *HashInfo |
= (struct HashInfo_struct *) get_storage(Pike_fp->current_object, |
HashInfo_program); |
|
werror("MD5_Info->INIT\n"); |
|
if (HashInfo && !HashInfo->meta) |
HashInfo->meta = &nettle_md5; |
else { |
/* Can't call Pike_error here. |
* Pike_error("Can't initialize this object.\n"); */ |
werror("MD5_Info->INIT failed\n"); |
} |
} |
} |
|
/*! @endclass MD5_Info */ |
|
/*! @class MD5_State |
*! |
*! State for MD5 hashing. |
*/ |
PIKECLASS MD5_State |
{ |
INHERIT MD5_Info; |
INHERIT HashState; |
CVAR struct md5_ctx md5; |
|
INIT |
{ |
struct HashState_struct *instance |
= (struct HashState_struct *) get_storage(Pike_fp->current_object, |
HashState_program); |
werror("MD5_State->INIT\n"); |
|
assert(instance); |
|
md5_init(&THIS->md5); |
instance->ctx = &THIS->md5; |
} |
} |
/*! @endclass MD5_State */ |
|
/*! @class SHA1_Info |
*! |
*! Internal mixin class, intended to be multiply inherited |
*! together with HashInfo. */ |
|
PIKECLASS SHA1_Info |
{ |
INIT |
{ |
struct HashInfo_struct *HashInfo |
= (struct HashInfo_struct *) get_storage(Pike_fp->current_object, |
HashInfo_program); |
|
werror("SHA1_Info->INIT\n"); |
|
if (HashInfo && !HashInfo->meta) |
HashInfo->meta = &nettle_sha1; |
else { |
/* Can't call Pike_error here. |
* Pike_error("Can't initialize this object.\n"); */ |
werror("SHA1_Info->INIT failed\n"); |
} |
} |
} |
|
/*! @endclass SHA1_Info */ |
|
/*! @class SHA1_State |
*! |
*! State for SHA1 hashing. |
*/ |
|
PIKECLASS SHA1_State |
{ |
INHERIT SHA1_Info; |
INHERIT HashState; |
CVAR struct sha1_ctx sha1; |
|
INIT |
{ |
struct HashState_struct *instance |
= (struct HashState_struct *) get_storage(Pike_fp->current_object, |
HashState_program); |
werror("SHA1_State->INIT\n"); |
|
assert(instance); |
|
sha1_init(&THIS->sha1); |
instance->ctx = &THIS->sha1; |
} |
} |
/*! @endclass SHA1_State */ |
|
/*! @endmodule Nettle */ |
|
void |
hash_init(void) |
{ |
werror("Nettle, hash init\n"); |
INIT; |
} |
|
void |
hash_exit(void) |
{ |
werror("Nettle, hash exit\n"); |
EXIT; |
} |
|
#endif /* HAVE_LIBNETTLE */ |
|