Fix distribution.
[u/mdw/catacomb] / key-pass.c
CommitLineData
d11a0bf7 1/* -*-c-*-
2 *
59b2b448 3 * $Id: key-pass.c,v 1.3 2004/03/27 00:04:19 mdw Exp $
d11a0bf7 4 *
5 * Encrypting keys with passphrases
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: key-pass.c,v $
59b2b448 33 * Revision 1.3 2004/03/27 00:04:19 mdw
34 * INCOMPATIBLE CHANGE. Use proper authentication on encrypted keys.
35 *
bbded534 36 * Revision 1.2 2000/06/17 11:26:35 mdw
37 * `rand_getgood' is deprecated.
38 *
d11a0bf7 39 * Revision 1.1 1999/12/22 15:47:48 mdw
40 * Major key-management revision.
41 *
42 */
43
44/*----- Header files ------------------------------------------------------*/
45
46#include <mLib/dstr.h>
47
48#include "key.h"
49#include "paranoia.h"
50#include "passphrase.h"
51#include "rand.h"
52
53#include "blowfish-cbc.h"
54#include "rmd160.h"
59b2b448 55#include "rmd160-mgf.h"
56#include "rmd160-hmac.h"
d11a0bf7 57
58/*----- Main code ---------------------------------------------------------*/
59
59b2b448 60/* --- Format --- *
61 *
62 * Choose a random 160-bit string %$R$%. Take the passphrase %$P$%, and
63 * the message %$m$%. Now, compute %$K_E \cat K_T = H(R \cat P)$%,
64 * %$y_0 = E_{K_E}(m)$% and %$\tau = T_{K_T}(y_0)$%. The ciphertext is
65 * %$y = N \cat \tau \cat y_0$%.
66 *
67 * This is not the original format. The original format was insecure, and
68 * has been replaced incompatibly.
69 */
70
d11a0bf7 71/* --- @key_plock@ --- *
72 *
73 * Arguments: @const char *tag@ = tag to use for passphrase
74 * @key_data *k@ = source key data block
75 * @key_data *kt@ = target key data block
76 *
77 * Returns: Zero if successful, nonzero if there was a problem.
78 *
79 * Use: Locks a key by encrypting it with a passphrase.
80 */
81
82int key_plock(const char *tag, key_data *k, key_data *kt)
83{
84 dstr d = DSTR_INIT;
59b2b448 85 octet b[RMD160_HASHSZ * 2];
86 octet *m;
87 size_t msz;
d11a0bf7 88 char buf[256];
89
90 /* --- Sanity check --- */
91
92 assert(((void)"Key data is already encrypted",
93 (k->e & KF_ENCMASK) != KENC_ENCRYPT));
94
59b2b448 95 /* --- Format the stuff in the buffer --- */
d11a0bf7 96
59b2b448 97 DENSURE(&d, RMD160_HASHSZ * 2);
98 rand_get(RAND_GLOBAL, d.buf, RMD160_HASHSZ);
99 d.len += RMD160_HASHSZ * 2;
d11a0bf7 100 key_encode(k, &d, 0);
101 if (k == kt)
102 key_destroy(k);
59b2b448 103 m = (octet *)d.buf + RMD160_HASHSZ * 2;
104 msz = d.len - RMD160_HASHSZ * 2;
d11a0bf7 105
59b2b448 106 /* --- Read the passphrase --- */
107
108 if (passphrase_read(tag, PMODE_VERIFY, buf, sizeof(buf))) {
109 dstr_destroy(&d);
110 return (-1);
111 }
112
113 /* --- Hash the passphrase to make a key --- */
d11a0bf7 114
115 {
59b2b448 116 rmd160_mgfctx r;
117 rmd160_mgfkeybegin(&r);
118 rmd160_mgfkeyadd(&r, d.buf, RMD160_HASHSZ);
119 rmd160_mgfkeyadd(&r, buf, strlen(buf));
120 rmd160_mgfencrypt(&r, 0, b, sizeof(b));
121 BURN(r);
d11a0bf7 122 BURN(buf);
123 }
124
59b2b448 125 /* --- Encrypt the plaintext --- */
d11a0bf7 126
127 {
128 blowfish_cbcctx c;
59b2b448 129 blowfish_cbcinit(&c, b, RMD160_HASHSZ, 0);
130 blowfish_cbcencrypt(&c, m, m, msz);
d11a0bf7 131 BURN(c);
132 }
133
59b2b448 134 /* --- MAC the ciphertext --- */
135
136 {
137 rmd160_mackey mk;
138 rmd160_macctx mc;
139 rmd160_hmacinit(&mk, b + RMD160_HASHSZ, RMD160_HASHSZ);
140 rmd160_macinit(&mc, &mk);
141 rmd160_machash(&mc, m, msz);
142 rmd160_macdone(&mc, d.buf + RMD160_HASHSZ);
143 BURN(mk);
144 BURN(mc);
145 }
146
147 /* --- Done --- */
d11a0bf7 148
59b2b448 149 BURN(b);
d11a0bf7 150 key_encrypted(kt, d.buf, d.len);
151 dstr_destroy(&d);
152 return (0);
153}
154
155/* --- @key_punlock@ --- *
156 *
157 * Arguments: @const char *tag@ = tag to use for passphrase
158 * @key_data *k@ = source key data block
159 * @key_data *kt@ = target key data block
160 *
161 * Returns: Zero if it worked, nonzero if it didn't.
162 *
163 * Use: Unlocks a passphrase-locked key.
164 */
165
166int key_punlock(const char *tag, key_data *k, key_data *kt)
167{
59b2b448 168 octet b[RMD160_HASHSZ * 2];
d11a0bf7 169 char buf[256];
170 octet *p;
171 size_t sz;
172
173 /* --- Sanity check --- */
174
175 assert(((void)"Key data isn't encrypted",
176 (k->e & KF_ENCMASK) == KENC_ENCRYPT));
177
59b2b448 178 /* --- Allocate a destination buffer --- */
d11a0bf7 179
59b2b448 180 if (k->u.k.sz < RMD160_HASHSZ * 2)
181 return (-1);;
182 sz = k->u.k.sz - RMD160_HASHSZ * 2;
183 p = xmalloc(k->u.k.sz);
d11a0bf7 184
59b2b448 185 /* --- Fetch the passphrase --- */
d11a0bf7 186
59b2b448 187 if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf)))
188 goto fail;
d11a0bf7 189
59b2b448 190 /* --- Hash the passphrase to make a key --- */
d11a0bf7 191
192 {
59b2b448 193 rmd160_mgfctx r;
194 rmd160_mgfkeybegin(&r);
195 rmd160_mgfkeyadd(&r, k->u.k.k, RMD160_HASHSZ);
196 rmd160_mgfkeyadd(&r, buf, strlen(buf));
197 rmd160_mgfencrypt(&r, 0, b, sizeof(b));
198 BURN(r);
d11a0bf7 199 BURN(buf);
200 }
201
202 /* --- Decrypt the key data --- */
203
204 {
205 blowfish_cbcctx c;
59b2b448 206 blowfish_cbcinit(&c, b, sizeof(b), 0);
207 blowfish_cbcdecrypt(&c, k->u.k.k + RMD160_HASHSZ, p, sz);
d11a0bf7 208 BURN(c);
59b2b448 209 }
210
211 /* --- Verify the MAC --- */
212
213 {
214 rmd160_mackey mk;
215 rmd160_macctx mc;
216 rmd160_hmacinit(&mk, b + RMD160_HASHSZ, RMD160_HASHSZ);
217 rmd160_macinit(&mc, &mk);
218 rmd160_machash(&mc, p, sz);
219 rmd160_macdone(&mc, b);
220 if (memcmp(b, k->u.k.k + RMD160_HASHSZ, RMD160_HASHSZ) != 0) {
d11a0bf7 221 passphrase_cancel(tag);
59b2b448 222 goto fail;
d11a0bf7 223 }
59b2b448 224 BURN(mk);
225 BURN(mc);
d11a0bf7 226 }
227
228 /* --- Decode the key data into the destination buffer --- */
229
230 if (k == kt) {
231 key_destroy(k);
232 passphrase_cancel(tag);
233 }
59b2b448 234 if (key_decode(p, sz, kt))
235 goto fail;
d11a0bf7 236
237 /* --- Done --- */
238
239 free(p);
240 return (0);
241
242 /* --- Tidy up if things went wrong --- */
243
59b2b448 244fail:
245 BURN(b);
d11a0bf7 246 free(p);
d11a0bf7 247 return (-1);
248}
249
250/*----- That's all, folks -------------------------------------------------*/