/* nettle.cmod -*- c -*- */ |
|
#include "global.h" |
RCSID("$Id: nettle.cmod,v 1.1 2003/03/12 17:07:10 nisse Exp $"); |
#include "interpret.h" |
#include "svalue.h" |
|
/* For this_object() */ |
#include "object.h" |
|
#include "module_support.h" |
|
#include "nettle.h" |
|
#include <nettle/md5.h> |
#include <nettle/aes.h> |
#include <nettle/sha.h> |
#include <nettle/nettle-meta.h> |
|
#include <assert.h> |
#include <stdio.h> |
#include <stdarg.h> |
|
/* #define sp Pike_sp */ |
|
DECLARATIONS |
|
#if 1 |
void |
werror(const char *format, ...) |
{ |
va_list args; |
|
va_start(args, format); |
vfprintf(stderr, format, args); |
va_end(args); |
} |
#endif |
|
/*! @module Nettle |
*/ |
|
PIKECLASS nettle_hash |
{ |
CVAR const struct nettle_hash *meta; |
|
PIKEFUN string name() |
{ |
if (!THIS->meta) |
Pike_error("nettle_hash not properly initialized."); |
|
push_string(make_shared_string(THIS->meta->name)); |
} |
|
PIKEFUN int digest_size() |
{ |
if (!THIS->meta) |
Pike_error("nettle_hash not properly initialized."); |
|
push_int(THIS->meta->digest_size); |
} |
|
PIKEFUN int block_size() |
{ |
if (!THIS->meta) |
Pike_error("nettle_hash not properly initialized."); |
|
push_int(THIS->meta->block_size); |
} |
INIT |
{ |
/* werror("nettle_hash->INIT\n"); */ |
THIS->meta = NULL; |
} |
} |
|
#define GET_META(o) \ |
( ((struct nettle_hash_struct *) get_storage((o), nettle_hash_program)) \ |
->meta) |
|
|
PIKECLASS hash_state |
{ |
INHERIT nettle_hash; |
|
/* FIXME: The ctx pointer isn't strictly needed, as the ctx is in |
* the storage area just after the poitner. But this seems like the |
* simplest and most portable way to get to it. */ |
CVAR void *ctx; |
|
PIKEFUN object update(string data) |
{ |
const struct nettle_hash *meta; |
|
if (! THIS->ctx) |
Pike_error("hash_state not properly initialized."); |
|
meta = GET_META(this_object()); |
|
NO_WIDE_STRING(data); |
meta->update(THIS->ctx, data->len, data->str); |
|
push_object(this_object()); |
} |
|
PIKEFUN string digest(int|void arg) |
{ |
const struct nettle_hash *meta; |
struct pike_string *digest; |
INT32 length; |
|
if (! THIS->ctx) |
Pike_error("hash_state not properly initialized."); |
|
meta = GET_META(this_object()); |
|
if (!arg) |
length = meta->digest_size; |
else |
{ |
if (arg->type != PIKE_T_INT) |
Pike_error("Bad argument type"); |
length = arg->u.integer; |
if (length <= 0 || length > meta->digest_size) |
Pike_error("Unsupported digest length"); |
} |
|
digest = begin_shared_string(length); |
meta->digest(THIS->ctx, length, digest->str); |
push_string(end_shared_string(digest)); |
} |
INIT |
{ |
/* werror("hash_state->INIT\n"); */ |
THIS->ctx = NULL; |
} |
} |
|
PIKECLASS sha1_state |
{ |
INHERIT hash_state; |
CVAR struct sha1_ctx ctx; |
|
/* FIXME: Move this to the generic hash_state class. */ |
PIKEFUN void create(void|object arg) |
{ |
struct sha1_state_struct *other; |
|
if (!arg) |
return; |
|
if ( (arg->type == PIKE_T_OBJECT) |
&& ((other = (struct sha1_state_struct *) |
get_storage(arg->u.object, sha1_state_program))) ) |
{ |
memcpy(&THIS->ctx, &other->ctx, sizeof(THIS->ctx)); |
return; |
} |
else |
Pike_error("Can't copy an incompatible hash state."); |
} |
|
INIT |
{ |
struct hash_state_struct *hash_state; |
struct nettle_hash_struct *nettle_hash; |
|
/* werror("sha1_state->INIT\n"); */ |
|
hash_state = (struct hash_state_struct *) |
get_storage(this_object(), hash_state_program); |
nettle_hash = (struct nettle_hash_struct *) |
get_storage(this_object(), nettle_hash_program); |
|
assert(hash_state); |
assert(nettle_hash); |
|
nettle_hash->meta = &nettle_sha1; |
hash_state->ctx = &THIS->ctx; |
|
sha1_init(&THIS->ctx); |
} |
} |
|
PIKECLASS md5 |
{ |
CVAR struct md5_ctx ctx; |
|
PIKEFUN string name() |
{ |
push_string(make_shared_string("md5")); |
} |
|
PIKEFUN int digest_size() |
{ |
push_int(MD5_DIGEST_SIZE); |
} |
|
PIKEFUN int block_size() |
{ |
push_int(MD5_DATA_SIZE); |
} |
|
PIKEFUN object update(string data) |
{ |
/* FIXME: What about multibyte strings? */ |
md5_update(&THIS->ctx, data->len, data->str); |
|
push_object(this_object()); |
} |
|
PIKEFUN string digest(int|void arg) |
{ |
struct pike_string *digest; |
INT32 length; |
|
if (!arg) |
length = MD5_DIGEST_SIZE; |
else |
{ |
if (arg->type != PIKE_T_INT) |
Pike_error("Bad argument type"); |
length = arg->u.integer; |
if (length <= 0 || length > MD5_DIGEST_SIZE) |
Pike_error("Unsupported digest length"); |
} |
|
digest = begin_shared_string(length); |
md5_digest(&THIS->ctx, length, digest->str); |
push_string(end_shared_string(digest)); |
} |
|
INIT |
{ |
/* werror("md5->INIT\n"); */ |
md5_init(&THIS->ctx); |
} |
|
EXIT |
{ |
memset(&THIS->ctx, 0, sizeof(THIS->ctx)); |
} |
} |
|
PIKECLASS aes |
{ |
CVAR struct aes_ctx ctx; |
CVAR void (*f)(struct aes_ctx *, unsigned length, |
uint8_t *dst, const uint8_t *src); |
|
PIKEFUN string name() |
{ |
push_string(make_shared_string("aes")); |
} |
|
PIKEFUN int key_size() |
{ |
/* Recommended key size. */ |
push_int(AES_KEY_SIZE); |
} |
|
PIKEFUN int block_size() |
{ |
push_int(AES_BLOCK_SIZE); |
} |
|
PIKEFUN object set_encrypt_key(string key) |
{ |
NO_WIDE_STRING(key); |
|
if ( (key->len < AES_MIN_KEY_SIZE) |
|| (key->len > AES_MAX_KEY_SIZE) ) |
Pike_error("Invalid key size for aes."); |
|
aes_set_encrypt_key(&THIS->ctx, key->len, key->str); |
|
THIS->f = aes_encrypt; |
|
push_object(this_object()); |
} |
|
PIKEFUN object set_decrypt_key(string key) |
{ |
NO_WIDE_STRING(key); |
|
if ( (key->len < AES_MIN_KEY_SIZE) |
|| (key->len > AES_MAX_KEY_SIZE) ) |
Pike_error("Invalid key size for aes."); |
aes_set_decrypt_key(&THIS->ctx, key->len, key->str); |
|
THIS->f = aes_decrypt; |
|
push_object(this_object()); |
} |
|
PIKEFUN string crypt(string data) |
{ |
struct pike_string *s; |
/* werror("aes->encrypt\n"); */ |
|
#if 0 |
{ |
struct aes_ctx test_ctx; |
const uint8_t clear[16] = "aaaaaaaaaaaaaaaa"; |
uint8_t cipher[16]; |
|
werror("tfoo\n"); |
|
aes_set_encrypt_key(&test_ctx, 16, "0123456789abcdef"); |
werror("tbar\n"); |
|
aes_encrypt(&test_ctx, 16, cipher, clear); |
|
werror("tbaz\n"); |
} |
#endif |
|
if (!THIS->f) |
Pike_error("Must install an encrypt or decrypt key first."); |
|
// werror("foo\n"); |
|
NO_WIDE_STRING(data); |
|
// werror("bar\n"); |
|
if (data->len % AES_BLOCK_SIZE) |
Pike_error("Data must be an integer number of blocks."); |
|
// werror("baz\n"); |
|
s = begin_shared_string(data->len); |
|
// werror("bazz\n"); |
|
// werror("ctx = %p, len = %d, dst = %p, src = %p\n", |
// &THIS->ctx, data->len, s->str, data->str); |
|
THIS->f(&THIS->ctx, data->len, s->str, data->str); |
/* aes_encrypt(&THIS->ctx, data->len, s->str, data->str); */ |
|
// werror("bazzz\n"); |
|
push_string(end_shared_string(s)); |
|
// werror("bazzzz\n"); |
} |
|
INIT |
{ |
/* werror("aes->INIT\n"); */ |
THIS->f = NULL; |
} |
|
EXIT |
{ |
/* werror("aes->EXIT\n"); */ |
memset(&THIS->ctx, 0, sizeof(THIS->ctx)); |
} |
} |
|