xref: /plan9/sys/src/cmd/gs/src/sarc4.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2001 Artifex Software, Inc.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: sarc4.c,v 1.10 2004/01/14 13:45:56 igor Exp $ */
18 
19 /* Arcfour cipher and filter implementation */
20 
21 #include "memory_.h"
22 #include "gserrors.h"
23 #include "gserror.h"
24 #include "strimpl.h"
25 #include "sarc4.h"
26 
27 /* This is an independent implementation of the symmetric block
28  * cipher commonly known as 'arcfour' based on Bruce Schneier's
29  * description of the algorithm in _Applied Cryptography_. Arcfour
30  * is believed to be functionally equivalent to the RC4(tm) cipher
31  * mentioned in the PDF specification. (RC4 is a registered
32  * trademark of RSA Data Security, Inc.)
33  */
34 
35 /* stream implementation */
36 
37 private_st_arcfour_state();	/* creates a gc object for our state, defined in sarc4.h */
38 
39 /* initialize the S box using the given key */
40 int
s_arcfour_set_key(stream_arcfour_state * state,const unsigned char * key,int keylength)41 s_arcfour_set_key(stream_arcfour_state * state, const unsigned char *key,
42 		  int keylength)
43 {
44     unsigned int x, y;
45     unsigned char s, *S = state->S;
46 
47     if (keylength < 1)
48 	return_error(gs_error_rangecheck);
49 
50     /* initialize to eponymous values */
51     for (x = 0; x < 256; x++)
52 	S[x] = x;
53 
54     /* scramble based on the key */
55     y = 0;
56     for (x = 0; x < 256; x++) {
57 	y = (y + S[x] + key[x % keylength]) & 0xFF;
58 	s = S[x];
59 	S[x] = S[y];
60 	S[y] = s;
61     }
62 
63     /* initialize the indicies */
64     state->x = 0;
65     state->y = 0;
66 
67     /* return successfully */
68     return 0;
69 }
70 
71 /* (de)crypt a section of text--the procedure is the same
72  * in each direction. see strimpl.h for return codes.
73  */
74 private int
s_arcfour_process(stream_state * ss,stream_cursor_read * pr,stream_cursor_write * pw,bool last)75 s_arcfour_process(stream_state * ss, stream_cursor_read * pr,
76 		  stream_cursor_write * pw, bool last)
77 {
78     stream_arcfour_state *const state = (stream_arcfour_state *) ss;
79     unsigned int x = state->x;
80     unsigned int y = state->y;
81     unsigned char s, *S = state->S;
82     unsigned char z;
83    const unsigned char *limit;
84     int status;
85 
86     /* figure out if we're going to run out of space */
87     if ((pr->limit - pr->ptr) > (pw->limit - pw->ptr)) {
88 	limit = pr->ptr + (pw->limit - pw->ptr);
89 	status = 1;
90     } else {
91 	limit = pr->limit;
92 	status = last ? EOFC : 0;
93     }
94     /* generate a pseudorandom byte stream and xor it with the input */
95     while (pr->ptr < limit) {
96 	x = (x + 1) & 0xFF;
97 	y = (y + S[x]) & 0xFF;
98 	s = S[x];
99 	S[x] = S[y];
100 	S[y] = s;
101 	z = S[(S[x] + S[y]) & 0xFF];
102 
103 	*++pw->ptr = (*++pr->ptr) ^ z;
104     }
105     /* save state */
106     state->x = x;
107     state->y = y;
108 
109     return status;
110 }
111 
112 /* stream template */
113 const stream_template s_arcfour_template = {
114     &st_arcfour_state, NULL, s_arcfour_process, 1, 1
115 };
116 
117 /* (de)crypt a section of text in a buffer -- the procedure is the same
118  * in each direction. see strimpl.h for return codes.
119  */
120 int
s_arcfour_process_buffer(stream_arcfour_state * ss,byte * buf,int buf_size)121 s_arcfour_process_buffer(stream_arcfour_state *ss, byte *buf, int buf_size)
122 {
123     stream_cursor_read r;
124     stream_cursor_write w;
125     const bool unused = false;
126 
127     r.ptr = w.ptr = buf - 1;
128     r.limit = w.limit = buf - 1 + buf_size;
129     return s_arcfour_process((stream_state *)ss, &r, &w, unused);
130 }
131 
132