/* -*-c-*-
*
- * $Id: key-pass.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
+ * $Id: key-pass.c,v 1.4 2004/03/28 01:58:26 mdw Exp $
*
* Encrypting keys with passphrases
*
/*----- Revision history --------------------------------------------------*
*
* $Log: key-pass.c,v $
+ * Revision 1.4 2004/03/28 01:58:26 mdw
+ * Ooops, fix all the bugs.
+ *
+ * Revision 1.3 2004/03/27 00:04:19 mdw
+ * INCOMPATIBLE CHANGE. Use proper authentication on encrypted keys.
+ *
+ * Revision 1.2 2000/06/17 11:26:35 mdw
+ * `rand_getgood' is deprecated.
+ *
* Revision 1.1 1999/12/22 15:47:48 mdw
* Major key-management revision.
*
#include "blowfish-cbc.h"
#include "rmd160.h"
+#include "rmd160-mgf.h"
+#include "rmd160-hmac.h"
/*----- Main code ---------------------------------------------------------*/
+/* --- Format --- *
+ *
+ * Choose a random 160-bit string %$R$%. Take the passphrase %$P$%, and
+ * the message %$m$%. Now, compute %$K_E \cat K_T = H(R \cat P)$%,
+ * %$y_0 = E_{K_E}(m)$% and %$\tau = T_{K_T}(y_0)$%. The ciphertext is
+ * %$y = N \cat \tau \cat y_0$%.
+ *
+ * This is not the original format. The original format was insecure, and
+ * has been replaced incompatibly.
+ */
+
/* --- @key_plock@ --- *
*
* Arguments: @const char *tag@ = tag to use for passphrase
int key_plock(const char *tag, key_data *k, key_data *kt)
{
dstr d = DSTR_INIT;
- octet hash[RMD160_HASHSZ];
+ octet b[RMD160_HASHSZ * 2];
+ octet *m;
+ size_t msz;
char buf[256];
/* --- Sanity check --- */
assert(((void)"Key data is already encrypted",
(k->e & KF_ENCMASK) != KENC_ENCRYPT));
- /* --- Read the passphrase --- */
+ /* --- Format the stuff in the buffer --- */
- 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;
+ DENSURE(&d, RMD160_HASHSZ * 2);
+ rand_get(RAND_GLOBAL, d.buf, RMD160_HASHSZ);
+ d.len += RMD160_HASHSZ * 2;
key_encode(k, &d, 0);
if (k == kt)
key_destroy(k);
+ m = (octet *)d.buf + RMD160_HASHSZ * 2;
+ msz = d.len - RMD160_HASHSZ * 2;
+
+ /* --- Read the passphrase --- */
+
+ if (passphrase_read(tag, PMODE_VERIFY, buf, sizeof(buf))) {
+ dstr_destroy(&d);
+ return (-1);
+ }
- /* --- Hash the passphrase into a key --- */
+ /* --- Hash the passphrase to make 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);
+ rmd160_mgfctx r;
+ rmd160_mgfkeybegin(&r);
+ rmd160_mgfkeyadd(&r, d.buf, RMD160_HASHSZ);
+ rmd160_mgfkeyadd(&r, buf, strlen(buf));
+ rmd160_mgfencrypt(&r, 0, b, sizeof(b));
+ BURN(r);
BURN(buf);
}
- /* --- Encrypt the key data --- */
+ /* --- Encrypt the plaintext --- */
{
blowfish_cbcctx c;
- blowfish_cbcinit(&c, hash, sizeof(hash), 0);
- blowfish_cbcencrypt(&c, d.buf + 4, d.buf + 4, d.len - 4);
- BURN(hash);
+ blowfish_cbcinit(&c, b, RMD160_HASHSZ, 0);
+ blowfish_cbcencrypt(&c, m, m, msz);
BURN(c);
}
- /* --- Put the key data back in the key --- */
+ /* --- MAC the ciphertext --- */
+ {
+ rmd160_mackey mk;
+ rmd160_macctx mc;
+ rmd160_hmacinit(&mk, b + RMD160_HASHSZ, RMD160_HASHSZ);
+ rmd160_macinit(&mc, &mk);
+ rmd160_machash(&mc, m, msz);
+ rmd160_macdone(&mc, d.buf + RMD160_HASHSZ);
+ BURN(mk);
+ BURN(mc);
+ }
+
+ /* --- Done --- */
+
+ BURN(b);
key_encrypted(kt, d.buf, d.len);
dstr_destroy(&d);
return (0);
int key_punlock(const char *tag, key_data *k, key_data *kt)
{
- octet hash[RMD160_HASHSZ];
+ octet b[RMD160_HASHSZ * 2];
char buf[256];
- octet *p;
+ octet *p = 0;
size_t sz;
/* --- Sanity check --- */
assert(((void)"Key data isn't encrypted",
(k->e & KF_ENCMASK) == KENC_ENCRYPT));
+ /* --- Check the size --- */
+
+ if (k->u.k.sz < RMD160_HASHSZ * 2)
+ return (-1);
+ sz = k->u.k.sz - RMD160_HASHSZ * 2;
+
/* --- Fetch the passphrase --- */
if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf)))
- goto fail_0;
+ goto fail;
- /* --- 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.
- */
+ /* --- Hash the passphrase to make a key --- */
- if (k->u.k.sz < 12)
- goto fail_0;
- sz = k->u.k.sz - 4;
- p = xmalloc(k->u.k.sz);
+ {
+ rmd160_mgfctx r;
+ rmd160_mgfkeybegin(&r);
+ rmd160_mgfkeyadd(&r, k->u.k.k, RMD160_HASHSZ);
+ rmd160_mgfkeyadd(&r, buf, strlen(buf));
+ rmd160_mgfencrypt(&r, 0, b, sizeof(b));
+ BURN(r);
+ BURN(buf);
+ }
- /* --- Hash the passphrase --- */
+ /* --- Verify the MAC --- */
{
- 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);
+ rmd160_mackey mk;
+ rmd160_macctx mc;
+ rmd160_hmacinit(&mk, b + RMD160_HASHSZ, RMD160_HASHSZ);
+ rmd160_macinit(&mc, &mk);
+ rmd160_machash(&mc, k->u.k.k + RMD160_HASHSZ * 2, sz);
+ rmd160_macdone(&mc, b + RMD160_HASHSZ);
+ if (memcmp(b + RMD160_HASHSZ, k->u.k.k + RMD160_HASHSZ,
+ RMD160_HASHSZ) != 0) {
+ passphrase_cancel(tag);
+ goto fail;
+ }
+ BURN(mk);
+ BURN(mc);
}
+ /* --- Allocate a destination buffer --- */
+
+ p = xmalloc(sz);
+
/* --- 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);
+ blowfish_cbcinit(&c, b, RMD160_HASHSZ, 0);
+ blowfish_cbcdecrypt(&c, k->u.k.k + RMD160_HASHSZ * 2, p, sz);
BURN(c);
- if (LOAD32(p) != 0) {
- passphrase_cancel(tag);
- goto fail_1;
- }
}
/* --- Decode the key data into the destination buffer --- */
key_destroy(k);
passphrase_cancel(tag);
}
- if (key_decode(p + 4, sz - 4, kt))
- goto fail_1;
+ if (key_decode(p, sz, kt))
+ goto fail;
/* --- Done --- */
/* --- Tidy up if things went wrong --- */
-fail_1:
+fail:
+ BURN(b);
free(p);
-fail_0:
return (-1);
}