Skip to content
Snippets Groups Projects
Select Git revision
  • 43b7268829e09a455abfa62ce494c9c2398a9e21
  • master default
  • wip-add-ed25519
  • disable-sha1
  • lsh-2.0.4
  • experimental-20050201
  • lsh-1.4.2
  • lsh-1.2
  • lsh_2.1_release_20130626
  • converted-master-branch-to-git
  • nettle_2.4_release_20110903
  • nettle_2.3_release_20110902
  • nettle_2.2_release_20110711
  • nettle_2.1_release_20100725
  • camellia_32bit_20100720
  • nettle_2.0_release_20090608
  • converted-lsh-2.0.4-branch-to-git
  • lsh_2.0.4_release_20070905
  • lsh_2.9_exp_release_20070404
  • nettle_1.15_release_20061128
  • after_experimental_merge_20060516
  • branch_before_experimental_merge_20060516
  • converted-experimental-branch-to-git
  • head_before_experimental_merge_20060516
  • lsh_2.0.3_release_20060509
  • lsh_2.0.2_release_20060127
  • nettle_1.14_release_20051205
  • nettle_1.13_release_20051006
28 results

crypto.c

Blame
  • Niels Möller's avatar
    Niels Möller authored
    43b72688
    History
    crypto.c 19.55 KiB
    /* crypto.c
     *
     * Encryption classes on top of nettle.
     *
     */
    
    /* lsh, an implementation of the ssh protocol
     *
     * Copyright (C) 2001 Niels Möller
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as
     * published by the Free Software Foundation; either version 2 of the
     * License, or (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301  USA
     */
    
    #if HAVE_CONFIG_H
    #include "config.h"
    #endif
    
    #include <assert.h>
    #include <string.h>
    
    #include "nettle/arcfour.h"
    #include "nettle/aes.h"
    #include "nettle/blowfish.h"
    #include "nettle/cast128.h"
    #include "nettle/des.h"
    #include "nettle/serpent.h"
    #include "nettle/twofish.h"
    
    #include "nettle/cbc.h"
    #include "nettle/ctr.h"
    #include "nettle/hmac.h"
    
    #include "crypto.h"
    
    #include "format.h"
    #include "lsh_string.h"
    #include "werror.h"
    #include "xalloc.h"
    
    #define GABA_DEFINE
    #include "crypto.h.x"
    #undef GABA_DEFINE
    
    #include "crypto.c.x"
    
    
    /* Arcfour/RC4 */
    /* GABA:
       (class
         (name arcfour_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct arcfour_ctx")))
    */
       
    static void
    do_crypt_arcfour(struct crypto_instance *s,
    		 uint32_t length,
    		 struct lsh_string *dst, uint32_t di,
    		 const struct lsh_string *src, uint32_t si)
    {
      CAST(arcfour_instance, self, s);
    
      assert(!(length % 8));
    
      lsh_string_crypt(dst, di, src, si, length,
    		   (nettle_crypt_func *) arcfour_crypt, &self->ctx);
    }
    
    static struct crypto_instance *
    make_arcfour_instance(struct crypto_algorithm *ignored UNUSED,
    		      int mode UNUSED,
    		      const uint8_t *key, const uint8_t *iv UNUSED)
    {
      NEW(arcfour_instance, self);
    
      self->super.block_size = 8;
      self->super.crypt = do_crypt_arcfour;
    
      arcfour_set_key(&self->ctx, 16, key);
    
      return &self->super;
    }
    
    struct crypto_algorithm crypto_arcfour_algorithm =
    { STATIC_HEADER,
      8, 16, 0, make_arcfour_instance };
    
    /* Create a CBC super class? */
    
    /* AES/Rijndael */
    /* GABA:
       (class
         (name aes_cbc_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE)")))
    */
    
    static void
    do_aes_cbc_encrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(aes_cbc_instance, self, s);
    
      lsh_string_cbc_encrypt(dst, di, src, si, length,
    			 AES_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) aes_encrypt,
    			 &self->ctx.ctx);
    }
    
    static void
    do_aes_cbc_decrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(aes_cbc_instance, self, s);
    
      lsh_string_cbc_decrypt(dst, di, src, si, length,
    			 AES_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) aes_decrypt,
    			 &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_aes_cbc_instance(struct crypto_algorithm *algorithm, int mode,
                          const uint8_t *key, const uint8_t *iv)
    {
      NEW(aes_cbc_instance, self);
    
      self->super.block_size = AES_BLOCK_SIZE;
    
      if (mode == CRYPTO_ENCRYPT)
        {
          self->super.crypt = do_aes_cbc_encrypt;
          aes_set_encrypt_key(&self->ctx.ctx, algorithm->key_size, key);
        }
      else
        {
          self->super.crypt = do_aes_cbc_decrypt;
          aes_set_decrypt_key(&self->ctx.ctx, algorithm->key_size, key);
        }
    
      CBC_SET_IV(&self->ctx, iv);
      
      return(&self->super);
    }
    
    struct crypto_algorithm crypto_aes128_cbc_algorithm =
    { STATIC_HEADER, AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE, make_aes_cbc_instance};
    
    struct crypto_algorithm crypto_aes256_cbc_algorithm =
    { STATIC_HEADER, AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE, make_aes_cbc_instance};
    
    /* GABA:
       (class
         (name aes_ctr_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CTR_CTX(struct aes_ctx, AES_BLOCK_SIZE)")))
    */
    
    static void
    do_aes_ctr_crypt(struct crypto_instance *s,
    		 uint32_t length,
    		 struct lsh_string *dst, uint32_t di,
    		 const struct lsh_string *src, uint32_t si)
    {
      CAST(aes_ctr_instance, self, s);
    
      lsh_string_ctr_crypt(dst, di, src, si, length,
    		       AES_BLOCK_SIZE, self->ctx.ctr,
    		       (nettle_crypt_func *) aes_encrypt,
    		       &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_aes_ctr_instance(struct crypto_algorithm *algorithm, int mode UNUSED,
                          const uint8_t *key, const uint8_t *iv)
    {
      NEW(aes_ctr_instance, self);
    
      self->super.block_size = AES_BLOCK_SIZE;
    
      self->super.crypt = do_aes_ctr_crypt;
      aes_set_encrypt_key(&self->ctx.ctx, algorithm->key_size, key);
    
      CTR_SET_COUNTER(&self->ctx, iv);
      
      return(&self->super);
    }
    
    struct crypto_algorithm crypto_aes128_ctr_algorithm =
    { STATIC_HEADER, AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE, make_aes_ctr_instance};
    
    struct crypto_algorithm crypto_aes256_ctr_algorithm =
    { STATIC_HEADER, AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE, make_aes_ctr_instance};
    
    /* Triple DES */
    /* GABA:
       (class
         (name des3_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CBC_CTX(struct des3_ctx, DES3_BLOCK_SIZE)")))
    */
    
    static void
    do_des3_encrypt(struct crypto_instance *s,
    		uint32_t length,
    		struct lsh_string *dst, uint32_t di,
    		const struct lsh_string *src, uint32_t si)
    {
      CAST(des3_instance, self, s);
    
      lsh_string_cbc_encrypt(dst, di, src, si, length,
    			 DES3_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) des3_encrypt,
    			 &self->ctx.ctx);
    }
    
    static void
    do_des3_decrypt(struct crypto_instance *s,
    		uint32_t length,
    		struct lsh_string *dst, uint32_t di,
    		const struct lsh_string *src, uint32_t si)
    {
      CAST(des3_instance, self, s);
    
      lsh_string_cbc_decrypt(dst, di, src, si, length,
    			 DES3_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) des3_decrypt,
    			 &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_des3_cbc_instance(struct crypto_algorithm *algorithm UNUSED,
                           int mode,
                           const uint8_t *key, const uint8_t *iv)
    {
      NEW(des3_instance, self);
    
      self->super.block_size = DES3_BLOCK_SIZE;
      self->super.crypt = ( (mode == CRYPTO_ENCRYPT)
    			? do_des3_encrypt
    			: do_des3_decrypt);
    
      CBC_SET_IV(&self->ctx, iv);
      
      if (des3_set_key(&self->ctx.ctx, key))
        return(&self->super);
      else
        {
          werror("Detected a weak DES key.\n");
          KILL(self);
          return NULL;
        }
    }
    
    struct crypto_algorithm crypto_des3_cbc_algorithm =
    { STATIC_HEADER,
      DES3_BLOCK_SIZE, DES3_KEY_SIZE, DES3_BLOCK_SIZE, make_des3_cbc_instance };
    
    /* GABA:
       (class
         (name des3_ctr_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CTR_CTX(struct des3_ctx, DES_BLOCK_SIZE)")))
    */
    
    static void
    do_des3_ctr_crypt(struct crypto_instance *s,
    		  uint32_t length,
    		  struct lsh_string *dst, uint32_t di,
    		  const struct lsh_string *src, uint32_t si)
    {
      CAST(des3_ctr_instance, self, s);
    
      lsh_string_ctr_crypt(dst, di, src, si, length,
    		       DES3_BLOCK_SIZE, self->ctx.ctr,
    		       (nettle_crypt_func *) des3_encrypt,
    		       &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_des3_ctr_instance(struct crypto_algorithm *algorithm UNUSED, int mode UNUSED,
    		       const uint8_t *key, const uint8_t *iv)
    {
      NEW(des3_ctr_instance, self);
    
      self->super.block_size = DES3_BLOCK_SIZE;
    
      self->super.crypt = do_des3_ctr_crypt;
      des3_set_key(&self->ctx.ctx, key);
    
      CTR_SET_COUNTER(&self->ctx, iv);
      
      return(&self->super);
    }
    
    struct crypto_algorithm crypto_des3_ctr_algorithm =
    { STATIC_HEADER,
      DES3_BLOCK_SIZE, DES3_KEY_SIZE, DES3_BLOCK_SIZE, make_des3_ctr_instance};
    
    /* Cast-128 */
    /* GABA:
       (class
         (name cast128_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CBC_CTX(struct cast128_ctx, CAST128_BLOCK_SIZE)")))
    */
    
    static void
    do_cast128_encrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(cast128_instance, self, s);
    
      lsh_string_cbc_encrypt(dst, di, src, si, length,
    			 CAST128_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) cast128_encrypt,
    			 &self->ctx.ctx);
    }
    
    static void
    do_cast128_decrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(cast128_instance, self, s);
    
      lsh_string_cbc_decrypt(dst, di, src, si, length,
    			 CAST128_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) cast128_decrypt,
    			 &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_cast128_cbc_instance(struct crypto_algorithm *algorithm, int mode,
                              const uint8_t *key, const uint8_t *iv)
    {
      NEW(cast128_instance, self);
    
      self->super.block_size = CAST128_BLOCK_SIZE;
      self->super.crypt = ( (mode == CRYPTO_ENCRYPT)
    			? do_cast128_encrypt
    			: do_cast128_decrypt);
    
      cast128_set_key(&self->ctx.ctx, algorithm->key_size, key);
      CBC_SET_IV(&self->ctx, iv);
    
      return(&self->super);
    }
    
    struct crypto_algorithm crypto_cast128_cbc_algorithm =
    { STATIC_HEADER,
      CAST128_BLOCK_SIZE, CAST128_KEY_SIZE, CAST128_BLOCK_SIZE,
      make_cast128_cbc_instance};
    
    
    /* Twofish */
    /* GABA:
       (class
         (name twofish_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CBC_CTX(struct twofish_ctx, TWOFISH_BLOCK_SIZE)")))
    */
    
    static void
    do_twofish_encrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(twofish_instance, self, s);
    
      lsh_string_cbc_encrypt(dst, di, src, si, length,
    			 TWOFISH_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) twofish_encrypt,
    			 &self->ctx.ctx);
    }
    
    static void
    do_twofish_decrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(twofish_instance, self, s);
    
      lsh_string_cbc_decrypt(dst, di, src, si, length,
    			 TWOFISH_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) twofish_decrypt,
    			 &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_twofish_cbc_instance(struct crypto_algorithm *algorithm, int mode,
    		      const uint8_t *key, const uint8_t *iv)
    {
      NEW(twofish_instance, self);
    
      self->super.block_size = TWOFISH_BLOCK_SIZE;
      self->super.crypt = ( (mode == CRYPTO_ENCRYPT)
    			? do_twofish_encrypt
    			: do_twofish_decrypt);
    
      twofish_set_key(&self->ctx.ctx, algorithm->key_size, key);
      CBC_SET_IV(&self->ctx, iv);
    
      return(&self->super);
    }
    
    struct crypto_algorithm crypto_twofish256_cbc_algorithm =
    { STATIC_HEADER,
      TWOFISH_BLOCK_SIZE, 32, TWOFISH_BLOCK_SIZE, make_twofish_cbc_instance};
    
    
    /* Blowfish */
    /* GABA:
       (class
         (name blowfish_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CBC_CTX(struct blowfish_ctx, BLOWFISH_BLOCK_SIZE)")))
    */
    
    static void
    do_blowfish_encrypt(struct crypto_instance *s,
    		    uint32_t length,
    		    struct lsh_string *dst, uint32_t di,
    		    const struct lsh_string *src, uint32_t si)
    {
      CAST(blowfish_instance, self, s);
    
      lsh_string_cbc_encrypt(dst, di, src, si, length,
    			 BLOWFISH_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) blowfish_encrypt,
    			 &self->ctx.ctx);
    }
    
    static void
    do_blowfish_decrypt(struct crypto_instance *s,
    		    uint32_t length,
    		    struct lsh_string *dst, uint32_t di,
    		    const struct lsh_string *src, uint32_t si)
    {
      CAST(blowfish_instance, self, s);
    
      lsh_string_cbc_decrypt(dst, di, src, si, length,
    			 BLOWFISH_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) blowfish_decrypt,
    			 &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_blowfish_cbc_instance(struct crypto_algorithm *algorithm, int mode,
                               const uint8_t *key, const uint8_t *iv)
    {
      NEW(blowfish_instance, self);
    
      self->super.block_size = BLOWFISH_BLOCK_SIZE;
      self->super.crypt = ( (mode == CRYPTO_ENCRYPT)
    			? do_blowfish_encrypt
    			: do_blowfish_decrypt);
    
      CBC_SET_IV(&self->ctx, iv);
    
      if (blowfish_set_key(&self->ctx.ctx, algorithm->key_size, key))
        return(&self->super);
      else
        {
          werror("Detected a weak blowfish key!\n");
          KILL(self);
          return NULL;
        }
    }
    
    struct crypto_algorithm crypto_blowfish_cbc_algorithm =
    { STATIC_HEADER,
      BLOWFISH_BLOCK_SIZE, BLOWFISH_KEY_SIZE, BLOWFISH_BLOCK_SIZE,
      make_blowfish_cbc_instance};
    
    
    /* Serpent */
    /* GABA:
       (class
         (name serpent_instance)
         (super crypto_instance)
         (vars
           (ctx . "struct CBC_CTX(struct serpent_ctx, SERPENT_BLOCK_SIZE)")))
    */
    
    static void
    do_serpent_encrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(serpent_instance, self, s);
    
      lsh_string_cbc_encrypt(dst, di, src, si, length,
    			 SERPENT_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) serpent_encrypt,
    			 &self->ctx.ctx);
    }
    
    static void
    do_serpent_decrypt(struct crypto_instance *s,
    		   uint32_t length,
    		   struct lsh_string *dst, uint32_t di,
    		   const struct lsh_string *src, uint32_t si)
    {
      CAST(serpent_instance, self, s);
    
      lsh_string_cbc_decrypt(dst, di, src, si, length,
    			 SERPENT_BLOCK_SIZE, self->ctx.iv,
    			 (nettle_crypt_func *) serpent_decrypt,
    			 &self->ctx.ctx);
    }
    
    static struct crypto_instance *
    make_serpent_cbc_instance(struct crypto_algorithm *algorithm, int mode,
    			  const uint8_t *key, const uint8_t *iv)
    {
      NEW(serpent_instance, self);
    
      self->super.block_size = SERPENT_BLOCK_SIZE;
      self->super.crypt = ( (mode == CRYPTO_ENCRYPT)
    			? do_serpent_encrypt
    			: do_serpent_decrypt);
    
      serpent_set_key(&self->ctx.ctx, algorithm->key_size, key);
      CBC_SET_IV(&self->ctx, iv);
    
      return(&self->super);
    }
    
    struct crypto_algorithm crypto_serpent256_cbc_algorithm =
    { STATIC_HEADER,
      SERPENT_BLOCK_SIZE, SERPENT_KEY_SIZE, SERPENT_BLOCK_SIZE,
      make_serpent_cbc_instance};
    
    
    /* Hashes */
    
    void
    hash_update(struct hash_instance *self,
    	    uint32_t length, const uint8_t *data)
    {
      self->type->update(self->ctx, length, data);
    }
    
    struct lsh_string *
    hash_digest_string(struct hash_instance *self)
    {
      struct lsh_string *s = lsh_string_alloc(self->type->digest_size);
      lsh_string_write_hash(s, 0, self->type, self->ctx);
    
      return s;
    }
    
    #define HASH_INSTANCE_SIZE(type) \
      (offsetof(struct hash_instance, ctx) + type->context_size)
    
    struct hash_instance *
    hash_copy(struct hash_instance *self)
    {
      CLONED_VAR_OBJECT(hash_instance, copy, self,
    		    HASH_INSTANCE_SIZE(self->type));
    
      return copy;
    }
    
    struct hash_instance *
    make_hash(const struct nettle_hash *algorithm)
    {
      NEW_VAR_OBJECT(hash_instance, instance,
    		 HASH_INSTANCE_SIZE(algorithm));
    
      instance->type = algorithm;
      algorithm->init(instance->ctx);
    
      return instance;
    }
    
    /* HMAC */
    
    /* GABA:
       (class
         (name hmac_instance)
         (super mac_instance)
         (vars
           (type . "const struct nettle_hash *")
           (ctx var-array char)))
    */
    
    #define HMAC_OUTER(self) ((self)->ctx)
    #define HMAC_INNER(self) ((self)->ctx + (self)->type->context_size)
    #define HMAC_STATE(self) ((self)->ctx + 2 * (self)->type->context_size)
    
    #define HMAC_SIZE(type) \
      (offsetof(struct hmac_instance, ctx) + 3 * type->context_size)
    
    static void
    do_hmac_update(struct mac_instance *s,
    	       uint32_t length, const uint8_t *data)
    {
      CAST(hmac_instance, self, s);
      self->type->update(HMAC_STATE(self), length, data);
    }
    
    static struct lsh_string *
    do_hmac_digest(struct mac_instance *s,
    	       struct lsh_string *res, uint32_t start)
    {
      CAST(hmac_instance, self, s);
      lsh_string_write_hmac(res, start, self->type, self->super.mac_size,
    			HMAC_OUTER(self), HMAC_INNER(self), HMAC_STATE(self));
      return res;
    }
    
    
    /* GABA:
       (class
         (name hmac_algorithm)
         (super mac_algorithm)
         (vars
           (type . "const struct nettle_hash *")))
    */
    
    static struct mac_instance *
    make_hmac_instance(struct mac_algorithm *s,
                       uint32_t key_length,
                       const uint8_t *key)
    {
      CAST(hmac_algorithm, self, s);
      NEW_VAR_OBJECT(hmac_instance, instance,
    		 HMAC_SIZE(self->type));
    
      instance->type = self->type;
      
      hmac_set_key(HMAC_OUTER(instance), HMAC_INNER(instance),
    	       HMAC_STATE(instance),
    	       self->type, key_length, key);
    
      instance->super.mac_size = self->super.mac_size;
      instance->super.update = do_hmac_update;
      instance->super.digest = do_hmac_digest;
    
      return &instance->super;
    }
    
    struct mac_algorithm *
    make_hmac_algorithm(const struct nettle_hash *h)
    {
      NEW(hmac_algorithm, self);
    
      self->super.mac_size = h->digest_size;
    
      /* Recommended in RFC-2104 */
      self->super.key_size = h->digest_size;
      self->super.make_mac = make_hmac_instance;
    
      self->type = h;
    
      return &self->super;
    }
    
    
    /* Utility functions */
    
    struct lsh_string *
    hash_string_l(const struct nettle_hash *a,
    	      uint32_t length, const uint8_t *data)
    {
      struct hash_instance *hash = make_hash(a);
      struct lsh_string *out;
    
      hash_update(hash, length, data);
      out = hash_digest_string(hash);
    
      KILL(hash);
    
      return out;
    }
    
    struct lsh_string *
    hash_string(const struct nettle_hash *a,
    	    const struct lsh_string *in,
    	    int free)
    {
      struct lsh_string *out = hash_string_l(a, STRING_LD(in));
    
      if (free)
        lsh_string_free(in);
    
      return out;
    }
    
    struct lsh_string *
    mac_string(struct mac_algorithm *a,
    	   const struct lsh_string *key,
    	   int kfree,
    	   const struct lsh_string *in,
    	   int ifree)
    {
      struct lsh_string *out;
      struct mac_instance *mac
        = MAKE_MAC(a, lsh_string_length(key), lsh_string_data(key));
    
      MAC_UPDATE(mac, lsh_string_length(in), lsh_string_data(in));
      out = MAC_DIGEST_STRING(mac);
    
      KILL(mac);
      
      if (kfree)
        lsh_string_free(key);
      if (ifree)
        lsh_string_free(in);
    
      return out;
    }
    
    /* Consumes input string. */
    struct lsh_string *
    crypt_string(struct crypto_instance *c,
    	     const struct lsh_string *in)
    {
      struct lsh_string *out;
      uint32_t length = lsh_string_length(in);
      
      if (c->block_size && (length % c->block_size))
        return NULL;
    
      /* Do the encryption in place. The type cast is permissible
       * because we're conceptually freeing the string and reusing the
       * storage. */
      out = (struct lsh_string *) in;
      
      CRYPT(c, length, out, 0, in, 0);
      
      return out;
    }
    
    /* This is only used for encrypted private keys. */
    /* Consumes input string. */
    struct lsh_string *
    crypt_string_pad(struct crypto_instance *c,
    		 const struct lsh_string *in)
    {
      struct lsh_string *s;
      uint32_t length = lsh_string_length(in);
      uint32_t pos;
      uint32_t pad = c->block_size - (length % c->block_size);
      
      assert(pad);
      
      s = ssh_format("%lfS%lr", in, pad, &pos);
      /* Use RFC 1423 and "generalized RFC 1423" as described in
       * PKCS#5 version 2. */
      lsh_string_set(s, pos, pad, pad);
    
      return crypt_string(c, s);
    }
    
    /* Consumes input string. */
    struct lsh_string *
    crypt_string_unpad(struct crypto_instance *c,
    		   const struct lsh_string *in)
    {
      struct lsh_string *out;
      uint32_t pad;
      uint32_t length = lsh_string_length(in);
      assert(length);
      
      out = crypt_string(c, in);
      if (!out)
        return NULL;
    
      length = lsh_string_length(out);
      pad = lsh_string_data(out)[length - 1];
    
      if ( (pad > 0) && (pad <= c->block_size) )
        {
          /* This should not happen, as crypt string
           * must return a multiple of the block size. */
          assert(pad <= length);
    
          lsh_string_trunc(out, length - pad);
          return out;
        }
      else
        {
          lsh_string_free(out);
          return NULL;
        }
    }
    
    struct keypair *
    make_keypair(uint32_t type,
    	     struct lsh_string *public,
    	     struct signer *private)
    {
      NEW(keypair, self);
      
      self->type = type;
      self->public = public;
      self->private = private;
      return self;
    }