X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/d11a0bf77a5230387d222ec727865a898767ff3e..df82bc85db06b9cd8917aec33aadaf151d9d4a46:/key-pass.c diff --git a/key-pass.c b/key-pass.c index 024a614..ab8e003 100644 --- a/key-pass.c +++ b/key-pass.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: key-pass.c,v 1.1 1999/12/22 15:47:48 mdw Exp $ + * $Id$ * * Encrypting keys with passphrases * * (c) 1999 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,26 +15,18 @@ * 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 @@ -46,165 +38,227 @@ #include "blowfish-cbc.h" #include "rmd160.h" +#include "rmd160-mgf.h" +#include "rmd160-hmac.h" /*----- Main code ---------------------------------------------------------*/ -/* --- @key_plock@ --- * +/* --- 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$%. * - * Arguments: @const char *tag@ = tag to use for passphrase - * @key_data *k@ = source key data block - * @key_data *kt@ = target key data block + * This is not the original format. The original format was insecure, and + * has been replaced incompatibly. + */ + +/* --- @key_lock@ --- * * - * Returns: Zero if successful, nonzero if there was a problem. + * Arguments: @key_data **kt@ = where to store the destination pointer + * @key_data *k@ = source key data block or null to use @*kt@ + * @const void *e@ = secret to encrypt key with + * @size_t esz@ = size of the secret * - * Use: Locks a key by encrypting it with a passphrase. + * Returns: --- + * + * Use: Encrypts a key data block using a secret. */ -int key_plock(const char *tag, key_data *k, key_data *kt) +void key_lock(key_data **kt, key_data *k, const void *e, size_t esz) { dstr d = DSTR_INIT; - octet hash[RMD160_HASHSZ]; - char buf[256]; + octet b[RMD160_HASHSZ * 2]; + octet *m; + size_t msz; + rmd160_mgfctx r; + blowfish_cbcctx c; + rmd160_mackey mk; + rmd160_macctx mc; /* --- Sanity check --- */ + if (k) key_incref(k); else k = *kt; 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); - - /* --- 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); - } + m = (octet *)d.buf + RMD160_HASHSZ * 2; + msz = d.len - RMD160_HASHSZ * 2; - /* --- Encrypt the key data --- */ + /* --- Hash the passphrase to make a key --- */ - { - 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); - } + rmd160_mgfkeybegin(&r); + rmd160_mgfkeyadd(&r, d.buf, RMD160_HASHSZ); + rmd160_mgfkeyadd(&r, e, esz); + rmd160_mgfencrypt(&r, 0, b, sizeof(b)); + BURN(r); - /* --- Put the key data back in the key --- */ + /* --- Encrypt the plaintext --- */ - key_encrypted(kt, d.buf, d.len); + blowfish_cbcinit(&c, b, RMD160_HASHSZ, 0); + blowfish_cbcencrypt(&c, m, m, msz); + BURN(c); + + /* --- MAC the ciphertext --- */ + + 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); + *kt = key_newencrypted(0, d.buf, d.len); + key_drop(k); dstr_destroy(&d); - return (0); } -/* --- @key_punlock@ --- * +/* --- @key_unlock@ --- * * - * Arguments: @const char *tag@ = tag to use for passphrase - * @key_data *k@ = source key data block - * @key_data *kt@ = target key data block + * Arguments: @key_data **kt@ = where to store the destination pointer + * @key_data *k@ = source key data block or null to use @*kt@ + * @const void *e@ = secret to decrypt the block with + * @size_t esz@ = size of the secret * - * Returns: Zero if it worked, nonzero if it didn't. + * Returns: Zero for success, or a @KERR_@ error code. * - * Use: Unlocks a passphrase-locked key. + * Use: Unlocks a key using a secret. */ -int key_punlock(const char *tag, key_data *k, key_data *kt) +int key_unlock(key_data **kt, key_data *k, const void *e, size_t esz) { - octet hash[RMD160_HASHSZ]; - char buf[256]; - octet *p; + octet b[RMD160_HASHSZ * 2]; + octet *p = 0; + int rc; + int drop = 0; + key_data *kd; + rmd160_mgfctx r; + blowfish_cbcctx c; + rmd160_mackey mk; + rmd160_macctx mc; size_t sz; /* --- Sanity check --- */ + if (!k) { k = *kt; drop = 1; } assert(((void)"Key data isn't encrypted", (k->e & KF_ENCMASK) == KENC_ENCRYPT)); - /* --- Fetch the passphrase --- */ + /* --- Check the size --- */ - 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); + if (k->u.k.sz < RMD160_HASHSZ * 2) + return (KERR_MALFORMED); + sz = k->u.k.sz - RMD160_HASHSZ * 2; + + /* --- Hash the passphrase to make a key --- */ + + rmd160_mgfkeybegin(&r); + rmd160_mgfkeyadd(&r, k->u.k.k, RMD160_HASHSZ); + rmd160_mgfkeyadd(&r, e, esz); + rmd160_mgfencrypt(&r, 0, b, sizeof(b)); + BURN(r); + + /* --- Verify the MAC --- */ + + 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) { + rc = KERR_BADPASS; + 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); - BURN(c); - if (LOAD32(p) != 0) { - passphrase_cancel(tag); - goto fail_1; - } - } + blowfish_cbcinit(&c, b, RMD160_HASHSZ, 0); + blowfish_cbcdecrypt(&c, k->u.k.k + RMD160_HASHSZ * 2, p, sz); + BURN(c); /* --- Decode the key data into the destination buffer --- */ - if (k == kt) { - key_destroy(k); - passphrase_cancel(tag); + if ((kd = key_decode(p, sz)) == 0) { + rc = KERR_MALFORMED; + goto fail; } - if (key_decode(p + 4, sz - 4, kt)) - goto fail_1; + *kt = kd; /* --- Done --- */ - free(p); + xfree(p); + if (drop) key_drop(k); return (0); /* --- Tidy up if things went wrong --- */ -fail_1: - free(p); -fail_0: - return (-1); +fail: + BURN(b); + xfree(p); + return (rc); +} + +/* --- @key_plock@ --- * + * + * Arguments: @key_data **kt@ = where to store the destination pointer + * @key_data *k@ = source key data block or null to use @*kt@ + * @const char *tag@ = tag to use for passphrase + * + * Returns: Zero if successful, a @KERR@ error code on failure. + * + * Use: Locks a key by encrypting it with a passphrase. + */ + +int key_plock(key_data **kt, key_data *k, const char *tag) +{ + char buf[256]; + + if (passphrase_read(tag, PMODE_VERIFY, buf, sizeof(buf))) + return (KERR_IO); + key_lock(kt, k, buf, strlen(buf)); + BURN(buf); + return (0); +} + +/* --- @key_punlock@ --- * + * + * Arguments: @key_data **kt@ = where to store the destination pointer + * @key_data *k@ = source key data block or null to use @*kt@ + * @const char *tag@ = tag to use for passphrase + * + * Returns: Zero if it worked, a @KERR_@ error code on failure. + * + * Use: Unlocks a passphrase-locked key. + */ + +int key_punlock(key_data **kt, key_data *k, const char *tag) +{ + char buf[256]; + int rc; + + if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf))) + return (KERR_IO); + rc = key_unlock(kt, k, buf, strlen(buf)); + BURN(buf); + if (rc == KERR_BADPASS || !k) + passphrase_cancel(tag); + return (rc); } /*----- That's all, folks -------------------------------------------------*/