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