01e1152003-03-12Niels Möller /* nettle.cmod -*- c -*- */ #include "global.h"
d7f88a2004-02-14Martin Nilsson RCSID("$Id: nettle.cmod,v 1.32 2004/02/13 23:27:29 nilsson Exp $");
01e1152003-03-12Niels Möller #include "interpret.h" #include "svalue.h" /* For this_object() */ #include "object.h"
7d54f42004-01-23Martin Nilsson #include "operators.h"
01e1152003-03-12Niels Möller #include "module_support.h"
d7f88a2004-02-14Martin Nilsson #include "threads.h"
01e1152003-03-12Niels Möller 
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] */
d7f88a2004-02-14Martin Nilsson  PIKEFUN void create(void|int arg) {
25f5432003-08-06Martin Nilsson  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)
d7f88a2004-02-14Martin Nilsson  optflags OPT_SIDE_EFFECT;
d745992003-08-05Martin Nilsson  { 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()
d7f88a2004-02-14Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
9109472003-08-07Martin Nilsson  { 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()
d7f88a2004-02-14Martin Nilsson  optflags OPT_EXTERNAL_DEPEND;
d745992003-08-05Martin Nilsson  {
324ca82003-11-10Niels Möller  if( !yarrow256_is_seeded(&THIS->ctx) ) Pike_error("Random generator not seeded.\n");
d7f88a2004-02-14Martin Nilsson  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()
d7f88a2004-02-14Martin Nilsson  optflags OPT_EXTERNAL_DEPEND;
d745992003-08-05Martin Nilsson  {
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()
d7f88a2004-02-14Martin Nilsson  optflags OPT_SIDE_EFFECT;
d745992003-08-05Martin Nilsson  {
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)
d7f88a2004-02-14Martin Nilsson  optflags OPT_SIDE_EFFECT;
f1d8912003-08-06Martin Nilsson  {
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");
61e14b2004-01-23Martin Nilsson  if( source<0 || (unsigned)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  }
01a1ba2003-12-14Martin Nilsson  /*! @decl int(0..) needed_sources() *! The number of sources that must reach the threshold before a *! slow reseed will happen. */
d745992003-08-05Martin Nilsson  PIKEFUN int(0..) needed_sources()
d7f88a2004-02-14Martin Nilsson  optflags OPT_EXTERNAL_DEPEND;
d745992003-08-05Martin Nilsson  {
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)
d7f88a2004-02-14Martin Nilsson  optflags OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT; /* We could however set this to not have side effect to allow unused values from not getting generated. */
d745992003-08-05Martin Nilsson  { 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)
d7f88a2004-02-14Martin Nilsson  optflags OPT_TRY_OPTIMIZE;
3955a92003-08-24Martin Nilsson { NO_WIDE_STRING(pw); NO_WIDE_STRING(salt);
d7f88a2004-02-14Martin Nilsson  THREADS_ALLOW(); push_text(crypt_md5(pw->len, pw->str,salt->len, salt->str)); THREADS_DISALLOW();
3955a92003-08-24Martin Nilsson }
221ebe2003-12-06Martin Nilsson  static const char *crypto_functions[] = { "block_size", "key_size", "set_encrypt_key", "set_decrypt_key", "crypt", 0 };
61e14b2004-01-23Martin Nilsson static const char * assert_is_crypto_object(struct program *p,
221ebe2003-12-06Martin Nilsson  const char **required) { while (*required) { if (find_identifier( (char *) *required, p) < 0) return *required; required++; } return 0; }
44ee952003-12-06Martin Nilsson static struct object *make_cipher_object(INT32 args) { ptrdiff_t fun;
61e14b2004-01-23Martin Nilsson  const char *missing;
44ee952003-12-06Martin Nilsson  struct svalue *top = Pike_sp-args; struct object *obj; switch(top->type) { case T_PROGRAM: obj = clone_object(top->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(obj = Pike_sp[-1].u.object); break; case T_OBJECT: fun = -1; missing = assert_is_crypto_object(top->u.object->prog, crypto_functions); if(missing) fun = FIND_LFUN(top->u.object->prog, LFUN_CALL); if(fun!=-1) { apply_low(top->u.object, fun, args-1); stack_swap(); pop_stack(); } else if(args!=1) Pike_error("Too many arguments.\n"); add_ref(obj = top->u.object); break; default: SIMPLE_BAD_ARG_ERROR("create", 1, "program|object|function"); } pop_stack(); missing = assert_is_crypto_object(obj->prog, crypto_functions); if(missing) { free_object(obj); Pike_error("Object is missing identifier \"%s\"\n", missing); } return obj; }
221ebe2003-12-06Martin Nilsson 
a5a7b82003-11-26Martin Nilsson /*! @class CBC
01a1ba2003-12-14Martin Nilsson  *! Implementation of the cipher block chaining mode (CBC). Works as *! a wrapper for the cipher algorithm put in create.
a5a7b82003-11-26Martin Nilsson  */ PIKECLASS CBC { CVAR struct object *object; CVAR unsigned INT8 *iv; CVAR INT32 block_size; CVAR INT32 mode; 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) {
44ee952003-12-06Martin Nilsson  MEMSET(THIS->iv, 0, THIS->block_size);
a5a7b82003-11-26Martin Nilsson  free(THIS->iv); } THIS->iv = 0; } 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); }
44ee952003-12-06Martin Nilsson  /*! @decl void create(program|object|function cipher, mixed ... args)
01a1ba2003-12-14Martin Nilsson  *! Initialize the CBC wrapper with a cipher algorithm. If it is a *! program, an object will be instantiated with @[args] as arguments. *! If it is an object that doesn't conform to the cipher API, but has *! an @[LFUN::`()], that LFUN will be called. If it is a function, *! that function will be called with @[args] as arguments.
44ee952003-12-06Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN void create(program|object|function cipher, mixed ... more) flags ID_STATIC; {
99ac112004-02-04Martin Nilsson  int old_block_size = THIS->block_size;
44ee952003-12-06Martin Nilsson  THIS->object = make_cipher_object(args);
a5a7b82003-11-26Martin Nilsson  safe_apply(THIS->object, "block_size", 0); if(Pike_sp[-1].type != T_INT) Pike_error("block_size() didn't return an int.\n");
99ac112004-02-04Martin Nilsson 
a5a7b82003-11-26Martin Nilsson  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);
99ac112004-02-04Martin Nilsson  if(THIS->iv) { MEMSET(THIS->iv, 0, old_block_size); free(THIS->iv); }
a5a7b82003-11-26Martin Nilsson  THIS->iv = (unsigned INT8 *)xalloc(THIS->block_size); MEMSET(THIS->iv, 0, THIS->block_size); }
4922e92003-12-12Martin Nilsson  /*! @decl string name()
a9981a2003-12-15Martin Nilsson  *! Returns the string @expr{"CBC(x)"@} where x is the *! encapsulated algorithm.
4922e92003-12-12Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN string name() optflags OPT_TRY_OPTIMIZE; {
a9981a2003-12-15Martin Nilsson  push_constant_text("CBC("); safe_apply(THIS->object, "name", 0); push_constant_text(")"); f_add(3);
4922e92003-12-12Martin Nilsson  }
a5a7b82003-11-26Martin Nilsson  /*! @decl int block_size()
01a1ba2003-12-14Martin Nilsson  *! Reurns the block size of the encapsulated cipher.
a5a7b82003-11-26Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN int block_size() optflags OPT_TRY_OPTIMIZE; {
a5a7b82003-11-26Martin Nilsson  RETURN THIS->block_size; } /*! @decl int key_size()
01a1ba2003-12-14Martin Nilsson  *! Returns the key size of the encapsulated cipher.
a5a7b82003-11-26Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN int key_size() optflags OPT_EXTERNAL_DEPEND; {
a5a7b82003-11-26Martin Nilsson  safe_apply(THIS->object, "key_size", args); }
01a1ba2003-12-14Martin Nilsson  /*! @decl this_program set_encrypt_key(string key) *! Prepare the cipher and the wrapper for encrypting *! with the given @[key].
a5a7b82003-11-26Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN object set_encrypt_key(string key) optflags OPT_SIDE_EFFECT; {
a5a7b82003-11-26Martin Nilsson  assert(THIS->block_size); THIS->mode = 0; safe_apply(THIS->object, "set_encrypt_key", args); pop_stack(); RETURN this_object(); }
01a1ba2003-12-14Martin Nilsson  /*! @decl this_program set_decrypt_key(string key) *! Prepare the cipher and the wrapper for decrypting *! with the given @[key].
a5a7b82003-11-26Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN object set_decrypt_key(string key) optflags OPT_SIDE_EFFECT; {
99ac112004-02-04Martin Nilsson  assert(THIS->block_size);
a5a7b82003-11-26Martin Nilsson  THIS->mode = 1;
99ac112004-02-04Martin Nilsson  safe_apply(THIS->object, "set_decrypt_key", args); pop_stack(); RETURN this_object();
a5a7b82003-11-26Martin Nilsson  }
01a1ba2003-12-14Martin Nilsson  /*! @decl this_program set_iv(string iv) *! Set the initialization vector to @[iv]. */
d7f88a2004-02-14Martin Nilsson  PIKEFUN object set_iv(string iv) optflags OPT_SIDE_EFFECT; {
a5a7b82003-11-26Martin Nilsson  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(); }
01a1ba2003-12-14Martin Nilsson  /*! @decl string crypt(string data) *! Encrypt/decrypt @[data] and return the result. @[data] must *! be an integral number of blocks. */
a5a7b82003-11-26Martin Nilsson  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) {
99ac112004-02-04Martin Nilsson  cbc_decrypt_step((const unsigned INT8 *)data->str + offset,
a5a7b82003-11-26Martin Nilsson  result + offset); offset += THIS->block_size; } } pop_n_elems(args); push_string(make_shared_binary_string((INT8 *)result, offset)); MEMSET(result, 0, offset); } }
44ee952003-12-06Martin Nilsson /*! @endclass */
f34dec2004-02-04Martin Nilsson /*! @class Buffer
44ee952003-12-06Martin Nilsson  *! Acts as a buffer so that data can be fed to a cipher in blocks *! that doesn't correspond to cipher block sizes. */ PIKECLASS Proxy { CVAR struct object *object; CVAR int block_size; CVAR unsigned char *backlog; CVAR int backlog_len; INIT { THIS->object = 0; THIS->block_size = 0; THIS->backlog = 0; THIS->backlog_len = 0; } EXIT { if(THIS->backlog) { MEMSET(THIS->backlog, 0, THIS->block_size); free(THIS->backlog); } if(THIS->object) free_object(THIS->object); } /*! @decl void create(program|object|function cipher, mixed ... args)
a9981a2003-12-15Martin Nilsson  *! Initialize the Proxy wrapper with a cipher algorithm. If it is a *! program, an object will be instantiated with @[args] as arguments. *! If it is an object that doesn't conform to the cipher API, but has *! an @[LFUN::`()], that LFUN will be called. If it is a function, *! that function will be called with @[args] as arguments.
44ee952003-12-06Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN void create(program|object|function cipher, mixed ... more) flags ID_STATIC; {
44ee952003-12-06Martin Nilsson  THIS->object = make_cipher_object(args); 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 %ld\n", DO_NOT_WARN((long)THIS->block_size)); THIS->backlog = (unsigned char *)xalloc(THIS->block_size); THIS->backlog_len = 0; MEMSET(THIS->backlog, 0, THIS->block_size); }
4922e92003-12-12Martin Nilsson  /*! @decl string name()
a9981a2003-12-15Martin Nilsson  *! Returns the string @expr{"CBC(x)"@} where x is the *! encapsulated algorithm.
4922e92003-12-12Martin Nilsson  */
d7f88a2004-02-14Martin Nilsson  PIKEFUN string name() optflags OPT_TRY_OPTIMIZE; {
a9981a2003-12-15Martin Nilsson  push_constant_text("Proxy("); safe_apply(THIS->object, "name", 0); push_constant_text(")"); f_add(3);
4922e92003-12-12Martin Nilsson  }
44ee952003-12-06Martin Nilsson  /*! @decl int block_size() *! *! Get the block size of the contained block crypto. */
d7f88a2004-02-14Martin Nilsson  PIKEFUN int block_size() optflags OPT_TRY_OPTIMIZE; {
44ee952003-12-06Martin Nilsson  RETURN THIS->block_size; } /*! @decl int key_size() *! *! Get the key size of the contained block crypto. */
d7f88a2004-02-14Martin Nilsson  PIKEFUN int key_size() optflags OPT_EXTERNAL_DEPEND; {
44ee952003-12-06Martin Nilsson  safe_apply(THIS->object, "key_size", args); } /*! @decl this_program set_encrypt_key(string key) *! *! Set the encryption key. *! *! @note *! As a side-effect any buffered data will be cleared. */
d7f88a2004-02-14Martin Nilsson  PIKEFUN object set_encrypt_key(string key) optflags OPT_SIDE_EFFECT; {
44ee952003-12-06Martin Nilsson  MEMSET(THIS->backlog, 0, THIS->block_size); THIS->backlog_len = 0; safe_apply(THIS->object, "set_encrypt_key", args); pop_stack(); RETURN this_object(); } /*! @decl this_program set_decrypt_key(string key) *! *! Set the decryption key. *! *! @note *! As a side-effect any buffered data will be cleared. */
d7f88a2004-02-14Martin Nilsson  PIKEFUN object set_decrypt_key(string key) optflags OPT_SIDE_EFFECT; {
44ee952003-12-06Martin Nilsson  MEMSET(THIS->backlog, 0, THIS->block_size); THIS->backlog_len = 0; safe_apply(THIS->object, "set_decrypt_key", args); pop_stack(); RETURN this_object(); } /*! @decl string crypt(string data) *! *! Encrypt some data. *! *! Adds data to be encrypted to the buffer. If there's enough *! data to en/decrypt a block, that will be done, and the result *! returned. Any uncrypted data will be left in the buffer. */ PIKEFUN string crypt(string data) { unsigned char *result; ptrdiff_t roffset = 0; ptrdiff_t soffset = 0; ptrdiff_t len; if (!(result = alloca(data->len + THIS->block_size))) Pike_error("Out of memory\n"); if (THIS->backlog_len) { if (data->len >= (THIS->block_size - THIS->backlog_len)) { MEMCPY(THIS->backlog + THIS->backlog_len, data->str, (THIS->block_size - THIS->backlog_len)); soffset += (THIS->block_size - THIS->backlog_len); THIS->backlog_len = 0; push_string(make_shared_binary_string((char *)THIS->backlog, THIS->block_size)); safe_apply(THIS->object, "crypt", 1); if (Pike_sp[-1].type != T_STRING) Pike_error("crypt() did not return string\n"); if (Pike_sp[-1].u.string->len != THIS->block_size) Pike_error("Unexpected string length %ld\n", DO_NOT_WARN((long)Pike_sp[-1].u.string->len)); MEMCPY(result, Pike_sp[-1].u.string->str, THIS->block_size); roffset = THIS->block_size; pop_stack(); MEMSET(THIS->backlog, 0, THIS->block_size); } else { MEMCPY(THIS->backlog + THIS->backlog_len, data->str, data->len); THIS->backlog_len += data->len; pop_n_elems(args); push_constant_text(""); return; } } len = (Pike_sp[-1].u.string->len - soffset); len -= len % THIS->block_size; if (len) { push_string(make_shared_binary_string(Pike_sp[-1].u.string->str + soffset, len)); soffset += len; safe_apply(THIS->object, "crypt", 1); if (Pike_sp[-1].type != T_STRING)
f34dec2004-02-04Martin Nilsson  Pike_error("crypt() did not return string.\n");
44ee952003-12-06Martin Nilsson  if (Pike_sp[-1].u.string->len != len)
f34dec2004-02-04Martin Nilsson  Pike_error("crypt() Unexpected string length %ld.\n", DO_NOT_WARN((long)Pike_sp[-1].u.string->len));
44ee952003-12-06Martin Nilsson  MEMCPY(result + roffset, Pike_sp[-1].u.string->str, len); pop_stack(); } if (soffset < Pike_sp[-1].u.string->len) { MEMCPY(THIS->backlog, Pike_sp[-1].u.string->str + soffset, Pike_sp[-1].u.string->len - soffset); THIS->backlog_len = Pike_sp[-1].u.string->len - soffset; } pop_n_elems(args); push_string(make_shared_binary_string((char *)result, roffset + len)); MEMSET(result, 0, roffset + len); } /*! @decl string pad() *! *! Pad and de/encrypt any data left in the buffer. *! *! @seealso *! @[unpad()] */ PIKEFUN string pad() { ptrdiff_t i; for (i = THIS->backlog_len; i < THIS->block_size - 1; i++) THIS->backlog[i] = DO_NOT_WARN((unsigned char)(my_rand() & 0xff)); THIS->backlog[THIS->block_size - 1] =
f34dec2004-02-04Martin Nilsson  DO_NOT_WARN((unsigned char)(THIS->block_size - THIS->backlog_len - 1));
44ee952003-12-06Martin Nilsson  push_string(make_shared_binary_string((const char *)THIS->backlog, THIS->block_size)); MEMSET(THIS->backlog, 0, THIS->block_size); THIS->backlog_len = 0; safe_apply(THIS->object, "crypt", 1); } /*! @decl string unpad(string data) *! *! De/encrypt and unpad a block of data. *! *! This performs the reverse operation of @[pad()]. *! *! @seealso *! @[pad()] */
f34dec2004-02-04Martin Nilsson  PIKEFUN string unpad(string str) {
44ee952003-12-06Martin Nilsson  ptrdiff_t len; len = str->len;
f34dec2004-02-04Martin Nilsson  if( len % THIS->block_size) Pike_error("String must be integral numbers of blocks.\n"); safe_apply(THIS->object, "crypt", 1); if (Pike_sp[-1].type != T_STRING) Pike_error("crypt() did not return string.\n"); if (Pike_sp[-1].u.string->len != len) Pike_error("crypt() Unexpected string length %ld.\n", DO_NOT_WARN((long)Pike_sp[-1].u.string->len)); str = Pike_sp[-1].u.string;
44ee952003-12-06Martin Nilsson  if (str->str[len - 1] > (THIS->block_size - 1))
f34dec2004-02-04Martin Nilsson  Pike_error("Invalid padding (%d > %d)\n", str->str[len-1], THIS->block_size-1);
44ee952003-12-06Martin Nilsson  len -= (str->str[len - 1] + 1); if (len < 0) Pike_error("String to short to unpad\n"); add_ref(str); pop_stack(); push_string(make_shared_binary_string(str->str, len)); free_string(str); } }
a5a7b82003-11-26Martin Nilsson /*! @endclass */
1ab4b12003-03-18Niels Möller /*! @endmodule */
770fee2003-03-12Henrik Grubbström (Grubba) 
099d682004-01-30Martin Nilsson 
654f152003-03-14Marcus Comstedt #endif /* HAVE_LIBNETTLE */
4e1f622003-03-13Niels Möller PIKE_MODULE_INIT {
099d682004-01-30Martin Nilsson #ifdef __NT__ struct program *nt_program = NULL; struct object *nt_object = NULL; #endif /* __NT__ */
4e1f622003-03-13Niels Möller  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 */
099d682004-01-30Martin Nilsson #ifdef __NT__ start_new_program(); nt_init(); nt_program = end_program(); add_object_constant("NT", nt_object=clone_object(nt_program,0), 0); free_object(nt_object); free_program(nt_program); #endif /* __NT__ */
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 */
099d682004-01-30Martin Nilsson #ifdef __NT__ nt_exit(); #endif /* __NT__ */
4e1f622003-03-13Niels Möller  EXIT; }