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