home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / src / scramble.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  247 lines

  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.  
  52. static unsigned char
  53. shifts[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  54. 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 114, 120,
  55. 53, 79, 96, 109, 72, 108, 70, 64, 76, 67, 116, 74, 68, 87, 111, 52,
  56. 75, 119, 49, 34, 82, 81, 95, 65, 112, 86, 118, 110, 122, 105, 41, 57,
  57. 83, 43, 46, 102, 40, 89, 38, 103, 45, 50, 42, 123, 91, 35, 125, 55,
  58. 54, 66, 124, 126, 59, 47, 92, 71, 115, 78, 88, 107, 106, 56, 36, 121,
  59. 117, 104, 101, 100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 58, 113,
  60. 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85, 223, 225, 216,
  61. 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190,
  62. 199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203,
  63. 226, 193, 174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238,
  64. 161, 179, 160, 212, 207, 221, 254, 173, 202, 146, 224, 151, 140, 196,
  65. 205, 130, 135, 133, 143, 246, 192, 159, 244, 239, 185, 168, 215, 144,
  66. 139, 165, 180, 157, 147, 186, 214, 176, 227, 231, 219, 169, 175, 156,
  67. 206, 198, 129, 164, 150, 210, 154, 177, 134, 127, 182, 128, 158, 208,
  68. 162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195, 243, 233,
  69. 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.  * malloc(). 
  79.  *
  80.  * descramble(SCRM) returns STR, again in its own malloc'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 malloc'd, scrambled version of STR. */
  86. char *
  87. scramble (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.    */
  97.   s = (char *) xmalloc (strlen (str) + 2);
  98.  
  99.   s[0] = 'A';   /* Scramble (TM) version prefix. */
  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. */
  109. char *
  110. descramble (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.    */
  119.   if (str[0] != 'A')
  120. #ifndef DIAGNOSTIC
  121.     error (1, 0, "descramble: unknown scrambling method");
  122. #else  /* DIAGNOSTIC */
  123.   {
  124.     fprintf (stderr, "descramble: unknown scrambling method\n", str);
  125.     fflush (stderr);
  126.     exit (EXIT_FAILURE);
  127.   }
  128. #endif  /* DIAGNOSTIC */
  129.  
  130.   /* Method `A' is symmetrical, so scramble again to decrypt. */
  131.   s = scramble (str + 1);
  132.  
  133.   /* Shift the whole string one char to the left, pushing the unwanted
  134.      'A' off the left end.  Safe, because s is null-terminated. */
  135.   for (i = 0; s[i]; i++)
  136.       s[i] = s[i + 1];
  137.  
  138.   return s;
  139. }
  140.  
  141. #endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */
  142.  
  143. #ifdef DIAGNOSTIC
  144. int
  145. main ()
  146. {
  147.   int i;
  148.   char *e, *m, biggie[256];
  149.  
  150.   char *cleartexts[5];
  151.   cleartexts[0] = "first";
  152.   cleartexts[1] = "the second";
  153.   cleartexts[2] = "this is the third";
  154.   cleartexts[3] = "$#% !!\\3";
  155.   cleartexts[4] = biggie;
  156.   
  157.   /* Set up the most important test string: */
  158.   /* Can't have a real ASCII zero in the string, because we want to
  159.      use printf, so we substitute the character zero. */
  160.   biggie[0] = '0';
  161.   /* The rest of the string gets straight ascending ASCII. */
  162.   for (i = 1; i < 256; i++)
  163.     biggie[i] = i;
  164.  
  165.   /* Test all the strings. */
  166.   for (i = 0; i < 5; i++)
  167.     {
  168.       printf ("clear%d: %s\n", i, cleartexts[i]);
  169.       e = scramble (cleartexts[i]);
  170.       printf ("scram%d: %s\n", i, e);
  171.       m = descramble (e);
  172.       free (e);
  173.       printf ("clear%d: %s\n\n", i, m);
  174.       free (m);
  175.     }
  176.  
  177.   fflush (stdout);
  178.   return 0;
  179. }
  180. #endif /* DIAGNOSTIC */
  181.  
  182. /*
  183.  * ;;; The Emacs Lisp that did the dirty work ;;;
  184.  * (progn
  185.  * 
  186.  *   ;; Helper func.
  187.  *   (defun random-elt (lst)
  188.  *     (let* ((len (length lst))
  189.  *            (rnd (random len)))
  190.  *       (nth rnd lst)))
  191.  * 
  192.  *   ;; A list of all characters under 127, each appearing once.
  193.  *   (setq non-meta-chars
  194.  *         (let ((i 0)
  195.  *               (l nil))
  196.  *           (while (< i 127)
  197.  *             (setq l (cons i l) 
  198.  *                   i (1+ i)))
  199.  *           l))
  200.  * 
  201.  *   ;; A list of all characters 127 and above, each appearing once.
  202.  *   (setq meta-chars
  203.  *         (let ((i 127)
  204.  *               (l nil))
  205.  *           (while (< i 256)
  206.  *             (setq l (cons i l) 
  207.  *                   i (1+ i)))
  208.  *           l))
  209.  * 
  210.  *   ;; A vector that will hold the chars in a random order.
  211.  *   (setq scrambled-chars (make-vector 256 0))
  212.  * 
  213.  *   ;; These characters should map to themselves.
  214.  *   (let ((i 0))
  215.  *     (while (< i 32)
  216.  *       (aset scrambled-chars i i)
  217.  *       (setq non-meta-chars (delete i non-meta-chars) 
  218.  *             i (1+ i))))
  219.  *   
  220.  *   ;; Assign random (but unique) values, within the non-meta chars. 
  221.  *   (let ((i 32))
  222.  *     (while (< i 127)
  223.  *       (let ((ch (random-elt non-meta-chars)))
  224.  *         (if (= 0 (aref scrambled-chars i))
  225.  *             (progn
  226.  *               (aset scrambled-chars i ch)
  227.  *               (aset scrambled-chars ch i)
  228.  *               (setq non-meta-chars (delete ch non-meta-chars)
  229.  *                     non-meta-chars (delete i non-meta-chars))))
  230.  *         (setq i (1+ i)))))
  231.  * 
  232.  *   ;; Assign random (but unique) values, within the non-meta chars. 
  233.  *   (let ((i 127))
  234.  *     (while (< i 256)
  235.  *       (let ((ch (random-elt meta-chars)))
  236.  *         (if (= 0 (aref scrambled-chars i))
  237.  *             (progn
  238.  *               (aset scrambled-chars i ch)
  239.  *               (aset scrambled-chars ch i)
  240.  *               (setq meta-chars (delete ch meta-chars)
  241.  *                     meta-chars (delete i meta-chars))))
  242.  *         (setq i (1+ i)))))
  243.  * 
  244.  *   ;; Now use the `scrambled-chars' vector to get your C array.
  245.  *   )
  246.  */
  247.