01e1152003-03-12Niels Möller /* nettle.cmod -*- c -*- */
afe0122010-11-11Martin Stjernholm /* $Id$ */
01e1152003-03-12Niels Möller  #include "global.h" #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>
329a6f2004-02-21Martin Nilsson #include <nettle/knuth-lfib.h>
3184172003-08-06Henrik Grubbström (Grubba) 
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;
d311272009-07-05Henrik Grubbström (Grubba) 
d1cb852009-07-05Henrik Grubbström (Grubba) #ifndef HAVE_STRUCT_YARROW256_CTX_SEED_FILE
d311272009-07-05Henrik Grubbström (Grubba)  /* NOTE: Nettle 2.0 does not have the automatic seed_file maintenance * that Nettle 1.x had. This stuff is needed since it affected * the state emitted by random_string(). When Nettle 2.0 is the * default, consider implementing this via overloading of the * various seeding functions instead, since it does have a bit * of overhead. * * /grubba 2009-07-05 */
d1cb852009-07-05Henrik Grubbström (Grubba)  PIKEVAR string seed_file flags ID_PRIVATE|ID_STATIC;
0ec1412009-07-05Henrik Grubbström (Grubba) #endif DECLARE_STORAGE;
d311272009-07-05Henrik Grubbström (Grubba) 
0ec1412009-07-05Henrik Grubbström (Grubba) #ifndef HAVE_STRUCT_YARROW256_CTX_SEED_FILE
d311272009-07-05Henrik Grubbström (Grubba)  static void pike_generate_seed_file(void) { struct pike_string *seed_file = begin_shared_string(YARROW256_SEED_FILE_SIZE); yarrow256_random(&THIS->ctx, YARROW256_SEED_FILE_SIZE, STR0(seed_file)); if (THIS->seed_file) { free_string(THIS->seed_file); } THIS->seed_file = end_shared_string(seed_file); } #else #define pike_generate_seed_file()
d1cb852009-07-05Henrik Grubbström (Grubba) #endif
25f5432003-08-06Martin Nilsson 
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)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
d7f88a2004-02-14Martin Nilsson  {
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)
c9edeb2009-07-01Henrik Grubbström (Grubba)  Pike_error("Seed must be at least %d characters.\n", YARROW256_SEED_FILE_SIZE);
d745992003-08-05Martin Nilsson  NO_WIDE_STRING(data);
c9edeb2009-07-01Henrik Grubbström (Grubba)  yarrow256_seed(&THIS->ctx, data->len, STR0(data));
d311272009-07-05Henrik Grubbström (Grubba)  pike_generate_seed_file();
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; }
d311272009-07-05Henrik Grubbström (Grubba)  /*! @decl string(0..255) get_seed()
776b502009-07-02Henrik Grubbström (Grubba)  *! Returns part of the internal state so that it can *! be saved for later seeding.
de03372009-07-01Henrik Grubbström (Grubba)  *!
9109472003-08-07Martin Nilsson  *! @seealso
776b502009-07-02Henrik Grubbström (Grubba)  *! @[seed()], @[random_string()]
d745992003-08-05Martin Nilsson  */ PIKEFUN string get_seed()
d7f88a2004-02-14Martin Nilsson  optflags OPT_EXTERNAL_DEPEND;
47ce5e2009-07-05Henrik Grubbström (Grubba)  rawtype tDeprecated(tFunc(tNone, tStr8));
d745992003-08-05Martin Nilsson  {
324ca82003-11-10Niels Möller  if( !yarrow256_is_seeded(&THIS->ctx) ) Pike_error("Random generator not seeded.\n");
ad67532009-07-01Henrik Grubbström (Grubba) 
d1cb852009-07-05Henrik Grubbström (Grubba) #ifdef HAVE_STRUCT_YARROW256_CTX_SEED_FILE
776b502009-07-02Henrik Grubbström (Grubba)  RETURN make_shared_binary_string(THIS->ctx.seed_file, YARROW256_SEED_FILE_SIZE);
d1cb852009-07-05Henrik Grubbström (Grubba) #else
d311272009-07-05Henrik Grubbström (Grubba)  if (THIS->seed_file) { REF_RETURN THIS->seed_file; } else { struct pike_string *s = begin_shared_string(YARROW256_SEED_FILE_SIZE); RETURN end_shared_string(s); }
776b502009-07-02Henrik Grubbström (Grubba) #endif /* HAVE_STRUCT_YARROW256_CTX_SEED_FILE */
d1cb852009-07-05Henrik Grubbström (Grubba)  }
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  {
c9edeb2009-07-01Henrik Grubbström (Grubba) #ifdef HAVE_NETTLE_YARROW256_SLOW_RESEED /* From change notes for Nettle 2.0: * * * Changes to the yarrow256 interface. The function * yarrow256_force_reseed has been replaced by the two * functions yarrow256_fast_reseed and yarrow256_slow_reseed, * which were previously static. */ yarrow256_slow_reseed(&THIS->ctx); #else
49acab2003-11-09Niels Möller  yarrow256_force_reseed(&THIS->ctx);
c9edeb2009-07-01Henrik Grubbström (Grubba) #endif
d311272009-07-05Henrik Grubbström (Grubba)  pike_generate_seed_file();
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  {
d311272009-07-05Henrik Grubbström (Grubba)  int ret;
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");
d311272009-07-05Henrik Grubbström (Grubba)  ret = yarrow256_update(&THIS->ctx, source, entropy, data->len, (const uint8_t *)data->str);
dce9da2010-05-26Jonas Wallden  if (ret) {
d311272009-07-05Henrik Grubbström (Grubba)  pike_generate_seed_file();
dce9da2010-05-26Jonas Wallden  }
d311272009-07-05Henrik Grubbström (Grubba)  RETURN ret;
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;
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);
baac7d2006-01-07Martin Nilsson  yarrow256_random(&THIS->ctx, length, (uint8_t *)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  }
22038d2008-05-30Martin Nilsson 
d745992003-08-05Martin Nilsson  EXIT
d3df7c2008-05-30Martin Nilsson  gc_trivial;
d745992003-08-05Martin Nilsson  {
22038d2008-05-30Martin Nilsson  if( THIS->sources ) { free(THIS->sources); }
d745992003-08-05Martin Nilsson  } } /*! @endclass
01e1152003-03-12Niels Möller  */
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 {
329a6f2004-02-21Martin Nilsson  char *hash;
3955a92003-08-24Martin Nilsson  NO_WIDE_STRING(pw); NO_WIDE_STRING(salt);
d7f88a2004-02-14Martin Nilsson  THREADS_ALLOW();
a467f92004-03-20Henrik Grubbström (Grubba)  hash = pike_crypt_md5(pw->len, pw->str,salt->len, salt->str);
d7f88a2004-02-14Martin Nilsson  THREADS_DISALLOW();
329a6f2004-02-21Martin Nilsson  push_text(hash);
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 };
5a6c872005-01-27Martin Nilsson static const char *assert_is_crypto_object(struct program *p, const char *const *required) {
221ebe2003-12-06Martin Nilsson  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
12beec2004-03-24Martin Nilsson  *! @belongs Crypto
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 {
22038d2008-05-30Martin Nilsson  THIS->object = NULL; THIS->iv = NULL;
a5a7b82003-11-26Martin Nilsson  THIS->block_size = 0; THIS->mode = 0; } EXIT
d3df7c2008-05-30Martin Nilsson  gc_trivial;
a5a7b82003-11-26Martin Nilsson  {
22038d2008-05-30Martin Nilsson  if(THIS->object) { free_object(THIS->object); }
a5a7b82003-11-26Martin Nilsson  if(THIS->iv) {
44ee952003-12-06Martin Nilsson  MEMSET(THIS->iv, 0, THIS->block_size);
a5a7b82003-11-26Martin Nilsson  free(THIS->iv); } }
5a6c872005-01-27Martin Nilsson  INLINE static void cbc_encrypt_step(const unsigned INT8 *const source,
a5a7b82003-11-26Martin Nilsson  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(); }
5a6c872005-01-27Martin Nilsson  INLINE static void cbc_decrypt_step(const unsigned INT8 *const source,
a5a7b82003-11-26Martin Nilsson  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)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
d7f88a2004-02-14Martin Nilsson  {
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;
afe0122010-11-11Martin Stjernholm  ONERROR uwp;
a5a7b82003-11-26Martin Nilsson  NO_WIDE_STRING(data); if(data->len % THIS->block_size) Pike_error("Data length not multiple of block size.\n");
afe0122010-11-11Martin Stjernholm  if(!(result = malloc(data->len)))
8a3e562004-05-19Martin Nilsson  SIMPLE_OUT_OF_MEMORY_ERROR("crypt", data->len);
afe0122010-11-11Martin Stjernholm  SET_ONERROR (uwp, free, result);
a5a7b82003-11-26Martin Nilsson  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);
afe0122010-11-11Martin Stjernholm  CALL_AND_UNSET_ONERROR (uwp);
a5a7b82003-11-26Martin Nilsson  } }
44ee952003-12-06Martin Nilsson /*! @endclass */
f34dec2004-02-04Martin Nilsson /*! @class Buffer
12beec2004-03-24Martin Nilsson  *! @belongs Crypto
44ee952003-12-06Martin Nilsson  *! Acts as a buffer so that data can be fed to a cipher in blocks
04e1b02010-06-22Henrik Grubbström (Grubba)  *! that don't correspond to cipher block sizes.
44ee952003-12-06Martin Nilsson  */ PIKECLASS Proxy { CVAR struct object *object; CVAR int block_size; CVAR unsigned char *backlog; CVAR int backlog_len; INIT {
22038d2008-05-30Martin Nilsson  THIS->object = NULL;
44ee952003-12-06Martin Nilsson  THIS->block_size = 0;
22038d2008-05-30Martin Nilsson  THIS->backlog = NULL;
44ee952003-12-06Martin Nilsson  THIS->backlog_len = 0; }
d3df7c2008-05-30Martin Nilsson  EXIT gc_trivial; {
44ee952003-12-06Martin Nilsson  if(THIS->backlog) { MEMSET(THIS->backlog, 0, THIS->block_size); free(THIS->backlog);
04e1b02010-06-22Henrik Grubbström (Grubba)  THIS->backlog = NULL;
44ee952003-12-06Martin Nilsson  }
22038d2008-05-30Martin Nilsson  if(THIS->object) {
44ee952003-12-06Martin Nilsson  free_object(THIS->object);
04e1b02010-06-22Henrik Grubbström (Grubba)  THIS->object = NULL;
22038d2008-05-30Martin Nilsson  }
44ee952003-12-06Martin Nilsson  } /*! @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)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
d7f88a2004-02-14Martin Nilsson  {
04e1b02010-06-22Henrik Grubbström (Grubba)  exit_Proxy_struct();
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()
2070852006-12-29Martin Nilsson  *! Returns the string @expr{"Proxy(x)"@} where x is the
a9981a2003-12-15Martin Nilsson  *! 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;
afe0122010-11-11Martin Stjernholm  ONERROR uwp;
44ee952003-12-06Martin Nilsson 
afe0122010-11-11Martin Stjernholm  if (!(result = malloc(data->len + THIS->block_size)))
8a3e562004-05-19Martin Nilsson  SIMPLE_OUT_OF_MEMORY_ERROR("crypt", data->len + THIS->block_size);
afe0122010-11-11Martin Stjernholm  SET_ONERROR (uwp, free, result);
44ee952003-12-06Martin Nilsson  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);
00734c2007-12-20Martin Nilsson  push_empty_string();
afe0122010-11-11Martin Stjernholm  CALL_AND_UNSET_ONERROR (uwp);
44ee952003-12-06Martin Nilsson  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);
afe0122010-11-11Martin Stjernholm  CALL_AND_UNSET_ONERROR (uwp);
44ee952003-12-06Martin Nilsson  }
2693a92010-06-22Martin Nilsson  /*! @decl string pad(void|int method)
44ee952003-12-06Martin Nilsson  *!
04e1b02010-06-22Henrik Grubbström (Grubba)  *! Pad and encrypt any data left in the buffer.
2693a92010-06-22Martin Nilsson  *! *! @param method
04e1b02010-06-22Henrik Grubbström (Grubba)  *! The type of padding to apply to the buffer.
2693a92010-06-22Martin Nilsson  *! @int *! @value Crypto.PAD_SSL *! @value Crypto.PAD_ISO_10126 *! @value Crypto.PAD_ANSI_X923 *! @value Crypto.PAD_PKCS7 *! @value Crypto.PAD_ZERO *! @endint *! Defaults to Crypto.PAD_SSL for compatibility reasons.
44ee952003-12-06Martin Nilsson  *! *! @seealso *! @[unpad()] */
2693a92010-06-22Martin Nilsson  PIKEFUN string pad(void|int method) {
44ee952003-12-06Martin Nilsson  ptrdiff_t i;
2693a92010-06-22Martin Nilsson  int m = 0; int size = THIS->block_size - THIS->backlog_len; if(method) { if(method->type != PIKE_T_INT) Pike_error("Bad argument type.\n"); m = method->u.integer; } switch(m) { case 0: size--; break; case 4: if( THIS->backlog_len>0 && THIS->backlog[THIS->backlog_len-1] == 0 ) Pike_error("Using zero padding on a zero terminated string.\n"); size = 0; break; }
44ee952003-12-06Martin Nilsson  for (i = THIS->backlog_len; i < THIS->block_size - 1; i++)
2693a92010-06-22Martin Nilsson  switch(m) { default: Pike_error("Unknown method.\n"); case 0: case 1: /* ISO 10126 */ THIS->backlog[i] = DO_NOT_WARN((unsigned char)(my_rand() & 0xff)); break; case 2: /* ANSI X.923 */ THIS->backlog[i] = 0; break; case 3: /* PKCS7 / RFC 3852 */ THIS->backlog[i] = DO_NOT_WARN((unsigned char)size); break; case 4: /* Null only */ THIS->backlog[i] = 0; break; }
44ee952003-12-06Martin Nilsson 
2693a92010-06-22Martin Nilsson  THIS->backlog[THIS->block_size - 1] = DO_NOT_WARN((unsigned char)size);
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); }
2693a92010-06-22Martin Nilsson  /*! @decl string unpad(string data, void|int method)
44ee952003-12-06Martin Nilsson  *!
04e1b02010-06-22Henrik Grubbström (Grubba)  *! Decrypt and unpad a block of data.
44ee952003-12-06Martin Nilsson  *! *! This performs the reverse operation of @[pad()]. *!
2693a92010-06-22Martin Nilsson  *! @param method
04e1b02010-06-22Henrik Grubbström (Grubba)  *! The type of padding that was applied to the original buffer.
2693a92010-06-22Martin Nilsson  *! @int *! @value Crypto.PAD_SSL *! @value Crypto.PAD_ISO_10126 *! @value Crypto.PAD_ANSI_X923 *! @value Crypto.PAD_PKCS7 *! @value Crypto.PAD_ZERO *! @endint *! Defaults to Crypto.PAD_SSL for compatibility reasons. *!
44ee952003-12-06Martin Nilsson  *! @seealso *! @[pad()] */
2693a92010-06-22Martin Nilsson  PIKEFUN string unpad(string str, void|int method) {
44ee952003-12-06Martin Nilsson  ptrdiff_t len;
2693a92010-06-22Martin Nilsson  int m = 0;
44ee952003-12-06Martin Nilsson  len = str->len;
f34dec2004-02-04Martin Nilsson  if( len % THIS->block_size) Pike_error("String must be integral numbers of blocks.\n");
2693a92010-06-22Martin Nilsson  if( method!=NULL ) { m = method->u.integer; pop_stack(); args--; }
f34dec2004-02-04Martin Nilsson  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;
2693a92010-06-22Martin Nilsson  if( m==0 ) { if (str->str[len - 1]+1 > THIS->block_size) Pike_error("Invalid padding (%d > %d)\n", str->str[len-1]+1, THIS->block_size-1); } else if (str->str[len - 1] > THIS->block_size) Pike_error("Invalid padding (%d > %d)\n", str->str[len-1], THIS->block_size-1);
44ee952003-12-06Martin Nilsson 
2693a92010-06-22Martin Nilsson  len -= str->str[len - 1]; switch( m ) { case 0: len--; break; case 4: { int c=THIS->block_size; while( str->str[len-1]==0 && c>0 ) { c--; len--; } } }
44ee952003-12-06Martin Nilsson  if (len < 0)
04e1b02010-06-22Henrik Grubbström (Grubba)  Pike_error("String too short to unpad\n");
44ee952003-12-06Martin Nilsson  add_ref(str); pop_stack(); push_string(make_shared_binary_string(str->str, len)); free_string(str); } }
a5a7b82003-11-26Martin Nilsson /*! @endclass */
329a6f2004-02-21Martin Nilsson #if 0 /* @class LFib * The Donald Knuth Lagged Fibonacci pseudo random number generator. * This is @b{not@} a source for cryptographic randomness. Use * @[Crypto.Yarrow] instead. */ PIKECLASS LFib { CVAR struct knuth_lfib_ctx *ctx; INIT { THIS->ctx = xalloc(sizeof(struct knuth_lfib_ctx)); }
d3df7c2008-05-30Martin Nilsson  EXIT gc_trivial; {
329a6f2004-02-21Martin Nilsson  free(THIS->ctx); } /* @decl void create(int seed) * The Lfib generator must be seeded with a number. */
c72a032004-10-23Martin Nilsson  PIKEFUN void create(int seed)
ecc9382008-06-29Martin Nilsson  flags ID_PROTECTED;
c72a032004-10-23Martin Nilsson  {
329a6f2004-02-21Martin Nilsson  knuth_lfib_init(THIS->ctx, seed); } /* @decl this_program reseed(int s) * Reseed this object with seed @[s]. * @return * Returns the current object. */ PIKEFUN object reseed(int s) { knuth_lfib_init(THIS->ctx, s); RETURN this_object(); } /* Get one 32bit pseudorandom integer. */ PIKEFUN int get() { RETURN knuth_lfib_get(THIS->ctx); } /* Get a pseudorandom string of length @[len]. */ PIKEFUN string get_string(int len) { struct pike_string *s = begin_shared_string(len); knuth_lfib_random(THIS->ctx, len, s->str); push_string(end_shared_string(s)); } } /* @endclass */ #endif
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; }