chiark / gitweb /
Add some more vectors, and a whinge about how Skipjack test vectors are.
[catacomb] / key-pass.c
1 /* -*-c-*-
2  *
3  * $Id: key-pass.c,v 1.2 2000/06/17 11:26:35 mdw Exp $
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 $
33  * Revision 1.2  2000/06/17 11:26:35  mdw
34  * `rand_getgood' is deprecated.
35  *
36  * Revision 1.1  1999/12/22 15:47:48  mdw
37  * Major key-management revision.
38  *
39  */
40
41 /*----- Header files ------------------------------------------------------*/
42
43 #include <mLib/dstr.h>
44
45 #include "key.h"
46 #include "paranoia.h"
47 #include "passphrase.h"
48 #include "rand.h"
49
50 #include "blowfish-cbc.h"
51 #include "rmd160.h"
52
53 /*----- Main code ---------------------------------------------------------*/
54
55 /* --- @key_plock@ --- *
56  *
57  * Arguments:   @const char *tag@ = tag to use for passphrase
58  *              @key_data *k@ = source key data block
59  *              @key_data *kt@ = target key data block
60  *
61  * Returns:     Zero if successful, nonzero if there was a problem.
62  *
63  * Use:         Locks a key by encrypting it with a passphrase.
64  */
65
66 int key_plock(const char *tag, key_data *k, key_data *kt)
67 {
68   dstr d = DSTR_INIT;
69   octet hash[RMD160_HASHSZ];
70   char buf[256];
71
72   /* --- Sanity check --- */
73
74   assert(((void)"Key data is already encrypted",
75           (k->e & KF_ENCMASK) != KENC_ENCRYPT));
76
77   /* --- Read the passphrase --- */
78
79   if (passphrase_read(tag, PMODE_VERIFY, buf, sizeof(buf)))
80     return (-1);
81
82   /* --- Extract the key data --- *
83    *
84    * On the front, put four random bytes to act as a passphrase salt (which
85    * remain in the clear), and four zero bytes to be able to spot duff
86    * passphrases when unlocking.
87    */
88
89   DENSURE(&d, 8);
90   rand_get(RAND_GLOBAL, d.buf, 4);
91   memset(d.buf + 4, 0, 4);
92   d.len += 8;
93   key_encode(k, &d, 0);
94   if (k == kt)
95     key_destroy(k);
96
97   /* --- Hash the passphrase into a key --- */
98
99   {
100     rmd160_ctx h;
101     rmd160_init(&h);
102     rmd160_hash(&h, d.buf, 4);
103     rmd160_hash(&h, buf, strlen(buf));
104     rmd160_done(&h, hash);
105     BURN(h);
106     BURN(buf);
107   }
108
109   /* --- Encrypt the key data --- */
110
111   {
112     blowfish_cbcctx c;
113     blowfish_cbcinit(&c, hash, sizeof(hash), 0);
114     blowfish_cbcencrypt(&c, d.buf + 4, d.buf + 4, d.len - 4);
115     BURN(hash);
116     BURN(c);
117   }
118
119   /* --- Put the key data back in the key --- */
120
121   key_encrypted(kt, d.buf, d.len);
122   dstr_destroy(&d);
123   return (0);
124 }
125
126 /* --- @key_punlock@ --- *
127  *
128  * Arguments:   @const char *tag@ = tag to use for passphrase
129  *              @key_data *k@ = source key data block
130  *              @key_data *kt@ = target key data block
131  *
132  * Returns:     Zero if it worked, nonzero if it didn't.
133  *
134  * Use:         Unlocks a passphrase-locked key.
135  */
136
137 int key_punlock(const char *tag, key_data *k, key_data *kt)
138 {
139   octet hash[RMD160_HASHSZ];
140   char buf[256];
141   octet *p;
142   size_t sz;
143
144   /* --- Sanity check --- */
145
146   assert(((void)"Key data isn't encrypted",
147           (k->e & KF_ENCMASK) == KENC_ENCRYPT));
148
149   /* --- Fetch the passphrase --- */
150
151   if (passphrase_read(tag, PMODE_READ, buf, sizeof(buf)))
152     goto fail_0;
153
154   /* --- Allocate a destination buffer --- *
155    *
156    * Minimum size for a key is four bytes salt, four bytes zeroes, two bytes
157    * type, and two bytes length, making a total of twelve.
158    */
159
160   if (k->u.k.sz < 12)
161     goto fail_0;
162   sz = k->u.k.sz - 4;
163   p = xmalloc(k->u.k.sz);
164
165   /* --- Hash the passphrase --- */
166
167   {
168     rmd160_ctx h;
169     rmd160_init(&h);
170     rmd160_hash(&h, k->u.k.k, 4);
171     rmd160_hash(&h, buf, strlen(buf));
172     rmd160_done(&h, hash);
173     BURN(h);
174     BURN(buf);
175   }
176
177   /* --- Decrypt the key data --- */
178
179   {
180     blowfish_cbcctx c;
181     blowfish_cbcinit(&c, hash, sizeof(hash), 0);
182     blowfish_cbcdecrypt(&c, k->u.k.k + 4, p, sz);
183     BURN(hash);
184     BURN(c);
185     if (LOAD32(p) != 0) {
186       passphrase_cancel(tag);
187       goto fail_1;
188     }
189   }
190
191   /* --- Decode the key data into the destination buffer --- */
192
193   if (k == kt) {
194     key_destroy(k);
195     passphrase_cancel(tag);
196   }
197   if (key_decode(p + 4, sz - 4, kt))
198     goto fail_1;
199
200   /* --- Done --- */
201
202   free(p);
203   return (0);
204
205   /* --- Tidy up if things went wrong --- */
206
207 fail_1:
208   free(p);
209 fail_0:
210   return (-1);
211 }
212
213 /*----- That's all, folks -------------------------------------------------*/