Major key-management revision.
[u/mdw/catacomb] / key-pass.c
diff --git a/key-pass.c b/key-pass.c
new file mode 100644 (file)
index 0000000..024a614
--- /dev/null
@@ -0,0 +1,210 @@
+/* -*-c-*-
+ *
+ * $Id: key-pass.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ *
+ * Encrypting keys with passphrases
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * Catacomb 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 Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: key-pass.c,v $
+ * Revision 1.1  1999/12/22 15:47:48  mdw
+ * Major key-management revision.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/dstr.h>
+
+#include "key.h"
+#include "paranoia.h"
+#include "passphrase.h"
+#include "rand.h"
+
+#include "blowfish-cbc.h"
+#include "rmd160.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @key_plock@ --- *
+ *
+ * Arguments:  @const char *tag@ = tag to use for passphrase
+ *             @key_data *k@ = source key data block
+ *             @key_data *kt@ = target key data block
+ *
+ * Returns:    Zero if successful, nonzero if there was a problem.
+ *
+ * Use:                Locks a key by encrypting it with a passphrase.
+ */
+
+int key_plock(const char *tag, key_data *k, key_data *kt)
+{
+  dstr d = DSTR_INIT;
+  octet hash[RMD160_HASHSZ];
+  char buf[256];
+
+  /* --- Sanity check --- */
+
+  assert(((void)"Key data is already encrypted",
+         (k->e & KF_ENCMASK) != KENC_ENCRYPT));
+
+  /* --- Read the passphrase --- */
+
+  if (passphrase_read(tag, PMODE_VERIFY, buf, sizeof(buf)))
+    return (-1);
+
+  /* --- Extract the key data --- *
+   *
+   * On the front, put four random bytes to act as a passphrase salt (which
+   * remain in the clear), and four zero bytes to be able to spot duff
+   * passphrases when unlocking.
+   */
+
+  DENSURE(&d, 8);
+  rand_getgood(RAND_GLOBAL, d.buf, 4);
+  memset(d.buf + 4, 0, 4);
+  d.len += 8;
+  key_encode(k, &d, 0);
+  if (k == kt)
+    key_destroy(k);
+
+  /* --- Hash the passphrase into a key --- */
+
+  {
+    rmd160_ctx h;
+    rmd160_init(&h);
+    rmd160_hash(&h, d.buf, 4);
+    rmd160_hash(&h, buf, strlen(buf));
+    rmd160_done(&h, hash);
+    BURN(h);
+    BURN(buf);
+  }
+
+  /* --- Encrypt the key data --- */
+
+  {
+    blowfish_cbcctx c;
+    blowfish_cbcinit(&c, hash, sizeof(hash), 0);
+    blowfish_cbcencrypt(&c, d.buf + 4, d.buf + 4, d.len - 4);
+    BURN(hash);
+    BURN(c);
+  }
+
+  /* --- Put the key data back in the key --- */
+
+  key_encrypted(kt, d.buf, d.len);
+  dstr_destroy(&d);
+  return (0);
+}
+
+/* --- @key_punlock@ --- *
+ *
+ * Arguments:  @const char *tag@ = tag to use for passphrase
+ *             @key_data *k@ = source key data block
+ *             @key_data *kt@ = target key data block
+ *
+ * Returns:    Zero if it worked, nonzero if it didn't.
+ *
+ * Use:                Unlocks a passphrase-locked key.
+ */
+
+int key_punlock(const char *tag, key_data *k, key_data *kt)
+{
+  octet hash[RMD160_HASHSZ];
+  char buf[256];
+  octet *p;
+  size_t sz;
+
+  /* --- Sanity check --- */
+
+  assert(((void)"Key data isn't encrypted",
+         (k->e & KF_ENCMASK) == KENC_ENCRYPT));
+
+  /* --- Fetch the passphrase --- */
+
+  if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf)))
+    goto fail_0;
+
+  /* --- Allocate a destination buffer --- *
+   *
+   * Minimum size for a key is four bytes salt, four bytes zeroes, two bytes
+   * type, and two bytes length, making a total of twelve.
+   */
+
+  if (k->u.k.sz < 12)
+    goto fail_0;
+  sz = k->u.k.sz - 4;
+  p = xmalloc(k->u.k.sz);
+
+  /* --- Hash the passphrase --- */
+
+  {
+    rmd160_ctx h;
+    rmd160_init(&h);
+    rmd160_hash(&h, k->u.k.k, 4);
+    rmd160_hash(&h, buf, strlen(buf));
+    rmd160_done(&h, hash);
+    BURN(h);
+    BURN(buf);
+  }
+
+  /* --- Decrypt the key data --- */
+
+  {
+    blowfish_cbcctx c;
+    blowfish_cbcinit(&c, hash, sizeof(hash), 0);
+    blowfish_cbcdecrypt(&c, k->u.k.k + 4, p, sz);
+    BURN(hash);
+    BURN(c);
+    if (LOAD32(p) != 0) {
+      passphrase_cancel(tag);
+      goto fail_1;
+    }
+  }
+
+  /* --- Decode the key data into the destination buffer --- */
+
+  if (k == kt) {
+    key_destroy(k);
+    passphrase_cancel(tag);
+  }
+  if (key_decode(p + 4, sz - 4, kt))
+    goto fail_1;
+
+  /* --- Done --- */
+
+  free(p);
+  return (0);
+
+  /* --- Tidy up if things went wrong --- */
+
+fail_1:
+  free(p);
+fail_0:
+  return (-1);
+}
+
+/*----- That's all, folks -------------------------------------------------*/