01e1152003-03-12Niels Möller /* nettle.cmod -*- c -*- */ #include "global.h"
a5a7b82003-11-26Martin Nilsson RCSID("$Id: nettle.cmod,v 1.20 2003/11/25 23:30:40 nilsson Exp $");
01e1152003-03-12Niels Möller #include "interpret.h" #include "svalue.h" /* For this_object() */ #include "object.h" #include "module_support.h"
4e1f622003-03-13Niels Möller #include "nettle_config.h"
770fee2003-03-12Henrik Grubbström (Grubba) #ifdef HAVE_LIBNETTLE
efb89c2003-08-06Henrik Grubbström (Grubba) #include "nettle.h"
01e1152003-03-12Niels Möller 
3184172003-08-06Henrik Grubbström (Grubba) #include <nettle/yarrow.h>
01e1152003-03-12Niels Möller #include <assert.h> #include <stdio.h> #include <stdarg.h> DECLARATIONS /*! @module Nettle
d745992003-08-05Martin Nilsson  *! Low level crypto functions used by the @[Crypto] module. Unless *! you are doing something very special, you would want to use the *! Crypto module instead. */ /*! @class Yarrow *! *! Yarrow is a family of pseudo-randomness generators, designed for *! cryptographic use, by John Kelsey, Bruce Schneier and Niels Ferguson. *! Yarrow-160 is described in a paper at *! @url{http://www.counterpane.com/yarrow.html@}, and it uses SHA1 and *! triple-DES, and has a 160-bit internal state. Nettle implements *! Yarrow-256, which is similar, but uses SHA256 and AES to get an *! internal state of 256 bits. */ PIKECLASS Yarrow {
49acab2003-11-09Niels Möller  CVAR struct yarrow256_ctx ctx;
25f5432003-08-06Martin Nilsson  CVAR struct yarrow_source *sources;
9109472003-08-07Martin Nilsson  /*! @decl void create(void|int sources) *! The number of entropy sources that will feed entropy to the *! random number generator is given as an argument to Yarrow *! during instantiation. *! @seealso *! @[update] */
25f5432003-08-06Martin Nilsson  PIKEFUN void create(void|int arg) { INT32 num = 0; if(arg) { if (arg->type != PIKE_T_INT) Pike_error("Bad argument type.\n"); num = arg->u.integer; if(num < 0) Pike_error("Invalid number of sources.\n");
49acab2003-11-09Niels Möller  free (THIS->sources);
25f5432003-08-06Martin Nilsson  THIS->sources = xalloc(sizeof(struct yarrow_source)*num); }
49acab2003-11-09Niels Möller  else { free (THIS->sources); THIS->sources = NULL; } yarrow256_init(&THIS->ctx, num, THIS->sources);
d745992003-08-05Martin Nilsson  } /*! @decl Yarrow seed(string data) *! The random generator needs to be seeded before *! it can be used. The seed must be at least 32 *! characters long. The seed could be stored from *! a previous run by inserting the value returned *! from @[get_seed]. *! @returns *! Returns the called object.
9109472003-08-07Martin Nilsson  *! @seealso *! @[min_seed_size], @[get_seed], @[is_seeded]
d745992003-08-05Martin Nilsson  */ PIKEFUN object seed(string data) { if(data->len < YARROW256_SEED_FILE_SIZE) Pike_error( "Seed must be at least 32 characters.\n" ); NO_WIDE_STRING(data);
49acab2003-11-09Niels Möller  yarrow256_seed(&THIS->ctx, data->len, data->str);
d745992003-08-05Martin Nilsson  RETURN this_object(); }
9109472003-08-07Martin Nilsson  /*! @decl int(0..) min_seed_size() *! Returns the minimal number of characters that the @[seed] *! needs to properly seed the random number generator. *! @seealso *! @[seed] */ PIKEFUN int(0..) min_seed_size() { RETURN YARROW256_SEED_FILE_SIZE; }
d745992003-08-05Martin Nilsson  /*! @decl string get_seed() *! Returns part of the internal state so that it can *! be saved for later seeding.
9109472003-08-07Martin Nilsson  *! @seealso *! @[seed]
d745992003-08-05Martin Nilsson  */ PIKEFUN string get_seed() {
324ca82003-11-10Niels Möller  if( !yarrow256_is_seeded(&THIS->ctx) ) Pike_error("Random generator not seeded.\n");
49acab2003-11-09Niels Möller  RETURN make_shared_binary_string(THIS->ctx.seed_file, YARROW256_SEED_FILE_SIZE);
d745992003-08-05Martin Nilsson  } /*! @decl int(0..1) is_seeded() *! Returns 1 if the random generator is seeded and ready *! to generator output. 0 otherwise.
9109472003-08-07Martin Nilsson  *! @seealso *! @[seed]
d745992003-08-05Martin Nilsson  */ PIKEFUN int(0..1) is_seeded() {
49acab2003-11-09Niels Möller  RETURN yarrow256_is_seeded(&THIS->ctx);
d745992003-08-05Martin Nilsson  }
9109472003-08-07Martin Nilsson  /*! @decl void force_reseed() *! By calling this function entropy is moved from the slow *! pool to the fast pool. Read more about Yarrow before using *! this. */
d745992003-08-05Martin Nilsson  PIKEFUN void force_reseed() {
49acab2003-11-09Niels Möller  yarrow256_force_reseed(&THIS->ctx);
d745992003-08-05Martin Nilsson  }
9109472003-08-07Martin Nilsson  /*! @decl int(0..1) update(string data, int source, int entropy) *! Inject additional entropy into the random number generator. *! *! @seealso *! @[create] */
f1d8912003-08-06Martin Nilsson  PIKEFUN int(0..1) update(string data, int source, int entropy) {
49acab2003-11-09Niels Möller  /* FIXME: Wide strings could actually be supported here */
f1d8912003-08-06Martin Nilsson  NO_WIDE_STRING(data);
49acab2003-11-09Niels Möller  if( !THIS->sources )
f1d8912003-08-06Martin Nilsson  Pike_error("This random generator has no sources.\n");
49acab2003-11-09Niels Möller  if( source<0 || source>=THIS->ctx.nsources )
f1d8912003-08-06Martin Nilsson  Pike_error("Invalid random source.\n"); if( entropy<0 ) Pike_error("Entropy must be positive.\n");
9109472003-08-07Martin Nilsson  if( entropy>(data->len*8) ) Pike_error("Impossibly large entropy value.\n");
49acab2003-11-09Niels Möller  RETURN yarrow256_update(&THIS->ctx, source, entropy, data->len, data->str);
f1d8912003-08-06Martin Nilsson  }
d745992003-08-05Martin Nilsson  PIKEFUN int(0..) needed_sources() {
49acab2003-11-09Niels Möller  RETURN yarrow256_needed_sources(&THIS->ctx);
d745992003-08-05Martin Nilsson  } /*! @decl string random_string(int length) *! Returns a pseudo-random string of the requested @[length]. */ PIKEFUN string random_string(int length) { struct pike_string *rnd; if(length < 0) Pike_error("Invalid length, must be positive.\n");
49acab2003-11-09Niels Möller  if( !yarrow256_is_seeded(&THIS->ctx) )
d745992003-08-05Martin Nilsson  Pike_error("Random generator not seeded.\n"); rnd = begin_shared_string(length);
49acab2003-11-09Niels Möller  yarrow256_random(&THIS->ctx, length, rnd->str);
d745992003-08-05Martin Nilsson  RETURN end_shared_string(rnd); } INIT {
49acab2003-11-09Niels Möller  THIS->sources = NULL; yarrow256_init(&THIS->ctx, 0, NULL);
d745992003-08-05Martin Nilsson  } EXIT {
49acab2003-11-09Niels Möller  /* It's ok to call free(NULL); */ free(THIS->sources);
d745992003-08-05Martin Nilsson  } } /*! @endclass
01e1152003-03-12Niels Möller  */
3955a92003-08-24Martin Nilsson char *crypt_md5(int pl, const char *pw, int sl, const char *salt);
9d4fc82003-08-25Martin Nilsson /*! @decl string crypt_md5(string password, string salt) *! Does the crypt_md5 abrakadabra (MD5 + snakeoil).
3955a92003-08-24Martin Nilsson  *! It is assumed that @[salt] does not contain "$". */ PIKEFUN string crypt_md5(string pw, string salt) { NO_WIDE_STRING(pw); NO_WIDE_STRING(salt); RETURN make_shared_string(crypt_md5(pw->len, pw->str, salt->len, salt->str)); }
a5a7b82003-11-26Martin Nilsson /*! @class CBC *! Implementation of the cipher block chaining mode (CBC). */ PIKECLASS CBC { CVAR struct object *object; CVAR unsigned INT8 *iv; CVAR INT32 block_size; CVAR INT32 mode; static const char *crypto_functions[] = { "block_size", "key_size", "set_encrypt_key", "set_decrypt_key", "crypt", NULL }; INIT { THIS->object = 0; THIS->iv = 0; THIS->block_size = 0; THIS->mode = 0; } EXIT { if(THIS->object) free_object(THIS->object); if(THIS->iv) { memset(THIS->iv, 0, THIS->block_size); free(THIS->iv); } THIS->iv = 0; } INLINE static void assert_is_crypto_object(struct program *p, const char **required) { while (*required) { if (find_identifier( (char *) *required, p) < 0) { Pike_error("Object is missing identifier \"%s\"\n", *required); } required++; } } INLINE static void cbc_encrypt_step(const unsigned INT8 *source, unsigned INT8 *dest) { INT32 block_size = THIS->block_size; INT32 i; for(i=0; i < block_size; i++) THIS->iv[i] ^= source[i]; push_string(make_shared_binary_string((INT8 *)THIS->iv, block_size)); safe_apply(THIS->object, "crypt", 1); if(Pike_sp[-1].type != T_STRING) Pike_error("Expected string from crypt()\n"); if(Pike_sp[-1].u.string->len != block_size) { Pike_error("Bad string length %ld returned from crypt()\n", DO_NOT_WARN((long)Pike_sp[-1].u.string->len)); } MEMCPY(THIS->iv, Pike_sp[-1].u.string->str, block_size); MEMCPY(dest, Pike_sp[-1].u.string->str, block_size); pop_stack(); } INLINE static void cbc_decrypt_step(const unsigned INT8 *source, unsigned INT8 *dest) { INT32 block_size = THIS->block_size; INT32 i; push_string(make_shared_binary_string((const INT8 *)source, block_size)); safe_apply(THIS->object, "crypt", 1); if(Pike_sp[-1].type != T_STRING) Pike_error("Expected string from crypt()\n"); if(Pike_sp[-1].u.string->len != block_size) { Pike_error("Bad string length %ld returned from crypt()\n", DO_NOT_WARN((long)Pike_sp[-1].u.string->len)); } for(i=0; i < block_size; i++) dest[i] = THIS->iv[i] ^ Pike_sp[-1].u.string->str[i]; pop_stack(); MEMCPY(THIS->iv, source, block_size); } /*! @decl void create(program|object algorithm, mixed ... args) */ PIKEFUN void create(program|object algorithm, mixed ... more) { switch(algorithm->type) { case T_PROGRAM: THIS->object = clone_object(algorithm->u.program, args-1); break; case T_FUNCTION: apply_svalue(Pike_sp - args, args-1); /* Check return value */ if(Pike_sp[-1].type != T_OBJECT) Pike_error("Returned value is not an object.\n"); add_ref(THIS->object = Pike_sp[-1].u.object); break; case T_OBJECT: if(args!=1) Pike_error("Too many arguments.\n"); add_ref(THIS->object = algorithm->u.object); break; default: SIMPLE_BAD_ARG_ERROR("CBC->create", 1, "program|object"); } pop_stack(); /* Just one element left on the stack in all cases */ assert_is_crypto_object(THIS->object->prog, crypto_functions); safe_apply(THIS->object, "block_size", 0); if(Pike_sp[-1].type != T_INT) Pike_error("block_size() didn't return an int.\n"); THIS->block_size = Pike_sp[-1].u.integer; pop_stack(); if ((!THIS->block_size) || (THIS->block_size > 4096)) Pike_error("Bad block size %d.\n", THIS->block_size); THIS->iv = (unsigned INT8 *)xalloc(THIS->block_size); MEMSET(THIS->iv, 0, THIS->block_size); } /*! @decl int block_size() */ PIKEFUN int block_size() { RETURN THIS->block_size; } /*! @decl int key_size() */ PIKEFUN int key_size() { safe_apply(THIS->object, "key_size", args); } /*! @decl void set_encrypt_key(string key) */ PIKEFUN object set_encrypt_key(string key) { assert(THIS->block_size); NO_WIDE_STRING(key); THIS->mode = 0; safe_apply(THIS->object, "set_encrypt_key", args); pop_stack(); RETURN this_object(); } /*! @decl void set_decrypt_key(string key) */ PIKEFUN object set_decrypt_key(string key) { f_CBC_set_encrypt_key(args); THIS->mode = 1; } PIKEFUN object set_iv(string iv) { assert(THIS->iv); NO_WIDE_STRING(iv); if(iv->len != THIS->block_size) Pike_error("Argument incompatible with cipher block size.\n"); MEMCPY(THIS->iv, iv->str, THIS->block_size); RETURN this_object(); } PIKEFUN string crypt(string data) { unsigned INT8 *result; INT32 offset = 0; NO_WIDE_STRING(data); if(data->len % THIS->block_size) Pike_error("Data length not multiple of block size.\n"); if(!(result = alloca(data->len))) Pike_error("Out of memory.\n"); if(THIS->mode == 0) { while (offset < data->len) { cbc_encrypt_step((const unsigned INT8 *)data->str + offset, result + offset); offset += THIS->block_size; } } else { while (offset < data->len) { cbc_encrypt_step((const unsigned INT8 *)data->str + offset, result + offset); offset += THIS->block_size; } } pop_n_elems(args); push_string(make_shared_binary_string((INT8 *)result, offset)); MEMSET(result, 0, offset); } } /*! @endclass */
1ab4b12003-03-18Niels Möller /*! @endmodule */
770fee2003-03-12Henrik Grubbström (Grubba) 
654f152003-03-14Marcus Comstedt #endif /* HAVE_LIBNETTLE */
4e1f622003-03-13Niels Möller PIKE_MODULE_INIT { INIT;
654f152003-03-14Marcus Comstedt #ifdef HAVE_LIBNETTLE
4e1f622003-03-13Niels Möller  hash_init();
636c422003-03-18Niels Möller  cipher_init();
654f152003-03-14Marcus Comstedt #endif /* HAVE_LIBNETTLE */
4e1f622003-03-13Niels Möller } PIKE_MODULE_EXIT {
654f152003-03-14Marcus Comstedt #ifdef HAVE_LIBNETTLE
636c422003-03-18Niels Möller  cipher_exit();
4e1f622003-03-13Niels Möller  hash_exit();
654f152003-03-14Marcus Comstedt #endif /* HAVE_LIBNETTLE */
4e1f622003-03-13Niels Möller  EXIT; }