From 59b2b448afd977128c84bcea6b18adaf37d4be69 Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 27 Mar 2004 00:04:19 +0000 Subject: [PATCH] INCOMPATIBLE CHANGE. Use proper authentication on encrypted keys. --- key-pass.c | 153 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 58 deletions(-) diff --git a/key-pass.c b/key-pass.c index b6bc73d..3785765 100644 --- a/key-pass.c +++ b/key-pass.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: key-pass.c,v 1.2 2000/06/17 11:26:35 mdw Exp $ + * $Id: key-pass.c,v 1.3 2004/03/27 00:04:19 mdw Exp $ * * Encrypting keys with passphrases * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: key-pass.c,v $ + * 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. * @@ -49,9 +52,22 @@ #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 @@ -66,7 +82,9 @@ 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 --- */ @@ -74,50 +92,61 @@ int key_plock(const char *tag, key_data *k, key_data *kt) 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); + /* --- Format the stuff in the buffer --- */ - /* --- 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_get(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; - /* --- Hash the passphrase into a key --- */ + /* --- Read the passphrase --- */ + + if (passphrase_read(tag, PMODE_VERIFY, buf, sizeof(buf))) { + dstr_destroy(&d); + return (-1); + } + + /* --- 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); @@ -136,7 +165,7 @@ int key_plock(const char *tag, key_data *k, key_data *kt) 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; size_t sz; @@ -146,31 +175,27 @@ int key_punlock(const char *tag, key_data *k, key_data *kt) assert(((void)"Key data isn't encrypted", (k->e & KF_ENCMASK) == KENC_ENCRYPT)); - /* --- Fetch the passphrase --- */ + /* --- Allocate a destination buffer --- */ - if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf))) - goto fail_0; + if (k->u.k.sz < RMD160_HASHSZ * 2) + return (-1);; + sz = k->u.k.sz - RMD160_HASHSZ * 2; + p = xmalloc(k->u.k.sz); - /* --- 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. - */ + /* --- Fetch the passphrase --- */ - if (k->u.k.sz < 12) - goto fail_0; - sz = k->u.k.sz - 4; - p = xmalloc(k->u.k.sz); + if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf))) + goto fail; - /* --- Hash the passphrase --- */ + /* --- Hash the passphrase to make a key --- */ { - 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); + 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); } @@ -178,14 +203,26 @@ int key_punlock(const char *tag, key_data *k, key_data *kt) { 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, sizeof(b), 0); + blowfish_cbcdecrypt(&c, k->u.k.k + RMD160_HASHSZ, p, sz); BURN(c); - if (LOAD32(p) != 0) { + } + + /* --- Verify the MAC --- */ + + { + rmd160_mackey mk; + rmd160_macctx mc; + rmd160_hmacinit(&mk, b + RMD160_HASHSZ, RMD160_HASHSZ); + rmd160_macinit(&mc, &mk); + rmd160_machash(&mc, p, sz); + rmd160_macdone(&mc, b); + if (memcmp(b, k->u.k.k + RMD160_HASHSZ, RMD160_HASHSZ) != 0) { passphrase_cancel(tag); - goto fail_1; + goto fail; } + BURN(mk); + BURN(mc); } /* --- Decode the key data into the destination buffer --- */ @@ -194,8 +231,8 @@ int key_punlock(const char *tag, key_data *k, key_data *kt) 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 --- */ @@ -204,9 +241,9 @@ int key_punlock(const char *tag, key_data *k, key_data *kt) /* --- Tidy up if things went wrong --- */ -fail_1: +fail: + BURN(b); free(p); -fail_0: return (-1); } -- 2.11.0