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