chiark / gitweb /
Make it build\!
[become] / src / icrypt.c
1 /* -*-c-*-
2  *
3  * $Id: icrypt.c,v 1.4 1998/01/12 16:46:02 mdw Exp $
4  *
5  * Higher level encryption functions
6  *
7  * (c) 1998 Mark Wooding
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of `become'
13  *
14  * `Become' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * `Become' 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 General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with `become'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------*
30  *
31  * $Log: icrypt.c,v $
32  * Revision 1.4  1998/01/12 16:46:02  mdw
33  * Fix copyright date.
34  *
35  * Revision 1.3  1997/09/26 09:14:58  mdw
36  * Merged blowfish branch into trunk.
37  *
38  * Revision 1.2.2.1  1997/09/26 09:08:07  mdw
39  * Use the Blowfish encryption algorithm instead of IDEA.  This is partly
40  * because I prefer Blowfish (without any particularly strong evidence) but
41  * mainly because IDEA is patented and Blowfish isn't.
42  *
43  * Revision 1.2  1997/08/04 10:24:22  mdw
44  * Sources placed under CVS control.
45  *
46  * Revision 1.1  1997/07/21  13:47:49  mdw
47  * Initial revision
48  *
49  */
50
51 /*----- Header files ------------------------------------------------------*/
52
53 /* --- ANSI headers --- */
54
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58
59 /* --- Local headers --- */
60
61 #include "blowfish.h"
62 #include "config.h"
63 #include "icrypt.h"
64
65 /*----- Main code ---------------------------------------------------------*/
66
67 /* --- @icrypt_init@ --- *
68  *
69  * Arguments:   @icrypt_job *j@ = pointer to job context block
70  *              @unsigned char *k@ = pointer to key data
71  *              @size_t sz@ = size of the key data
72  *              @const unsigned char *iv@ = pointer to IV
73  *
74  * Returns:     ---
75  *
76  * Use:         Primes the context block ready for encryption.
77  */
78
79 void icrypt_init(icrypt_job *j, unsigned char *k,
80                  size_t sz, const unsigned char *iv)
81 {
82   blowfish_setKey(&j->k, k, sz);
83   if (iv)
84     memcpy(j->iv, iv, BLOWFISH_BLKSIZE);
85   else
86     memset(j->iv, 0, BLOWFISH_BLKSIZE);
87   j->i = 8;
88 }
89
90 /* --- @icrypt_encrypt@ --- *
91  *
92  * Arguments:   @icrypt_job *j@ = job handle
93  *              @const void *src@ = pointer to source buffer
94  *              @void *dest@ = pointer to destination buffer
95  *              @size_t sz@ = size of buffers to handle
96  *
97  * Returns:     ---
98  *
99  * Use:         Encrypts data from the source to the destination, using the
100  *              key attached to the job handle.
101  */
102
103 void icrypt_encrypt(icrypt_job *j, const void *src, void *dest, size_t sz)
104 {
105   const unsigned char *s = src;
106   unsigned char *d = dest;
107   int i;
108
109   /* --- First, use up bytes in the buffer --- */
110
111   while (j->i < BLOWFISH_BLKSIZE && sz > 0) {
112     *d++ = j->iv[j->i++] ^= *s++;
113     sz--;
114   }
115   if (!sz) return;
116
117   /* --- Now encrypt larger chunks at a time --- */
118
119   while (sz >= BLOWFISH_BLKSIZE) {
120
121     /* --- Freshen the IV --- */
122
123     blowfish_encrypt(&j->k, j->iv, j->iv);
124
125     /* --- Now encrypt some more bytes --- */
126
127     for (i = 0; i < BLOWFISH_BLKSIZE; i++) {
128       *d++ = j->iv[i] ^= *s++;
129     }
130     sz -= BLOWFISH_BLKSIZE;
131   }
132   if (!sz) return;
133
134   /* --- Do the tail-end bits --- */
135
136   blowfish_encrypt(&j->k, j->iv, j->iv);
137   j->i = 0;
138   while (sz) {
139     *d++ = j->iv[j->i++] ^= *s++;
140     sz--;
141   }
142 }
143
144 /* --- @icrypt_decrypt@ --- *
145  *
146  * Arguments:   @icrypt_job *j@ = job handle
147  *              @const void *src@ = pointer to source buffer
148  *              @void *dest@ = pointer to destination buffer
149  *              @size_t sz@ = size of buffers to handle
150  *
151  * Returns:     ---
152  *
153  * Use:         Decrypts data from the source to the destination, using
154  *              the key attached to the job handle.
155  */
156
157 void icrypt_decrypt(icrypt_job *j, const void *src, void *dest, size_t sz)
158 {
159   unsigned const char *s = src;
160   unsigned char *d = dest;
161   int i;
162   unsigned char c;
163
164   /* --- First, use up bytes in the buffer --- */
165
166   while (j->i < BLOWFISH_BLKSIZE && sz > 0) {
167     c = *s++;
168     *d++ = j->iv[j->i] ^ c;
169     j->iv[j->i++] = c;
170     sz--;
171   }
172   if (!sz) return;
173
174   /* --- Now encrypt larger chunks at a time --- */
175
176   while (sz >= BLOWFISH_BLKSIZE) {
177
178     /* --- Freshen the IV --- */
179
180     blowfish_encrypt(&j->k, j->iv, j->iv);
181
182     /* --- Now encrypt some more bytes --- */
183
184     for (i = 0; i < BLOWFISH_BLKSIZE; i++) {
185       c = *s++;
186       *d++ = j->iv[i] ^ c;
187       j->iv[i] = c;
188     }
189     sz -= BLOWFISH_BLKSIZE;
190   }
191   if (!sz) return;
192
193   /* --- Do the tail-end bits --- */
194
195   blowfish_encrypt(&j->k, j->iv, j->iv);
196   j->i = 0;
197   while (sz) {
198     c = *s++;
199     *d++ = j->iv[j->i] ^ c;
200     j->iv[j->i++] = c;
201     sz--;
202   }
203 }
204
205 /* --- @icrypt_reset@ --- *
206  *
207  * Arguments:   @icrypt_job *j@ = pointer to job context block
208  *              @unsigned char *k@ = pointer to key data, or zero for
209  *                      no change
210  *              @size_t sz@ = size of the key in bytes
211  *              @const unsigned char *iv@ = pointer to IV, or zero
212  *
213  * Returns:     ---
214  *
215  * Use:         Alters the context block.  This can be used after recovery
216  *              of a session key, for example.
217  */
218
219 void icrypt_reset(icrypt_job *j, unsigned char *k,
220                   size_t sz, const unsigned char *iv)
221 {
222   if (k)
223     blowfish_setKey(&j->k, k, sz);
224   if (iv)
225     memcpy(j->iv, iv, BLOWFISH_BLKSIZE);
226   else {
227     unsigned char b[BLOWFISH_BLKSIZE];
228     int n = j->i, o = BLOWFISH_BLKSIZE - j->i;
229
230     memcpy(b, j->iv, sizeof(b));
231     memcpy(j->iv, b + n, o);
232     memcpy(j->iv + o, b, n);
233   }
234   j->i = 8;
235 }
236
237 /* --- @icrypt_saveIV@ --- *
238  *
239  * Arguments:   @icrypt_job *j@ = pointer to job context block
240  *              @unsigned char *iv@ = where to store the IV
241  *
242  * Returns:     ---
243  *
244  * Use:         Writes out the job's IV after munging it a little.
245  */
246
247 void icrypt_saveIV(icrypt_job *j, unsigned char *iv)
248 {
249   int n = j->i, o = BLOWFISH_BLKSIZE - j->i;
250
251   memcpy(j->iv, iv + n, o);
252   memcpy(j->iv + o, iv, n);
253   blowfish_encrypt(&j->k, iv, iv);
254 }
255
256 /*----- Test rig ----------------------------------------------------------*/
257
258 #ifdef TEST_RIG
259
260 #include <errno.h>
261 #include <pwd.h>
262 #include <unistd.h>
263 #include "crypt.h"
264 #include "mdwopt.h"
265 #include "md5.h"
266 #include "utils.h"
267
268 void icrypt(icrypt_job *j,
269             void (*proc)(icrypt_job *j,
270                          const void *src,
271                          void *dest,
272                          size_t sz),
273             FILE *fp)
274 {
275   char buff[71];
276   size_t r;
277
278   for (;;) {
279     r = fread(buff, 1, sizeof(buff), fp);
280     if (!r) break;
281     proc(j, buff, buff, r);
282     fwrite(buff, 1, r, stdout);
283   }
284 }
285
286 int main(int argc, char *argv[])
287 {
288   icrypt_job j;
289   md5 md;
290   void (*proc)(icrypt_job *j,
291                const void *src,
292                void *dest,
293                size_t sz) = icrypt_encrypt;
294
295   ego(argv[0]);
296
297   for (;;) {
298     int i = getopt(argc, argv, "d");
299     if (i < 0)
300       break;
301     if (i == 'd')
302       proc = icrypt_decrypt;
303   }
304
305   {
306     char *pass = getpass("Password: ");
307     unsigned char k[BLOWFISH_KEYSIZE];
308     md5_init(&md);
309     md5_buffer(&md, pass, strlen(pass));
310     memset(pass, 0, strlen(pass));
311     md5_final(&md, k);
312
313     icrypt_init(&j, k, BLOWFISH_KEYSIZE, 0);
314   }
315
316   if (optind >= argc)
317     icrypt(&j, proc, stdin);
318
319   while (optind < argc) {
320     char *p = argv[optind++];
321     if (strcmp(p, "-") == 0)
322       icrypt(&j, proc, stdin);
323     else {
324       FILE *fp = fopen(p, "rb");
325       if (!fp)
326         die("couldn't open `%s': %s", p, strerror(errno));
327       icrypt(&j, proc, fp);
328       fclose(fp);
329     }
330   }
331
332   return (0);
333 }
334
335 #endif    
336
337 /*----- That's all, folks -------------------------------------------------*/