PageRenderTime 57ms CodeModel.GetById 21ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/cvs/src/scramble.c

https://bitbucket.org/freebsd/freebsd-head/
C | 245 lines | 92 code | 24 blank | 129 comment | 7 complexity | f3dccc6afd10bcd5f629e6191f9b35d2 MD5 | raw file
  1/*
  2 * Trivially encode strings to protect them from innocent eyes (i.e.,
  3 * inadvertent password compromises, like a network administrator
  4 * who's watching packets for legitimate reasons and accidentally sees
  5 * the password protocol go by).
  6 * 
  7 * This is NOT secure encryption.
  8 *
  9 * It would be tempting to encode the password according to username
 10 * and repository, so that the same password would encode to a
 11 * different string when used with different usernames and/or
 12 * repositories.  However, then users would not be able to cut and
 13 * paste passwords around.  They're not supposed to anyway, but we all
 14 * know they will, and there's no reason to make it harder for them if
 15 * we're not trying to provide real security anyway.
 16 */
 17
 18/* Set this to test as a standalone program. */
 19/* #define DIAGNOSTIC */
 20
 21#ifndef DIAGNOSTIC
 22#include "cvs.h"
 23#else /* ! DIAGNOSTIC */
 24/* cvs.h won't define this for us */
 25#define AUTH_CLIENT_SUPPORT
 26#define xmalloc malloc
 27/* Use "gcc -fwritable-strings". */
 28#include <stdio.h>
 29#include <stdio.h>
 30#include <string.h>
 31#endif /* ! DIAGNOSTIC */
 32
 33#if defined(AUTH_CLIENT_SUPPORT) || defined(AUTH_SERVER_SUPPORT)
 34
 35/* Map characters to each other randomly and symmetrically, A <--> B.
 36 *
 37 * We divide the ASCII character set into 3 domains: control chars (0
 38 * thru 31), printing chars (32 through 126), and "meta"-chars (127
 39 * through 255).  The control chars map _to_ themselves, the printing
 40 * chars map _among_ themselves, and the meta chars map _among_
 41 * themselves.  Why is this thus?
 42 *
 43 * No character in any of these domains maps to a character in another
 44 * domain, because I'm not sure what characters are legal in
 45 * passwords, or what tools people are likely to use to cut and paste
 46 * them.  It seems prudent not to introduce control or meta chars,
 47 * unless the user introduced them first.  And having the control
 48 * chars all map to themselves insures that newline and
 49 * carriage-return are safely handled.
 50 */
 51
 52static unsigned char
 53shifts[] = {
 54    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 55   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
 56  114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
 57  111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
 58   41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
 59  125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
 60   36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
 61   58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
 62  225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
 63  199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
 64  174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
 65  207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
 66  192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
 67  227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
 68  182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
 69  243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 };
 70
 71
 72/* SCRAMBLE and DESCRAMBLE work like this:
 73 *
 74 * scramble(STR) returns SCRM, a scrambled copy of STR.  SCRM[0] is a
 75 * single letter indicating the scrambling method.  As of this
 76 * writing, the only legal method is 'A', but check the code for more
 77 * up-to-date information.  The copy will have been allocated with
 78 * xmalloc(). 
 79 *
 80 * descramble(SCRM) returns STR, again in its own xmalloc'd space.
 81 * descramble() uses SCRM[0] to determine which method of unscrambling
 82 * to use.  If it does not recognize the method, it dies with error.
 83 */
 84
 85/* Return a xmalloc'd, scrambled version of STR. */
 86char *
 87scramble (str)
 88    char *str;
 89{
 90    int i;
 91    char *s;
 92
 93    /* +2 to hold the 'A' prefix that indicates which version of
 94       scrambling this is (the first, obviously, since we only do one
 95       kind of scrambling so far), and then the '\0' of course.  */
 96    s = (char *) xmalloc (strlen (str) + 2);
 97
 98    /* Scramble (TM) version prefix. */
 99    s[0] = 'A';
100    strcpy (s + 1, str);
101
102    for (i = 1; s[i]; i++)
103	s[i] = shifts[(unsigned char)(s[i])];
104
105    return s;
106}
107
108/* Decode the string in place. */
109char *
110descramble (str)
111    char *str;
112{
113    char *s;
114    int i;
115
116    /* For now we can only handle one kind of scrambling.  In the future
117       there may be other kinds, and this `if' will become a `switch'.  */
118    if (str[0] != 'A')
119#ifndef DIAGNOSTIC
120	error (1, 0, "descramble: unknown scrambling method");
121#else  /* DIAGNOSTIC */
122    {
123	fprintf (stderr, "descramble: unknown scrambling method\n", str);
124	fflush (stderr);
125	exit (EXIT_FAILURE);
126    }
127#endif  /* DIAGNOSTIC */
128
129    /* Method `A' is symmetrical, so scramble again to decrypt. */
130    s = scramble (str + 1);
131
132    /* Shift the whole string one char to the left, pushing the unwanted
133       'A' off the left end.  Safe, because s is null-terminated. */
134    for (i = 0; s[i]; i++)
135	s[i] = s[i + 1];
136
137    return s;
138}
139
140#endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */
141
142#ifdef DIAGNOSTIC
143int
144main ()
145{
146    int i;
147    char *e, *m, biggie[256];
148
149    char *cleartexts[5];
150    cleartexts[0] = "first";
151    cleartexts[1] = "the second";
152    cleartexts[2] = "this is the third";
153    cleartexts[3] = "$#% !!\\3";
154    cleartexts[4] = biggie;
155
156    /* Set up the most important test string: */
157    /* Can't have a real ASCII zero in the string, because we want to
158       use printf, so we substitute the character zero. */
159    biggie[0] = '0';
160    /* The rest of the string gets straight ascending ASCII. */
161    for (i = 1; i < 256; i++)
162	biggie[i] = i;
163
164    /* Test all the strings. */
165    for (i = 0; i < 5; i++)
166    {
167	printf ("clear%d: %s\n", i, cleartexts[i]);
168	e = scramble (cleartexts[i]);
169	printf ("scram%d: %s\n", i, e);
170	m = descramble (e);
171	free (e);
172	printf ("clear%d: %s\n\n", i, m);
173	free (m);
174    }
175
176    fflush (stdout);
177    return 0;
178}
179#endif /* DIAGNOSTIC */
180
181/*
182 * ;;; The Emacs Lisp that did the dirty work ;;;
183 * (progn
184 * 
185 *   ;; Helper func.
186 *   (defun random-elt (lst)
187 *     (let* ((len (length lst))
188 *            (rnd (random len)))
189 *       (nth rnd lst)))
190 * 
191 *   ;; A list of all characters under 127, each appearing once.
192 *   (setq non-meta-chars
193 *         (let ((i 0)
194 *               (l nil))
195 *           (while (< i 127)
196 *             (setq l (cons i l) 
197 *                   i (1+ i)))
198 *           l))
199 * 
200 *   ;; A list of all characters 127 and above, each appearing once.
201 *   (setq meta-chars
202 *         (let ((i 127)
203 *               (l nil))
204 *           (while (< i 256)
205 *             (setq l (cons i l) 
206 *                   i (1+ i)))
207 *           l))
208 * 
209 *   ;; A vector that will hold the chars in a random order.
210 *   (setq scrambled-chars (make-vector 256 0))
211 * 
212 *   ;; These characters should map to themselves.
213 *   (let ((i 0))
214 *     (while (< i 32)
215 *       (aset scrambled-chars i i)
216 *       (setq non-meta-chars (delete i non-meta-chars) 
217 *             i (1+ i))))
218 *   
219 *   ;; Assign random (but unique) values, within the non-meta chars. 
220 *   (let ((i 32))
221 *     (while (< i 127)
222 *       (let ((ch (random-elt non-meta-chars)))
223 *         (if (= 0 (aref scrambled-chars i))
224 *             (progn
225 *               (aset scrambled-chars i ch)
226 *               (aset scrambled-chars ch i)
227 *               (setq non-meta-chars (delete ch non-meta-chars)
228 *                     non-meta-chars (delete i non-meta-chars))))
229 *         (setq i (1+ i)))))
230 * 
231 *   ;; Assign random (but unique) values, within the non-meta chars. 
232 *   (let ((i 127))
233 *     (while (< i 256)
234 *       (let ((ch (random-elt meta-chars)))
235 *         (if (= 0 (aref scrambled-chars i))
236 *             (progn
237 *               (aset scrambled-chars i ch)
238 *               (aset scrambled-chars ch i)
239 *               (setq meta-chars (delete ch meta-chars)
240 *                     meta-chars (delete i meta-chars))))
241 *         (setq i (1+ i)))))
242 * 
243 *   ;; Now use the `scrambled-chars' vector to get your C array.
244 *   )
245 */