home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / sci / crypt / 2740 < prev    next >
Encoding:
Text File  |  1992-07-25  |  13.1 KB  |  363 lines

  1. Path: sparky!uunet!zaphod.mps.ohio-state.edu!news.acns.nwu.edu!uicvm.uic.edu!u27239
  2. Organization: University of Illinois at Chicago
  3. Date: Saturday, 25 Jul 1992 14:23:18 CDT
  4. From: Gerald Strom <U27239@uicvm.uic.edu>
  5. Message-ID: <92207.142318U27239@uicvm.uic.edu>
  6. Newsgroups: sci.crypt
  7. Subject:    transposition ciphers
  8. Lines: 353
  9.  
  10. The following is a little piece I wrote recently about transposition
  11. ciphers.  As I am far from being an expert in this field, I hope I
  12. didn't get too much wrong and I would appreciate comments.
  13.  
  14.  
  15.                    TRANSPOSITION CIPHERS
  16.  
  17.                       Gerald S. Strom
  18.                University of Illinois at Chicago
  19.  
  20.      When Julius Caesar wanted to keep his messages from being read
  21. by his enemies (and probably a few friends as well), he devised a simple
  22. substitution cipher whereby one letter was replaced by another.  This
  23. Caesar Cipher is not secure by the standards of today but interestingly,
  24. the method used, substituting one letter or character for another in a
  25. regular way, is still the fundamental basis for encipherment in modern
  26. ciphers systems.  The DES system developed by the United States
  27. government, the various public key ciphers systems, as well as the
  28. German Enigma cipher cracked by Allen Turing during World War II
  29. using one of the first computers are all substitution ciphers whereby
  30. letters in the plain (or un-enciphered) text are replaced by different
  31. letters or characters to create the cipher (or enciphered) text.
  32.      The cipher described here differs fundamentally from the
  33. substitution ciphers systems in that it does not rely on replacing one
  34. letter with another.  Instead, it is a transposition cipher that relies on
  35. scrambling the letters of the plain text in a random fashion so that the
  36. enciphered file has the same characteristics as the plain text file.  This
  37. makes it difficult to break because the normal statistical methods use
  38. to break ciphers do not work.  The letter counts, for example, will be
  39. identical in the plain and cipher text files and this means that one
  40. cannot use letter count correlations to guess what letters may have been
  41. substituted for another.
  42.      How does a transposition cipher work?  After all, randomizing the
  43. letters in a file as a means of enciphering is only useful if there is some
  44. way that they can be unscrambled again to their original order.  This is
  45. where one of the otherwise problematic properties of random number
  46. generators is a great virtue.  This property is that as implemented on
  47. modern computers, random number generators always return the same
  48. series of quasi-random numbers if given the same seed value.  To see
  49. how this property can be used in a cipher, consider as an example a
  50. string of fixed length, say one made up of the first five letters of the
  51. alphabet: a, b, c, d, and e.  Now generate five random numbers from a
  52. given seed and number them from 0 to 4.  Now sort the random
  53. numbers but keep the original numbering associated with each number.
  54. These original numbering numbers are now in random order and can be
  55. used as an string or (array) index to randomize the order of letters.  For
  56. example, after sorting the original numbering numbers may be in the
  57. following order (3, 1, 0, 4, 2).  If this string of numbers is placed in an
  58. array r, then encipherment takes place according to the following
  59. formula:
  60.  enciphered_text[i] = original_text[r[i]] (for i = 0 to 4)
  61. Thus the original abcde string is now dbaec in the enciphered_text
  62. string.
  63.      Deciphering the enciphered text is simply the reserve of the
  64. above operation.  Generate the same sequence of random numbers with
  65. the same seed, number them and sort them.  This will result in
  66. obtaining the same (3, 1, 0, 4, 2) sequence as above.  Now apply the
  67. following formula:
  68.  restored_text[r[i]] = enciphered_text[i] (for i = 0 to 4)
  69. The first enciphered_text character is d so for i equal to zero above the
  70. first character will be written into the fourth (base 0 remember)
  71. position in restored_text (r[0] = 3), which is exactly where d should be.
  72.      Listings 1 and 2 provide a simple implementation of this cipher
  73. in ANSI C.  The first listing enciphers a file (but does not change the
  74. file itself) and the second listing deciphers a file.  It can be seen that
  75. there is a great deal of redundancy in the two listings and some may
  76. choose to combine the routines into one file capable of both
  77. encipherment and decipherment.
  78.      There are several things to note about the implementation in the
  79. listings. First, fixed size blocks of size 256 are used so that the program
  80. actually randomizes the content of a file within blocks of 256 characters.
  81. There is no particular reason why this block size was selected and
  82. others, even variable ones based on some algorthim using the key, could
  83. be used.   One factor to bear in mind, however, is that the programs
  84. need to sort to both encrypt and decrypt and the length of the block will
  85. have a significant impact on how long these sorts take.   In general, the
  86. longer the block used, the longer program execution will take but the
  87. more secure the encryption.  Readers may wish to try various block sizes
  88. with various file sizes and determine if there is a general optimal block
  89. size.  Remember though to use the same block sizes for encrypting and
  90. decrypting.
  91.      Second, note that the random number generator used is the
  92. default rand() supplied with most compilers.  Similarly, this generator
  93. is seeded with the standard srand().  Other generators would be used
  94. but note that the int definition for num1 in the structure needs to be
  95. changed to float if a floating point generator is used.  Actually, using
  96. different random generators enhances the security because different
  97. generators produce different sequences so that two files enciphered with
  98. the same key but different generators will be enciphered differently.
  99.      Third, the seed for the random number generator is derived in
  100. the listings by adding the numeric values of the letters in the key to a
  101. predetermined value (1947 in the listings).  This is obviously not a very
  102. original or secure method and those interested in serious
  103. implementations will want to use their creativity here, using a non-
  104. obvious and "hard" method of deriving the seed from the key.
  105.      One possibility is this regard is to use a random number generator
  106. that takes a floating point number as a seed.  By using a creative
  107. method of converting the integer values of the key letters into a floating
  108. point number, the possible seeds becomes effectively infinite and
  109. precludes the possibility of a brute force attempt to find the key.
  110.      Fourth, a routine not implemented in the listings is to waste
  111. some predetermined number of the random numbers before saving
  112. those that will be used in the letter randomization.  This could be done,
  113. for example, by predetermining a fixed number of times to execute a
  114. loop calling the random number sub-routine or by varying this number
  115. for different files based upon the key.
  116.      Finally, note that all files are opened for reading or writing in
  117. binary so that it is possible to encipher text files, executable files (i.e.
  118. .EXE and .COM files) and archive or compressed files.  In fact, by first
  119. compressing a file and then randomizing the content of the resulting
  120. archive significantly increases the security of the encrypted file.
  121.                               /*  LISTING 1
  122.                           ENCRYPTION ROUTINE  */
  123. #include <stdio.h>
  124. #include <stdlib.h>
  125. #include <string.h>
  126.  
  127. #define MAX         512
  128. #define NAME_SIZE   30
  129. #define BLOCK_SIZE  256
  130.  
  131. typedef struct {
  132.           unsigned int num1;
  133.           int num2;
  134.           } rnums;
  135.  
  136. void encrypt(FILE *, FILE *);
  137. void no_memory(void);
  138. int comp(rnums *, rnums *);
  139. void reorder(int, int *);
  140. FILE *open_file(char *, char *);
  141.  
  142. void main()
  143. {
  144.      char *key, *filein, *fileout;
  145.     int i, seed = 1947;
  146.      FILE *fin, *fout;
  147.  
  148.      if ((filein = malloc(NAME_SIZE)) == NULL)
  149.           no_memory();
  150.      if ((fileout = malloc(NAME_SIZE)) == NULL)
  151.           no_memory();
  152.      if ((key = malloc(MAX)) == NULL)
  153.           no_memory();
  154.  
  155.      fprintf(stdout, "\nEnter name of input file: ");
  156.      scanf("%s", filein);
  157.      fprintf(stdout, "\nEnter name for output file: ");
  158.      scanf("%s", fileout);
  159.      fprintf(stdout, "\nEnter encryption key (256 max; ENTER ends): ");
  160.      scanf("%s", key);
  161.  
  162.      fin = open_file(filein, "rb");
  163.      fout = open_file(fileout, "wb");
  164.  
  165.     for (i = 0; i < strlen(key); i++)
  166.         seed += *(key + i);
  167.     srand(seed);
  168.      encrypt(fin, fout);
  169.     fclose(fin);
  170.     fclose(fout);
  171. }
  172. void encrypt(FILE *fin, FILE *fout)
  173. {
  174.      register int i;
  175.      int j, block_length, *source, *rnum;
  176.  
  177.      if ((source = malloc(MAX * sizeof(int))) == NULL)
  178.           no_memory();
  179.      if ((rnum = malloc(MAX * sizeof(int))) == NULL)
  180.           no_memory();
  181.  
  182.      i = 0;
  183.      block_length = BLOCK_SIZE;
  184.      while (!feof(fin)) {
  185.         if ((*(source + i) = fgetc(fin)) != EOF) {
  186.                 if (++i == block_length) {
  187.                      i = 0;
  188.                      reorder(block_length, rnum);
  189.                      for (j = 0; j < block_length; j++)
  190.                          putc(*(source + *(rnum + j)), fout);
  191.                 }
  192.           }
  193.           else {
  194.                 reorder(i, rnum);
  195.                 for (j = 0; j < i; j++)
  196.                      putc(*(source + *(rnum + j)), fout);
  197.           }
  198.      }
  199. }
  200. void reorder(int n, int *num)
  201. {
  202.      int i;
  203.      rnums rand_struct[MAX];
  204.  
  205.      for (i = 0; i < n; i++) {
  206.         rand_struct[i].num1 = rand();
  207.           rand_struct[i].num2 = i;
  208.      }
  209.      qsort(rand_struct, n, sizeof(rnums), comp);
  210.      for (i = 0; i < MAX; i++)
  211.           *(num + i) = rand_struct[i].num2;
  212.  
  213. }
  214. int comp(rnums *e1, rnums *e2)
  215. {
  216.      if ((e1->num1 - e2->num1)> 0)
  217.           return 1;
  218.      else if ((e1->num1 - e2->num1) < 0)
  219.           return -1;
  220.      else
  221.           return 0;
  222. }
  223. FILE *open_file(char *name, char *type)
  224. {
  225.      FILE *fp;
  226.  
  227.      if ((fp = fopen(name, type)) == NULL) {
  228.           fprintf(stdout, "\ncannot open %s\n", name);
  229.           exit(1);
  230.      }
  231.      return fp;
  232. }
  233. void no_memory(void)
  234. {
  235.      puts("\nCannot allocate memory -- Aborting\n");
  236.      exit(1);
  237. }
  238.                               /* LISTING 2
  239.                           DECRYPTION ROUTINE  */
  240.  
  241. #include <stdio.h>
  242. #include <stdlib.h>
  243. #include <string.h>
  244.  
  245. #define MAX         512
  246. #define NAME_SIZE   30          /* In case anyone has a long path */
  247. #define BLOCK_SIZE  256
  248.  
  249. typedef struct {
  250.           unsigned int num1;
  251.           int num2;
  252.           } rnums;
  253.  
  254. void decrypt(FILE *, FILE *);
  255. void plant_seed(char *);
  256. void no_memory(void);
  257. int comp(rnums *, rnums *);
  258. void reorder(int, int *);
  259. FILE *open_file(char *, char *);
  260.  
  261. void main()
  262. {
  263.      char *key, *filein, *fileout;
  264.     int i, seed = 1947;
  265.      FILE *fin, *fout;
  266.  
  267.      if ((filein = malloc(NAME_SIZE)) == NULL)
  268.           no_memory();
  269.      if ((fileout = malloc(NAME_SIZE)) == NULL)
  270.           no_memory();
  271.      if ((key = malloc(MAX)) == NULL)
  272.           no_memory();
  273.  
  274.      fprintf(stdout, "\nEnter name of input file: ");
  275.      scanf("%s", filein);
  276.      fprintf(stdout, "\nEnter name for output file: ");
  277.      scanf("%s", fileout);
  278.      fprintf(stdout, "\nEnter encryption key (256 max; ENTER ends): ");
  279.      scanf("%s", key);
  280.  
  281.      fin = open_file(filein, "rb");
  282.      fout = open_file(fileout, "wb");
  283.  
  284.     for (i = 0; i < strlen(key); i++)
  285.         seed += *(key + i);
  286.     srand(seed);
  287.     decrypt(fin, fout);
  288.     fclose(fin);
  289.     fclose(fout);
  290. }
  291. void decrypt(FILE *fin, FILE *fout)
  292. {
  293.      register int i;
  294.      int j, block_length, *source, *destination, *rnum;
  295.  
  296.      if ((source = malloc(MAX * sizeof(int))) == NULL)
  297.           no_memory();
  298.      if ((destination = malloc(MAX * sizeof(int))) == NULL)
  299.           no_memory();
  300.      if ((rnum = malloc(MAX * sizeof(int))) == NULL)
  301.           no_memory();
  302.  
  303.      i = 0;
  304.      block_length = BLOCK_SIZE;
  305.      while (!feof(fin)) {
  306.         if ((*(source + i) = fgetc(fin)) != EOF) {
  307.                 if (++i == block_length) {
  308.                      i = 0;
  309.                      reorder(block_length, rnum);
  310.                      for (j = 0; j < block_length; j++)
  311.                           *(destination + *(rnum + j)) = *(source + j);
  312.                      for (j = 0; j < block_length; j++)
  313.                           putc(*(destination + j), fout);
  314.                 }
  315.           }
  316.           else {
  317.               reorder(i, rnum);
  318.               for (j = 0; j < i; j++)
  319.                 *(destination + *(rnum + j)) = *(source + j);
  320.               for (j = 0; j < i; j++)
  321.                 putc(*(destination + j), fout);
  322.           }
  323.      }
  324. }
  325. void reorder(int n, int *num)
  326. {
  327.      int i;
  328.         rnums rand_struct[MAX];
  329.  
  330.      for (i = 0; i < n; i++) {
  331.         rand_struct[i].num1 = rand();
  332.           rand_struct[i].num2 = i;
  333.      }
  334.      qsort(rand_struct, n, sizeof(rnums), comp);
  335.      for (i = 0; i < MAX; i++)
  336.           *(num + i) = rand_struct[i].num2;
  337.  
  338. }
  339. int comp(rnums *e1, rnums *e2)
  340. {
  341.      if ((e1->num1 - e2->num1)> 0)
  342.           return 1;
  343.      else if ((e1->num1 - e2->num1) < 0)
  344.           return -1;
  345.      else
  346.           return 0;
  347. }
  348. FILE *open_file(char *name, char *type)
  349. {
  350.      FILE *fp;
  351.  
  352.      if ((fp = fopen(name, type)) == NULL) {
  353.           fprintf(stdout, "\ncannot open %s\n", name);
  354.           exit(1);
  355.      }
  356.      return fp;
  357. }
  358. void no_memory(void)
  359. {
  360.      puts("\nCannot allocate memory -- Aborting\n");
  361.      exit(1);
  362. }
  363.