home *** CD-ROM | disk | FTP | other *** search
/ PCMania 10 / Pcmania_Ep2_10_CD-01.iso / ARTICULOS / tecnologia / DLOCK2.ZIP / THESIS.TXT < prev   
Encoding:
Text File  |  1988-11-07  |  153.3 KB  |  5,185 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7. BEYOND DES:
  8.  
  9. DATA COMPRESSION AND THE MPJ ENCRYPTION ALGORITHM
  10.  
  11. by
  12.  
  13. Michael Paul Johnson
  14.  
  15. B. S., University of Colorado at Boulder, 1980
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25. A thesis submitted to the
  26.  
  27. Faculty of the Graduate School of the
  28.  
  29. University of Colorado in partial fulfillment
  30.  
  31. of the requirements for the degree of
  32.  
  33. Master of Science
  34.  
  35. Department of Electrical Engineering
  36.  
  37. 1989
  38.  
  39. Copyright (C) 1989 Michael Paul Johnson.
  40.  
  41. All Rights Reserved.
  42.  
  43. This thesis for the Master of Science degree by
  44.  
  45. Michael Paul Johnson
  46.  
  47. has been approved for the
  48.  
  49. Department of
  50.  
  51. Electrical Engineering
  52.  
  53. by
  54.  
  55.  
  56.  
  57.  
  58. Mark A. Wickert
  59.  
  60.  
  61.  
  62.  
  63. Charles E. Fosha, Jr.
  64.  
  65.  
  66.  
  67.  
  68. Rodger E. Ziemer
  69.  
  70.  
  71.  
  72. Date                                   
  73.  
  74. Johnson, Michael Paul (M. S., Electrical Engineering)
  75.  
  76. Beyond DES:  Data Compression and the MPJ Encryption Algorithm
  77.  
  78.  
  79. Thesis directed by Assistant Professor Mark A. Wickert
  80.  
  81. Many encryption algorithms have come and gone as cryptography, cryptanalysis, 
  82. and technology have progressed.  Today's communication and computer 
  83. technologies need cryptography to truly secure data in many applications. 
  84. The demands on the cryptography needed for some commercial applications 
  85. will exceed the security offered by the National Bureau of Standards 
  86. Data Encryption Standard (DES) in the near future due to advances 
  87. in technology, advances in cryptanalysis, and the increasing rewards 
  88. for breaking such a heavily used algorithm.  To meet part of this 
  89. need, a new block encryption algorithm is proposed.  A Pascal program 
  90. to implement this algorithm is given.
  91.  
  92. One way to further increase security of encrypted data, as well as 
  93. to achieve storage and/or transmission economy, is by redundancy reduction 
  94. prior to encryption.  A linguistic approach to redundancy reduction, 
  95. together with an example computer program to implement it, is given 
  96. for this purpose.
  97.  
  98. LIST OF FIGURES    viii
  99.  
  100. I.    INTRODUCTION    1
  101.  
  102. A.  Motivation    2
  103.  
  104. B.  Approach    4
  105.  
  106. II.    HISTORY OF CRYPTOGRAPHY    6
  107.  
  108. III.    ELEMENTS OF ENCRYPTION    8
  109.  
  110. A.  Substitution    8
  111.  
  112. 1.  Monoalphabetic    8
  113.  
  114. 2.  Polyalphabetic    10
  115.  
  116. B.  Permutation    11
  117.  
  118. C.  Noise Addition    12
  119.  
  120. D.  Feedback & Chaining    13
  121.  
  122. 1.  Plain Text Feedback    13
  123.  
  124. 2.  Cipher Text Feedback    14
  125.  
  126. E.  Analog Encryption    15
  127.  
  128. IV.    FACTORS RELATED TO ENCRYPTION    17
  129.  
  130. A.  Change of Language    17
  131.  
  132. B.  Digitization    18
  133.  
  134. C.  Compression    18
  135.  
  136. D.  Multiplexing    19
  137.  
  138. V.    COMPARISON OF SELECTED ALGORITHMS    20
  139.  
  140. A.  One-Time Key Tape    20
  141.  
  142. B.  Linear Shift Register Feedback    21
  143.  
  144. C.  Exponential Encryption    22
  145.  
  146. D.  Knapsack    24
  147.  
  148. E.  Rotor Machines    24
  149.  
  150. F.  Codes    27
  151.  
  152. G.  Galois Field and Hill Cryptosystems    28
  153.  
  154. H.  DES    30
  155.  
  156. VI.    DESIGN CONSIDERATIONS FOR MPJ    33
  157.  
  158. A.  Strength Based on Key    33
  159.  
  160. B.  Usability of Random Keys    33
  161.  
  162. C.  Key Length & Block Size    34
  163.  
  164. D.  Effort Required to Break    34
  165.  
  166. E.  Computational Efficiency    35
  167.  
  168. F.  Communication Channel Efficiency    36
  169.  
  170. G.  No Back Doors or Spare Keys    36
  171.  
  172. VII.    MPJ ENCRYPTION ALGORITHM    37
  173.  
  174. A.  Description    37
  175.  
  176. 1.  Overall Structure of MPJ    37
  177.  
  178. 2.  Substitution Boxes    39
  179.  
  180. 3.  Wire Crossings    39
  181.  
  182. 4.  Key Generation    40
  183.  
  184. B.  Implementation in Pascal    44
  185.  
  186. 1.  Exceptions from Standard Pascal    44
  187.  
  188. 2.  Main Program    45
  189.  
  190. 3.  Procedures Encrypt & Decrypt    46
  191.  
  192. 4.  Procedures Permute & Ipermute    47
  193.  
  194. 5.  Procedures Substitute & Isubst    47
  195.  
  196. C.  Implementation in Hardware    47
  197.  
  198. D.  Strengths & Weaknesses    48
  199.  
  200. VIII.    DATA COMPRESSION    50
  201.  
  202. A.  Purpose    50
  203.  
  204. B.  Linguistic Parsing    53
  205.  
  206. C.  Huffman Coding    55
  207.  
  208. D.  Pascal Programs    55
  209.  
  210. IX.    CONCLUSION    58
  211.  
  212. REFERENCES    59
  213.  
  214. APPENDIX
  215.  
  216. A.    MPJ in Pascal    64
  217.  
  218. B.    Linguistic Data Compression Programs    72
  219.  
  220. FIGURE
  221.  
  222. III.B    Permutation.    11
  223.  
  224. III.C.    Noise Addition    12
  225.  
  226. III.D.    Block Cipher Modes.    14
  227.  
  228. III.E.    Analog Time & Frequency Encryption    15
  229.  
  230. V.A.    One-time key tape (AKA One-time pad)    21
  231.  
  232. V.A.1    Typex Rotor Machine    25
  233.  
  234. V.E.2.    Wired Rotors    25
  235.  
  236. V.H.1.    DES Enciphering    30
  237.  
  238. V.H.2.    DES Nonlinear Function    30
  239.  
  240. V.H.3.    DES Internal Key Generation    31
  241.  
  242. VII.A.1.    Overall Structure of MPJ    38
  243.  
  244. VII.A.3.    Wire Crossings    39
  245.  
  246. I.   INTRODUCTION
  247.  
  248. The increasing proliferation of digital communication and computer 
  249. data base storage has brought with it increasing difficulty of maintaining 
  250. the privacy of that data.  There is only one effective way to protect 
  251. the privacy of communications sent over such channels as satellites, 
  252. terrestrial microwave, and cellular telephones.  This is by encryption.  It 
  253. is clearly impossible to deny unauthorized access by a determined 
  254. and knowledgeable interceptor to the communications, but it is possible 
  255. to render the communications totally unintelligible to all but the 
  256. intended receiver(s).
  257.  
  258. There are many ways to reversibly transform data from its plain form 
  259. to something that looks unintelligible, but many of these can be figured 
  260. out (broken) by someone else.  The study of how to hide secrets is 
  261. cryptology. Trying to figure out the secrets that someone else has 
  262. hidden is cryptanalysis.  These two sciences are, of course, very 
  263. much intertwined. History reveals many examples of cryptology that 
  264. worked, and that didn't [KAH]. Successful cryptanalysis depends on 
  265. taking advantage of as many of the following as are available to the 
  266. cryptanalyst: (1) taking advantage of the redundancy in any natural 
  267. language to determine the validity of assumptions, (2) clues gained 
  268. from corresponding plain and cipher text, (3) information that might 
  269. be known about the algorithm(s) used, (4) the general expected content 
  270. of the cryptograms, (5) all of the cipher text that is available in 
  271. the same system & key, (6) compromised keys, (7) as much computational 
  272. and analytical power as can be obtained, and (8) mistakes made in 
  273. the users of the cryptographic system.  The cryptographer can make 
  274. life as difficult as possible for the cryptanalyst by depriving him 
  275. of some of these things by (1) using redundancy reduction before encryption, 
  276. (2) using an algorithm that is resistant to the known plain text attack, 
  277. (3) & (4) using a strong enough algorithm that these clues aren't 
  278. really useful, (5) changing keys often and selecting them properly, 
  279. (6) guarding keys as closely as the data they protect justifies, (7) 
  280. ensuring that there aren't enough computers in the world to do a brute 
  281. force attack on the algorithm, and (8) making sure users of the system 
  282. understand how to properly use it.
  283.  
  284. This thesis proposes one solution to the above challenge by proposing 
  285. (1) an approach to linguistically based redundancy reduction, and 
  286. (2) proposing a new data encryption algorithm (MPJ) that can be used 
  287. where DES is in use now, but is more secure.
  288.  
  289. A.  Motivation
  290.  
  291. There has been a great deal of discussion of the security of DES in 
  292. the open literature.  Most of it has been favorable to DES [MEY], 
  293. but there are a few indications that it would be wise to supplement 
  294. the aging DES and eventually replace it.
  295.  
  296. DES has been in use since 1977, and has been used in a large number 
  297. of applications where people have had many possible motivations for 
  298. trying to break this cipher.  During this time, it is possible that 
  299. someone has discovered a computationally feasible method for doing 
  300. so [KRU].  Under such circumstances, it is highly unlikely that such 
  301. a discovery would be made known.  There is no way to really know this 
  302. for sure, unless you are one of the ones who has broken DES.  The 
  303. closest thing that I have found to an open admission of breaking DES 
  304. is a story of the FBI successfully decrypting a file of drug transaction 
  305. records that were encrypted on a PC using a DES board. [MCL] The DES 
  306. board that the criminal used has an algorithm to generate a key from 
  307. a word or phrase.  By an exhaustive search of an English dictionary 
  308. and key names from the criminal's family & friends using a supercomputer, 
  309. the file was solved.  This indicates some weakness in DES, but even 
  310. more weakness in the way the key was chosen. The key was not chosen 
  311. randomly, so the FBI's job was much easier.
  312.  
  313. DES is subject to attacks that require precomputation that could tie 
  314. up a supercomputer for a few years, after which it would take only 
  315. a few days to solve a DES cryptogram.  This is becoming less of a 
  316. barrier as the price of computers drops and the speed and storage 
  317. capacity of computers increase.
  318.  
  319. The U. S. National Security Agency (NSA) is acting to release some  of  its 
  320. own algorithms for ``sensitive but unclassified'' applications, such 
  321. as communications between government contractors.  The NSA also releases 
  322. some classified algorithms to chip manufacturers for use in classified 
  323. devices, but under strict controls [ULT].  This will take some of 
  324. the load off of the DES algorithm, but there is a catch.  They intend 
  325. to keep the algorithms secret and control the keys.  Since the security 
  326. of the algorithm is dependent on the key in a way that only  the NSA  knows, 
  327. this gives the NSA the exclusive ability to read everybody's' communications.  That 
  328. is not all bad, as it discourages the use of one of those systems 
  329. by someone engaged in spying or other illegal activity.  Unfortunately, 
  330. these systems are not an option for protection of a corporations proprietary 
  331. data that may have a great deal to do  with profits and  losses, but 
  332. are not really in the domain of the NSA.
  333.  
  334. There are other alternatives to DES now, but none of them in the public 
  335. domain are even as good, let alone better, for general cryptography.  For 
  336. example, RSA encryption has great advantages in the authentication 
  337. of digital signatures, but the complications of selecting good keys 
  338. and the fact that the security of RSA relies heavily on the failure 
  339. of the state of the art in mathematics to progress makes it at least 
  340. inconvenient to use and at most insecure.
  341.  
  342. Because of the above considerations, it is my intentions to suggest 
  343. a better algorithm (MPJ) for general use in the private sector.  Although 
  344. the MPJ algorithm might be useful for government applications, too, 
  345. the design requirements for the two areas of application vary [CHA] 
  346. and the latter is kept shrouded in secrecy, so we shall leave it to 
  347. the NSA.
  348.  
  349. B.  Approach
  350.  
  351. First, the problem is defined.  As explained in the above section, 
  352. the basic problem is to create an algorithm to supplement DES.  Design 
  353. criteria are then conceived such that an algorithm that meets those 
  354. criteria will solve the problem as defined.  The design criteria chosen 
  355. for the MPJ algorithm are discussed in chapter VI.  To avoid repetition 
  356. of one or more of the many mistakes that have been made throughout 
  357. history with cryptography, it is, of course, necessary to research 
  358. what was done in the past, both distant and recent.  From this, many 
  359. good ideas can be gleaned that apply to the problem at hand.  These 
  360. ideas, along with a knowledge of current technology are then applied 
  361. to design criteria with a bit of creativity and a lot of hard work 
  362. to define the new algorithm.
  363.  
  364. In the process of doing all of the above, it became apparent that 
  365. the security of encrypted data was vastly improved by first removing 
  366. as much redundancy from the data as possible.  Therefore, as sort 
  367. of a bonus, a linguistic approach to data compression is also presented 
  368. that can either be used in conjunction with the MPJ encryption algorithm, 
  369. another encryption method, or just by itself for the savings that 
  370. it gains in communications channel capacity and/or data storage space.
  371.  
  372. II.       HISTORY OF CRYPTOGRAPHY
  373.  
  374. One of the best works on the history of cryptography is <MI>The Codebreakers, 
  375. by David Kahn [KAH].  In that book, David Kahn discusses cryptography 
  376. from the prehistory to World War II.  The first codes and ciphers 
  377. were in written form, and used to protect the privacy of communications 
  378. sent by courier or mail through hostile or unknown territory.  Some 
  379. of these were reasonably good, but most were not difficult to break 
  380. using manual methods, provided that the interceptor had sufficient 
  381. cipher text and perhaps some probable text.  The use of radio, especially 
  382. by the military, increased the need for cryptography, as well as increasing 
  383. the rewards for those who could break the encryption schemes in use.  Kahn's 
  384. documentation of the efforts of those who broke some very complex 
  385. encryption schemes, like the German Enigma and the Japanese Purple 
  386. ciphers, lend great insight to the kind of process cryptanalysis really 
  387. is.
  388.  
  389. Kahn points out the kinds of mistakes the inventors and users of cryptographic 
  390. algorithms tend to make that reduce the security of their communications.  For 
  391. example, German users of Enigma tended to choose a three-letter indicator 
  392. for their messages that consisted of three consecutive letters on 
  393. the keyboard.  This substantially reduced the number of keys that 
  394. had to be searched to determine the one that they were using.  While 
  395. the designer of an algorithm may calculate the great number of combinations 
  396. of keys that there are, the cryptanalyst looks at ways to isolate 
  397. parts of the key so that the difficulty of a solution is much less 
  398. than the size of the key space indicates.  The difference in mind 
  399. set between the concealer of secrets and the one who prys into them 
  400. has caused many an inventor of an encryption algorithm to be overconfident.
  401.  
  402. The job of the cryptanalyst is a tedious one.  He tries all kinds 
  403. of things to try to unscramble the cipher text in front of him.  Sometimes 
  404. the search is fruitless.  Sometimes the search yields something that 
  405. looks like a meaningful language.  It is this ability to recognize 
  406. a meaningful message when it comes out of the various operations that 
  407. the cryptanalyst tries that makes the whole process possible.  It 
  408. is also helpful for the cryptanalyst to know some probable plain text 
  409. that is contained in a message.  This is almost always the case.  For 
  410. example, military messages even now have a very stereotyped format, 
  411. with the from, to, and date indicators in the same places in the message. 
  412. The cryptanalyst almost always knows what language to expect a message 
  413. to be written in, and this is a great help.  Natural languages contain 
  414. a great deal of redundancy.  A message that is only 90% recovered 
  415. is usually readable.  Natural languages also have very consistent 
  416. statistical properties that are very useful in cryptanalysis, especially 
  417. when the cryptanalysis is automated.  The only time that these things 
  418. don't help the cryptanalyst is in the ``one-time pad.''
  419.  
  420. III.      ELEMENTS OF ENCRYPTION
  421.  
  422. Several basic elements make up the basis of a multitude of possible 
  423. encryption algorithms, either alone or in combination [BEK][BAL].  Although 
  424. most of these elements may be used to form the basis of an encryption 
  425. method all by itself, the most secure methods of encryption will several 
  426. of them.  For example, substitution and permutation are basic elements 
  427. of both DES and MPJ encryption algorithms.  These algorithms, in turn, 
  428. are best used with some form of feedback.
  429.  
  430. A.  Substitution
  431.  
  432. A substitution cipher simply substitutes one symbol from the plain 
  433. text alphabet for another one from a cipher text alphabet.  The plain 
  434. text alphabet can be a natural language alphabet, ASCII, EBCDIC, Baudot, 
  435. the set {0,1}, or any other finite set.  Cipher text alphabets, likewise, 
  436. may be any finite set.  To be able to easily apply computer methods 
  437. to the manipulation of these alphabets, it is preferable to use alphabets 
  438. that are groups of binary digits (bits).  This is not a severe limitation, 
  439. since a correspondence can be set up between any finite set and a 
  440. set of binary numbers.
  441.  
  442. 1.  Monoalphabetic
  443.  
  444. A monoalphabetic substitution cipher is one in which each letter of 
  445. the plain text alphabet is always substituted for by the same cipher 
  446. text alphabet. The cipher text alphabet need not be in any particular 
  447. order.  A subset of the monoalphabetic substitution cipher is the 
  448. Caesar cipher.  This cipher replaces each letter with a letter that 
  449. is n letters later in the alphabet.  This cipher is so named because 
  450. it was reportedly first used by Caesar. [KAH]  With only 26 possible 
  451. keys, this is obviously not very secure.  In fact, any substitution 
  452. cipher that substitutes one letter for another is vulnerable to solution 
  453. by frequency analysis, and can be solved, given enough cipher text 
  454. with the same key.  How much cipher text is enough depends on the 
  455. nature of the plain text, but for plain English, as many characters 
  456. as there are letters in the alphabet is sufficient for the probabilities 
  457. of occurrences of letters to betray enough letter identities to make 
  458. solution probable.  While ciphers of this type no longer have any 
  459. value for serious cryptography, they do make fun puzzles for elementary 
  460. school children.  For example, the following cryptogram is presented 
  461. for your solution:
  462.  
  463. UIJT JT B DBFTBS TVCTUJUVUO DJQIFS/  XPVME ZPV USVTU VPVS TFDSFST 
  464. UP JU@
  465.  
  466. Substitution ciphers can be made more secure by operating on substitutions 
  467. of more than one letter at a time.  For example, the substitution 
  468. could be made on digraphs or trigraphs (groups of two or three letters).  A 
  469. more practical example is the Data Encryption Standard.  DES is actually 
  470. a substitution cipher with an effective alphabet size of 2^64, 
  471. or about 1.84 x 10^19, and the MPJ Encryption Algorithm is a 
  472. substitution cipher with an effective alphabet size of 2^128 
  473. or about 3.4 x 10^38.   Not only is it difficult to get that 
  474. large of a sample to analyze for statistics, but the memory required 
  475. to store the substitution table is impractical even for computer systems 
  476. using large optical storage disks.
  477.  
  478. 2.  Polyalphabetic
  479.  
  480. A polyalphabetic substitution cipher is one in which each letter of 
  481. the plain text alphabet may be replaced a letter from one of many 
  482. cipher alphabets. The selection of which alphabet to take the substitution 
  483. from may be determined in many ways.  The most usual method is by 
  484. selecting the cipher alphabet by a combination of a message indicator 
  485. and the number of characters from the beginning of the message.  The 
  486. classic example of this type of cipher is the rotor-based machine.  The 
  487. substitution occurs by physical wire crossings within rotors.  After 
  488. each character is enciphered, one or more rotors are rotated by a 
  489. ratchet mechanism.  The message indicator, which is part of the key, 
  490. determines the starting position of the rotors.  This effectively 
  491. allows the use of more cipher alphabets than there are letters in 
  492. the message.  Because of this, the use of statistical analysis on 
  493. any one message to guess at the substitutions is useless.  There is, 
  494. however a good way to attack this kind of cipher when it is used heavily. 
  495. This is by analyzing the statistics of the first character in each 
  496. message, then the second, etc.  This is called analyzing the messages 
  497. ``in depth.''
  498.  
  499. Although the rotor-based polyalphabetic ciphers used by Germany and 
  500. Japan in World War II contributed greatly to their losses because 
  501. their messages were read regularly by the allies, it is possible to 
  502. create a more secure polyalphabetic substitution with computer technology. 
  503. The primary weakness of the mechanical rotor machines was the infrequent 
  504. changing of many of the parts of the key such as rotor wiring and 
  505. ratchet construction.  A more general method of using a different 
  506. set of alphabets for each message would be very secure.  Unfortunately, 
  507. it would result in keys larger than the message.  Since the minimum 
  508. key length for absolute, provable cryptographic security, as determined 
  509. by C. E. Shannon [SHA], is exactly the length of the message, this 
  510. solution is not very efficient with respect to key management.
  511.  
  512. B.  Permutation
  513.  
  514. Permutation is taking the same symbols and writing them in a different 
  515. order to confuse an interceptor.  There are many ways of doing this 
  516. geometrically. For example, words may be written vertically then transcribed 
  517. horizontally, or they may be written on a strip of paper wrapped along 
  518. the length of a rod of a given diameter, then unwrapped for delivery.
  519.  
  520. In general, a permutation operation may be considered as an operation 
  521. on a block of symbols, where each symbol's position is changed to 
  522. another position within the block according to some rule.  The blocks 
  523. may overlap each other if the permutation is undone from the end of 
  524. the message to the beginning.
  525.  
  526. The rule(s) determining how the permutation is done may be fixed, 
  527. or they may depend in some way on a key.  Although historical permutation 
  528. ciphers tended to be rather simple, computer methods allow them to 
  529. be potentially rather complex, especially if the symbols that are 
  530. scrambled are individual bits.
  531.  
  532. Permutation, when used in combination with substitution, is very useful 
  533. in further increasing the complexity of a cipher, since the two algorithms 
  534. act in different ways to baffle the interceptor.  This is significant, 
  535. since it is not possible to actually increase the security of a substitution 
  536. cipher by simply repeating the same thing with a different key.  The 
  537. result in such a case would be another substitution cipher with the 
  538. same complexity.
  539.  
  540. C.  Noise Addition
  541.  
  542. Noise addition can either be a way of enhancing another encryption 
  543. scheme, or of hiding the very existence of a message.  For example, 
  544. a grid can be set up on a piece of paper where only certain positions 
  545. are significant.  These positions are then concatenated together to 
  546. reveal the secret message.  The rest of the paper is then filled with 
  547. something that uses those characters, but contains something different, 
  548. like a letter to someone's mother.  The same thing can be done electronically, 
  549. by defining a block of bits with only part of the bits significant.  The 
  550. rest of the bits are then filled with truly random noise, like the 
  551. output of a Geiger counter.  This method can be very effective, especially 
  552. if the position of the information-bearing bits vary from block to 
  553. block in a pseudorandom manner, and if there is a relatively large 
  554. proportion of truly random noise.  The obvious disadvantage to this 
  555. kind of scheme is that it makes very poor use of communications channels 
  556. and data storage facilities.
  557.  
  558. One useful variation on the noise addition method is to multiplex 
  559. several encrypted streams of data (encrypted with another method) 
  560. together with some pseudorandom interleaving.  Since the other encrypted 
  561. streams of data act like the random noise added to any one stream 
  562. of data, this is a good way to improve security when a large volume 
  563. of encrypted data must be sent through the same channel.
  564.  
  565. D.  Feedback & Chaining
  566.  
  567. A block cipher like DES or MPJ, when applied directly to an input 
  568. file with a highly repetitive structure (i. e., lots of spaces between 
  569. columns) will also display some of that structure.  Although it may 
  570. not be possible to determine the exact contents of what has been encrypted, 
  571. it may be rather easy to determine something about the nature of what 
  572. has been encrypted.  To deny the interceptor even this information, 
  573. and to further increase the complexity of the encrypted information, 
  574. feedback and chaining may be used.  Chaining refers to making the 
  575. results of the encryption of one block dependent on previous results.  This 
  576. is usually done in one of two ways.  One is by adding the plain text 
  577. from the last block to the cipher text of this block, modulo two.  The 
  578. other is by adding the cipher text from the preceding block to the 
  579. cipher text of the current block, modulo two.  These are referred 
  580. to as plain text feedback and cipher text feedback, respectively.
  581.  
  582. 1.  Plain Text Feedback
  583.  
  584. Plain text feedback has the property that any errors in transmission 
  585. get propagated clear through the rest of the message.  This may be 
  586. a desirable property if it is necessary to detect any tampering with 
  587. the message, but it makes it difficult to use real (error-prone) channels.  If 
  588. it is necessary to have the property of error propagation to detect 
  589. tampering and to use real channels, then the message should be transmitted 
  590. using an error detection and correction protocol of some sort.
  591.  
  592. 2.  Cipher Text Feedback
  593.  
  594. Cipher text feedback also causes some error propagation, but not clear 
  595. through to the end of a message.  An error in one block will cause 
  596. an error in that block in the bit positions where the error occurred 
  597. and in all of the next block, but the receiving station can recover 
  598. all subsequent error-free blocks.  This method is a good compromise 
  599. between security and error recovery.  It is still desirable to wrap 
  600. encrypted data in an error detection and correction protocol to avoid 
  601. having a one bit error wipe out many bits.
  602.  
  603. E.  Analog Encryption
  604.  
  605. There are several methods of analog encryption.  None of them are 
  606. as secure as digital methods can be.  Analog encryption is generally 
  607. based on spectrum inversion, spectrum scrambling, time slice scrambling, 
  608. and (for video signals) suppression of synchronization information.  These 
  609. elements are also used in combination [LOD].  These methods are commonly 
  610. used by cable TV companies (and sometimes on satellite channels) to 
  611. ensure that people only get the programming that they have paid for.  Articles 
  612. on how to build devices to defeat some of these things appear periodically 
  613. in electronic hobbyist magazines.
  614.  
  615. The state of the art in current use for protection of satellite TV 
  616. signals is the General Instruments Video Cipher II.  This device used 
  617. digital (DES) encryption of the audio information and a partially 
  618. analog encryption of the video signal.  This device is a deterrent 
  619. to those who receive satellite TV without paying a cable TV operator, 
  620. but it has been broken by a hacker who figured out that it was possible 
  621. to modify the microcode in the device so that a key purchased for 
  622. one machine would work on all of them with modified code.  This is, 
  623. of course, illegal, but it allows one person to pay for a service 
  624. and many people to use it for free [DOH].  The problem here is not 
  625. one of the encryption algorithm, but in the key management.
  626.  
  627. IV.       FACTORS RELATED TO ENCRYPTION
  628.  
  629. A.  Change of Language
  630.  
  631. Although it is not really encryption, the use of a different language 
  632. from what the interceptor is likely to know does increase the difficulty 
  633. of cryptanalysis.  For example, I know that it would be far more difficult 
  634. for me to solve even a simple Caesar substitution cipher in Chinese 
  635. than in English, Spanish, or German.  This principal was used effectively 
  636. by the United States against Japan in World War II by using the Navajo 
  637. language for spoken radio communications [KAH].  Since the Navajo 
  638. language had no written form, and was only spoken by a small group 
  639. of Native Americans, there were no Japanese who knew the language.  The 
  640. Japanese never did figure that ``code'' out.  Thus, the Navajo ``Code 
  641. Talkers'' made a great contribution to their country.
  642.  
  643. Part of the reason for the success of the Navajo Code Talkers was 
  644. that the Japanese had no idea what was going on.  Since this success 
  645. is now well known, it is difficult to determine the potential success 
  646. of a repeat of this kind of approach.  There are still some languages 
  647. that are spoken only by a very few people in the world, some of which 
  648. have no written form.  These could be used to increase the effective 
  649. ``key space.''
  650.  
  651. Although a change of language was a great victory for the Navajo People 
  652. and the United States of America during World War II, it is difficult 
  653. to adapt this success to computerized communication methods.
  654.  
  655. B.  Digitization
  656.  
  657. The very act of digitizing an audio or video signal provides some 
  658. protection from the casual eavesdropper.  Although this provides no 
  659. protection against a determined snooper, it is an appropriate level 
  660. of additional security for protecting the privacy of things like mobile 
  661. telephone conversations.  Of course, once an analog signal is digitized, 
  662. there is a wide range of digital encryption methods available.  Of 
  663. course, some methods would be overkill, since the same communication 
  664. would probably be transmitted in the clear over wire and/or microwave 
  665. channels as well as by radio between the car and the stationary cellular 
  666. transceiver.
  667.  
  668. Although there has been some ill-conceived efforts by the mobile telephone 
  669. industry to legislate privacy for such applications by saying that 
  670. it is illegal to listen to someone else's phone calls around 800 MHz 
  671. (where cellular phones usually operate), this kind of thing is unenforceable. 
  672. Worse yet, such legislation provides a false sense of security in 
  673. a world where scanners and other receivers that operate in that range 
  674. are readily available.
  675.  
  676. C.  Compression
  677.  
  678. Data compression itself tends to obscure things by taking, for example, 
  679. and ASCII text file in English and reducing it to a binary file that 
  680. is not as easy to read.  There is a more important effect of data 
  681. compression, however. The removal of the natural redundancy of the 
  682. plain text data before encrypting it with some kind of encryption 
  683. algorithm makes it much more difficult to cryptanalyze the cipher 
  684. text.  In the extreme case where all of the redundancy of a message 
  685. is removed, all messages of a given length would be meaningful, and 
  686. it would be impossible for the cryptanalyst to determine which one 
  687. was intended.
  688.  
  689. D.  Multiplexing
  690.  
  691. Multiplexed signals are less readable to the casual observer, but 
  692. standard multiplexing offers no real increase in cryptographic strength.  It 
  693. can, however, increase the strength of multiple streams of encrypted 
  694. data when the multiplexing is done with a pseudorandom interleave 
  695. (as discussed above under noise addition).   This makes the multiplexing 
  696. and demultiplexing processes more complex with respect to synchronization 
  697. and timing, and is likely to introduce more delay into the system 
  698. than more straight forward multiplexing arrangements.
  699.  
  700. V.   COMPARISON OF SELECTED ALGORITHMS
  701.  
  702. A.  One-Time Key Tape
  703.  
  704. The one-time key tape, also called the one-time pad, has a tremendous 
  705. advantage.  It is the only commonly used encryption method that is 
  706. provably secure.  Proving the security of most other systems generally 
  707. reduces to an impossible negative proof <197> an attempt to prove 
  708. the lack of a method to defeat it.
  709.  
  710. The way the one-time key tape works is to add each character of the 
  711. message to a character of the key modulo the alphabet size.  When 
  712. working with any binary stream of data, this is easy to implement 
  713. by exclusive-oring the input stream with the key stream.  At the receiving 
  714. end, the same thing is done to decrypt the data.  Since P + K + K 
  715. = P (modulo 2), the original stream is recovered.
  716.  
  717. As implied by the name, it is important that each key be used only 
  718. once.  If it were used more than once, then the system would be vulnerable 
  719. to attack with the known cipher text and corresponding plain text 
  720. attack.  The key is obtained from the boolean identity:  K = (P + 
  721. K) + P, where K is the key, P is the plain text, P + K is the cipher 
  722. text, and all additions are modulo the alphabet size (usually 2).  The 
  723. key thus recovered would then be used to decipher the next message 
  724. that used it.
  725.  
  726. According to C. E. Shannon [SHA], for a cipher to be provably secure, 
  727. the number of keys must be as great as the number of potential messages.  The 
  728. number of keys he refers to, of course, is the number of keys that 
  729. yields a distinctly different transformation of the message text into 
  730. cipher text.
  731.  
  732. This method of encryption is provably secure, since an exhaustive 
  733. search of the keys applied to any cipher text of a given length will 
  734. yield all possible plain text messages of the same length.  Since 
  735. there are many messages of the same length that make sense, many of 
  736. which have totally contradictory or unrelated meanings, the cryptanalyst 
  737. has no way of knowing which one was intended unless he has the key.
  738.  
  739. Naturally, any method of encryption this secure has a price.  The 
  740. price is the sheer volume of keying material that must be kept secure 
  741. and managed.  For any communication network or data storage system 
  742. that handles large amounts of data, key management becomes a nightmare 
  743. with this system.
  744.  
  745. B.  Linear Shift Register Feedback
  746.  
  747. Linear shift registers with selected feedback taps are commonly used 
  748. to generate pseudorandom sequences for such things as spread spectrum 
  749. communications.  They could be (and are, in some cases) applied to 
  750. cryptography by exclusive-oring the pseudorandom stream with the plain 
  751. text stream.
  752.  
  753. The main weakness to this approach is the cipher text with corresponding 
  754. plain text attack.  If the cryptanalyst obtains the plain text that 
  755. came from a certain cipher text, then he can recreate a portion of 
  756. the pseudorandom stream by exclusive-oring the two together.  The 
  757. linear shift register feedback function can then be expressed as a 
  758. system of linear boolean equations that will solve the portion of 
  759. the cycle that was received.  A solution of this system of equations 
  760. is possible with only enough bits to be a few times as long as the 
  761. shift register at the most [DEN].  Since this amount of plain text 
  762. required to break the cipher is so much less than the length of the 
  763. pseudorandom sequence, it is likely that this solution can then be 
  764. applied to additional cipher text to recover it, too.
  765.  
  766. C.  Exponential Encryption
  767.  
  768. The classic algorithm of this type is the RSA algorithm, which is 
  769. named after the initials of its creators (R. L. Rivest, A. Shamir, 
  770. and L. Aldeman).  The security of this algorithm rests on the 
  771. fact that even with supercomputers, it is very difficult to factor 
  772. the product of two very large prime numbers.  The RSA algorithm has 
  773. a unique property in that the key has two parts, one of which may 
  774. be made public.  This makes this algorithm very well suited to the 
  775. use of digital signatures.
  776.  
  777. The RSA algorithm defines the relationships between the plain text 
  778. message, the cipher text, and the elements of the key as follows [JAC]:
  779.  
  780. C = P^e mod m
  781.  
  782. P = C^d mod m
  783.  
  784. m = pq
  785. where C = Cipher text, P = Plain text, e = encryption key, d = private 
  786. decryption key, m = public modulus, and p and q are randomly chosen 
  787. large (> 150 digits each) prime numbers.  The receiver chooses a private 
  788. key d and calculates a public key e.  d must be relatively prime to 
  789. (p - 1) and (q - 1).  The algorithm works because ed = 1 mod 
  790. the least common multiple of (p - 1)(q - 1).  The algorithm 
  791. is only secure if very large prime numbers are used.  A number of 
  792. 100 digits is too small - this size of number can be factored 
  793. now with a multiprocessor technique developed by Arjen K. Lenstra 
  794. of the University of Chicago and Mark Manasse of Digital Equipment 
  795. Corporation [COS].
  796.  
  797. The key generation for RSA is a bit nasty, but is reasonable using 
  798. Rabin's test for primality:  Let n = 2^rd+1, where d is odd. 
  799. Choose a at random from 1 < a < n - 1.  Accept n as prime if either 
  800. a^d = 1 mod n or a^2jd = -1 mod n for some j such that 
  801. 0 <= j < r, otherwise reject it.
  802.  
  803. RSA is excellent for public key and authentication use, but it does 
  804. have certain disadvantages for general encryption use.  The processing 
  805. time required for key generation and for the encryption/decryption 
  806. process makes it a poor choice for use with high data rates, although 
  807. there are some reasonably efficient ways to do the exponentiation 
  808. [CHI].  The complexity of the algorithm makes it more difficult to 
  809. implement than many others [VAN].  The worst problem, though is the 
  810. way that the complexity of solving the algorithm could be reduced 
  811. by several orders of magnitude by mathematical research.  For example, 
  812. J. Sattler and C. P. Schnorr recently published some algorithms that 
  813. would appear to reduce the complexity of solving an RSA key by a factor 
  814. of about 10^4 [SAT].  Granted that we are talking about taking 
  815. 9 x 10^8 years instead of 1.5 x 10^13 years, but it is 
  816. the potential for other discoveries that may drastically reduce this 
  817. time even further that is the real threat.
  818.  
  819. D.  Knapsack
  820.  
  821. A knapsack or trapdoor algorithm is one that is relatively easy to 
  822. perform, but which is very difficult to invert.  The RSA algorithm 
  823. is one such algorithm.  Another one, proposed by Ralph C. Merkle, 
  824. uses the following vector operation:  given an integer s and an integer 
  825. vector a = a1, a2, ..., an find a vector k 
  826. = x1, x2, ..., xn where xi is in {0,1} 
  827. such that s = x * a. (* denotes dot product.)  [MER]  This 
  828. algorithm is referred to in another paper as having been broken [VAN].  Another 
  829. algorithm using matrix operations is suggested by H. Retkin [RET].  This 
  830. algorithm may be good, but it is not obvious to me that no one will 
  831. come up with a good solution to breaking it, too.  Therefore, I prefer 
  832. to use encryption algorithms that have simple brute force solutions 
  833. that are well understood, but just take too long to perform to be 
  834. of concern.
  835.  
  836. E.  Rotor Machines
  837.  
  838. Rotor machines were once the state of the art in cryptography.  They 
  839. are a way to form a polyalphabetic solution automatically.  An excellent 
  840. history of these machines is contained in [KAH], [DEA], and [KOZ].  Although 
  841. they are obsolete now due to the superiority of many computer algorithms, 
  842. they played a major role in the history of cryptography.
  843.  
  844. There were many different variations on the rotor machine, but the 
  845. main principle of each of them was that the input, which is normally 
  846. a indicated by one of 27 (or whatever the alphabet size in use is) 
  847. wires is connected to a voltage level by a keyboard.  This wire is 
  848. then connected via rotary contacts to a rotor that physically permutes 
  849. the position of the wire.  This causes a simple substitution for each 
  850. character, or a poly alphabetic substitution. The output is taken 
  851. from rotary contacts on the other side of the rotor. Several of these 
  852. rotors are placed in series.  After each character is encrypted, one 
  853. or more of the rotors is moved to a new position by a ratchet mechanism.  The 
  854. net effect is a different simple substitution for each letter in the 
  855. message.  Common additions to this scheme are a plugboard style permutation 
  856. performed before or after the rotors and the addition of a reflecting 
  857. rotor to run the signal back through the rotors in the opposite direction, 
  858. using each rotor twice.
  859.  
  860. The key used is a combination of several things:  (1) the permutation 
  861. performed by each rotor (changed by rewiring it), (2) the order in 
  862. which the rotors were assembled, (3) the starting position of the 
  863. rotors, (4) the plugboard connections, (4) the number of rotors used, 
  864. and (5) the ratchet arrangement.  Taken all together, these form a 
  865. large key space.  If the entire key space is varied simultaneously 
  866. and for every message, then this polyalphabetic substitution is very 
  867. secure.  Due to the construction of these machines, some of the variables 
  868. were not as easy to change as others. Therefore in practical use, 
  869. the variables were not changed all at once.  For example, the number 
  870. of rotors and the ratchet arrangement would probably be fixed for 
  871. the life of the machine.  Therefore, if this portion of the key is 
  872. solved for once, that is enough until a new kind of machine replaces 
  873. it, perhaps years later.  The rotor wiring is tedious to change, and 
  874. therefore unlikely to be changed very often.  The order of the rotors 
  875. might be changed periodically, but during heavy use, the only thing 
  876. that was changed for each message is usually the starting position 
  877. of the rotors.
  878.  
  879. Using an alphabet size of 26 and five rotors, varying only the starting 
  880. position of the rotors provides a key space of less than 12 million, 
  881. which is within the range of possibility of solution by mechanical 
  882. computer, and a quick task for one of today's PCs.  With many messages 
  883. encrypted with the same rotors, the rotor wiring can be solved by 
  884. frequency analysis ``in depth.''  In other words, the permutation 
  885. applied to the first letter of each message can be solved by determining 
  886. the frequency of occurrence of each code letter and comparing that 
  887. with the language of the source language.  This can be done for each 
  888. position in the message.  From these substitutions, the rotor wiring 
  889. and plugboard connections may be reduced.  This is a more lengthy 
  890. process than solving for the rotor starting position, but once done 
  891. the solution is likely to be good for a while.  Using this kind of 
  892. approach, isolating the parts of the key, the Allies read many German 
  893. and Japanese messages during World War II.
  894.  
  895. Rotor machines can be simulated in a computer program with more flexibility 
  896. than in mechanical hardware, with many improvements.  There are, however, 
  897. better methods to use in computer algorithms that were not easy to 
  898. use in mechanical devices.  Therefore, rotor machines are interesting 
  899. to study for historical value, but they are obsolete at a time when 
  900. computers are becoming almost as common as televisions.
  901.  
  902. F.  Codes
  903.  
  904. Codes, as opposed to ciphers, operate on linguistic units like words, 
  905. phrases, and sentences, rather than directly on the units of the alphabet.  Codes 
  906. have the advantage that they generally compress the message.  For 
  907. example, the codeword ``APPLE'' might mean ``The supplies will be 
  908. shipped on Monday via private courier'' and ``GRAPE'' might mean ``The 
  909. bid is too high.  Reduce it by 10%.''  If there are only a few different 
  910. messages that might be encoded, a substantial savings in space can 
  911. be realized.
  912.  
  913. Codes are useful for compression of information, even when no encryption 
  914. is intended.  For example, the Uniform Commercial Code, used for telegraphy 
  915. saves on tolls, even though it is published and gives no real security.  Another 
  916. example is the use of Q signals on amateur radio, where encryption 
  917. is illegal but brevity is important, especially when using a slower 
  918. mode of communication like Morse Code.  There QST means ``The following 
  919. is a message of interest to all Amateurs'' and QSL means ``My location 
  920. is _____.''
  921.  
  922. When used to hide the meaning of the message, the code must be changed 
  923. often. This is much more difficult to do than to change the key to 
  924. an encryption algorithm.  Therefore, this technique has limited value 
  925. except for some diplomatic and military codes.  For commercial applications 
  926. where brevity and security are both required, it is easier to first 
  927. encode the plain text with a fixed code to reduce its size, then to 
  928. encrypt the encoded text with an encryption algorithm whose key can 
  929. be easily changed.  This technique is more secure than the use of 
  930. the encryption algorithm alone, even if the code used is widely known.  See 
  931. chapter VIII for more on the effects of data compression when used 
  932. with encryption.
  933.  
  934. G.  Galois Field and Hill Cryptosystems
  935.  
  936. A Galois Field cryptosystem is one in which the letters of the encryption 
  937. alphabet are assigned arbitrarily to the integers from 0 to p^n, 
  938. where p is prime and n is an integer.  These integers are then operated 
  939. on in blocks of m letters by matrix multiplication with a matrix that 
  940. represents monic irreducible polynomials of order m - 1.  All operations 
  941. are done modulo p^n.  To decrypt the data, the ciphertext is 
  942. multiplied in the same manner by the inverse of the encryption matrix 
  943. (obtained using the same modulo arithmetic).  The resulting numbers 
  944. are then substituted back for the letters they represent.
  945.  
  946. The Hill cryptosystem is similar, except that n is fixed at one, and 
  947. that p need not be absolutely prime as long as several integers less 
  948. than p are relatively prime to it.  For more details on how these 
  949. cryptosystems work, see the articles by Hill, Cooper, and Patti [HIL] 
  950. [HLL] [COO] [PAT].
  951.  
  952. Both of these systems are based on linear algebra over a limited field 
  953. of integers.  Therefore, they are subject to solution of the key in 
  954. use by linear algebra if enough cipher text and corresponding plain 
  955. text is available.  If the permutation of the encryption alphabet 
  956. in use is known, then the amount of corresponding plain and cipher 
  957. text needed for a solution is merely the key length.  If the permutation 
  958. of the encryption alphabet in use is not known then there must be 
  959. a sufficient quantity to also perform statistical analysis attacks 
  960. on the alphabet in use.  Therefore, I do not recommend the use of 
  961. these systems for serious encryption because of these vulnerabilities.  Not 
  962. only are they less secure than their key length (the combined length 
  963. of the coefficients of their matrices) would indicate, they are computationally 
  964. less efficient than DES and MPJ.  Key generation for these systems 
  965. becomes increasingly complex as the size of the key grows, too, because 
  966. the probability of coming up with a valid set of monic irreducible 
  967. polynomials that form an invertible matrix decreases rapidly with 
  968. matrix size.
  969.  
  970. These cryptosystems, do, however, provide interesting mathematical 
  971. illustrations on what can be done with Galois Fields.  They also provide 
  972. adequate security for cases where the information being secured is 
  973. not of great commercial value, and is therefore unlikely to be cryptanalyzed.
  974.  
  975. H.  DES
  976.  
  977. The National Bureau of Standards (now known as NITS) Data Encryption 
  978. Standard (DES) was published in the Federal Information Processing 
  979. Standards Publication Number 46, dated January 15, 1977 (FIPS PUB 
  980. 46) [DES].  For details, please refer to that publication.  A summary 
  981. of the algorithm follows.
  982.  
  983. Encryption consists of an initial permutation, sixteen rounds of encryption, 
  984. then an inverse of the initial permutation.  Each of the sixteen rounds 
  985. of encryption consist of taking the right half of the input block 
  986. (32 of the 64 bits) and running it through a nonlinear function of 
  987. the 32 bits and an internal key, then adding this result to the left 
  988. half of the input modulo two.  This 32 bit answer becomes the next 
  989. round's right half block.  The next round's left half becomes the 
  990. right half block without modification.  The nonlinear function used 
  991. consists of a bit selection E that selects 48 bits from the input 
  992. of 32 (several of the bits are repeated).  These 48 bits are added 
  993. modulo 2 to the round key of 48 bits.  The result of that operation 
  994. are then fed six bits each into eight substitution boxes.  Each of 
  995. the eight substitution boxes are different, but the same set of eight 
  996. boxes are used for each round.  Each substitution box gives an output 
  997. of 4 bits.  The output of these boxes are fed into a permutation P 
  998. that rearranges the output in a fixed manner.
  999.  
  1000. The sixteen internal keys are generated from the 56 bit input key 
  1001. by feeding the input key into a fixed permutation that rearranges 
  1002. the order of the key bits.  The key is then split into left and right 
  1003. halves called C and D.  Each half is shifted left one or two times 
  1004. (according to a fixed table) before generating each internal key.  Each 
  1005. of the sixteen internal keys is generated by taking the two halves 
  1006. of the key as shifted and permuting them in a fixed manner.
  1007.  
  1008. The key and the resulting internal keys are the only things that vary 
  1009. in this algorithm.  The initial and final permutations and the contents 
  1010. of each of the substitution boxes are constant.  The two permutations 
  1011. used in generating the internal keys are constant.  The bit selection 
  1012. and permutation used within the nonlinear function are constant.
  1013.  
  1014. The strengths of the DES is that its cryptographic strength depends 
  1015. only on the key, that the algorithm is easy to implement in a single 
  1016. IC, that it has been well tested an no one has publicly announced 
  1017. a solution, that hardware and software that uses it is readily available, 
  1018. and that the algorithm places very few restrictions on key generation 
  1019. so that random numbers may be generated by the users for use as keys.
  1020.  
  1021. The weaknesses of the DES are that the key is too short for security 
  1022. in the face of anticipated increases of computing power, that it is 
  1023. old enough that it is likely that someone has broken it (found a short-cut 
  1024. solution), that hardware implementations of the DES are too slow for 
  1025. some applications, and that it limits itself to be simpler than is 
  1026. really necessary with current technology.
  1027.  
  1028. VI.  DESIGN CONSIDERATIONS FOR MPJ
  1029.  
  1030. The following paragraphs describe the design considerations that I 
  1031. used in creating the MPJ Encryption Algorithm, and the reasons for 
  1032. each.
  1033.  
  1034. A.  Strength Based on Key
  1035.  
  1036. The strength of the system must rely on the security of the key only.  It 
  1037. cannot depend on the algorithm being kept secret, because the algorithm 
  1038. will be published.  Even if the algorithm were not published, it would 
  1039. probably be reverse engineered from software implementations of the 
  1040. algorithm.  The algorithm must be constructed in such a way that there 
  1041. is no computationally feasible way to derive the key from samples 
  1042. of corresponding plain text and cipher text.
  1043.  
  1044. B.  Usability of Random Keys
  1045.  
  1046. The key selection should be as easy as the random selection of a number 
  1047. in a given range.  Selecting a very secure key should be no more difficult 
  1048. than flipping a coin once for each bit of the key, or generating keys 
  1049. using a pseudorandom sequence combined with random events such as 
  1050. timing of keystrokes on a computer.  A one bit change in the key should 
  1051. provide a drastically different transformation, so that a potential 
  1052. cryptanalyst has no idea when a key that he guesses might be ``close'' 
  1053. to the right one. 
  1054.  
  1055. C.  Key Length & Block Size
  1056.  
  1057. The key length should be significantly longer than the DES 56 bit 
  1058. size.  A key size of 128 bits (sixteen 8-bit bytes) was chosen as 
  1059. being very manageable, yet highly secure even when attacked by multiple 
  1060. array supercomputers.  The block size was also chosen as 128 bits 
  1061. (twice the size of DES) to provide a significant increase in complexity 
  1062. of the encryption.
  1063.  
  1064. D.  Effort Required to Break
  1065.  
  1066. The effort required to break the algorithm by any method should be 
  1067. so great as to make such a task unfeasible even if significant advances 
  1068. are made in computer technology.
  1069.  
  1070. This requirement is intimately linked to the choice for key size and 
  1071. block size.  For example, if one thousand keys could be tried every 
  1072. nanosecond (10^12 attempts per second), an exhaustive key search 
  1073. that resulted in success after only testing one millionth of the possible 
  1074. keys (extremely good luck) would take 2^128/((10^12)(10^6)) 
  1075. = 3.4 x 10^20 seconds = 1 x 10^13 years.  If someone figured 
  1076. out a computational method or weakness in the algorithm that reduced 
  1077. the complexity by a factor of a million, and that someone also figured 
  1078. out how to compute the solution a thousand times faster, and they 
  1079. still believed in one in a million chances at good luck, they could 
  1080. possibly come up with a solution in only 10,000 years. By way of contrast, 
  1081. testing keys at the rate of 10^12 per second for DES with its 
  1082. 56 bit key, all of the keys can be tested in 7.2 x 10^4 seconds, 
  1083. or about 20 hours.  While trying a trillion keys a second is not realistic 
  1084. with current general purpose computers, current technology could be 
  1085. applied to dedicated, highly parallel encryption/decryption engines 
  1086. that could approach that speed - at a cost that would be prohibitive 
  1087. for all but large governments at today's prices.
  1088.  
  1089. Other than time, the other main measure of complexity of an algorithm 
  1090. is the storage capacity required to implement a lookup table attack.  Suppose 
  1091. a lookup table were to be constructed that contained the encrypted 
  1092. version of just one block of cipher text corresponding to a very common 
  1093. block of plain text (such as 16 ASCII spaces) for every key possible.  For 
  1094. the MPJ algorithm, this would take 2^128 x 128 = 4.356 x 10^40 
  1095. bits.  If this memory were constructed with some kind of device that 
  1096. could store one bit per atom of silicon, this would take 4.356 x 10^40 
  1097. bits x 28.086 amu/atom x 1.660531 x 10^-24 grams/amu x 10^-6 
  1098. metric tons/gram = 2.03 x 10^12 metric tons of silicon.  That 
  1099. is about one thousandth of the mass of Deimos, the smaller of Mars' 
  1100. two moons.  [CRC]  For DES, the same table would only require about 
  1101. 215 micrograms of silicon.  Nobody has come up with memory that dense, 
  1102. and fundamental physical limits make such a task difficult, indeed.  It 
  1103. is not difficult to conceive of some breakthroughs in optical storage 
  1104. technology coming close, say using a thousand molecules of something 
  1105. per bit. Under those circumstances, DES would be vulnerable to such 
  1106. an attack, where MPJ would still be safe.
  1107.  
  1108. E.  Computational Efficiency
  1109.  
  1110. The MPJ encryption algorithm must be computationally efficient enough 
  1111. to be implemented in software on a standard IBM PC or compatible (or 
  1112. on an Apple computer of comparable power), and fast enough to handle 
  1113. at least 10 megabits per second when implemented in dedicated hardware.  Note 
  1114. that this is less restrictive with respect to the hardware for DES, 
  1115. which was required to be simple enough to implement on a single chip 
  1116. using 1970s technology.
  1117.  
  1118. F.  Communication Channel Efficiency
  1119.  
  1120. The MPJ encryption algorithm must not significantly increase the size 
  1121. of the plain text when encrypting it.  This precludes the use of noise 
  1122. addition as a technique to be used.
  1123.  
  1124. G.  No Back Doors or Spare Keys
  1125.  
  1126. While it may be impossible to guarantee that no ``back doors'' or  ways 
  1127. to decipher a message without the key exist, the algorithm should  be 
  1128. sufficiently complex combination of simple, well-understood operations  that 
  1129. no help is offered to the cryptanalyst from the structure of  the 
  1130. algorithm. Spare keys (the situation where more than one unique  key 
  1131. will decipher a message) are avoided by making the number of keys  possible 
  1132. much less than the number of possible transformations that can be 
  1133. done  on a set of blocks.  This is true for MPJ because 2^128 
  1134. << 2^128!.
  1135.  
  1136. VII.      MPJ ENCRYPTION ALGORITHM
  1137.  
  1138. A.  Description
  1139.  
  1140. The MPJ Encryption Algorithm can be looked at from the outside like 
  1141. a rather large electronic codebook that operates on 128 bit blocks.  The 
  1142. algorithm may be used in several modes.  It can be used directly in 
  1143. electronic codebook mode, in block chaining with ciphertext feedback 
  1144. mode, in block chaining with plain text feedback mode, and in stream 
  1145. cipher generation mode.
  1146.  
  1147. Given a 128 bit key, instructions to encrypt or decrypt, and a 128 
  1148. bit input block, a unique 128 bit output block comes out. Encryption 
  1149. and decryption are inverse operations that can be done in either order.  For 
  1150. example, if P is the plain text block, C is the cipher text block, 
  1151. EK1 is encryption with key 1, and DK1 is decryption 
  1152. with key 1, then C = EK1(P); P = DK1(P).  A different 
  1153. cipher text results if the plain text is decrypted first, but DK1(EK1(P)) 
  1154. = P = EK1(DK1(P)).  Multiple encryption can be done 
  1155. with several keys, as in these examples with three:
  1156.  
  1157. C = EK1(EK2(EK3(P))); P = DK1(DK2(DK3(C))) 
  1158. or a different method:
  1159.  
  1160. C1 = EK1(DK2(EK3(P))); P = DK1(EK2(DK3(C)))
  1161.  
  1162. 1.  Overall Structure of MPJ
  1163.  
  1164. Before encryption or decryption occurs, the substitution boxes are 
  1165. filled based on the input key.
  1166.  
  1167. To encrypt a 128 bit input block, it is run sequentially through ten 
  1168. rounds of substitution.  Each round of substitution operates on the 
  1169. 16 eight-bit bytes that make up the input block individually.  In 
  1170. between each round of substitution is a round of permutation, for 
  1171. a total of 9 rounds of permutation.  The permutation operation is 
  1172. identical each time.  Each operation (substitution and permutation) 
  1173. has an inverse operation.  Decryption is done by running the inverse 
  1174. operation of each of the above steps in the opposite order.
  1175.  
  1176. After one round of permutation, each bit in the output block depends 
  1177. on every bit in the byte that it is in and on eight bits of the key.  After 
  1178. a round of permutation and the second round of substitution, each 
  1179. bit in the block depends on eight bytes of the input block and on 
  1180. eight bytes in the key.  After the third round of substitution, each 
  1181. bit in the block is functionally dependent on 15 of the input bytes 
  1182. and on 15 bytes of the key.  After the fourth round of substitution, 
  1183. each bit in the block is functionally dependent on every bit of the 
  1184. input block and on each bit of the key.  After the tenth round of 
  1185. substitution the functional dependence on every bit of the key and 
  1186. the input block is so complex that it would be infeasable to determine 
  1187. the key used, even if the cryptanalyst has known corresponding plain 
  1188. and cipher text and knows the algorithm used.  Because the substitution 
  1189. boxes are totally nonlinear functions, the problem of finding each 
  1190. of the 40,960 internal key bits is a tough one, indeed.  It would 
  1191. be easier to find the original key of only 128 bits by brute force 
  1192. - something that is difficult, indeed.
  1193.  
  1194. 2.  Substitution Boxes
  1195.  
  1196. The substitution boxes are designed to be big enough to provide a 
  1197. large number of possible arrangements, but small enough to still fit 
  1198. comfortably within the memory of an MS-DOS computer.  Each substitution 
  1199. box is therefore a collection of 16 substitution boxes that operate 
  1200. on only 8 bits at a time, with a total of 256 entries.  The substitution 
  1201. boxes may be an array or look-up table in a computer, or they may 
  1202. be implemented in hardware using RAM.
  1203.  
  1204. The substitution boxes are filled during the internal key generation 
  1205. process with a permutation of numbers that depends on the main key 
  1206. in a different way for each substitution box.
  1207.  
  1208. 3.  Wire Crossings
  1209.  
  1210. The wire crossings serve to extend the functional dependence of the 
  1211. output block on the input block across the internal byte boundaries.  This 
  1212. is done by making each byte of the output of the permutation to contain 
  1213. one bit from each of eight different bytes.  The selection of bits 
  1214. was chosen to make a computer implementation fairly efficient.  A 
  1215. pure hardware implementation of this operation is, of course, much 
  1216. faster, since it involves only the propagation delay of the signal 
  1217. from one end of a short wire to the other.  The input block bit positions 
  1218. are numbered from left to right (MSB to LSB) as 127 down to 0, then 
  1219. the new positions those bits occupy after the wire crossing are (MSB 
  1220. to LSB):
  1221.  
  1222. 55, 46, 37, 28, 19, 10, 1, 120, 111, 102, 93, 84, 75, 66, 57, 48, 
  1223. 39, 30, 21, 12, 3, 122, 113,  104, 95, 86, 77, 68, 59, 50, 41, 32, 
  1224. 23, 14, 5, 124, 115, 106, 97,  88, 79, 70, 61, 52, 43, 34, 25, 16, 
  1225. 7, 126, 117, 108, 99, 90, 81, 72, 63, 54, 45, 36, 27, 18, 9, 0
  1226.  
  1227. 4.  Key Generation
  1228.  
  1229. Internal key generation in the MPJ encryption algorithm consists of 
  1230. filling all of the substitution boxes (arrays in software or RAM in 
  1231. hardware).  There are 16 substitution boxes used for each of 10 rounds.  Each 
  1232. substitution box contains 256 entries of 8 bits each.  Therefore, 
  1233. the actual internal keys have a combined length of 16 x 10 x 256 x 
  1234. 8 = 327,680 bits.  These are obtained by manipulation of the 128 input 
  1235. key bits.  Note that trying to attack the MPJ encryption algorithm 
  1236. by brute force trial and error using internal keys instead of using 
  1237. the 128 input key bits is ridiculous.  The calculations given above 
  1238. indicate how difficult even a 128 bit random key is to solve by brute 
  1239. force.  The only way that an attack on internal keys is useful is 
  1240. if there are parts of the internal keys that can be solved for separately, 
  1241. without having to solve for as many as 128 bits at once.
  1242.  
  1243. Attacks against the internal key structure are made computationally 
  1244. intractable in three ways.  First, the smallest chunk of the internal 
  1245. key that could be meaningfully solved for is the contents of one of 
  1246. the substitution boxes.  Each of these contain 256 bytes, or 16 times 
  1247. the length of the input key. Remember that the addition of each bit 
  1248. doubles the complexity of the solution, so this is not attractive 
  1249. compared to solving for the input key.  The second impediment to this 
  1250. attack is to make the relationship between the contents of the substitution 
  1251. boxes and the input key quite nonlinear.  The way this is done is 
  1252. by using a combination of rotating bit selection and the use of the 
  1253. last substitution box filled to compute the contents of the next one.  The 
  1254. third line of defense against the solution of internal keys is the 
  1255. use of ten nonlinear rounds of encryption to make any attempt at constructing 
  1256. a system of linear equations to solve for the internal key given known 
  1257. plain text and corresponding cipher text infeasable.  Note that each 
  1258. round of encryption in MPJ causes the whole 128 bit block to be changed, 
  1259. where each of the rounds in DES only modifies half of its 64 bit block.  Therefore 
  1260. the internal structure of MPJ is very difficult to solve for, with 
  1261. each bit of the output having a nonlinear functional dependence on 
  1262. every bit of the input and on the contents of 1 + 8 + 15 + (7 x 16) 
  1263. = 136 of the substitution boxes, containing a total of 34,816 bits.  If 
  1264. the substitution boxes were linear, this solution would be possible, 
  1265. but there is no method I know of to solve such a system of nonlinear 
  1266. equations, either here or the simpler case of the DES internal structure.
  1267.  
  1268. To find the inverse of the substitution box functions, separate inverse 
  1269. substitution boxes are formed that place each address of a substitution 
  1270. box at the address of the data contained in the substitution box.  For 
  1271. example, if the contents of the first substitution box in the first 
  1272. round of encryption for the input value of 1 is 219, then the contents 
  1273. of the first inverse substitution box in the last round of decryption 
  1274. for the input of 219 will be 1.  In equations, SI[i, j, S[i, j, k]] 
  1275. = k for all i, j, k, where the first index of the array is the round 
  1276. of encryption, numbered from 0 to 9, or the round of decryption, numbered 
  1277. from 9 to 0 (defined differently for programming convenience); the 
  1278. second index is the position of the 8 bits that the substitution applies 
  1279. to in the input block, numbered from 0 to 15, left to right; and the 
  1280. third index is the value of the 8 bits input to the block.
  1281.  
  1282. The actual algorithm for substitution box filling consists of three 
  1283. main parts.  The first one is a nested loop to fill one substitution 
  1284. box, permute the key with the same permutation used for the encryption 
  1285. operation, then to run each byte of the key through the substitution 
  1286. box that was just filled. This is done for each round of encryption, 
  1287. from 0 to 9, with each substitution box used in one round of encryption, 
  1288. from left to right, done within each of these rounds.  In other words, 
  1289. the index of the three dimensional array that selects the position 
  1290. of the substitution box within each array varies faster than the index 
  1291. that selects the number of the round of encryption that the box uses.
  1292.  
  1293. The second algorithm is the one that fills each substitution box based 
  1294. on the contents of the input key, as modified by the previous steps.  This 
  1295. algorithm uses bit selection and rotation to determine where each 
  1296. value of the output of the substitution box goes.  To be an invertable 
  1297. function, each of the possible output values from 0 to 255 must appear 
  1298. exactly once somewhere within the array with 256 possible slots, numbered 
  1299. from 0 to 255.  The first number placed in the array is 255, and there 
  1300. are 256 possible places to put it.  The second one is 254, with 255 
  1301. places to put it.  This is continued until the last value, 0 is placed 
  1302. in the one remaining slot.  For the first half of the values, the 
  1303. formula pos = (n * m) div 255 is used to determine which of the unfilled 
  1304. slots (counting in index order from 0 to n) is to be used to contain 
  1305. n.  The variable pos is the position (counting only unfilled slots), 
  1306. * denotes multiplication, and div is the integer division operator 
  1307. (remainders are ignored).  The variable m is determined for the first 
  1308. value of n (255) by selecting one bit from each byte of the key, starting 
  1309. with the least significant bit from the least significant byte of 
  1310. the key.  The next bit (place value of 2) is selected from the next 
  1311. most significant bit of the key, and so on until m has eight bits.  For 
  1312. the next value of n (254), the same thing is done, except that the 
  1313. bit selected is one bit position to the left of the one selected last 
  1314. time.  The place value of the bit selected is the same in m as it 
  1315. is in the byte it came from.  The bit to the left of the MSB in a 
  1316. byte is the LSB of the byte to the left of it.  The byte to the left 
  1317. of the most significant byte is the least significant byte.  For the 
  1318. values of n from 127 to 0, then the same thing is done, except that 
  1319. only seven bits are selected for m, and the position is determined 
  1320. from pos = (n * m) div 127. For a more concise explanation of this 
  1321. process, see the commented pascal procedure makesbox in the program 
  1322. in appendix A.
  1323.  
  1324. The third algorithm used in internal key generation is the generation 
  1325. of inverse substitution boxes.  This is done with a simple nested 
  1326. loop that fills the inverse substitution boxes according to the formula 
  1327. si[i, j, s[i, j, k]] for i from 0 to 9, j from 0 to 15, and k from 
  1328. 0 to 255.  The array si is the collection of inverse substitution 
  1329. boxes, and the array s is the collection of substitution boxes filled 
  1330. by the above two algorithms.  Filling of inverse substitution boxes 
  1331. is only needed for decryption mode.
  1332.  
  1333. B.  Implementation in Pascal
  1334.  
  1335. Pascal source code for a program to implement the MPJ Encryption Algorithm 
  1336. is given in Appendix A.
  1337.  
  1338. 1.  Exceptions from Standard Pascal
  1339.  
  1340. This program was written for MS-DOS computers and compiled using Borland 
  1341. Turbo Pascal 5.0.  To adapt this program for use on another system, 
  1342. note that the following features of Turbo Pascal that do not conform 
  1343. to the ANSI/IEEE770X3.97-1983 Standard Pascal were used in this program:
  1344.  
  1345. (i)  The assign procedure is used to associate an operating system 
  1346. file name with a Pascal file name.
  1347.  
  1348. (ii)  The nonstandard file handling procedures blockread, blockwrite, 
  1349. close, and seek, were used.  The nonstandard function filepos was 
  1350. used.
  1351.  
  1352. (iii)  The type longint (a 32 bit integer) was used for input handling 
  1353. to allow range checking without invoking a system error for a number 
  1354. that was only slightly out of range.  A 16 bit integer could be used 
  1355. instead.
  1356.  
  1357. (iv)  A generic file type was used, which is not defined in ANSI Pascal.
  1358.  
  1359. (v)  The nonstandard operators shl and xor were used.  The shl could 
  1360. be replaced with integer division by 2 (div 2), and the xor could 
  1361. be replaced by expressions of the form ((A and (not B)) or ((not A) 
  1362. and B)).
  1363.  
  1364. (vi)  Logical operators (and, or, not, xor) were used with integers 
  1365. to perform bit-wise operations.
  1366.  
  1367. (vii)  The + operator was used to concatenate strings.
  1368.  
  1369. (viii)  The uses clause links in separately compiled units.
  1370.  
  1371. (ix)  The include comment {$I filename} includes additional source 
  1372. code to be compiled with the current file.
  1373.  
  1374. (v)  Additional nonstandard features were used in writing startup  and 
  1375. the file handling functions that are unique to MS-DOS.  These functions 
  1376. would best be rewritten for a different target system.
  1377.  
  1378. 2.  Main Program
  1379.  
  1380. The main program calls startup to initialize variables, get the key 
  1381. from the user, and determine which files are to be encrypted or decrypted. 
  1382. It then calls makesbox to generate the internal keys (fill the substitution 
  1383. boxes). If the decryption mode is to be used, it calls makesi to fill 
  1384. the inverse substitution boxes.  It then does the actual encryption 
  1385. or decryption.
  1386.  
  1387. The main program allows for the encryption of multiple files (specified 
  1388. using MS-DOS wildcards), and passes these files to the encryption 
  1389. routine one block at a time.  To provide additional security, files 
  1390. are encrypted in place, with each block of output overwriting the 
  1391. corresponding input block in the same place on the disk.  If it is 
  1392. desired to keep a copy of both encrypted and plain text versions of 
  1393. the file, the input file should be copied before running this program.
  1394.  
  1395. Because this program uses block chaining with ciphertext feedback, 
  1396. only the encryption mode of the MPJ algorithm is used, the source 
  1397. of the feedback (input or output) being determined by the decryption 
  1398. boolean variable.  This mode is used because (1) it obscures repetitive 
  1399. patterns in the source file that the electronic codebook mode might 
  1400. not hide, (2) it accommodates files of any number of bytes (including 
  1401. a short block at the end) with no complications and results in an 
  1402. output file that is the same length as the input file, and (3) it 
  1403. is slightly faster in operation because the procedure makesi does 
  1404. not have to be called.  This mode does require an initialization vector, 
  1405. but since the initialization vector is encrypted before use, a constant 
  1406. initialization vector may be used.
  1407.  
  1408. To use the electronic codebook mode, delete the for statement following 
  1409. the calls to encrypt, replace one call to encrypt with a call to decrypt, 
  1410. and remove the comment delimiters from around the call to makesi.
  1411.  
  1412. 3.  Procedures Encrypt & Decrypt
  1413.  
  1414. These procedures directly reflect the overall structure of MPJ.  The 
  1415. are simply calls to the routines that perform the substitutions and 
  1416. permutations, calling them in the proper order and passing a parameter 
  1417. to the substitution routines that select the right set of substitution 
  1418. (or inverse substitution) boxes for the operation being done.  The 
  1419. procedure encrypt makes 10 calls to substitute, with 9 calls to permute 
  1420. (one call to permute between each pair of calls to substitute.  The 
  1421. procedure decrypt makes 10 calls to isubst, with 9 calls to ipermute, 
  1422. done in the inverse order of encryption.
  1423.  
  1424. 4.  Procedures Permute & Ipermute
  1425.  
  1426. Permute just scrambles the order of the bits in the 128 bit block 
  1427. in such a way as to maximize the dependence of each byte on every 
  1428. other byte of the input.  Each byte is formed by selecting the least 
  1429. significant bit from the least significant bit of the corresponding 
  1430. input byte, then the next most significant bit from the next byte 
  1431. to the left, and so on.  The least significant byte is considered 
  1432. to be to the left of the most significant byte. Ipermute is just the 
  1433. inverse of this permutation, with bytes being selected to the right 
  1434. instead of the left.
  1435.  
  1436. 5.  Procedures Substitute & Isubst
  1437.  
  1438. These procedures are simple array lookups in which each byte of the 
  1439. input block is used as the third index of the array s for the procedure 
  1440. substitute or si for the procedure isubst.  The output is the contents 
  1441. of the array.  The first index is the round of encryption or decryption 
  1442. (counting backwards if it is decryption), and the second index of 
  1443. the array is the byte position (0 to 15) within the input and output 
  1444. blocks.
  1445.  
  1446. C.  Implementation in Hardware
  1447.  
  1448. For use with high data rates (greater than 10 Megabits per second), 
  1449. it is desirable to implement the MPJ algorithm directly in hardware. 
  1450. This also provides the advantage of greater security against tampering 
  1451. than a program on a general purpose computer might be subject to.
  1452.  
  1453. The hardware implementation consists of six basic elements:  (1) Key 
  1454. generation, (2) serial to parallel conversion, (3) substitution, (4) 
  1455. wire crossings, (5) parallel to serial conversion, and (6) timing 
  1456. control.  The key generation is done by a program running in a microprocessor.  This 
  1457. program takes the key as input and fills the substitution boxes, which 
  1458. are simply static RAM chips. Serial to parallel conversion and parallel 
  1459. to serial conversion is done with shift registers.  The wire crossings 
  1460. are done with physical wire crossings (or printed circuit board trace 
  1461. crossings) - a technique that is hard to beat for speed.  Timing 
  1462. control is done with a sequential circuit that is synchronized to 
  1463. the incoming data stream.
  1464.  
  1465. The output data stream will, of necessity, be delayed by at least 
  1466. the block size of 128 bits, and some kind of protocol must be used 
  1467. to synchronize the blocks at the sending and receiving ends.
  1468.  
  1469. The following diagram shows a block diagram of a hardware implementation 
  1470. of the MPJ Encryption Algorithm.  There are, of course, many variations 
  1471. possible.  For example, block chaining could be used with hardware 
  1472. exclusive-or gates to do the modulo 2 addition and flip-flops for 
  1473. unit delays.
  1474.  
  1475. D.  Strengths & Weaknesses
  1476.  
  1477. The main strengths of the MPJ encryption algorithm are:
  1478.  
  1479. It is much more secure than DES.
  1480.  
  1481. When used in conjunction with data compression, MPJ is probably 
  1482. more secure than many of the best military and diplomatic codes & 
  1483. ciphers.
  1484.  
  1485. It is easy to generate a key for MPJ.
  1486.  
  1487. It is capable of high data rates when implemented in hardware.
  1488.  
  1489. It will run on a personal computer.
  1490.  
  1491. It takes more time to generate internal keys from an external 
  1492. key than to actually encrypt or decrypt data, making exhaustive key 
  1493. search attack more difficult than normal use.
  1494.  
  1495. The algorithm is published and may be freely used for any 
  1496. legal purpose.
  1497.  
  1498. There has not been a lot of time for anyone to search for 
  1499. a short-cut solution to MPJ, nor the volume of sensitive material 
  1500. to motivate such a search as DES has had.
  1501.  
  1502. The main weaknesses of the MPJ encryption algorithm are:
  1503.  
  1504. The key and block sizes are fixed (optimized for the memory 
  1505. and processing power of the IBM PC), so it doesn't take very good 
  1506. advantage of more powerful computers other than running faster.
  1507.  
  1508. The software implementation isn't very fast.
  1509.  
  1510. There is no way to prove that there is no short-cut solution 
  1511. to MPJ (or DES, or almost any encryption algorithm except for the 
  1512. one-time key tape).
  1513.  
  1514. Since the MPJ encryption algorithm is my own invention, 
  1515. I could possibly be blind to some weakness that it might contain.
  1516.  
  1517. VIII.     DATA COMPRESSION
  1518.  
  1519. A.  Purpose
  1520.  
  1521. Data compression has two obvious purposes:  to save on communication 
  1522. channel capacity required to send a message and to save on media capacity 
  1523. required to store a message.  The third purpose for data compression, 
  1524. pointed out by C. E. Shannon, is to make decryption of a message more 
  1525. difficult [SHA].  In reading through the history of cryptanalysis, 
  1526. it became very obvious to me that the one thing that all cryptanalysis 
  1527. relies on the most is the presence of a great deal of redundancy present 
  1528. in natural languages.  This is especially true for messages that the 
  1529. cryptanalyst already has something of an idea of what the message 
  1530. is about.  It is this redundancy that enables the cryptanalyst to 
  1531. tell which of several possible solutions is the right one - the 
  1532. one that ``makes sense.''  For example, if the message is between 
  1533. English-speaking parties, then the of the possible messages ``ACCEPT 
  1534. THE PROPOSAL,'' ``A;LSDI FUPE ZAARED,'' and ``XXDKFJ DDDLKJDJFFZA,'' 
  1535. the first message is instantly recognized as the only one that makes 
  1536. sense.  The reason that this is so obvious is because of the redundancy 
  1537. of natural languages.  If all of the redundancy of a message is removed, 
  1538. then there is no criteria to select one possible answer over another, 
  1539. and the cryptanalyst is left baffled.
  1540.  
  1541. The task at hand is to try to eliminate or at least reduce the amount 
  1542. of redundancy in a message before encryption, then restore the message 
  1543. to its original meaning after decryption.  If all of the redundancy 
  1544. of a message is removed, it means that all possible messages that 
  1545. can be constructed from an alphabet have meaning, and that the length 
  1546. of a message is inversely proportional to its probability.  This ideal 
  1547. can probably be achieved only for special circumstances with very 
  1548. limited messages.  For use with general correspondence in a natural 
  1549. language, however, it is not practical to totally remove the redundancy 
  1550. from all messages.  In fact, it is very difficult to even measure 
  1551. redundancy or entropy in a natural language.  The concepts of redundancy 
  1552. and entropy (as defined in communication theory texts) are useful 
  1553. for comparisons of various methods of redundancy reduction.
  1554.  
  1555. Most existing methods of redundancy reduction use either a manually 
  1556. constructed code like the amateur radio operator's Q-signals or an 
  1557. automatic method that operates on either the alphabet or some groupings 
  1558. of alphabet symbols, like trigraphs.  Manual techniques are fine for 
  1559. their intended application, but automatic methods that are well-suited 
  1560. for computer implementation are better for use with encryption.  Automatic 
  1561. methods are likely to achieve good results with much greater ease 
  1562. of use and less opportunities for errors.
  1563.  
  1564. The probability of occurrence of various letters in most natural languages 
  1565. are fairly constant over a wide range of types of text, and have been 
  1566. studied and published many times.  These probabilities for English 
  1567. letters are published in several of the texts on cryptography listed 
  1568. in the references section of this thesis.  Probabilities of digraphs 
  1569. (groups of two letters) and trigraphs (groups of three letters) have 
  1570. likewise been studied, and are fairly constant for a given language.  Just 
  1571. changing the representation of trigraphs to variable length codes 
  1572. that are shorter for more common trigraphs and longer for less common 
  1573. trigraphs results in a substantial savings in length of an English 
  1574. message.
  1575.  
  1576. There are many such methods for compressing data that are fairly straight 
  1577. forward.  This and other methods, many of which are discussed by James 
  1578. Storer in his book on data compression [STO].  There are also several 
  1579. public domain and share-ware programs that are available on many bulletin 
  1580. boards that perform data compression.  My favorite is PKARC, written 
  1581. by Phil Katz.  It dynamically analyzes each input file to determine 
  1582. which one of five compression methods or storing with no compression 
  1583. results in the smallest file.  The compression methods used by PKARC 
  1584. are repetition coding, Huffman encoding, Ziv-Lempel-Welch compression, 
  1585. and two different variations on Dynamic Ziv-Lempel-Welch compression 
  1586. [KAT].  PKARC also has an option that allows a rather crude encryption 
  1587. of the archive files with a password. Although this doesn't provide 
  1588. strong cryptographic security, it does help to obscure the redundancy 
  1589. that PKARC adds back in, in the form of cyclic redundancy checks on 
  1590. files and file headers.  The CRC checks and file headers would be 
  1591. a good point of vulnerability when trying to cryptanalyze an archived 
  1592. (compressed) file.
  1593.  
  1594. My feeling was that it was possible to compress natural language text 
  1595. even more than was commonly being done by using linguistic parsing 
  1596. of the text to form a dictionary.  I was partially right.  My method 
  1597. does remove more redundancy and make most text files smaller and more 
  1598. secure.  It won't win any speed contests with PKARC, however, which 
  1599. I recommend that you use if speed is of great importance or if you 
  1600. are going to compress binary files (such as executable programs).  
  1601.  
  1602. In comparing the performance of SQUEEZE with PKARC, I compressed a 
  1603. 4,316,030 byte ASCII text file (the King James Version of the Holy 
  1604. Bible) to 1,312,493 bytes with a language code file of 163,236 bytes.  PKARC 
  1605. compressed the same file to 1,779,184 bytes.  This is a removal of 
  1606. 69.6% of the redundancy for SQUEEZE (or 65.8% if you add the size 
  1607. of the language code file), compared with a redundancy reduction of 
  1608. only 58.8% for PKARC.  This may not seem like much of a difference, 
  1609. but the smaller compressed file fits on a 1.44 Megabyte 3 1/2 inch 
  1610. floppy disk, and the other one doesn't.  This would be more of a significant 
  1611. achievement if SQUEEZE weren't so slow.  It took well over two hours 
  1612. to do this running on one of the fastest PC's available (25 MHz 80386), 
  1613. while PKARC worked for about a minute on the task.  I believe that 
  1614. both the speed and amount of redundancy reduction can be improved 
  1615. upon.  I am therefore publishing the source code for what I did in 
  1616. Appendix B, so that someone else may be able to build upon this idea.
  1617.  
  1618. B.  Linguistic Parsing
  1619.  
  1620. Instead of developing a Huffman code based on trigraphs or other such 
  1621. arbitrary chunks of fixed length, why not develop a Huffman code based 
  1622. on the way people read words?  Letter combinations made from statistically 
  1623. properly distributed trigraphs will probably contain a lot of valid 
  1624. English words, but they will contain a lot of garbage, too.  If, however, 
  1625. all symbols correspond to English words (or punctuation), then a collection 
  1626. of random symbols will look a lot more like English.  Of course, the 
  1627. arrangement of words will probably not make sense in either group, 
  1628. but an intuitive analysis indicates that a code based on linguistic 
  1629. parsing of words will contain a lot less redundancy than will a fixed-length 
  1630. code.
  1631.  
  1632. To define linguistic symbols, I called any grouping of alphabetic 
  1633. symbols unbroken by non-alphabetic symbols a word symbol.  I called 
  1634. any group of contiguous spaces a space symbol.  I called a carriage 
  1635. return + line feed combination a new line symbol.  Any other punctuation 
  1636. and numbers were called symbols themselves.  There may be more efficient 
  1637. ways to split up text into symbols, since, for example, words are 
  1638. almost always followed by a space.  I also counted upper and lower 
  1639. case words different symbols.  It may have been more efficient to 
  1640. use a modifier symbol to indicate that the following word is capitalized 
  1641. or written in all capitol letters.  Of course, if all of the input 
  1642. text is all upper case, as would be the case for some telegraphic 
  1643. type communications systems, this is not a concern.
  1644.  
  1645. Once a linguistic symbol is detected in the input text, it is encoded 
  1646. with its corresponding Huffman code representation.  This is then 
  1647. decoded at the other end of the communications link or after retrieving 
  1648. the data from storage, using the same Huffman code.
  1649.  
  1650. So that the Huffman code generation does not have to be done each 
  1651. time a file is compressed, an escape code that meant ``the following 
  1652. symbol of ____ bits is not in the code, and is to be interpreted directly'' 
  1653. is used.  For these symbols, a simple suppression of the most significant 
  1654. bit is used, resulting in a savings of one out of eight bits.
  1655.  
  1656. C.  Huffman Coding
  1657.  
  1658. Given a set of symbols and their associated probabilities of occurrence, 
  1659. a Huffman code for those symbols is constructed by generating a tree.  Start 
  1660. with a set of symbols as individual nodes.  While there are still 
  1661. separate nodes, combine the two nodes with the lowest probability 
  1662. (resolve ties arbitrarily) into a new node with a probability equal 
  1663. to the sum of the probabilities of the two nodes that were combined.  Attach 
  1664. one of the nodes to the new node via a 1 and the other node via a 
  1665. 0.  After all of the nodes are combined, the code for each symbol 
  1666. is the sequence of ones and zeroes assigned to the branches of the 
  1667. tree starting at the root and ending at the symbol. [STO]
  1668.  
  1669. Note that this algorithm results in a very similar code to a Shannon-Fanno 
  1670. code (which generates the tree by starting at the root and building 
  1671. out to the leaves), but it is computationally more efficient to implement.
  1672.  
  1673. D.  Pascal Programs
  1674.  
  1675. The pascal programs that implement this linguistic file compression 
  1676. are in appendix B.  The first one, COUNT, merely counts the frequency 
  1677. of occurrence of words in sample text.  It is not necessary that the 
  1678. text analyzed be the same text to be compressed, just that it be similar.  For 
  1679. example, better compression would be expected when using a code based 
  1680. on personnel records when using that code to compress personnel records 
  1681. than when compressing medical discussions.  However, the significant 
  1682. gains made in compressing the more common words in the code offset 
  1683. the lesser compression (or even possible expansion) encountered when 
  1684. words not in the code are encountered.  It is also desirable to COUNT 
  1685. a large sample of text to ensure accurate word frequencies.
  1686.  
  1687. The second program, MAKETREE takes the frequency data from the output 
  1688. file generated by COUNT and generates a Huffman code from it.  It 
  1689. then writes this tree out into a file that is used by SQUEEZE.  To 
  1690. get reasonable speed from this program, it uses as much memory as 
  1691. MS-DOS will let it for the more frequently accessed information, and 
  1692. uses a temporary file for the rest of the information.  The program 
  1693. runs significantly faster if this temporary file is on a RAM disk 
  1694. in extended or expanded memory (beyond the basic 640 KBytes of the 
  1695. MS-DOS domain).
  1696.  
  1697. SQUEEZE, the third program, does the squeezing and unsqueezing of 
  1698. files based on the output file of MAKETREE.  The same Huffman coding 
  1699. tree can be used for many different input text files, because the 
  1700. statistics of English (especially when the same types of text, such 
  1701. as all business letters or all technical reports) remain fairly constant 
  1702. even when the content of the text conveys different meanings.  SQUEEZE 
  1703. handles words not in its dictionary in stride, but highlights them 
  1704. as they scroll across the screen in processing so that the user can 
  1705. get a feel for how well the text is matched to the code tree in use. 
  1706. If only a few proper names and such are highlighted, then the code 
  1707. in use is a good one to use.  If not, then perhaps a regeneration 
  1708. of the code would be in order.  Note that the code file used to SQUEEZE 
  1709. a file must be identical to the one used to unSQUEEZE it, so it must 
  1710. either be stored or sent with the file, or sent in advance and agreed 
  1711. upon by communicating parties.
  1712.  
  1713. After testing these programs on various ASCII text files, it can be  seen that
  1714. significant compression can be obtained, and that the compressed  files can be
  1715. recovered reliably.  There is, however, room for improvement  in the exact way
  1716. that text is parsed and in the speed of the implementation.  Nevertheless, 
  1717. when maximum security is desired, I recommend first compressing an  ASCII text
  1718. file with SQUEEZE, then encrypting it with CRYPTMPJ.  The  code file
  1719. (LANGUAGE.COD) used by SQUEEZE and the encryption key should  be sent by a
  1720. separate, secure channel to the receiving party (or stored  in a physically
  1721. secure location for data storage) in advance of the  message.  The combination
  1722. of minimal natural redundancy in the message  sent and the use of a good
  1723. encryption algorithm should be difficult  to crack.
  1724.  
  1725. IX.       CONCLUSION
  1726.  
  1727. The MPJ Encryption algorithm provides an alternative to DES that is 
  1728. more secure, providing that the software and/or hardware does not 
  1729. get corrupted or tampered with, and providing that the keys are managed 
  1730. effectively.  I have implemented and tested the algorithm in software 
  1731. for the IBM PC and compatible machines.  The algorithm may be implemented 
  1732. directly in hardware for faster data rates.  The MPJ Encryption Algorithm 
  1733. may be used by itself, or it may be improved upon by compressing the 
  1734. data before encryption.
  1735.  
  1736. The use of data compression in conjunction with any encryption algorithm 
  1737. drastically increases the security of the encrypted data.  For natural 
  1738. language text, one approach that yields improved compression over 
  1739. the compression of constant size blocks of data is the compression 
  1740. of linguistic units, such as words.  I have achieved reversible compression 
  1741. of such files to less than 35% of their original size using linguistic 
  1742. parsing and a Huffman code. For binary data, such as computer programs, 
  1743. the use of existing techniques, such as those in PKARC, written by 
  1744. Phil Katz and available on most computer bulletin boards, are recommended.
  1745.  
  1746. It is hoped that the MPJ encryption algorithm, as well as some of 
  1747. my ideas on data compression, will make a positive contribution towards 
  1748. data security, communications privacy, and efficiency of data storage 
  1749. and transmission.  May God prosper those who use this knowledge and 
  1750. build upon it for good.
  1751.  
  1752. REFERENCES
  1753.  
  1754. [ALB]  Douglas J. Albert and Stephen P. Morse,``Combating 
  1755. Software Piracy by Encryption and Key Management,''Computer, 
  1756. Vol. 21, No. 5, April 1984, pp. 68-73 Los Alamitos, CA: IEEE Computer 
  1757. Society.
  1758.  
  1759. [AME]  Stanley R. Ames, Jr., Morrie Gasser, and Roger 
  1760. R. Schell, ``Security Kernel Design and Implementation:  An Introduction,'' 
  1761. Computer, Vol. 16, No. 7, July 1983, pp. 14-22 Los Alamitos, 
  1762. CA: IEEE Computer Society.
  1763.  
  1764. [BAL]  W. W. Rouse Ball & H. S. M. Coxeter, Mathematical 
  1765. Recreations & Essays.  New York:  The MacMillan Company, 1962.
  1766.  
  1767. [BAU]  Friedrich L. Bauer, ``Cryptology - Methods 
  1768. and Maxims,'' in Proceedings of the Workshop on Cryptography at 
  1769. Burg Feuerstein, Germany, March 29-April 2, 1982, Berlin, Heidelberg, 
  1770. New York: Springer-Verlag, 1983.
  1771.  
  1772. [BEK]  H. J. Beker, ``A Survey of Encryption Algorithms,'' 
  1773. in International Conference on Secure Communication Systems, 
  1774. 22-23 February 1984, London, New York: Institute of Electrical 
  1775. Engineers, 1984. TK5102.5.I519.1984
  1776.  
  1777. [BET]  Thomas Beth, Introduction to Proceedings of 
  1778. the Workshop on Cryptography at Burg Feuerstein, Germany, March 29 
  1779. - April 2, 1982, Berlin, Heidelberg, New York: Springer-Verlag, 
  1780. 1983.
  1781.  
  1782. [BON]  D. J. Bond, ``Practical Primality Testing,'' in 
  1783. International Conference on Secure Communication Systems, 22-23 
  1784. February 1984, London, New York: Institute of Electrical Engineers, 
  1785. 1984. TK5102.5.I519.1984
  1786.  
  1787. [BRO]  C. B. Brookson and S. C. Serpell, ``Security on 
  1788. the British Telecom Satstream Service'' in International Conference 
  1789. on Secure Communication Systems, 22-23 February 1984, London, 
  1790. New York: Institute of Electrical Engineers, 1984. TK5102.5.I519.1984
  1791.  
  1792. [BUR]  Dave Bursky, ``Protect Your EEPROM Data and Gain 
  1793. More Flexibility,'' Electronic Design, 26 May 1988, pp.43-48. 
  1794. Waseca, MN:  Brown Printing Co.
  1795.  
  1796. [CHA]  Leslie S. Chalmers, ``An Analysis of the Differences 
  1797. Between the Computer Security Practices in the Military and Private 
  1798. Sectors,'' in Proceedings of the IEEE 1986 Symposium on Security 
  1799. and Privacy, Oakland, CA, April 7-9, 1986. QA76.9.A25.595.1986
  1800.  
  1801. [CHI]  H. R. Chivers, ``A Practical Fast Exponentiation 
  1802. Algorithm for Public Key,'' in International Conference on Secure 
  1803. Communication Systems, 22-23 February 1984, London, New York: 
  1804. Institute of Electrical Engineers, 1984.  TK5102.5.I519.1984
  1805.  
  1806. [COO]  R. H. Cooper, ``Linear Transformations in Galois 
  1807. Fields and their Application to Cryptography,'' Cryptologia Magazine, 
  1808. Volume 4, Number 3, July 1980, pages 184-188.  Republished electronically 
  1809. by Tony Patti.
  1810.  
  1811. [COS]  Terry Costlow, ``Global Computer Network Cracks 
  1812. Cryptographic Mathematics Barrier,'' Electronic Engineering Times, 
  1813. Issue 508, 17 October 1988, p. 14, Manhasset, NY:  CMP Publications, 
  1814. Inc.
  1815.  
  1816. [CRC]  Handbook of Chemistry and Physics, 53rd 
  1817. Edition, Cleveland, OH: The Chemical Rubber Company, 1972.
  1818.  
  1819. [DEA]  Cipher A. Deavers and Louis Kruh, Machine 
  1820. Cryptography and Modern Cryptanalysis, Norwood, MA: Artech House, 
  1821. Inc., 1985.  Z103.D43.1985
  1822.  
  1823. [DEN]  Dorothy Elisabeth Robling Denning, Cryptography 
  1824. and Data Security, Reading, MA; Menlo Park, CA; London; Amsterdam; 
  1825. Don Mills, Ontario; Sydney: Addison-Wesley Publishing Company, 1982. 
  1826. QA76.9.A25.D46.1982
  1827.  
  1828. [DES]  National Bureau of Standards, Federal Information 
  1829. Processing Standards Publication Number 46 Dated 15 January 1977.
  1830.  
  1831. [DOH]  Richard Doherty, ``FBI Nabs Pirated VCII,'' Electronic 
  1832. Engineering Times, Manhasset, N. Y.:  CMP Publications, Inc., Issue 
  1833. 500, August 22, 1988.
  1834.  
  1835. [EET]  ``NSA OKs Decryption Unit,'' Electronic Engineering 
  1836. Times, August 29, 1988, Manhasset, N. Y.: CMP Publications, Inc.
  1837.  
  1838. [FRA]  Ole Immanuel Franksen, Mr. Babbage's Secret 
  1839. - The Tale of a Cipher and APL, Englewood Cliffs, NJ: Prentice-Hall, 
  1840. 1985. Z103.B2.F72.1985
  1841.  
  1842. [FRI]  H. J. Beker, J. M. K. Friend, and P. W. Halliden, 
  1843. ``Simplifying Key Management in Electronic Fund Transfer Point of 
  1844. Sale Systems,'' in International Conference on Secure Communication 
  1845. Systems, 22-23 February 1984, London, New York: Institute of 
  1846. Electrical Engineers, 1984.  TK5102.5.I519.1984
  1847.  
  1848. [FRM]  Lester J. Fraim, ``Scomp: A Solution to the Multilevel 
  1849. Security Problem,'' Computer, Vol. 16, No. 7, July 1983,pp. 
  1850. 26-34, Los Alamitos, CA: IEEE Computer Society.
  1851.  
  1852. [GOO]  G. Goos and J. Hartmans, Lecture Notes in 
  1853. Computer Science.  Z102.5.W67.1982
  1854.  
  1855. [GOR]  J. A. Gordon and H. Retkin, ``Are Big S-Boxes 
  1856. Best?'' in Proceedings of the Workshop on Cryptography at Burg 
  1857. Feuerstein, Germany, March 29-April 2, 1982, Berlin, Heidelberg, 
  1858. New York: Springer-Verlag, 1983.
  1859.  
  1860. [HAE]  D. G. Haenshke, D. A. Kettler, and E. Oberer, 
  1861. ``Network Management and Congestion in the U. S. Telecommunications 
  1862. Network,'' IEEE Transactions on Communications, volume COM-29,pp. 
  1863. 376-385, April 1981.
  1864.  
  1865. [HEL]  Gilbert Held and Thomas R. Marshall, Data 
  1866. Compression, Second Edition; Chichester, New York, Brisbane,Toronto, 
  1867. Singapore: John Wiley & Sons, 1987.  QA76.9.D33.H44.1987
  1868.  
  1869. [HIL]  Lester S. Hill, ``Cryptography in an Algebraic 
  1870. Alphabet,'' American Mathematical Monthly, June 1929, pages 
  1871. 306-312, the American Mathematical Society.  Republished electronically 
  1872. by Tony Patti by permission.
  1873.  
  1874. [HLL]  Lester S. Hill, ``Concerning Certain Linear Transformation 
  1875. Apparatus of Cryptography,'' American Mathematical Society, 
  1876. March 1931, pages 135-154.  Republished electronically by Tony Patti 
  1877. by permission.
  1878.  
  1879. [JAC]  A. M. Jackson, N. A. McEvoy, and B. B.Newman, 
  1880. ``Project Universe Encryption Experiment'' in International Conference 
  1881. on Secure Communication Systems, 22-23 February 1984, London, 
  1882. New York: Institute of Electrical Engineers, 1984. TK5102.5.I519.1984
  1883.  
  1884. [KAH]  David Kahn, The Codebreakers - The Story 
  1885. of Secret Writing, New York: The MacMillan Company, 1987. Z103.K28
  1886.  
  1887. [KRU]  Cipher A. Deavers, David Kahn, Louis Kruh, Greg 
  1888. Mellen, and Brian Winkel, Cryptology Yesterday, Today and Tomorrow, 
  1889. Norwood, MA: Artech House, Inc., 1987.  Z103.C76.1987
  1890.  
  1891. [LAN]  Carl E. Landwehr, The Best Available Technologies 
  1892. for Computer Security,'' Computer, Vol. 16, No. 7, July 1983,pp. 
  1893. 86-100, Los Alamitos, CA: IEEE Computer Society.
  1894.  
  1895. [KAT]  Phil Katz, PKARC FAST! Archive Create/Update 
  1896. Utility Version 3.5 04-27-87, published electronically in PKX35A35.EXE.
  1897.  
  1898. [KON]  Alan G. Konheim, Cryptography:  A Primer, 
  1899. New York: John Wiley & Sons.  Z103.K66
  1900.  
  1901. [KOZ]  Wladyslaw Kozaczuk, Enigma - How the German 
  1902. Machine Cipher was Broken and How it was Read by the Allies in World 
  1903. War Two, University Publications of America, Inc., 1984.D810.C88.K6813.1984
  1904.  
  1905. [LIN]  Christer Lind<130>n, ``Electronic Seal for Protection 
  1906. of Electronic Money in Sweden, Finland, and Norway'' in Proceedings 
  1907. of 1986 International Carnahan Conference on Security Technology: 
  1908. Electronic Crime Countermeasures, August 12-14, 1986. QA76.9.A25.C41.1986
  1909.  
  1910. [LOD]  N. Lodge, B. Flannaghan, and R. Morcom,``Vision 
  1911. Scrambling of C-MAC DBS Signals,'' in International Conference 
  1912. on Secure Communication Systems, 22-23 February 1984, London, 
  1913. New York: Institute of Electrical Engineers, 1984. TK5102.5.I519.1984
  1914.  
  1915. [LU]  W. P. Lu and M. K. Sandareshan, ``A Hierarchical 
  1916. Key Management Scheme for End-to-End Encryption in Internet Environments'' 
  1917. in Proceedings of the IEEE 1986 Symposium on Security and Privacy, 
  1918. Oakland, CA, April 7-9, 1986.  QA76.9.A25.595.1986
  1919.  
  1920. [MCL]  Vin McLellan, ``Drugs and DES:  A New Connection,'' 
  1921. Digital Review, August 24, 1987.
  1922.  
  1923. [MER]  Ralph C. Merkle, Secrecy, Authentication, 
  1924. and Public Key Systems, Ann Arbor, MI: UMI Research Press,1982.  QA76.9.A25M47.1982
  1925.  
  1926. [MEY]  Carl H. Meyer & Stephen M. Matyas,Cryptography:  a 
  1927. New Dimension in Computer Data Security - A Guide for the Design 
  1928. and Implementation of Secure Systems, New York, Chichester, Brisbane, 
  1929. Toronto, Singapore: John Wiley & Sons, 1982.  Z103.M55.1982
  1930.  
  1931. [MIT]  C. J. Mitchell, ``A Comparison of the Cryptographic 
  1932. Requirements for Digital Secure Speech Systems Operating at Different 
  1933. Bit Rates,'' in International Conference on Secure Communication 
  1934. Systems, 22-23 February 1984, London, New York: Institute of 
  1935. Electrical Engineers, 1984.  TK5102.5.I519.1984
  1936.  
  1937. [PAT]  Tony Patti, A Galois Field Cryptosystem, 
  1938. 1986. Published electronically by Tony Patti, editor of Cryptosystems 
  1939. Journal, 9755 Oatley Lane, Burke, VA 22015.
  1940.  
  1941. [PIP]  Fred Piper, ``Stream Ciphers,'' in Proceedings 
  1942. of the Workshop on Cryptography at Burg Feuerstein, Germany, March 
  1943. 29-April 2, 1982, Berlin, Heidelberg, New York: Springer-Verlag, 
  1944. 1983.
  1945.  
  1946. [PER]  Tekla S. Perry and Paul Wallich, ``Can Computer 
  1947. Crime be Stopped?,''  IEEE Spectrum, May, 1984, pp.34-49.  New 
  1948. York, NY: The Institute of Electrical and Electronic Engineers, Inc.
  1949.  
  1950. [RET]  H. Retkin, ``Multi-Level Knapsack Encryption,'' 
  1951. in International Conference on Secure Communication Systems, 
  1952. 22-23 February 1984, London, New York: Institute of Electrical 
  1953. Engineers, 1984. TK5102.5.I519.1984
  1954.  
  1955. [SAT]  J. Sattler and C. P. Schnorr, ``Ein Effizienzvergleich 
  1956. Der Faktorisierungsverfahren von Morrison-Brillhart und Schroeppel,'' 
  1957. in Proceedings of the Workshop on Cryptography at Burg Feuerstein, 
  1958. Germany, March 29-April 2, 1982, Berlin, Heidelberg, New York: 
  1959. Springer-Verlag, 1983.
  1960.  
  1961. [SCH]  C. P. Schnorr, ``Is the RSA Scheme Safe?'' in 
  1962. Proceedings of the Workshop on Cryptography at Burg Feuerstein, 
  1963. Germany, March 29-April 2, 1982, Berlin, Heidelberg, New York: 
  1964. Springer-Verlag, 1983.
  1965.  
  1966. [SHA]  C. E. Shannon, ``Communication Theory of Secrecy 
  1967. Systems,'' Bell System Technical Journal, Volume 28, 1949.
  1968.  
  1969. [STO]  James A. Storer, Data Compression Methods 
  1970. and Theory.  Rockville, MD:  Computer Science Press, 1988. QA76.9.D33S76
  1971.  
  1972. [TIL]  Henk C. A. van Tilborg, An Introduction to 
  1973. Cryptology, Boston, Dordrecht, Lancaster: Kluwer Academic Publishers, 
  1974. 1988.  Z103.T54.1987
  1975.  
  1976. [RET]  H. Retkin, ``Multi-Level Knapsack Encryption,'' 
  1977. in International Conference on Secure Communication Systems, 
  1978. 22-23 February 1984, London, New York: Institute of Electrical 
  1979. Engineers, 1984. TK5102.5.I519.1984
  1980.  
  1981. [ULT]  Ultron Labs Corporation, ``Crypto Module Processes 
  1982. TOP SECRET Data,'' EE Product News, October 1988, p. 16, Overland 
  1983. Park, KS: Intertec Publishing.
  1984.  
  1985. [VAN]  J. Vandewalle, R. Govaerts, W. De Becker, M. Decroos, 
  1986. & G. Speybrouk, ``RSA-Based Implementation of Public Key Cryptographic 
  1987. Protection in Office Systems'' in Proceedings of 1986 International 
  1988. Carnahan Conference on Security Technology:  Electronic Crime Countermeasures, 
  1989. August 12-14, 1986.  QA76.9.A25.C41.1986
  1990.  
  1991. APPENDIX A.  MPJ in Pascal
  1992.  
  1993. {$R-}    {Range checking off}
  1994.  
  1995. {$S-}    {Stack checking off}
  1996.  
  1997. {$I+}    {I/O checking on}
  1998.  
  1999. {$N-}    {Don't use 80x87 numeric coprocessor}
  2000.  
  2001. program cryptmpj;
  2002.  
  2003. { Encryption designed to exceed DES in security value and be implementable 
  2004. on
  2005.  
  2006.   an IBM PC compatible machine. }
  2007.  
  2008.  
  2009.  
  2010. Uses Crt, Dos;  { Include screen handling & MS DOS interface functions. 
  2011. }
  2012.  
  2013.  
  2014.  
  2015. const maxinbuffer = 16;
  2016.  
  2017.       ap = #39;                            { Apostrophe for write 
  2018. statements. }
  2019.  
  2020.  
  2021.  
  2022. type blocks = array[0..15] of byte;             { 16 byte (128 bit) 
  2023. blocks. }
  2024.  
  2025.      stype = array[0..9,0..15,0..255] of byte;  { Holds substitution 
  2026. boxes. }
  2027.  
  2028.      ptrstype = ^stype;  { Dynamic variable required to get beyond 
  2029. 64K limit. }
  2030.  
  2031.      string80 = string[80];                     { Long character strings. 
  2032. }
  2033.  
  2034.      string15 = string[15];                     { Short character 
  2035. strings. }
  2036.  
  2037.  
  2038.  
  2039. var initial,                  { Initialiazation vector. }
  2040.  
  2041.     feedback,                 { Chaining feedback array. }
  2042.  
  2043.     key,                      { Encryption/decryption key. }
  2044.  
  2045.     buffer, outbuf:  blocks;  { File read/write buffers. }
  2046.  
  2047.     s,                        { Substitution boxes. }
  2048.  
  2049.     si: ptrstype;             { Inverse substitution boxes. }
  2050.  
  2051.     bytesdone,                { Number of bytes done. }
  2052.  
  2053.     number: longint;          { Used to read in key & initialization 
  2054. vector. }
  2055.  
  2056.     que,                      { Position in file specification que. 
  2057. }
  2058.  
  2059.     i, j, k,                  { Iteration & array indexes. }
  2060.  
  2061.     actualread: integer;      { Actual number of bytes read in from 
  2062. file. }
  2063.  
  2064.     inputfile: file;          { File to encrypt or decrypt in place. 
  2065. }
  2066.  
  2067.     keyfile: text;            { External key file. }
  2068.  
  2069.     intkeyfile: file of stype; {Holds s and si. }
  2070.  
  2071.     keyname,                  { Name of external key file. }
  2072.  
  2073.     intkeyname,               { Name of internal key file. }
  2074.  
  2075.     path,                     { Used in parsing file specification. 
  2076. }
  2077.  
  2078.     temp: string[255];        { Used in determining encrypt/decrypt 
  2079. option. }
  2080.  
  2081.     inputfilename,            { MS-DOS name of inputfile. }
  2082.  
  2083.     filespec: string80;       { File specification that may include 
  2084. wild cards}
  2085.  
  2086.     fileque: array[0..15] of string80; { Names of multiple file specifications}
  2087.  
  2088.     name: string15;           { Name of next file to process. }
  2089.  
  2090.     decryption,               { True iff decryption is desired. }
  2091.  
  2092.     filefound: boolean;       { At least one file was found to process.}
  2093.  
  2094.     ch: char;                 { Character input. }
  2095.  
  2096.     search: searchrec;        { Used in finding matches to wild cards. 
  2097. }
  2098.  
  2099.  
  2100.  
  2101. procedure permute(x: blocks; var y: blocks);
  2102.  
  2103. { This procedure is designed to make each bit of the output dependent 
  2104. on as
  2105.  
  2106.   many bytes of the input as possible, especially after repeated application.
  2107.  
  2108.   Each output byte takes its least significant bit from the corresponding
  2109.  
  2110.   input byte.  The next higher bit comes from the corresponding bit 
  2111. of the
  2112.  
  2113.   input byte to the left.  This is done until all bits of the output 
  2114. byte
  2115.  
  2116.   are filled.  Where there is no byte to the left, the byte at the 
  2117. far right
  2118.  
  2119.   is used. }
  2120.  
  2121.  
  2122.  
  2123.   begin
  2124.  
  2125.     y[0] := (x[0] and 1) or (x[1] and 2) or (x[2] and 4) or
  2126.  
  2127.             (x[3] and 8) or (x[4] and 16) or (x[5] and 32) or
  2128.  
  2129.             (x[6] and 64) or (x[7] and 128);
  2130.  
  2131.     y[1] := (x[1] and 1) or (x[2] and 2) or (x[3] and 4) or
  2132.  
  2133.             (x[4] and 8) or (x[5] and 16) or (x[6] and 32) or
  2134.  
  2135.             (x[7] and 64) or (x[8] and 128);
  2136.  
  2137.     y[2] := (x[2] and 1) or (x[3] and 2) or (x[4] and 4) or
  2138.  
  2139.             (x[5] and 8) or (x[6] and 16) or (x[7] and 32) or
  2140.  
  2141.             (x[8] and 64) or (x[9] and 128);
  2142.  
  2143.     y[3] := (x[3] and 1) or (x[4] and 2) or (x[5] and 4) or
  2144.  
  2145.             (x[6] and 8) or (x[7] and 16) or (x[8] and 32) or
  2146.  
  2147.             (x[9] and 64) or (x[10] and 128);
  2148.  
  2149.     y[4] := (x[4] and 1) or (x[5] and 2) or (x[6] and 4) or
  2150.  
  2151.             (x[7] and 8) or (x[8] and 16) or (x[9] and 32) or
  2152.  
  2153.             (x[10] and 64) or (x[11] and 128);
  2154.  
  2155.     y[5] := (x[5] and 1) or (x[6] and 2) or (x[7] and 4) or
  2156.  
  2157.             (x[8] and 8) or (x[9] and 16) or (x[10] and 32) or
  2158.  
  2159.             (x[11] and 64) or (x[12] and 128);
  2160.  
  2161.     y[6] := (x[6] and 1) or (x[7] and 2) or (x[8] and 4) or
  2162.  
  2163.             (x[9] and 8) or (x[10] and 16) or (x[11] and 32) or
  2164.  
  2165.             (x[12] and 64) or (x[13] and 128);
  2166.  
  2167.     y[7] := (x[7] and 1) or (x[8] and 2) or (x[9] and 4) or
  2168.  
  2169.             (x[10] and 8) or (x[11] and 16) or (x[12] and 32) or
  2170.  
  2171.             (x[13] and 64) or (x[14] and 128);
  2172.  
  2173.     y[8] := (x[8] and 1) or (x[9] and 2) or (x[10] and 4) or
  2174.  
  2175.             (x[11] and 8) or (x[12] and 16) or (x[13] and 32) or
  2176.  
  2177.             (x[14] and 64) or (x[15] and 128);
  2178.  
  2179.     y[9] := (x[9] and 1) or (x[10] and 2) or (x[11] and 4) or
  2180.  
  2181.             (x[12] and 8) or (x[13] and 16) or (x[14] and 32) or
  2182.  
  2183.             (x[15] and 64) or (x[0] and 128);
  2184.  
  2185.     y[10] := (x[10] and 1) or (x[11] and 2) or (x[12] and 4) or
  2186.  
  2187.             (x[13] and 8) or (x[14] and 16) or (x[15] and 32) or
  2188.  
  2189.             (x[0] and 64) or (x[1] and 128);
  2190.  
  2191.     y[11] := (x[11] and 1) or (x[12] and 2) or (x[13] and 4) or
  2192.  
  2193.             (x[14] and 8) or (x[15] and 16) or (x[0] and 32) or
  2194.  
  2195.             (x[1] and 64) or (x[2] and 128);
  2196.  
  2197.     y[12] := (x[12] and 1) or (x[13] and 2) or (x[14] and 4) or
  2198.  
  2199.             (x[15] and 8) or (x[0] and 16) or (x[1] and 32) or
  2200.  
  2201.             (x[2] and 64) or (x[3] and 128);
  2202.  
  2203.     y[13] := (x[13] and 1) or (x[14] and 2) or (x[15] and 4) or
  2204.  
  2205.             (x[0] and 8) or (x[1] and 16) or (x[2] and 32) or
  2206.  
  2207.             (x[3] and 64) or (x[4] and 128);
  2208.  
  2209.     y[14] := (x[14] and 1) or (x[15] and 2) or (x[0] and 4) or
  2210.  
  2211.             (x[1] and 8) or (x[2] and 16) or (x[3] and 32) or
  2212.  
  2213.             (x[4] and 64) or (x[5] and 128);
  2214.  
  2215.     y[15] := (x[15] and 1) or (x[0] and 2) or (x[1] and 4) or
  2216.  
  2217.             (x[2] and 8) or (x[3] and 16) or (x[4] and 32) or
  2218.  
  2219.             (x[5] and 64) or (x[6] and 128);
  2220.  
  2221.   end;
  2222.  
  2223.  
  2224.  
  2225. procedure ipermute(x: blocks; var y: blocks);
  2226.  
  2227. { This is the inverse of the procedure permute. }
  2228.  
  2229.  
  2230.  
  2231.   begin
  2232.  
  2233.     y[0] := (x[0] and 1) or (x[15] and 2) or (x[14] and 4) or
  2234.  
  2235.             (x[13] and 8) or (x[12] and 16) or (x[11] and 32) or
  2236.  
  2237.             (x[10] and 64) or (x[9] and 128);
  2238.  
  2239.     y[1] := (x[1] and 1) or (x[0] and 2) or (x[15] and 4) or
  2240.  
  2241.             (x[14] and 8) or (x[13] and 16) or (x[12] and 32) or
  2242.  
  2243.             (x[11] and 64) or (x[10] and 128);
  2244.  
  2245.     y[2] := (x[2] and 1) or (x[1] and 2) or (x[0] and 4) or
  2246.  
  2247.             (x[15] and 8) or (x[14] and 16) or (x[13] and 32) or
  2248.  
  2249.             (x[12] and 64) or (x[11] and 128);
  2250.  
  2251.     y[3] := (x[3] and 1) or (x[2] and 2) or (x[1] and 4) or
  2252.  
  2253.             (x[0] and 8) or (x[15] and 16) or (x[14] and 32) or
  2254.  
  2255.             (x[13] and 64) or (x[12] and 128);
  2256.  
  2257.     y[4] := (x[4] and 1) or (x[3] and 2) or (x[2] and 4) or
  2258.  
  2259.             (x[1] and 8) or (x[0] and 16) or (x[15] and 32) or
  2260.  
  2261.             (x[14] and 64) or (x[13] and 128);
  2262.  
  2263.     y[5] := (x[5] and 1) or (x[4] and 2) or (x[3] and 4) or
  2264.  
  2265.             (x[2] and 8) or (x[1] and 16) or (x[0] and 32) or
  2266.  
  2267.             (x[15] and 64) or (x[14] and 128);
  2268.  
  2269.     y[6] := (x[6] and 1) or (x[5] and 2) or (x[4] and 4) or
  2270.  
  2271.             (x[3] and 8) or (x[2] and 16) or (x[1] and 32) or
  2272.  
  2273.             (x[0] and 64) or (x[15] and 128);
  2274.  
  2275.     y[7] := (x[7] and 1) or (x[6] and 2) or (x[5] and 4) or
  2276.  
  2277.             (x[4] and 8) or (x[3] and 16) or (x[2] and 32) or
  2278.  
  2279.             (x[1] and 64) or (x[0] and 128);
  2280.  
  2281.     y[8] := (x[8] and 1) or (x[7] and 2) or (x[6] and 4) or
  2282.  
  2283.             (x[5] and 8) or (x[4] and 16) or (x[3] and 32) or
  2284.  
  2285.             (x[2] and 64) or (x[1] and 128);
  2286.  
  2287.     y[9] := (x[9] and 1) or (x[8] and 2) or (x[7] and 4) or
  2288.  
  2289.             (x[6] and 8) or (x[5] and 16) or (x[4] and 32) or
  2290.  
  2291.             (x[3] and 64) or (x[2] and 128);
  2292.  
  2293.     y[10] := (x[10] and 1) or (x[9] and 2) or (x[8] and 4) or
  2294.  
  2295.             (x[7] and 8) or (x[6] and 16) or (x[5] and 32) or
  2296.  
  2297.             (x[4] and 64) or (x[3] and 128);
  2298.  
  2299.     y[11] := (x[11] and 1) or (x[10] and 2) or (x[9] and 4) or
  2300.  
  2301.             (x[8] and 8) or (x[7] and 16) or (x[6] and 32) or
  2302.  
  2303.             (x[5] and 64) or (x[4] and 128);
  2304.  
  2305.     y[12] := (x[12] and 1) or (x[11] and 2) or (x[10] and 4) or
  2306.  
  2307.             (x[9] and 8) or (x[8] and 16) or (x[7] and 32) or
  2308.  
  2309.             (x[6] and 64) or (x[5] and 128);
  2310.  
  2311.     y[13] := (x[13] and 1) or (x[12] and 2) or (x[11] and 4) or
  2312.  
  2313.             (x[10] and 8) or (x[9] and 16) or (x[8] and 32) or
  2314.  
  2315.             (x[7] and 64) or (x[6] and 128);
  2316.  
  2317.     y[14] := (x[14] and 1) or (x[13] and 2) or (x[12] and 4) or
  2318.  
  2319.             (x[11] and 8) or (x[10] and 16) or (x[9] and 32) or
  2320.  
  2321.             (x[8] and 64) or (x[7] and 128);
  2322.  
  2323.     y[15] := (x[15] and 1) or (x[14] and 2) or (x[13] and 4) or
  2324.  
  2325.             (x[12] and 8) or (x[11] and 16) or (x[10] and 32) or
  2326.  
  2327.             (x[9] and 64) or (x[8] and 128);
  2328.  
  2329.   end;
  2330.  
  2331.  
  2332.  
  2333. procedure makesbox(key: blocks);
  2334.  
  2335. { This procedure generates internal keys by filling the substitution 
  2336. box array
  2337.  
  2338.   s^ based on the external key given as input. }
  2339.  
  2340.   var i, j, k: integer;
  2341.  
  2342.   procedure makeonebox(i, j: integer; key: blocks);
  2343.  
  2344.     var pos, m, n, p, startbit, bitmask, startbyte, keybyte: word;
  2345.  
  2346.         empty: array[0..255] of boolean;
  2347.  
  2348.     begin
  2349.  
  2350.       for m := 0 to 255 do    { The empty array is used to make sure 
  2351. that }
  2352.  
  2353.         empty[m] := true;     { each byte of the array is filled only 
  2354. once. }
  2355.  
  2356.       startbit := 1;
  2357.  
  2358.       startbyte := 0;
  2359.  
  2360.       for n := 255 downto 128 do  { n counts the number of bytes left 
  2361. to fill }
  2362.  
  2363.         begin
  2364.  
  2365.           keybyte := startbyte;
  2366.  
  2367.           bitmask := startbit;
  2368.  
  2369.           m := 0;
  2370.  
  2371.           for p := 0 to 7 do   { m is obtained by bit selection on 
  2372. the key }
  2373.  
  2374.             begin
  2375.  
  2376.               m := m or (key[keybyte] and bitmask);
  2377.  
  2378.               bitmask := bitmask shl 1;
  2379.  
  2380.               if bitmask > 128 then
  2381.  
  2382.                 begin
  2383.  
  2384.                   bitmask := 1;
  2385.  
  2386.                   inc(keybyte);
  2387.  
  2388.                   if keybyte > 15 then keybyte := 0;
  2389.  
  2390.                 end;
  2391.  
  2392.             end;
  2393.  
  2394.           pos := (n * m) div 255;  { pos is the position among the 
  2395. UNFILLED }
  2396.  
  2397.           m := 0;                  { components of the s^ array that 
  2398. the    }
  2399.  
  2400.           p := 0;                  { number n should be placed.  }
  2401.  
  2402.           while m < pos do
  2403.  
  2404.             begin
  2405.  
  2406.               inc(p);
  2407.  
  2408.               if empty[p] then inc(m);
  2409.  
  2410.             end;
  2411.  
  2412.           while not empty[p] do inc(p);
  2413.  
  2414.           s^[i, j, p] := n;
  2415.  
  2416.           empty[p] := false;
  2417.  
  2418.           startbit := startbit shl 1;  { The starting position of 
  2419. the bit  }
  2420.  
  2421.           if startbit > 128 then       { selection for the key is 
  2422. rotated  }
  2423.  
  2424.             begin                      { left one bit for the next 
  2425. n.      }
  2426.  
  2427.               startbit := 1;
  2428.  
  2429.               inc(startbyte);
  2430.  
  2431.               if startbyte > 15 then startbyte := 0
  2432.  
  2433.             end;
  2434.  
  2435.         end;
  2436.  
  2437.       startbyte := 0;
  2438.  
  2439.       startbit := 1;
  2440.  
  2441.       for n := 127 downto 1 do         { This half of the algorithm 
  2442. is the   }
  2443.  
  2444.         begin                          { same as the upper half, except 
  2445. that }
  2446.  
  2447.           keybyte := startbyte;        { only 7 bits are selected 
  2448. for m.     }
  2449.  
  2450.           bitmask := startbit;
  2451.  
  2452.           m := 0;
  2453.  
  2454.           for p := 0 to 6 do
  2455.  
  2456.             begin
  2457.  
  2458.               m := m or (key[keybyte] and bitmask);
  2459.  
  2460.               bitmask := bitmask shl 1;
  2461.  
  2462.               if bitmask > 64 then
  2463.  
  2464.                 begin
  2465.  
  2466.                   bitmask := 1;
  2467.  
  2468.                   keybyte := keybyte + 3;
  2469.  
  2470.                   if keybyte > 15 then keybyte := keybyte - 16;
  2471.  
  2472.                 end;
  2473.  
  2474.             end;
  2475.  
  2476.           pos := (n * m) div 127;
  2477.  
  2478.           m := 0;
  2479.  
  2480.           p := 0;
  2481.  
  2482.           while m < pos do
  2483.  
  2484.             begin
  2485.  
  2486.               inc(p);
  2487.  
  2488.               if empty[p] then inc(m);
  2489.  
  2490.             end;
  2491.  
  2492.           while not empty[p] do inc(p);
  2493.  
  2494.           s^[i, j, p] := n;
  2495.  
  2496.           empty[p] := false;
  2497.  
  2498.           startbit := startbit shl 1;
  2499.  
  2500.           if startbit > 64 then
  2501.  
  2502.             begin
  2503.  
  2504.               startbit := 1;
  2505.  
  2506.               inc(startbyte);
  2507.  
  2508.               if startbyte > 15 then startbyte := 0
  2509.  
  2510.             end;
  2511.  
  2512.         end;
  2513.  
  2514.       p := 0;
  2515.  
  2516.       while not empty[p] do
  2517.  
  2518.         inc(p);
  2519.  
  2520.       s^[i,j,p] := 0;
  2521.  
  2522.     end;
  2523.  
  2524.  
  2525.  
  2526.   begin
  2527.  
  2528.     new(s);
  2529.  
  2530.     for i := 0 to 9 do
  2531.  
  2532.       for j := 0 to 15 do
  2533.  
  2534.         begin
  2535.  
  2536.           write(#13,'Filling substitution boxes for round ',i+1,' 
  2537. of 10, byte ',
  2538.  
  2539.                 j+1,' of 16.  ');
  2540.  
  2541.           makeonebox(i, j, key);
  2542.  
  2543.           permute(key, key);            { Shuffle key bit positions.        }
  2544.  
  2545.           for k := 0 to 15 do           { Run key through last s-box 
  2546. before }
  2547.  
  2548.             key[k] := s^[i, j, key[k]]; { making the next s-box.            }
  2549.  
  2550.         end;
  2551.  
  2552.     writeln;
  2553.  
  2554.   end;
  2555.  
  2556.  
  2557.  
  2558. procedure makesi;
  2559.  
  2560. { This procedure fills the inverse substitution box array si^.  It 
  2561. is not
  2562.  
  2563.   necessary to call this procedure unless the decryption mode is used.  }
  2564.  
  2565.   var i, j, k: integer;
  2566.  
  2567.   begin
  2568.  
  2569.     new(si);
  2570.  
  2571.     for i := 0 to 9 do
  2572.  
  2573.       for j := 0 to 15 do
  2574.  
  2575.         for k := 0 to 255 do
  2576.  
  2577.           si^[i, j, s^[i, j, k]] := k;
  2578.  
  2579.   end;
  2580.  
  2581.  
  2582.  
  2583. {$I CRYPTINC.PAS}   { Include additional file handling & user interface. 
  2584. }
  2585.  
  2586.  
  2587.  
  2588. procedure substitute(round: integer; x: blocks; var y: blocks);
  2589.  
  2590. var i: integer;
  2591.  
  2592. begin
  2593.  
  2594.   for i := 0 to 15 do
  2595.  
  2596.     y[i] := s^[round,i,x[i]];
  2597.  
  2598. end;
  2599.  
  2600.  
  2601.  
  2602. procedure isubst(round: integer; x: blocks; var y: blocks);
  2603.  
  2604. var i: integer;
  2605.  
  2606. begin
  2607.  
  2608.   for i := 0 to 15 do
  2609.  
  2610.     y[i] := si^[round,i,x[i]];
  2611.  
  2612. end;
  2613.  
  2614.  
  2615.  
  2616. procedure encrypt(x: blocks; var y: blocks);
  2617.  
  2618. { Encrypt a block of 16 bytes. }
  2619.  
  2620. var z: blocks;
  2621.  
  2622. begin
  2623.  
  2624.   substitute(0, x, y);
  2625.  
  2626.   permute(y, z);
  2627.  
  2628.   substitute(1, z, y);
  2629.  
  2630.   permute(y, z);
  2631.  
  2632.   substitute(2, z, y);
  2633.  
  2634.   permute(y, z);
  2635.  
  2636.   substitute(3, z, y);
  2637.  
  2638.   permute(y, z);
  2639.  
  2640.   substitute(4, z, y);
  2641.  
  2642.   permute(y, z);
  2643.  
  2644.   substitute(5, z, y);
  2645.  
  2646.   permute(y, z);
  2647.  
  2648.   substitute(6, z, y);
  2649.  
  2650.   permute(y, z);
  2651.  
  2652.   substitute(7, z, y);
  2653.  
  2654.   permute(y, z);
  2655.  
  2656.   substitute(8, z, y);
  2657.  
  2658.   permute(y, z);
  2659.  
  2660.   substitute(9, z, y);
  2661.  
  2662. end;
  2663.  
  2664.  
  2665.  
  2666. procedure decrypt(x: blocks; var y: blocks);
  2667.  
  2668. { Decrypt a block of 16 bytes. }
  2669.  
  2670. var z: blocks;
  2671.  
  2672. begin
  2673.  
  2674.   isubst(9, x, y);
  2675.  
  2676.   ipermute(y, z);
  2677.  
  2678.   isubst(8, z, y);
  2679.  
  2680.   ipermute(y, z);
  2681.  
  2682.   isubst(7, z, y);
  2683.  
  2684.   ipermute(y, z);
  2685.  
  2686.   isubst(6, z, y);
  2687.  
  2688.   ipermute(y, z);
  2689.  
  2690.   isubst(5, z, y);
  2691.  
  2692.   ipermute(y, z);
  2693.  
  2694.   isubst(4, z, y);
  2695.  
  2696.   ipermute(y, z);
  2697.  
  2698.   isubst(3, z, y);
  2699.  
  2700.   ipermute(y, z);
  2701.  
  2702.   isubst(2, z, y);
  2703.  
  2704.   ipermute(y, z);
  2705.  
  2706.   isubst(1, z, y);
  2707.  
  2708.   ipermute(y, z);
  2709.  
  2710.   isubst(0, z, y);
  2711.  
  2712. end;
  2713.  
  2714.  
  2715.  
  2716. begin
  2717.  
  2718.   startup;  { Initialize files, call makesbox (and makesi if required). 
  2719. }
  2720.  
  2721.   que := 0;
  2722.  
  2723.   while (que < 16) and (fileque[que] <> '') do
  2724.  
  2725.     begin
  2726.  
  2727.       filespec := fileque[que];
  2728.  
  2729.       inputfilename := filespec;
  2730.  
  2731.       path := '';
  2732.  
  2733.       repeat
  2734.  
  2735.         i := pos('\',inputfilename);
  2736.  
  2737.         if i > 0 then
  2738.  
  2739.           begin
  2740.  
  2741.             path := path + copy(inputfilename, 1, i);
  2742.  
  2743.             inputfilename := copy(inputfilename, i+1, length(inputfilename));
  2744.  
  2745.           end;
  2746.  
  2747.       until i = 0;
  2748.  
  2749.       findfirst(filespec, $22, search);
  2750.  
  2751.       while doserror = 0 do
  2752.  
  2753.         begin
  2754.  
  2755.           inputfilename := path + search.name;
  2756.  
  2757.           assign(inputfile, inputfilename);
  2758.  
  2759.           reset(inputfile,1);
  2760.  
  2761.           filefound := true;
  2762.  
  2763.           bytesdone := 0;
  2764.  
  2765.           for i := 0 to 15 do
  2766.  
  2767.             feedback[i] := initial[i];
  2768.  
  2769.           if decryption then
  2770.  
  2771.            begin
  2772.  
  2773.             writeln('Decrypting ',inputfilename);
  2774.  
  2775.             while not eof(inputfile) do
  2776.  
  2777.               begin
  2778.  
  2779.                 blockread(inputfile,buffer,maxinbuffer,actualread);
  2780.  
  2781.                 encrypt(feedback,outbuf);
  2782.  
  2783.                 { Note that decrypt is not ever called when using 
  2784. block
  2785.  
  2786.                   chaining with ciphertext feedback.  It would be 
  2787. called
  2788.  
  2789.                   if the electronic codebook mode were used, instead. 
  2790. }
  2791.  
  2792.                 for i := 0 to 15 do
  2793.  
  2794.                   begin
  2795.  
  2796.                     outbuf[i] := outbuf[i] xor buffer[i];
  2797.  
  2798.                     feedback[i] := buffer[i]
  2799.  
  2800.                   end;
  2801.  
  2802.                 seek(inputfile, filepos(inputfile) - actualread);
  2803.  
  2804.                 blockwrite(inputfile, outbuf, actualread);
  2805.  
  2806.                 bytesdone := bytesdone + actualread;
  2807.  
  2808.                 write(#13, bytesdone:9,' bytes decrypted. ');
  2809.  
  2810.               end;
  2811.  
  2812.             writeln(#13, bytesdone:9,' bytes decrypted.  ');
  2813.  
  2814.            end
  2815.  
  2816.           else
  2817.  
  2818.            begin
  2819.  
  2820.             writeln('Encrypting ',inputfilename);
  2821.  
  2822.             while not eof(inputfile) do
  2823.  
  2824.               begin
  2825.  
  2826.                 blockread(inputfile,buffer,maxinbuffer,actualread);
  2827.  
  2828.                 encrypt(feedback,outbuf);
  2829.  
  2830.                 for i := 0 to 15 do
  2831.  
  2832.                   begin
  2833.  
  2834.                     outbuf[i] := outbuf[i] xor buffer[i];
  2835.  
  2836.                     feedback[i] := outbuf[i]
  2837.  
  2838.                   end;
  2839.  
  2840.                 seek(inputfile, filepos(inputfile) - actualread);
  2841.  
  2842.                 blockwrite(inputfile, outbuf, actualread);
  2843.  
  2844.                 bytesdone := bytesdone + actualread;
  2845.  
  2846.                 write(#13, bytesdone:9,' bytes encrypted.  ');
  2847.  
  2848.               end;
  2849.  
  2850.             writeln(#13, bytesdone:9,' bytes encrypted.  ');
  2851.  
  2852.            end;
  2853.  
  2854.           close(inputfile);
  2855.  
  2856.           findnext(search);
  2857.  
  2858.         end;
  2859.  
  2860.       inc(que);
  2861.  
  2862.     end;
  2863.  
  2864.   if not filefound then writeln('No matching files found.');
  2865.  
  2866.   writeln('Done.');
  2867.  
  2868. end.
  2869.  
  2870. APPENDIX B.  Linguistic Data Compression Programs
  2871.  
  2872. program count;
  2873.  
  2874. {Program to count the probability of occurances of words in text.}
  2875.  
  2876.  
  2877.  
  2878. uses dos, crt;
  2879.  
  2880. const maxbuf = 4096;
  2881.  
  2882.       maxstr = 15;
  2883.  
  2884.       ap = #39;
  2885.  
  2886.  
  2887.  
  2888. type wd = string[maxstr];
  2889.  
  2890.      ptr = ^entry;
  2891.  
  2892.      yarn = string[80];
  2893.  
  2894.      entry = record
  2895.  
  2896.                wrd:  wd;        {Linguistic word}
  2897.  
  2898.                count: longint;  {How many times this word was found}
  2899.  
  2900.                next: ptr;       {Next record in sequence}
  2901.  
  2902.              end;
  2903.  
  2904.  
  2905.  
  2906. var outfile,             {File with output report}
  2907.  
  2908.     infile: text;        {File with input text to be analyzed}
  2909.  
  2910.     bottom,              {Last entry record}
  2911.  
  2912.     newbuf,              {New entry record}
  2913.  
  2914.     prev: ptr;           {Previous entry record}
  2915.  
  2916.     buffer,              {Current entry record}
  2917.  
  2918.     top: array[1..255] of ptr;  {First entry record}
  2919.  
  2920.     words: wd;           {Word under construction}
  2921.  
  2922.     temp,
  2923.  
  2924.     path,                    {Path of input file}
  2925.  
  2926.     filemask,                {File name mask}
  2927.  
  2928.     filespec,                {Path + name (including wild cards)}
  2929.  
  2930.     inname,                  {Name of input file}
  2931.  
  2932.     outname: yarn;           {Name of output file}
  2933.  
  2934.     ch: char;
  2935.  
  2936.     i, j, cmdparameter, topindex: integer;
  2937.  
  2938.     cnt: longint;
  2939.  
  2940.     filefound: boolean;
  2941.  
  2942.     inbuf, outbuf: array[1..maxbuf] of byte;
  2943.  
  2944.     s: searchrec;           {Record fill: array[1..21] of byte;attr:byte;time,
  2945.  
  2946.                               size:longint;name: string[12]}
  2947.  
  2948.  
  2949.  
  2950. function exist(filename: wd): boolean;
  2951.  
  2952. {Returns TRUE iff the file exists.}
  2953.  
  2954. var f: file;
  2955.  
  2956. begin {exist}
  2957.  
  2958.   assign(f,filename);
  2959.  
  2960.   {$I-}
  2961.  
  2962.   reset(f);
  2963.  
  2964.   {$I+}
  2965.  
  2966.   if IOresult = 0 then
  2967.  
  2968.     begin
  2969.  
  2970.       exist := true;
  2971.  
  2972.       close(f)
  2973.  
  2974.     end
  2975.  
  2976.   else
  2977.  
  2978.     exist := false;
  2979.  
  2980. end;  {exist}
  2981.  
  2982.  
  2983.  
  2984. function punct(ch: char): boolean;
  2985.  
  2986. {TRUE iff ch is not a letter or chr(255).}
  2987.  
  2988.   var c:  integer;
  2989.  
  2990.   begin
  2991.  
  2992.     c := ord(ch);
  2993.  
  2994.     if ((c > 10) and (c <= 64)) or ((c >= 91) and (c <= 96))
  2995.  
  2996.     or ((c >= 123) and (c <= 254)) or ((c > 0) and (c < 10)) then
  2997.  
  2998.       punct := true
  2999.  
  3000.     else
  3001.  
  3002.       punct := false;
  3003.  
  3004.   end;
  3005.  
  3006.  
  3007.  
  3008. function letter(ch: char): boolean;
  3009.  
  3010. {TRUE iff ch is a letter A-Z or a-z.}
  3011.  
  3012.   var c: integer;
  3013.  
  3014.   begin
  3015.  
  3016.     c := ord(ch);
  3017.  
  3018.     if ((c >= 65) and (c <= 90)) or ((c >= 97) and (c <= 122)) then
  3019.  
  3020.       letter := true
  3021.  
  3022.     else
  3023.  
  3024.       letter := false;
  3025.  
  3026.   end;
  3027.  
  3028.  
  3029.  
  3030. procedure parse(var words: wd; var ch: char);
  3031.  
  3032. {Extracts a word or item of punctuation from input file.}
  3033.  
  3034.   begin  {parse}
  3035.  
  3036.     words := '';
  3037.  
  3038.     while not (letter(ch) or punct(ch) or eof(infile)) do
  3039.  
  3040.       begin
  3041.  
  3042.         read(infile,ch);
  3043.  
  3044.       end;
  3045.  
  3046.     if punct(ch) then
  3047.  
  3048.       begin
  3049.  
  3050.         if ord(ch) = 13 then
  3051.  
  3052.           begin
  3053.  
  3054.             words := chr(255)+chr(255);
  3055.  
  3056.             if not eof(infile) then read(infile, ch);
  3057.  
  3058.           end
  3059.  
  3060.         else
  3061.  
  3062.           if ch = ' ' then
  3063.  
  3064.             begin
  3065.  
  3066.               words := ch;
  3067.  
  3068.               while (not eof(infile)) and (ch = ' ') and (length(words) 
  3069. < maxstr) do
  3070.  
  3071.                 begin
  3072.  
  3073.                   read(infile,ch);
  3074.  
  3075.                   if ch = ' ' then words := words + ch;
  3076.  
  3077.                 end;
  3078.  
  3079.               if (length(words) = maxstr) and (not eof(infile)) then
  3080.  
  3081.                 read(infile,ch);
  3082.  
  3083.             end
  3084.  
  3085.           else
  3086.  
  3087.             begin
  3088.  
  3089.               words := ch; {return one punctuation character}
  3090.  
  3091.               if not eof(infile) then read(infile, ch);
  3092.  
  3093.             end;
  3094.  
  3095.       end
  3096.  
  3097.     else
  3098.  
  3099.       begin
  3100.  
  3101.         if letter(ch) then
  3102.  
  3103.           begin
  3104.  
  3105.             words := ch;
  3106.  
  3107.             while (not eof(infile)) and letter(ch) and (length(words) 
  3108. < maxstr) do
  3109.  
  3110.               begin
  3111.  
  3112.                 read(infile,ch);
  3113.  
  3114.                 if letter(ch) then words := words + ch;
  3115.  
  3116.               end;
  3117.  
  3118.             if (length(words) = maxstr) and (not eof(infile)) then
  3119.  
  3120.               read(infile,ch);
  3121.  
  3122.           end;
  3123.  
  3124.       end;
  3125.  
  3126.   end;  {parse}
  3127.  
  3128.  
  3129.  
  3130. procedure update(words: wd);
  3131.  
  3132. {Increments the count associated with a word.}
  3133.  
  3134.   begin
  3135.  
  3136.     topindex := ord(words[1]);
  3137.  
  3138.     buffer[topindex] := top[topindex];
  3139.  
  3140.     {Find record that matches word, if it exists.}
  3141.  
  3142.     while (buffer[topindex]^.wrd < words) and (buffer[topindex]^.next 
  3143. <> nil) do
  3144.  
  3145.       begin
  3146.  
  3147.         prev := buffer[topindex];
  3148.  
  3149.         buffer[topindex] := buffer[topindex]^.next
  3150.  
  3151.       end;
  3152.  
  3153.  
  3154.  
  3155.     if buffer[topindex]^.wrd = words then
  3156.  
  3157.       {Increment count on word that already exists}
  3158.  
  3159.       inc(buffer[topindex]^.count)
  3160.  
  3161.     else
  3162.  
  3163.       begin  {Add word to middle of list with count of one}
  3164.  
  3165.         new(newbuf);
  3166.  
  3167.         newbuf^.wrd := words;
  3168.  
  3169.         newbuf^.count := 1;
  3170.  
  3171.         newbuf^.next := prev^.next;
  3172.  
  3173.         prev^.next := newbuf;
  3174.  
  3175.       end;
  3176.  
  3177.   end;
  3178.  
  3179.  
  3180.  
  3181. procedure report;
  3182.  
  3183. {Produces a report file.}
  3184.  
  3185.   var total: longint;
  3186.  
  3187.   begin
  3188.  
  3189.     assign(outfile, paramstr(1));
  3190.  
  3191.     rewrite(outfile);
  3192.  
  3193.     total := 0;
  3194.  
  3195.     for topindex := 1 to 255 do
  3196.  
  3197.       begin
  3198.  
  3199.         buffer[topindex] := top[topindex];
  3200.  
  3201.         while (buffer[topindex]^.next <> nil) do
  3202.  
  3203.           begin
  3204.  
  3205.             buffer[topindex] := buffer[topindex]^.next;
  3206.  
  3207.             if buffer[topindex]^.count > 0 then
  3208.  
  3209.               begin
  3210.  
  3211.                 writeln(outfile,buffer[topindex]^.wrd);
  3212.  
  3213.                 writeln(outfile,buffer[topindex]^.count);
  3214.  
  3215.                 total := total + buffer[topindex]^.count;
  3216.  
  3217.               end;
  3218.  
  3219.           end;
  3220.  
  3221.       end;
  3222.  
  3223.     writeln(outfile, chr(255));
  3224.  
  3225.     writeln(outfile, '1');
  3226.  
  3227.     writeln(outfile, 'Total count:  ',total);
  3228.  
  3229.     close(outfile);
  3230.  
  3231.   end; {report}
  3232.  
  3233.  
  3234.  
  3235. begin
  3236.  
  3237.   clrscr;
  3238.  
  3239.   writeln('  This program counts words in a set    This program may 
  3240. be copied freely ');
  3241.  
  3242.   writeln('  of input files to determine their     for educational 
  3243. use or to try it  ');
  3244.  
  3245.   writeln('  frequency of occurance.  This data    out.  If you like 
  3246. it, donations   ');
  3247.  
  3248.   writeln('  is then stored in a file for use by   will be accepted 
  3249. by the author.   ');
  3250.  
  3251.   writeln('  MAKETREE, which constructs a code     This program is 
  3252. believed to be    ');
  3253.  
  3254.   writeln('  tree with the Huffman algorithm.      reliable, but it 
  3255. is the user',ap,'s    ');
  3256.  
  3257.   writeln('  The code tree is used by SQUEEZE.     responsibility 
  3258. to determine its   ');
  3259.  
  3260.   writeln('                                        fitness for use.  No 
  3261. liability    ');
  3262.  
  3263.   writeln('  Mike Johnson                          will be assumed 
  3264. by the author.    ');
  3265.  
  3266.   writeln('  P. O. Box 1151                        Copyright (C) 1988 
  3267. Mike Johnson.  ');
  3268.  
  3269.   writeln('  Longmont, CO 80502-1151               All rights reserved.              ');
  3270.  
  3271.   if paramcount < 2 then
  3272.  
  3273.     begin
  3274.  
  3275.       writeln;
  3276.  
  3277.       writeln('Syntax: COUNT outputfilename inputfilename[s]');
  3278.  
  3279.       writeln('        input file names may include * and ?');
  3280.  
  3281.       writeln('        Input files are assumed to be ASCII text.');
  3282.  
  3283.       writeln;
  3284.  
  3285.       writeln('If a previous COUNT ouput file named LANGUAGE.OUT exists, 
  3286. then new counts');
  3287.  
  3288.       writeln('will be added to the counts in LANGUAGE.OUT.');
  3289.  
  3290.       writeln('Maximum effectiveness will be obtained if the nature 
  3291. of the files COUNTed');
  3292.  
  3293.       writeln('is similar to the nature of the files to be compressed 
  3294. with SQUEEZE.');
  3295.  
  3296.     end
  3297.  
  3298.   else
  3299.  
  3300.     begin
  3301.  
  3302.       filefound := false;
  3303.  
  3304.       new(bottom);
  3305.  
  3306.       bottom^.wrd := chr(255);
  3307.  
  3308.       bottom^.count := 0;
  3309.  
  3310.       bottom^.next := nil;
  3311.  
  3312.       for topindex := 1 to 255 do
  3313.  
  3314.         begin
  3315.  
  3316.           new(top[topindex]);
  3317.  
  3318.           top[topindex]^.wrd := chr(1);
  3319.  
  3320.           top[topindex]^.count := 0;
  3321.  
  3322.           top[topindex]^.next := bottom;
  3323.  
  3324.           buffer[topindex] := top[topindex];
  3325.  
  3326.         end;
  3327.  
  3328.       ch := chr(0);
  3329.  
  3330.       words := '                              ';
  3331.  
  3332.  
  3333.  
  3334.       if exist('LANGUAGE.OUT') then
  3335.  
  3336.         begin
  3337.  
  3338.           assign(infile,'LANGUAGE.OUT');
  3339.  
  3340.           reset(infile);
  3341.  
  3342.           writeln('Reading in existing LANGUAGE.OUT.');
  3343.  
  3344.           while (not eof(infile)) and (words <> chr(255)) do
  3345.  
  3346.             begin
  3347.  
  3348.               readln(infile,words);
  3349.  
  3350.               if words <> chr(255) then
  3351.  
  3352.                 begin
  3353.  
  3354.                   topindex := ord(words[1]);
  3355.  
  3356.                   readln(infile,cnt);
  3357.  
  3358.                   new(newbuf);
  3359.  
  3360.                   newbuf^.wrd := words;
  3361.  
  3362.                   newbuf^.count := cnt;
  3363.  
  3364.                   newbuf^.next := bottom;
  3365.  
  3366.                   buffer[topindex]^.next := newbuf;
  3367.  
  3368.                   buffer[topindex] := newbuf;
  3369.  
  3370.                   write(#13,words,'            ');
  3371.  
  3372.                 end;
  3373.  
  3374.             end;
  3375.  
  3376.           close(infile);
  3377.  
  3378.           writeln;
  3379.  
  3380.         end;
  3381.  
  3382.  
  3383.  
  3384.       {Initialize input files.}
  3385.  
  3386.       for cmdparameter := 2 to paramcount do
  3387.  
  3388.         begin
  3389.  
  3390.           filespec := paramstr(cmdparameter);
  3391.  
  3392.           filemask := filespec;
  3393.  
  3394.           path := '';
  3395.  
  3396.           repeat
  3397.  
  3398.             i := pos('\',filemask);
  3399.  
  3400.             if i > 0 then
  3401.  
  3402.               begin
  3403.  
  3404.                 path := path + copy(filemask, 1, i);
  3405.  
  3406.                 filemask := copy(filemask, i+1, length(filemask));
  3407.  
  3408.               end;
  3409.  
  3410.           until i = 0;
  3411.  
  3412.           findfirst(filespec, readonly + hidden + archive, s);
  3413.  
  3414.           while doserror = 0 do
  3415.  
  3416.             begin
  3417.  
  3418.               filefound := true;
  3419.  
  3420.               inname := path + s.name;
  3421.  
  3422.               assign(infile, inname);
  3423.  
  3424.               reset(infile);
  3425.  
  3426.               words := '                              ';
  3427.  
  3428.   writeln('>>>>>>>>>>>>>>>>>>>>> Processing ',inname);
  3429.  
  3430.               while (not eof(infile)) and (words <> '') and (not keypressed) 
  3431. do
  3432.  
  3433.                 begin
  3434.  
  3435.                   parse(words,ch);     {Find word or punctuation}
  3436.  
  3437.                   if words = chr(255)+chr(255) then
  3438.  
  3439.                     writeln
  3440.  
  3441.                   else
  3442.  
  3443.                     write(words);
  3444.  
  3445.                   if length(words) > 0 then
  3446.  
  3447.                     update(words);     {Increment word counter}
  3448.  
  3449.                 end;
  3450.  
  3451.               close(infile);
  3452.  
  3453.               findnext(s);
  3454.  
  3455.             end;
  3456.  
  3457.         end;
  3458.  
  3459.  
  3460.  
  3461.       if not filefound then writeln('No matching files found.');
  3462.  
  3463.       report;
  3464.  
  3465.     end;
  3466.  
  3467. end.
  3468.  
  3469. {$R+}
  3470.  
  3471. {$M 3072,4096,655360}
  3472.  
  3473. program maketree;
  3474.  
  3475.  
  3476.  
  3477. uses crt;
  3478.  
  3479. const maxstr = 15;
  3480.  
  3481.       ap = #39;
  3482.  
  3483.  
  3484.  
  3485. type wd = string[maxstr];
  3486.  
  3487.      yarn = string[80];
  3488.  
  3489.      mem = ^mementry;
  3490.  
  3491.      entry = record
  3492.  
  3493.                wrd:  wd;        {Which linguistic word in input file}
  3494.  
  3495.                memory: mem;     {Corresponding mementry.}
  3496.  
  3497.              end;
  3498.  
  3499.  
  3500.  
  3501.      mementry = record
  3502.  
  3503.                   count: longint; {Word count.}
  3504.  
  3505.                   onezero: byte;  {Is this record pointed to by 1 
  3506. or 0?}
  3507.  
  3508.                   root,           {Position of record nearer root.}
  3509.  
  3510.                   next:  mem;     {Position of next record.}
  3511.  
  3512.                 end;
  3513.  
  3514.  
  3515.  
  3516. var temp: file of entry; {Temporary file}
  3517.  
  3518.     infile: text;        {File with input text to be analyzed}
  3519.  
  3520.     buffer,              {Current entry record}
  3521.  
  3522.     newbuf: entry;       {New entry record}
  3523.  
  3524.     mtop,
  3525.  
  3526.     mbottom,
  3527.  
  3528.     mbuffer,
  3529.  
  3530.     mnewbuf,
  3531.  
  3532.     mprev: mem;
  3533.  
  3534.     inname,              {Name of input file}
  3535.  
  3536.     outname,             {Name of output file}
  3537.  
  3538.     words: wd;           {Word under construction}
  3539.  
  3540.     ch: char;
  3541.  
  3542.     cnt1,
  3543.  
  3544.     cnt2,
  3545.  
  3546.     cnt:  longint;
  3547.  
  3548.     i, j: integer;
  3549.  
  3550.     tempname: yarn;
  3551.  
  3552.  
  3553.  
  3554. function exist(filename: wd): boolean;
  3555.  
  3556. {Returns TRUE iff the file exists.}
  3557.  
  3558. var f: file;
  3559.  
  3560. begin {exist}
  3561.  
  3562.   assign(f,filename);
  3563.  
  3564.   {$I-}
  3565.  
  3566.   reset(f);
  3567.  
  3568.   {$I+}
  3569.  
  3570.   if IOresult = 0 then
  3571.  
  3572.     begin
  3573.  
  3574.       exist := true;
  3575.  
  3576.       close(f)
  3577.  
  3578.     end
  3579.  
  3580.   else
  3581.  
  3582.     exist := false;
  3583.  
  3584. end;  {exist}
  3585.  
  3586.  
  3587.  
  3588. procedure fanno;
  3589.  
  3590.   begin
  3591.  
  3592.     cnt1 := 0;
  3593.  
  3594.     repeat
  3595.  
  3596.  
  3597.  
  3598.       {Find smallest two records.}
  3599.  
  3600.       mprev := mtop^.next;
  3601.  
  3602.       mbuffer := mprev^.next;
  3603.  
  3604.  
  3605.  
  3606.       {Combine lowest 2 probabilities of counts.}
  3607.  
  3608.       mtop^.next := mbuffer^.next;
  3609.  
  3610.       new(mnewbuf);
  3611.  
  3612.       mnewbuf^.count := mbuffer^.count + mprev^.count;
  3613.  
  3614.       mnewbuf^.onezero := 2;
  3615.  
  3616.       mnewbuf^.root := nil;
  3617.  
  3618.       mprev^.root := mnewbuf;
  3619.  
  3620.       mprev^.onezero := 1;
  3621.  
  3622.       mbuffer^.root := mnewbuf;
  3623.  
  3624.       mbuffer^.onezero := 0;
  3625.  
  3626.  
  3627.  
  3628.       {Place combined entry in proper place in chain.}
  3629.  
  3630.       mbuffer := mtop;
  3631.  
  3632.       repeat
  3633.  
  3634.         mprev := mbuffer;
  3635.  
  3636.         mbuffer := mbuffer^.next;
  3637.  
  3638.       until (mnewbuf^.count <= mbuffer^.count);
  3639.  
  3640.       mprev^.next := mnewbuf;
  3641.  
  3642.       mnewbuf^.next := mbuffer;
  3643.  
  3644.  
  3645.  
  3646.       {Check for completion.}
  3647.  
  3648.       inc(cnt1);
  3649.  
  3650.       write(#13,cnt1,' nodes combined.  ');
  3651.  
  3652.     until (cnt1 >= cnt2);
  3653.  
  3654.   end;  {fanno}
  3655.  
  3656.  
  3657.  
  3658. procedure placeit;
  3659.  
  3660.   begin
  3661.  
  3662.         write(#13,cnt:11,' ',words,'          ');
  3663.  
  3664.         mbuffer := mtop;
  3665.  
  3666.         repeat
  3667.  
  3668.           mprev := mbuffer;
  3669.  
  3670.           mbuffer := mbuffer^.next;
  3671.  
  3672.         until mbuffer^.count >= cnt;
  3673.  
  3674.         new(mnewbuf);
  3675.  
  3676.         newbuf.wrd := words;
  3677.  
  3678.         newbuf.memory := mnewbuf;
  3679.  
  3680.     write(temp,newbuf);
  3681.  
  3682.         mnewbuf^.count := cnt;
  3683.  
  3684.         mnewbuf^.onezero := 2;
  3685.  
  3686.     mnewbuf^.root := nil;
  3687.  
  3688.         mnewbuf^.next := mbuffer;
  3689.  
  3690.         mprev^.next := mnewbuf;
  3691.  
  3692.   end;
  3693.  
  3694.  
  3695.  
  3696. procedure filegen;
  3697.  
  3698. var cod: file of byte;
  3699.  
  3700.     ascnum: yarn;
  3701.  
  3702.     c: char;
  3703.  
  3704.     b, d: byte;
  3705.  
  3706.     i, shifter: integer;
  3707.  
  3708.  
  3709.  
  3710.   begin
  3711.  
  3712.     assign(cod,outname);
  3713.  
  3714.     rewrite(cod);
  3715.  
  3716.     reset(temp);
  3717.  
  3718.     repeat
  3719.  
  3720.       read(temp,buffer);
  3721.  
  3722.       mbuffer := buffer.memory;
  3723.  
  3724.       if buffer.wrd <> '' then
  3725.  
  3726.     begin
  3727.  
  3728.           for i := 0 to length(buffer.wrd) do
  3729.  
  3730.             begin
  3731.  
  3732.               b := ord(buffer.wrd[i]);
  3733.  
  3734.               write(cod,b);
  3735.  
  3736.             end;
  3737.  
  3738.           ascnum := '';
  3739.  
  3740.           while (mbuffer^.root <> nil) do
  3741.  
  3742.             begin
  3743.  
  3744.               if mbuffer^.onezero = 0 then
  3745.  
  3746.                 ascnum := ascnum + '0'
  3747.  
  3748.               else
  3749.  
  3750.                 ascnum := ascnum + '1';
  3751.  
  3752.               mbuffer := mbuffer^.root;
  3753.  
  3754.             end;
  3755.  
  3756.           d := ord(ascnum[0]);
  3757.  
  3758.           write(cod,d);
  3759.  
  3760.           shifter := 1;
  3761.  
  3762.           b := 0;
  3763.  
  3764.           for i := d downto 1 do
  3765.  
  3766.             begin
  3767.  
  3768.               if ascnum[i] = '1' then b := b + shifter;
  3769.  
  3770.               shifter := shifter shl 1;
  3771.  
  3772.               if shifter >= 256 then
  3773.  
  3774.                 begin
  3775.  
  3776.                   write(cod,b);
  3777.  
  3778.                   b := 0;
  3779.  
  3780.                   shifter := 1
  3781.  
  3782.                 end;
  3783.  
  3784.             end;
  3785.  
  3786.           if shifter > 1 then write(cod,b);
  3787.  
  3788.           write(#13,buffer.wrd:maxstr,' = ',ascnum,'                           ');
  3789.  
  3790.         end;
  3791.  
  3792.     until eof(temp);
  3793.  
  3794.     close(cod);
  3795.  
  3796.     close(temp);
  3797.  
  3798.     erase(temp);
  3799.  
  3800.   end;
  3801.  
  3802.  
  3803.  
  3804. begin
  3805.  
  3806.   clrscr;
  3807.  
  3808.   writeln('  MAKETREE takes the word count         This program may 
  3809. be copied freely ');
  3810.  
  3811.   writeln('  data created by COUNT and creates     for educational 
  3812. use or to try it  ');
  3813.  
  3814.   writeln('  a code tree using the Huffman         out.  If you like 
  3815. it, donations   ');
  3816.  
  3817.   writeln('  algorithm.  The resulting code tree   will be accepted 
  3818. by the author.   ');
  3819.  
  3820.   writeln('  is used by SQUEEZE when it            This program is 
  3821. believed to be    ');
  3822.  
  3823.   writeln('  compresses ASCII text files.          reliable, but it 
  3824. is the user',ap,'s    ');
  3825.  
  3826.   writeln('                                        responsibility 
  3827. to determine its   ');
  3828.  
  3829.   writeln('                                        fitness for use.  No 
  3830. liability    ');
  3831.  
  3832.   writeln('  Mike Johnson                          will be assumed 
  3833. by the author.    ');
  3834.  
  3835.   writeln('  P. O. Box 1151                        Copyright (C) 1988 
  3836. Mike Johnson.  ');
  3837.  
  3838.   writeln('  Longmont, CO 80502-1151               All rights reserved.              ');
  3839.  
  3840.   if paramcount < 2 then
  3841.  
  3842.     begin
  3843.  
  3844.       writeln('Syntax: MAKETREE infile outfile [tempfile]');
  3845.  
  3846.       writeln('                 infile is input file name (generated 
  3847. by COUNT)');
  3848.  
  3849.       writeln('                 outfile is output file name to be 
  3850. used by SQUEEZE');
  3851.  
  3852.       writeln('                 tempfile is filename to use for temporary 
  3853. file');
  3854.  
  3855.       writeln('The temporary file is best put on a RAM disk in extended 
  3856. or expanded memory,');
  3857.  
  3858.       writeln('but a hard disk or even a floppy will do if that is 
  3859. the fastest you have.');
  3860.  
  3861.       writeln('Don',ap,'t use a RAM disk in conventional (lower 640K) 
  3862. memory, as this program');
  3863.  
  3864.       writeln('already uses most of that in generating the coding 
  3865. tree.');
  3866.  
  3867.     end
  3868.  
  3869.   else
  3870.  
  3871.     begin
  3872.  
  3873.       inname := paramstr(1);
  3874.  
  3875.       outname := paramstr(2);
  3876.  
  3877.       if exist(inname) then
  3878.  
  3879.         begin
  3880.  
  3881.           assign(infile,inname);
  3882.  
  3883.           reset(infile);
  3884.  
  3885.         end
  3886.  
  3887.       else
  3888.  
  3889.         begin
  3890.  
  3891.           writeln('Unable to open ',inname);
  3892.  
  3893.           exit
  3894.  
  3895.         end;
  3896.  
  3897.       if paramcount > 2 then
  3898.  
  3899.         tempname := paramstr(3)
  3900.  
  3901.       else
  3902.  
  3903.         tempname := 'ZYXWVUTS.$$$';
  3904.  
  3905.       assign(temp,tempname);
  3906.  
  3907.       {$I- }
  3908.  
  3909.       rewrite(temp);
  3910.  
  3911.       {$I+ }
  3912.  
  3913.       if ioresult <> 0 then
  3914.  
  3915.         begin
  3916.  
  3917.           writeln('I/O error attempting to open temporary file ',tempname);
  3918.  
  3919.           halt;
  3920.  
  3921.         end;
  3922.  
  3923.       new(mtop);
  3924.  
  3925.       new(mbottom);
  3926.  
  3927.       mtop^.count := -1;
  3928.  
  3929.       mtop^.onezero := 2;
  3930.  
  3931.       mtop^.root := nil;
  3932.  
  3933.       mtop^.next := mbottom;
  3934.  
  3935.       mbottom^.count := 2147483647;
  3936.  
  3937.       mbottom^.onezero := 2;
  3938.  
  3939.       mbottom^.root := nil;
  3940.  
  3941.       mbottom^.next := nil;
  3942.  
  3943.       cnt2 := 2;
  3944.  
  3945.       writeln('Reading in and sorting word frequency data.');
  3946.  
  3947.       repeat
  3948.  
  3949.         readln(infile,words);
  3950.  
  3951.         readln(infile,cnt);
  3952.  
  3953.         placeit;
  3954.  
  3955.         inc(cnt2);
  3956.  
  3957.       until (words = chr(255)) or eof(infile);
  3958.  
  3959.       close(infile);
  3960.  
  3961.       words := chr(255) + chr(255);
  3962.  
  3963.       placeit;
  3964.  
  3965.       words := words + chr(255);
  3966.  
  3967.       placeit;
  3968.  
  3969.       words := words + chr(255);
  3970.  
  3971.       placeit;
  3972.  
  3973.       writeln(#13,cnt2,' nodes to add to Huffman coding tree.                  ');
  3974.  
  3975.       fanno;
  3976.  
  3977.       writeln;
  3978.  
  3979.       writeln('Writing output file.');
  3980.  
  3981.       filegen;
  3982.  
  3983.       writeln(#13,'Done.                                          ');
  3984.  
  3985.     end;
  3986.  
  3987. end.
  3988.  
  3989. {$R+}
  3990.  
  3991. {$M 2048,4096,655360}
  3992.  
  3993. program squash;
  3994.  
  3995.  
  3996.  
  3997. uses dos, crt;
  3998.  
  3999.  
  4000.  
  4001. const maxbuf = 4096;
  4002.  
  4003.       maxstr = 15;
  4004.  
  4005.       ap = #39;
  4006.  
  4007.  
  4008.  
  4009. type wd = string[maxstr];
  4010.  
  4011.      yarn = string[80];
  4012.  
  4013.      ptr = ^entry;
  4014.  
  4015.      entry = record
  4016.  
  4017.                wrd:  wd;        {Linguistic word}
  4018.  
  4019.                count:  byte;    {How many bits in code}
  4020.  
  4021.                code: longint;   {Code (right justified in 4 byte integer)}
  4022.  
  4023.                next: ptr;       {Pointer to next entry}
  4024.  
  4025.              end;
  4026.  
  4027.  
  4028.  
  4029. var outfile,                 {File with output report}
  4030.  
  4031.     infile: file;            {File with input text to be analyzed}
  4032.  
  4033.     temp,
  4034.  
  4035.     path,                    {Path of input file}
  4036.  
  4037.     filemask,                {File name mask}
  4038.  
  4039.     filespec,                {Path + name (including wild cards)}
  4040.  
  4041.     inname,                  {Name of input file}
  4042.  
  4043.     outname: yarn;           {Name of output file}
  4044.  
  4045.     words: wd;               {Word under construction}
  4046.  
  4047.     ch: char;
  4048.  
  4049.     top,
  4050.  
  4051.     bottom: array[1..32] of ptr;
  4052.  
  4053.     last,
  4054.  
  4055.     newbuf,
  4056.  
  4057.     newline,
  4058.  
  4059.     endfile,
  4060.  
  4061.     buf: ptr;
  4062.  
  4063.     mask,
  4064.  
  4065.     masked,
  4066.  
  4067.     place,
  4068.  
  4069.     long,
  4070.  
  4071.     cd,
  4072.  
  4073.     cnt:  longint;
  4074.  
  4075.     infilepos,              {Current position in input file buffer}
  4076.  
  4077.     inbitpos,               {Current bit mask in input file buffer}
  4078.  
  4079.     inbytes,                {Actual number of bytes read}
  4080.  
  4081.     outfilepos,             {Current position in output file buffer}
  4082.  
  4083.     outbitpos,              {Current bit mask in output file buffer}
  4084.  
  4085.     outbytes:  word;        {Actual number of bytes to write}
  4086.  
  4087.     cmdparameter,           {Command line parameter number}
  4088.  
  4089.     start,                  {Starting point for command line file 
  4090. name scan}
  4091.  
  4092.     strlen,
  4093.  
  4094.     bite,
  4095.  
  4096.     b, i, j, k, m: integer;
  4097.  
  4098.     squish, filefound, done: boolean;
  4099.  
  4100.     outbite:  byte;
  4101.  
  4102.     inbuf,
  4103.  
  4104.     outbuf: array[1..maxbuf] of byte;
  4105.  
  4106.     s: searchrec;           {Record fill: array[1..21] of byte;attr:byte;time,
  4107.  
  4108.                               size:longint;name: string[12]}
  4109.  
  4110.  
  4111.  
  4112. function exist(filename: yarn): boolean;
  4113.  
  4114. {Returns TRUE iff the file exists.}
  4115.  
  4116. var f: file;
  4117.  
  4118. begin {exist}
  4119.  
  4120.   assign(f,filename);
  4121.  
  4122.   {$I-}
  4123.  
  4124.   reset(f);
  4125.  
  4126.   {$I+}
  4127.  
  4128.   if IOresult = 0 then
  4129.  
  4130.     begin
  4131.  
  4132.       exist := true;
  4133.  
  4134.       close(f)
  4135.  
  4136.     end
  4137.  
  4138.   else
  4139.  
  4140.     exist := false;
  4141.  
  4142. end;  {exist}
  4143.  
  4144.  
  4145.  
  4146. procedure getbit(var b: integer);
  4147.  
  4148. begin
  4149.  
  4150.   if infilepos = 0 then
  4151.  
  4152.     begin
  4153.  
  4154.       if eof(infile) then
  4155.  
  4156.         done := true
  4157.  
  4158.       else
  4159.  
  4160.         begin
  4161.  
  4162.           blockread(infile, inbuf, maxbuf, inbytes);
  4163.  
  4164.           infilepos := 1;
  4165.  
  4166.           inbitpos := 1;
  4167.  
  4168.         end;
  4169.  
  4170.     end;
  4171.  
  4172.   if not done then
  4173.  
  4174.     begin
  4175.  
  4176.       b := inbuf[infilepos] and inbitpos;
  4177.  
  4178.       if b > 0 then b := 1;
  4179.  
  4180.       inbitpos := inbitpos shl 1;
  4181.  
  4182.       if inbitpos > 128 then
  4183.  
  4184.         begin
  4185.  
  4186.           inbitpos := 1;
  4187.  
  4188.           inc(infilepos);
  4189.  
  4190.           if infilepos > inbytes then infilepos := 0;
  4191.  
  4192.         end;
  4193.  
  4194.     end;
  4195.  
  4196. end;
  4197.  
  4198.  
  4199.  
  4200. procedure getbite(var b: integer);
  4201.  
  4202. begin
  4203.  
  4204.   if infilepos = 0 then
  4205.  
  4206.     begin
  4207.  
  4208.       if eof(infile) then
  4209.  
  4210.        begin
  4211.  
  4212.         done := true;
  4213.  
  4214.         b := 0
  4215.  
  4216.        end
  4217.  
  4218.       else
  4219.  
  4220.         begin
  4221.  
  4222.           blockread(infile, inbuf, maxbuf, inbytes);
  4223.  
  4224.           infilepos := 1;
  4225.  
  4226.         end;
  4227.  
  4228.     end;
  4229.  
  4230.   if not done then
  4231.  
  4232.     begin
  4233.  
  4234.       if inbitpos > 1 then
  4235.  
  4236.         begin
  4237.  
  4238.           inc(infilepos);
  4239.  
  4240.           writeln('Bit sync error in getbite!')
  4241.  
  4242.         end;
  4243.  
  4244.       b := inbuf[infilepos];
  4245.  
  4246.       inbitpos := 1;
  4247.  
  4248.       inc(infilepos);
  4249.  
  4250.       if infilepos > inbytes then infilepos := 0;
  4251.  
  4252.     end;
  4253.  
  4254. end;
  4255.  
  4256.  
  4257.  
  4258. procedure putbit(b: integer);
  4259.  
  4260. begin
  4261.  
  4262.   if (b > 1) or (b < 0) then writeln('Bad data passed to putbit.');
  4263.  
  4264.   outbite := outbite or (outbitpos * b);
  4265.  
  4266.   outbitpos := outbitpos shl 1;
  4267.  
  4268.   if outbitpos > 128 then
  4269.  
  4270.     begin
  4271.  
  4272.       inc(outfilepos);
  4273.  
  4274.       outbuf[outfilepos] := outbite;
  4275.  
  4276.       outbite := 0;
  4277.  
  4278.       outbitpos := 1;
  4279.  
  4280.       if outfilepos >= maxbuf then
  4281.  
  4282.         begin
  4283.  
  4284.           blockwrite(outfile, outbuf, maxbuf, outbytes);
  4285.  
  4286.           if outbytes < maxbuf then
  4287.  
  4288.             begin
  4289.  
  4290.               writeln('Disk full error.');
  4291.  
  4292.               done := true;
  4293.  
  4294.             end;
  4295.  
  4296.           outfilepos := 0;
  4297.  
  4298.         end;
  4299.  
  4300.     end;
  4301.  
  4302. end;
  4303.  
  4304.  
  4305.  
  4306. procedure putbite(b: integer);
  4307.  
  4308. begin
  4309.  
  4310.   if (b > 255) or (b < 0) then writeln('Bad data passed to putbite.');
  4311.  
  4312.   outbite := b;
  4313.  
  4314.   inc(outfilepos);
  4315.  
  4316.   outbuf[outfilepos] := outbite;
  4317.  
  4318.   outbite := 0;
  4319.  
  4320.   outbitpos := 1;
  4321.  
  4322.   if outfilepos >= maxbuf then
  4323.  
  4324.     begin
  4325.  
  4326.       blockwrite(outfile, outbuf, maxbuf, outbytes);
  4327.  
  4328.       if outbytes < maxbuf then
  4329.  
  4330.         begin
  4331.  
  4332.           writeln('Disk full error.');
  4333.  
  4334.           done := true;
  4335.  
  4336.         end;
  4337.  
  4338.       outfilepos := 0;
  4339.  
  4340.     end;
  4341.  
  4342. end;
  4343.  
  4344.  
  4345.  
  4346. procedure flushbit;
  4347.  
  4348. begin
  4349.  
  4350.   if outbitpos > 1 then
  4351.  
  4352.     begin
  4353.  
  4354.       inc(outfilepos);
  4355.  
  4356.       outbuf[outfilepos] := outbite;
  4357.  
  4358.     end;
  4359.  
  4360.   blockwrite(outfile, outbuf, outfilepos, outbytes);
  4361.  
  4362.   outbite := 0;
  4363.  
  4364.   outbitpos := 1;
  4365.  
  4366.   outfilepos := 0;
  4367.  
  4368. end;
  4369.  
  4370.  
  4371.  
  4372. function punct(ch: char): boolean;
  4373.  
  4374. {TRUE iff ch is not a letter or chr(255).}
  4375.  
  4376.   var c:  integer;
  4377.  
  4378.   begin
  4379.  
  4380.     c := ord(ch);
  4381.  
  4382.     if ((c > 10) and (c <= 64)) or ((c >= 91) and (c <= 96))
  4383.  
  4384.     or ((c >= 123) and (c <= 254)) or ((c > 0) and (c < 10)) then
  4385.  
  4386.       punct := true
  4387.  
  4388.     else
  4389.  
  4390.       punct := false;
  4391.  
  4392.   end;
  4393.  
  4394.  
  4395.  
  4396. function letter(ch: char): boolean;
  4397.  
  4398. {TRUE iff ch is a letter A-Z or a-z.}
  4399.  
  4400.   var c: integer;
  4401.  
  4402.   begin
  4403.  
  4404.     c := ord(ch);
  4405.  
  4406.     if ((c >= 65) and (c <= 90)) or ((c >= 97) and (c <= 122)) then
  4407.  
  4408.       letter := true
  4409.  
  4410.     else
  4411.  
  4412.       letter := false;
  4413.  
  4414.   end;
  4415.  
  4416.  
  4417.  
  4418.  
  4419.  
  4420.  
  4421.  
  4422. procedure parse(var words: wd; var ch: char);
  4423.  
  4424. {Extracts a word or item of punctuation from input file.}
  4425.  
  4426.   var byt: integer;
  4427.  
  4428.   begin  {parse}
  4429.  
  4430.     words := '';
  4431.  
  4432.     while not (letter(ch) or punct(ch) or done) do
  4433.  
  4434.       begin
  4435.  
  4436.         getbite(byt);
  4437.  
  4438.         ch := chr(byt);
  4439.  
  4440.       end;
  4441.  
  4442.     if punct(ch) then
  4443.  
  4444.       begin
  4445.  
  4446.         if ord(ch) = 13 then
  4447.  
  4448.           begin
  4449.  
  4450.             words := chr(255)+chr(255);
  4451.  
  4452.             if not done then begin getbite(byt); ch := chr(byt) end;
  4453.  
  4454.           end
  4455.  
  4456.         else
  4457.  
  4458.           if ch = ' ' then
  4459.  
  4460.             begin
  4461.  
  4462.               words := ch;
  4463.  
  4464.               while (not done) and (ch = ' ') and (length(words) < maxstr) do
  4465.  
  4466.                 begin
  4467.  
  4468.                   getbite(byt);
  4469.  
  4470.                   ch := chr(byt);
  4471.  
  4472.                   if ch = ' ' then words := words + ch;
  4473.  
  4474.                 end;
  4475.  
  4476.               if (length(words) = maxstr) and (not done) then
  4477.  
  4478.                 begin
  4479.  
  4480.                   getbite(byt);
  4481.  
  4482.                   ch := chr(byt)
  4483.  
  4484.                 end;
  4485.  
  4486.             end
  4487.  
  4488.           else
  4489.  
  4490.             begin
  4491.  
  4492.               words := ch; {return one punctuation character}
  4493.  
  4494.               if not done then begin getbite(byt); ch := chr(byt) end;
  4495.  
  4496.             end;
  4497.  
  4498.       end
  4499.  
  4500.     else
  4501.  
  4502.       begin
  4503.  
  4504.         if letter(ch) then
  4505.  
  4506.           begin
  4507.  
  4508.             words := ch;
  4509.  
  4510.             while (not done) and letter(ch) and (length(words) < maxstr) 
  4511. do
  4512.  
  4513.               begin
  4514.  
  4515.                 getbite(byt);
  4516.  
  4517.                 ch := chr(byt);
  4518.  
  4519.                 if letter(ch) then words := words + ch;
  4520.  
  4521.               end;
  4522.  
  4523.             if (length(words) = maxstr) and (not done) then
  4524.  
  4525.               begin
  4526.  
  4527.                 getbite(byt);
  4528.  
  4529.                 ch := chr(byt)
  4530.  
  4531.               end;
  4532.  
  4533.           end;
  4534.  
  4535.       end;
  4536.  
  4537.   end;  {parse}
  4538.  
  4539.  
  4540.  
  4541. begin
  4542.  
  4543.   clrscr;
  4544.  
  4545.   writeln('  SQUEEZE is designed to remove         This program may 
  4546. be copied freely ');
  4547.  
  4548.   writeln('  redundancy from ASCII text files,     for educational 
  4549. use or to try it  ');
  4550.  
  4551.   writeln('  making them smaller for transmission  out.  If you like 
  4552. it, donations   ');
  4553.  
  4554.   writeln('  and storage.  It also improves the    will be accepted 
  4555. by the author.   ');
  4556.  
  4557.   writeln('  security of files encrypted after     This program is 
  4558. believed to be    ');
  4559.  
  4560.   writeln('  SQUEEZING.  It uses LANGUAGE.COD,     reliable, but it 
  4561. is the user',ap,'s    ');
  4562.  
  4563.   writeln('  created with COUNT and MAKETREE.      responsibility 
  4564. to determine its   ');
  4565.  
  4566.   writeln('                                        fitness for use.  No 
  4567. liability    ');
  4568.  
  4569.   writeln('  Mike Johnson                          will be assumed 
  4570. by the author.    ');
  4571.  
  4572.   writeln('  P. O. Box 1151                        Copyright (C) 1988 
  4573. Mike Johnson.  ');
  4574.  
  4575.   writeln('  Longmont, CO 80502-1151               All rights reserved.              ');
  4576.  
  4577.   if (paramcount < 3) then
  4578.  
  4579.     begin
  4580.  
  4581.       writeln;
  4582.  
  4583.       writeln('Syntax: SQUEEZE a|s|u|x outputfile inputfile(s)');
  4584.  
  4585.       writeln('a and s both mean add or squash, u and x both mean 
  4586. unsquash or extract.');
  4587.  
  4588.       writeln('Input and output files must be different.');
  4589.  
  4590.       writeln('Input file name(s) may include wild cards.');
  4591.  
  4592.       writeln('LANGUAGE.COD  (made with MAKETREE) must be in default 
  4593. directory.');
  4594.  
  4595.     end
  4596.  
  4597.   else
  4598.  
  4599.     begin
  4600.  
  4601.       {Read in language code dictionary.}
  4602.  
  4603.       assign(infile,'LANGUAGE.COD');
  4604.  
  4605.       reset(infile,1);
  4606.  
  4607.       infilepos := 0;
  4608.  
  4609.       inbitpos := 1;
  4610.  
  4611.       done := eof(infile);
  4612.  
  4613.       newline := nil;
  4614.  
  4615.       last := nil;
  4616.  
  4617.       endfile := nil;
  4618.  
  4619.       if paramcount >= 1 then
  4620.  
  4621.         temp := paramstr(1)
  4622.  
  4623.       else
  4624.  
  4625.         temp := 'X';
  4626.  
  4627.       temp := upcase(temp[1]);
  4628.  
  4629.       if (temp = 'A') or (temp = 'S') then
  4630.  
  4631.         squish := true
  4632.  
  4633.       else
  4634.  
  4635.         squish := false;
  4636.  
  4637.       writeln('Reading in LANGUAGE.COD.');
  4638.  
  4639.       for i := 1 to 32 do
  4640.  
  4641.         begin
  4642.  
  4643.           new(top[i]);
  4644.  
  4645.           top[i]^.wrd := '';
  4646.  
  4647.           top[i]^.count := 0;
  4648.  
  4649.           top[i]^.code := 0;
  4650.  
  4651.           top[i]^.next := nil;
  4652.  
  4653.           bottom[i] := top[i];
  4654.  
  4655.         end;
  4656.  
  4657.       last := nil;
  4658.  
  4659.       while not done do
  4660.  
  4661.         begin
  4662.  
  4663.           new(newbuf);
  4664.  
  4665.           newbuf^.wrd := '';
  4666.  
  4667.           getbite(strlen);
  4668.  
  4669.           if not done then
  4670.  
  4671.             begin
  4672.  
  4673.               for i := 1 to strlen do
  4674.  
  4675.                 begin
  4676.  
  4677.                   getbite(bite);
  4678.  
  4679.                   newbuf^.wrd := newbuf^.wrd + chr(bite);
  4680.  
  4681.                 end;
  4682.  
  4683.               getbite(bite);
  4684.  
  4685.               newbuf^.count := bite;
  4686.  
  4687.               getbite(bite);
  4688.  
  4689.               newbuf^.code := bite;
  4690.  
  4691.               if newbuf^.count > 8 then
  4692.  
  4693.                 begin
  4694.  
  4695.                   getbite(bite);
  4696.  
  4697.                   long := bite;
  4698.  
  4699.                   newbuf^.code := newbuf^.code + (long shl 8);
  4700.  
  4701.                   if newbuf^.count > 16 then
  4702.  
  4703.                     begin
  4704.  
  4705.                       getbite(bite);
  4706.  
  4707.                       long := bite;
  4708.  
  4709.                       newbuf^.code := newbuf^.code + (long shl 16);
  4710.  
  4711.                       if newbuf^.count > 24 then
  4712.  
  4713.                         begin
  4714.  
  4715.                           getbite(bite);
  4716.  
  4717.                           long := bite;
  4718.  
  4719.                           newbuf^.code := newbuf^.code + (long shl 
  4720. 24);
  4721.  
  4722.                         end;
  4723.  
  4724.                     end;
  4725.  
  4726.                 end;
  4727.  
  4728.               newbuf^.next := nil;
  4729.  
  4730.               if newbuf^.wrd = chr(255) then
  4731.  
  4732.                 begin
  4733.  
  4734.                   last := newbuf;
  4735.  
  4736.                 end
  4737.  
  4738.               else
  4739.  
  4740.                 if newbuf^.wrd = chr(255) + chr(255) then
  4741.  
  4742.                   newline := newbuf
  4743.  
  4744.                 else
  4745.  
  4746.                   if newbuf^.wrd = chr(255) + chr(255) + chr(255) 
  4747. then
  4748.  
  4749.                     endfile := newbuf;
  4750.  
  4751.               if squish then
  4752.  
  4753.                 begin
  4754.  
  4755.                   if ord(newbuf^.wrd[1]) > 107 then
  4756.  
  4757.                     i := length(newbuf^.wrd) + 15
  4758.  
  4759.                   else
  4760.  
  4761.                     i := length(newbuf^.wrd)
  4762.  
  4763.                 end
  4764.  
  4765.               else
  4766.  
  4767.                 i := newbuf^.count;
  4768.  
  4769.               bottom[i]^.next := newbuf;
  4770.  
  4771.               bottom[i] := newbuf;
  4772.  
  4773.               write(#13,newbuf^.wrd,'                     ');
  4774.  
  4775.             end;
  4776.  
  4777.         end;
  4778.  
  4779.       if newline = nil then
  4780.  
  4781.         writeln('Error:  newline symbol not in LANGUAGE.COD! ');
  4782.  
  4783.       writeln;
  4784.  
  4785.       close(infile);
  4786.  
  4787.  
  4788.  
  4789.       {Initialize input & output files and global variables.}
  4790.  
  4791.       outname := paramstr(2);
  4792.  
  4793.       filefound := false;
  4794.  
  4795.       assign(outfile,outname);
  4796.  
  4797.       if exist(outname) then
  4798.  
  4799.         begin
  4800.  
  4801.           reset(outfile,1);
  4802.  
  4803.           seek(outfile,filesize(outfile))
  4804.  
  4805.         end
  4806.  
  4807.       else
  4808.  
  4809.         rewrite(outfile,1);
  4810.  
  4811.  
  4812.  
  4813.       outfilepos := 0;
  4814.  
  4815.       outbitpos := 1;
  4816.  
  4817.       outbite := 0;
  4818.  
  4819.       if squish then start := 3 else start := 2;
  4820.  
  4821.       for cmdparameter := start to paramcount do
  4822.  
  4823.         begin
  4824.  
  4825.           filespec := paramstr(cmdparameter);
  4826.  
  4827.           filemask := filespec;
  4828.  
  4829.           path := '';
  4830.  
  4831.           repeat
  4832.  
  4833.             i := pos('\',filemask);
  4834.  
  4835.             if i > 0 then
  4836.  
  4837.               begin
  4838.  
  4839.                 path := path + copy(filemask, 1, i);
  4840.  
  4841.                 filemask := copy(filemask, i+1, length(filemask));
  4842.  
  4843.               end;
  4844.  
  4845.           until i = 0;
  4846.  
  4847.           findfirst(filespec, readonly + hidden + archive, s);
  4848.  
  4849.           while doserror = 0 do
  4850.  
  4851.             begin
  4852.  
  4853.               filefound := true;
  4854.  
  4855.               inname := path + s.name;
  4856.  
  4857.               assign(infile, inname);
  4858.  
  4859.               reset(infile,1);
  4860.  
  4861.               infilepos := 0;
  4862.  
  4863.               inbitpos := 1;
  4864.  
  4865.               done := eof(infile);
  4866.  
  4867.  
  4868.  
  4869.               {Perform compression on input file(s).}
  4870.  
  4871.               if squish then
  4872.  
  4873.                begin
  4874.  
  4875.                 writeln('Compressing ',inname);
  4876.  
  4877.                 ch := chr(0);
  4878.  
  4879.                 while not done do
  4880.  
  4881.                   begin
  4882.  
  4883.                     parse(words,ch);     {Find word or punctuation}
  4884.  
  4885.                     if length(words) > 0 then
  4886.  
  4887.                       begin
  4888.  
  4889.                         if ord(words[1]) > 107 then
  4890.  
  4891.                           buf := top[length(words) + 15]
  4892.  
  4893.                         else
  4894.  
  4895.                           buf := top[length(words)];
  4896.  
  4897.                         mask := 1;
  4898.  
  4899.                         while (buf^.wrd <> words) and (buf^.next <> 
  4900. nil) do
  4901.  
  4902.                           buf := buf^.next;
  4903.  
  4904.                         if buf^.wrd <> words then
  4905.  
  4906.                           begin
  4907.  
  4908.                             highvideo;
  4909.  
  4910.                             if words = chr(255) + chr(255) then
  4911.  
  4912.                               writeln('Newline code not found in tree! 
  4913. ')
  4914.  
  4915.                             else
  4916.  
  4917.                               write(words);
  4918.  
  4919.                             for i := 1 to last^.count do
  4920.  
  4921.                               begin
  4922.  
  4923.                                 masked := last^.code and mask;
  4924.  
  4925.                                 mask := mask shl 1;
  4926.  
  4927.                                 if masked = 0 then
  4928.  
  4929.                                   putbit(0)
  4930.  
  4931.                                 else
  4932.  
  4933.                                   putbit(1);
  4934.  
  4935.                               end;
  4936.  
  4937.                             for i := 0 to length(words) do
  4938.  
  4939.                               begin
  4940.  
  4941.                                 for j := 0 to 6 do
  4942.  
  4943.                                   begin
  4944.  
  4945.                                     b := (ord(words[i]) shr j) and 
  4946. 1;
  4947.  
  4948.                                     putbit(b)
  4949.  
  4950.                                   end;
  4951.  
  4952.                               end;
  4953.  
  4954.                           end
  4955.  
  4956.                         else
  4957.  
  4958.                           begin
  4959.  
  4960.                             for i := 1 to buf^.count do
  4961.  
  4962.                               begin
  4963.  
  4964.                                 masked := buf^.code and mask;
  4965.  
  4966.                                 mask := mask shl 1;
  4967.  
  4968.                                 if masked = 0 then
  4969.  
  4970.                                   putbit(0)
  4971.  
  4972.                                 else
  4973.  
  4974.                                   putbit(1);
  4975.  
  4976.                               end;
  4977.  
  4978.                             lowvideo;
  4979.  
  4980.                             if words = chr(255) + chr(255) then
  4981.  
  4982.                               writeln
  4983.  
  4984.                             else
  4985.  
  4986.                               write(buf^.wrd);
  4987.  
  4988.                           end;
  4989.  
  4990.                     end;
  4991.  
  4992.                   end;
  4993.  
  4994.                 mask := 1;
  4995.  
  4996.                 for i := 1 to endfile^.count do
  4997.  
  4998.                   begin
  4999.  
  5000.                     masked := endfile^.code and mask;
  5001.  
  5002.                     mask := mask shl 1;
  5003.  
  5004.                     if masked = 0 then
  5005.  
  5006.                       putbit(0)
  5007.  
  5008.                     else
  5009.  
  5010.                       putbit(1);
  5011.  
  5012.                   end;
  5013.  
  5014.                end
  5015.  
  5016.               else
  5017.  
  5018.  
  5019.  
  5020.                 {Decompress input file.}
  5021.  
  5022.                 begin
  5023.  
  5024.                   writeln('Decompressing ',inname);
  5025.  
  5026.                   cd := 0;
  5027.  
  5028.                   mask := 1;
  5029.  
  5030.                   cnt := 0;
  5031.  
  5032.                   while not done do
  5033.  
  5034.                     begin
  5035.  
  5036.                       getbit(b);
  5037.  
  5038.                       if b > 0 then cd := cd or mask;
  5039.  
  5040.                       mask := mask shl 1;
  5041.  
  5042.                       if mask <= 0 then writeln('Error: code too long.');
  5043.  
  5044.                       inc(cnt);
  5045.  
  5046.                       buf := top[cnt];
  5047.  
  5048.                       while (buf^.next <> nil) and
  5049.  
  5050.                             ((cnt <> buf^.count) or (cd <> buf^.code)) 
  5051. do
  5052.  
  5053.                         buf := buf^.next;
  5054.  
  5055.                       if (cnt = buf^.count) and (cd = buf^.code) then
  5056.  
  5057.                         begin
  5058.  
  5059.                          if buf = endfile then
  5060.  
  5061.                           done := true
  5062.  
  5063.                          else
  5064.  
  5065.                           if buf^.wrd = chr(255) then
  5066.  
  5067.                             begin
  5068.  
  5069.                               j := 0;
  5070.  
  5071.                               for k := 0 to 6 do
  5072.  
  5073.                                 begin
  5074.  
  5075.                                   getbit(b);
  5076.  
  5077.                                   j := j + (b shl k);
  5078.  
  5079.                                 end;
  5080.  
  5081.                               for i := 1 to j do
  5082.  
  5083.                                 begin
  5084.  
  5085.                                   m := 0;
  5086.  
  5087.                                   for k := 0 to 6 do
  5088.  
  5089.                                     begin
  5090.  
  5091.                                       getbit(b);
  5092.  
  5093.                                       m := m + (b shl k)
  5094.  
  5095.                                     end;
  5096.  
  5097.                                   putbite(m);
  5098.  
  5099.                                   highvideo;
  5100.  
  5101.                                   write(chr(m));
  5102.  
  5103.                                 end;
  5104.  
  5105.                             end
  5106.  
  5107.                           else
  5108.  
  5109.                            if buf^.wrd = chr(255) + chr(255) then
  5110.  
  5111.                             begin
  5112.  
  5113.                              writeln;
  5114.  
  5115.                              putbite(13);
  5116.  
  5117.                              putbite(10);
  5118.  
  5119.                             end
  5120.  
  5121.                            else
  5122.  
  5123.                             begin
  5124.  
  5125.                               for i := 1 to length(buf^.wrd) do
  5126.  
  5127.                                 begin
  5128.  
  5129.                                   b := ord(buf^.wrd[i]);
  5130.  
  5131.                                   putbite(b)
  5132.  
  5133.                                 end;
  5134.  
  5135.                               lowvideo;
  5136.  
  5137.                               write(buf^.wrd)
  5138.  
  5139.                             end;
  5140.  
  5141.                           cd := 0;
  5142.  
  5143.                           cnt := 0;
  5144.  
  5145.                           mask := 1;
  5146.  
  5147.                         end;
  5148.  
  5149.                     end;
  5150.  
  5151.                 end;
  5152.  
  5153.  
  5154.  
  5155.               {Finish up or loop back for more work to do.}
  5156.  
  5157.               flushbit;
  5158.  
  5159.               close(infile);
  5160.  
  5161.               findnext(s);
  5162.  
  5163.             end;
  5164.  
  5165.         end;
  5166.  
  5167.  
  5168.  
  5169.       if not filefound then writeln('No matching files found.');
  5170.  
  5171.       flushbit;
  5172.  
  5173.       close(outfile);
  5174.  
  5175.     end;
  5176.  
  5177. end.
  5178.  
  5179.  
  5180.  
  5181. {That's all, folks!}
  5182.  
  5183.  
  5184.  
  5185.