01e1152003-03-12Niels Möller /* nettle.cmod -*- c -*- */ #include "global.h"
770fee2003-03-12Henrik Grubbström (Grubba) RCSID("$Id: nettle.cmod,v 1.2 2003/03/12 20:33:33 grubba Exp $");
01e1152003-03-12Niels Möller #include "interpret.h" #include "svalue.h" /* For this_object() */ #include "object.h" #include "module_support.h"
770fee2003-03-12Henrik Grubbström (Grubba) #ifdef HAVE_LIBNETTLE
01e1152003-03-12Niels Möller #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
770fee2003-03-12Henrik Grubbström (Grubba)  * the storage area just after the pointer. But this seems like the
01e1152003-03-12Niels Möller  * 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)); } }
770fee2003-03-12Henrik Grubbström (Grubba)  #endif /* HAVE_LIBNETTLE */