About
Community
Bad Ideas
Drugs
Ego
Erotica
Fringe
Society
Technology
Hack
Phreak
Broadcast Technology
Computer Technology
Cryptography
Science & Technology
Space, Astronomy, NASA
Telecommunications
The Internet: Technology of Freedom
Viruses
register | bbs | search | rss | faq | about
meet up | add to del.icio.us | digg it

Primary Cryption

by Vernon Nemitz

// CRYPTION.C, A Data Protection Tool,
// Copyright (C) 2004 by Vernon Nemitz
// Originally published at www.totse.com;
// seek the original there if needed.
//
//     Publishing rights are shared with the General Public
//     only as follows:
// (1) This copyright description, including the notices given
//     by any other author, must be entirely retained as the
//     first thing in every copy of this document; its intent
//     and meaning may not be altered by anyone.
// (2) All of the content of this document, as originally
//     acquired by any person, must be retained in all copies
//     made by that person.  However, brief passages may be
//     quoted in reviews and other descriptions.  And anyone
//     is free to clone this copyright description by itself
//     to a new document, and become the original author of
//     the rest of that document.
// (3) Radical editing of this document is allowed, but only
//     of the parts that follow this copyright description.
//     The way to edit this document while retaining prior
//     work is to mark/disable any chosen portion as being
//     inadequate and/or unclear and/or obsolete and/or
//     [describe!] -- and then, likely, to insert and/or
//     append new/replacement material.
// (4) Each who edits this document must clearly identify the
//     work done, and is expected to add a brief note and
//     copyright declaration, similar to the lines for
//     original author(s) above, in the space provided below.
// (5) No one is required to republish this document after
//     editing it, but if that is done, then this copyright
//     notice will continue to apply to it.
//
//
//
// End of copyright information, for this Evolving
// Multi-Owner Document.

// Notice:  This document has been edited from the original
// format, to a narrower column width.  No significant other
// changes have been made (besides adding this Notice, and
// fixing the odd typo or comment have been made -- and the
// original author, who made those changes, did not think it
// necessary to disable the entire program (wider form) and
// append a near-duplicate (narrower form).

/*
The purpose of this program is to encrypt any specified file easily
and fairly quickly, and also to reverse the process equally easily
-- yet use an encryption scheme so potent that even a quantum
supercomputer would have trouble breaking it.  Of course time will
tell; there are no powerful quantum computers at this writing.

Note that that is the PURPOSE of this program.  It DOES modify files,
and it does successfully unmodify those files, but the algorithms by
which it does its work have not at this writing been subjected to
intense scrutiny by Experts In The Field.  Perhaps there is a fatal
flaw that is unknown to the original author; if so, the security that
the program is intended to provide would just be an illusion.  On the
other hand, perhaps this program really is as good as has been
attempted.  One reason for publishing it is to let the Experts analyze
it, so that the Truth will become known.  Meanwhile, those risk-takers
who gamble on its security can at least be assured that their data
will be protected UNTIL a flaw is discovered -- which may take a
while.

The algorithms invoke a unique property of prime numbers, which the
original author happened to independently discover, and then publish
in the "Journal of Recreational Mathematics", Volume 14, Number 2
(1981-1982), pg 141.  The reciprocal of prime P in at least one
arithmetic Base (and possibly in an infinite quantity of Bases) will
be a repeating series of digits having a length or "period" of P-1.
For example, in the common Base Ten, if P is the prime number 7 and
its reciprocal is computed, the period is P-1 or 6 digits (repeating
142857).  And although when P is the equally prime number 3, its
reciprocal in Base Ten only has a period of 1 digit (repeating 3), in
Base Two (and others) its period is indeed P-1 or 2 digits (repeating
01 in Base Two).  Meanwhile, for every Composite number C, its
reciprocal always has a period that is less than C-1 digits, no matter
in what Base it is calculated.

When examining the digits of a single P-1 period for a prime number,
some order may be detected.  Ignoring 2, primes are odd numbers, so
their longest periods have even quantities of digits.  It is
interesting that if the first half of the longest period is added to
the second half, the result is a series of identical digits, each
being B-1, where B is the Base in which the reciprocal had been taken.
For example, look at the 142857 from 7 and Base Ten above; split and
add: 142 + 857 = 999.  Other than that, though, the digits in the
first half of the period seem to be reasonably pseudo-random.  This is
good because there are lots of prime numbers; we could simply take the
reciprocal of some prime larger than 100 million, and obtain 50
million pseudo-random digits quite easily and repeatably.

One simple way to obtain greater security, however, is to divide that
prime into some other number than One (a reciprocal is defined by
division into One).  Any pseudo-random number smaller than the prime
will do (if bigger than the prime, only the division-remainder would
be relevant to these considerations of period-properties).  The net
effect is that the same repeating sequence of digits is generated as
if the reciprocal of the prime had been computed, but the sequence
starts in a different place.  So, if the sequence has a length of
millions, then making its starting point part of the secret encryption
key does indeed increase security somewhat.

Yet there is more.  If multiple large primes are chosen, each able to
yield millions of pseudo-random digits, then those sets of digits can
be combined (effectively increasing randomness) to make the actual
encrypting-numbers for a message.  Also, if a message to be encrypted
is only a few thousand bytes long, then aren't vast quantities of
potential encrypting-digits being "wasted"?  What if, instead of
using generated digits as soon as they are available, some were
deliberately skipped first?  Depending on the way those digits were
created from more than one prime, this can be a far more devious
thing, than just another variation on the theme of "divide into a
different number than One".  In fact, consider the notion of skipping
a (semirandom) few digits inside the heart of the algorithm, for every
character of any processed message....  Finally, what if you had
several files to encrypt, and you could encrypt all of them at once,
with the same key, using blocks of pseudo-random digits that were
separated by irregular quantities of unused digits?  With this
CRYPTION program, you can do exactly that!

The most perfect encryption system uses totally random numbers to
modify the content of a message.  With totally random numbers, the
message cannot be cracked even in theory, no matter how powerful a
quantum supercomputer is used.  In practice, though, while totally
random numbers appear to be obtainable for encryption, the message
must still be decryptable by the permitted parties -- and for that it
is necessary to use the exact same sequence of totally random numbers.
But guaranteed-identical sequences of totally random numbers have in
the past been essentially impossible to independently obtain at the
separate locations of sender and receiver (it would be a violation of
the definition of "totally random"!).  However, modern quantum
encryption techniques can use the phenomenon known as "entanglement"
to allow completely secure transmission/sharing of totally random
numbers, which are generated just ONCE -- but this trick is just
barely coming out of the laboratory with a high price tag, so it
cannot quite be called ready for prime time.  Thus, until then, for
totally random numbers to be used in encryption, the list of numbers
has to be carried about by the message-recipient, which represents a
security risk.

Meanwhile, the repeatable generation of pseudo-random numbers means
that they can be independently and identically computed at separate
locations.  Their weakness with respect to encryption is, of course,
the fact that they are not totally random.  As noted above, however,
there are ways of mixing pseudorandom numbers together, to make the
result more closely approach the totally random condition.  Note that
such procedures can be computationally intensive, and thus detract
from ease and speed of use.  The particular mixing scheme employed
here takes advantage of the facts that every large prime number offers
an easy way to compute a lot of pseudo-random digits, that there are
infinitely many prime numbers, and that programs can often "trade"
memory for speed (in this case, it uses a lot of memory to hold a lot
of calculation scratchpads, and its main algorithm runs comfortably
fast enough).

Digression:  There is a convenience problem that is directly
associated with encrypting a message using a lot of prime numbers.
Overall, the list of those primes -- and the numbers which they will
be dividing -- constitute the "encryption key", the information needed
to decrypt a message later.  Who is going to remember such a key?  And
writing it down leads to the same security risk as already mentioned.
The chosen solution is to obtain the list of primes from an
encipherable source....

Enciphering is not the same as encryption.  Ciphering represents a
larger concept, of which encryption is just a subset.  Thus ciphers
can use random ideas to hide other ideas, while encryption is
thoroughly mathematical these days.  So, an example pre-arranged
cipher might be: "If I should happen to use the word 'Friday' in the
next conversation, you will stop listening at the door and call the
fire department."  The context of a cipher can be as important as the
cipher itself!

So, let us consider a List Of Only/All Prime Numbers Smaller Than One
Billion (for example).  There are many millions of primes on that
List.  If we choose to use one thousand of them in combination to
encrypt a message, we can decide to specify those primes either by
exact value, or by position in the List.  The difference is quite
significant.  Primes are particular numbers, not always easy to
identify (especially when large), while mere positions on a list are
ordinary numbers.  And ordinary numbers can be obtained anywhere!
(So, how many ways are there to select a thousand primes, to be used
as an encryption key, from many-millions?  It is a large enough number
to give pause to any would-be code-breaker!  And we can easily make
message-cracking tougher by choosing a longer Main List of primes
-- CRYPTION.EXE uses more than 200 Million -- and also by selecting
more than a mere thousand of them -- CRYPTION.EXE can select 65
thousand.)

Now please consider an already existing file of some sort, perhaps an
".MP3" music file.  Examined from the currently relevant perspective,
this file is just a collection of numbers that represent music-data.
Better, it is compressed data, which means that most of the
repetitiveness of the data in that file has been squeezed out --
leaving mostly random numbers behind!  Suppose we use this modestly
random collection of ordinary numbers as a way to select primes from
the List of Only/All Primes -- with the length of that file indicating
how many to select?  That means the file is the key to encrypting/
decrypting the message, and easy to remember!  More, you can now
encrypt the message and pass it on, and at some unrelated (even
earlier!) point in time, mention to the recipients a particular .MP3
file that they should hear.  This enciphering of the key makes
cracking the message at their end easy, but hard for anyone else.

Keep in mind that there are lots of other kinds of compressed data
files that can be used as encryption keys in this scheme.  Nor do the
key files have to be compressed, because the overall algorithm only
indirectly uses the data in the key files (it is pulled,
pseudorandomized, and THEN used to select primes!).  Nevertheless,
you and your pals could consider owning identical copies of some
particular version of a data-compression program, such that you know
that any file that might get compressed by the program will be
compressed identically.  Then you could plan some sneaky thing like
saying, "Go to this Web address ...", which means to do exactly that.
But it also means, "Save that Web page as a local file, compress the
file, and then use it as the decryption key."  (Do note that date/time
stamps may interfere with that notion's simplicity -- but then, this
will depend on the "particular version" of the compression program.)
If you are concerned about the Web page being modified before it can
be used as a decryption key, then try www.archive.org -- their job is
to archive billions of Web pages, with the goal of preserving them
just as they were.   Anyway, be creative with your enciphering of the
encryption key!  Even encrypted files can be used as the keys to other
encrypted files!  And, suppose you occasionally put the decryption
information for your next message -- including the Key File! --
somewhere inside a zipped-up current message, just to provide someone
monitoring your communications with not even a hint regarding anS
enciphered key....  Digression ends.

This CRYPTION program will request a file-name to use as the key, and
also a list of files to be encrypted or decrypted, and other
information such as skip-numbers.  Only a minimal check will be made
to find some random data in the key file, so you have many choices --
and no record at all will be made of the relationship between the key
file and the message file(s), because such a record is still a
security risk.  If the user wishes to create a personal list of "keys
and files", and encrypt THAT, so that its encryption key is the only
thing to remember, fine.  All this program will do is encrypt/decrypt.
Managing any other details is not its job.

The reason for taking that position here is, such a list can
potentially be complicated enough to require a special computer
program of its own, just to manage it.  After all, just because a file
has been encrypted, that does not mean someone might never want to
encrypt it again, for additional security, with either the same key
or another key.  More, it is important to realize that simply because
the decryption process is the exact inverse of the encryption process,
then this program's decryption process could be used INSTEAD of this
program's encryption process, to scramble a message, after which the
encryption process would be needed to unscramble it!  When you
consider that a message might be scrambled multiple times in alternate
ways using multiple keys, then you might agree that keeping track of
all the possibilities (and the correct overall unscrambling sequence)
is beyond the scope of the present program, a simple "encryption/
decryption engine".

One minor dilemma results from the fact that any scrambled file will
of course no longer be worthy of its original file extension (like
.TXT).  All scrambled files will consist of simple binary data, and
any program that expects something else (the format of the original
file) will likely claim that the file has become corrupted.  Therefore
it is logical that the newly created scrambled file be given a new
file extension, a unique group of letters that no other program will
claim an ability to properly digest for presentation to the user.  The
chosen replacement extension is the first three consonents of this
program's name: .CRP, which coincidently lets the file now brag about
its own "corruption" (or even "crappiness") as far as its use by any
other program is concerned....

Next, should some special program be written to manage files and keys,
that program might call this one with a long string of "parameters",
and thereby pass the file-name and other information that the CRYPTION
program needs, and bypass the requests it would otherwise make.  The
user of such an overall controller program would be convenienced by
that arrangement.  Therefore, formally, when the CRYPTION program is
invoked by another, via a command to the computer's Operating System,
the list of parameters must be as follows:  (1) A required name of the
file, inside quotation marks, to be used as a key (Drive and Path
optional); (2) An optional letter D, to delete the key file after all
work is done -- the default is to retain the file; (3) A required skip
number, though 0 (zero) is okay; (4) A required algorithm code-letter,
either E for Encrypt or D for Decrypt; (5) The required name of a file
to be affected by that algorithm, again enclosed by quotes; (6) An
optional letter D to delete that file after all work is done -- this
letter is only relevant for files that do not have a .CRP extension,
because any .CRP file is assumed to be scrambled and does not need to
persist beyond its time of intermediacy (so a further-scrambled .CRP
file always REPLACES the prior .CRP file, and a finally-unscrambled
.CRP file will have its file-extension changed).  The last four
parameters may be repeated as a group several times, allowing one key
to be used to affect many files.  Here is an example (one repetition):

CRYPTION.EXE
  "C:\KEY FILE.BIN"2222E"C:\TMP\MESSAGE1.TXT"7654D"MSG2.TXT"D

Above, Values 2222 and 7654 are skip numbers; the file MESSAGE1.TXT
will be processed via Encryption algorithm, and the MSG2.TXT file via
Decryption; and lastly, only MSG2.TXT will be deleted, and then only
if all work has been successfully completed.  (NOTE: skip numbers must
be positive, and if they are too large -- say, more than a million --
they will significantly slow down the CRYPTION program.  Thus the
maximum allowed skip number is 9999999, just a trifle under ten
million).  Files named in that example may be any other thing
appropriate, of course, and if the drive and directory path are not
included, the CRYPTION program will let the Operating System seek it
in the usual default places.  Ordinary quotation-mark  "  symbols are
required to guarantee correct parsing of file names from the
parameters, especially when they contain spaces, such as KEY FILE.BIN
in the example.  (Note that  "  symbols are not allowed, by the
Operating System, to be part of a file name, which means quotes are
perfect markers for the start and end of a path\file name.)  Next, the
example shows minimum spaces used as item separators, but additional
spaces are quite acceptable (except that quote marks must exactly
delimit file names).  IMPORTANT:  The length limit for any one
DRIVE:\PATH\FILENAME.EXT is 48 characters.  Equally important:  If
parameters are supplied to the CRYPTION program when the Operating
System is told to run it, those parameters will be tested for
validity.  Anything missing or incorrect will cause a specific request
for needed information, just as if the CRYPTION program had been
invoked with no parameters.  Thus an automated controller program that
invokes CRYPTION must be certain it passes valid data in the
parameters, because otherwise this program will sit and wait until it
gets human input.

Next, another and much more serious dilemma also flows from the
possibility that some file might be scrambled multiple times, and that
the Decryption option might be used to Encrypt it.  If this program is
going to replace the original file extension with another, how is it
going to recognize that an original file has been restored, so that
the original extension can be restored?  Only a very iron-clad policy
with respect to file-manipulation is going to solve the dilemma, and
this is it:
 1. Regardless of encryption/decryption mode, this program will always
    pay attention to the file's current extension, and make a quick
    examination of the start of the file.
 2. If the original file is about to receive its initial scrambling,
    then its extension will not be .CRP, and this program will expect
    to NOT find a certain key phrase at the start of the file.  In
    other words, finding that phrase will imply that the file
    currently exists in a scrambled state; not finding that phrase
    means that it will be inserted at the beginning of the file.
 3. When this program inserts the key phrase to the beginning of the
    file, it will place it there TWICE, along with an additional
    phrase that holds the original file extension.  For example, if
    the extension was TXT, then this is what gets added to the start
    of the to-be-scrambled file:
      DATA PROTECTED FROM SNOOPERCOMPUTERS WITH CRYPTIONITE:
      Data Protected From Snoopercomputers With Cryptionite:
      The Original File Extension is TXT.
 4. The preceding will be one long string of text, with two spaces
    after each part of it, including the third part (it's not the
    multi-line thing just presented).  The long message has two
    purposes.  First, no existing file nor future file has any need to
    begin with that exact long sequence of characters, UNLESS it has
    been altered by CRYPTION.EXE.  Second, the last two parts of that
    text will be scrambled along with the rest of the file.  When that
    text reappears after this program has performed either encryption
    or decryption, then this program can make the reasonable
    assumption that the rest of the original file has also been
    restored.
 5. At that point CRYPTION will take the just-revealed file extension
    and apply it -- and also completely remove the special text.  Note
    that the exact identifier just described is 87 characters from
    "Data Protected " to " Extension is ".  Also note that each
    character is normally stored in one "byte" of memory, and that a
    byte can hold any of 256 possible characters.  Thus, for this
    particular sequence of characters to be generated at random, the
    odds are 1 in 256-raised-to-the-87th-power!  This is the basis
    behind the reasonable assumption that when the last two parts of
    the inserted text appear, the original file is restored.
 6. When multiple scramblings are performed, this will be indicated by
    the first (capitalized) part of the specially-inserted text
    (including two spaces after the colon).  When it is present,
    nothing will be done to the start of the file, but everything
    after that phrase will have either Encryption or the inverse
    (Decryption) applied to it.  Of course, after every such process,
    this program will check to see if the rest of the original
    inserted text has reappeared, as already described.
 7. Now, will embedding such a plainly-stated phrase make it easier
    for those wanting to unscramble a message, against whom the
    message was encrypted in the first place?  Perhaps.  Nevertheless,
    it will remain true that thousands of prime numbers, chosen with
    semi-randomness from more than 200 million, must be exactly
    identified BEFORE even that initial identifier can be correctly
    unscrambled, to say nothing of the rest of the message.  With
    200-million-raised-to-the-thousandth-power as the MINIMUM number
    ways to encrypt a message, by the time they can build big enough
    quantum supercomputers to crack the message, not only will the
    temporal relevance of the message have passed, but by then the
    truly-unbreakable quantum encryption techniques will be in wide
    use.
WARNING: Any other program that modifies any aspect of the preceding
may cause an inability to restore the original file!  (Of course, if
you really know what you are doing, you might acquire even greater
security for your messages, instead.  But if you goof, don't say you
weren't warned!)

A variant dilemma will be discovered by anyone who attempts to do
this:
  CRYPTION.EXE
    "C:\KEY.BIN" 905 E "C:\MESSAGE.TXT" 823 D "C:\MESSAGE.CRP"
which attempts to first apply the encryption algorithm to MESSAGE.TXT
-- and which should successfully create a file called MESSAGE.CRP (the
newly created file is always located in the same directory as the
original file).  However, using a completely different group of
pseudorandom numbers derived from the key file (thanks to that initial
encryption effort and the skip numbers), the above example specifies
applying the decryption algorithm to the just-created file.  The
dilemma is NOT the fact that MESSAGE.CRP will not exist at the time
the CRYPTION program checks for valid parameters; the program has code
in it designed to handle this situation -- but you do have to specify
an IDENTICAL path for the second file.  No, the dilemma concerns
unscrambling the file! --which requires separate stages.  Example:
  CRYPTION.EXE
    "C:\KEY.BIN" 905 E "C:\GARBAGE.CRP" 823 E "C:\MESSAGE.CRP"
where GARBAGE.CRP is simply a disposable copy of MESSAGE.CRP -- and
the second stage:
  CRYPTION.EXE "C:\KEY.BIN" 905 D "C:\MESSAGE.CRP"

See, the algorithms quickly generate, use, and FORGET pseudorandom
numbers (which for one thing is why the skip numbers cannot be
negative numbers).  The algorithms are not "commutative", in which the
order of "Encryptions" and "Decryptions" is unimportant -- that order
IS important!  So the second scrambling of MESSAGE.TXT has to be
undone first, which naturally requires getting at the precise place in
the sequence of pseudorandom numbers where the second part began, of
the original scrambling.  Finding that location involves the length of
the original file MESSAGE.TXT, which was modified by adding the
identifier-text described earlier -- including adding the file
extension, which might not be 3 characters!  But by design, the
initial AND any subsequent scramblings of a file always mess with the
same amount of added-on text.  This is what makes it possible to copy
MESSAGE.CRP to the new file GARBAGE.CRP, and use it as a "filler", as
if its length was just a skip number.  Note that either Encryption or
Decryption can be specified for GARBAGE.CRP, because the result should
be discarded.  Also, recall that CRYPTION.EXE does not change the
filename GARBAGE.CRP, so specifying a D (before the 823) in the above
unscramble-example is useless.  The CRYPTION program already
automatically deletes "original" .CRP files, by overwriting them with
the do-not-delete "resulting" .CRP files.  Thus you would have to
manually delete GARBAGE.CRP sometime after that first
unscramble-stage.

There IS an alternative to using a copied/renamed file like
GARBAGE.CRP.  If you know the exact length of the .CRP file, as
measured in bytes (let's pretend here it is 12345), then a grand Skip
Number CAN be computed for the first unscrambling stage.  Since all
.CRP files will begin with a special capitalized identifier phrase (56
bytes long) that is never scrambled, the portion of the file that IS
scrambled is always 56 less than the total length (12345-56=12289 in
this pretending).  So, add that computed 12289 to all other
appropriate Skip Numbers (905 and 823 above), and the first
unscrambling stage is:
  CRYPTION.EXE "C:\KEY.BIN" 14017 E "C:\MESSAGE.CRP"

Well, from the preceding, you may imagine that a special program that
keeps track of scrambling-data is going to need to be intelligent
enough to deal with the dilemma just described.  (However, that
computation based on file-length would be a very easy thing for it to
do.)  And due to the number of data items about which it will need to
record (although, remember, some parameters ARE optional), users of
CRYPTION.EXE are going to want it sooner, not later.  The original
author DOES have tentative plans to develop a controller program, but
getting the CRYPTION program working correctly and "out there" has
greater priority -- and due to other commitments, the author would be
neither surprised nor complaining if someone else wrote it first.

As stated previously, a List of Prime Numbers is required to be
available for this program to work.  A suitable List does exist,
prepared in a format that compresses the data yet allows easy access.
That List holds all primes smaller than 4,294,967,296, or all primes
that fit in 32 bits of data.  There are 203,280,221 prime numbers on
that List, and they manage to fit in about 100 megabytes of space.
The name of this compressed-Primes file, including the directory where
the CRYPTION.EXE program expects to find it, is
"\PRIMES\COMPRESS.PRM".  The actual drive holding this directory and
file doesn't matter; CRYPTION.EXE will search all the computer's
drives (except A: and B:), looking for it (and will abort if not
found).  In addition to "COMPRESS.PRM", the "\PRIMES" directory must
also contain a file named "CMPRMDEX.QNT", which is a special index
allowing easy access to the Nth prime inside "COMPRESS.PRM".  The
CRYPTION.EXE program will also abort if it cannot find that index
file.

The two files are easily and fairly quickly created by another program
that is called "PRMPRESS.EXE" (a 150-Mhz processor can crank out
COMPRESS.PRM in about 20 minutes).  PRMPRESS.EXE can in turn be
obtained by compiling the source file "PRMPRESS.C".  You should be
able to find it on the Web, perhaps at www.totse.com.  All the details
regarding the compressed-data-format and index files are described in
"PRMPRESS.C".  Also, for minor entertainment, there is a program
called "PIKPRIME.EXE", which utilizes both data files.  It lets you
enter a number  N  and then (1) tells you if that number is a prime,
and (2) tells you what the Nth prime is -- provided N is smaller than
203,280,222.  PIKPRIME.EXE can be obtained by compiling the source
file "PIKPRIME.C", and it also should be findable on the Web.  The
reason that PIKPRIME.EXE is mentioned here is that its methods of
using the index file to access the Nth prime are part of the
CRYPTION.EXE program.

/////////////////////////////////////////////
SEQUENCE OF EVENTS AS CRYPTION.EXE RUNS:

0. Checks each drive, starting at C: for a \PRIMES directory
   containing the COMPRESS.PRM and CMPRMDEX.QNT files.  Aborts if not
   found.
1. Checks parameters.  Missing info is requested.  The user just types
   the data and sometimes presses the ENTER key.  (Single-character
   data items do not need ENTERing.  Simple editing of ENTERed data,
   via Up-Arrow and BackSpace keys, is also included.)  CRYPTION
   verifies existence of the specified Key File, and all specified
   "Message" files.
2. The Key File must be at least 8K in length, but can be lots longer.
   CRYPTION loads up to a megabyte of the Key File for a minimally-
   random test and later use.  Invalid info leads to repeated requests
   for input.
3. Loads the CMPRMDEX.QNT file and constructs a table which will be
   used to quickly locate the Nth prime in the COMPRESS.PRM file.
4. Uses previously-loaded Key-File data to construct an array of
   primes, their quantity being roughtly 1/8 the length of the Key
   File (so a 16K Key could yield an array of 2048 primes -- except
   that duplicates are mostly prevented.  And while the maximum-loaded
   key-file-data can be a megabyte, no more than a 64K array of primes
   will be created).  These primes, plucked pseudorandomly from the
   COMPRESS.PRM file, will in turn yield pseudorandom numbers used to
   process any/all "Message" file(s).
5. Opens each "Message" file, along with a new .CRP file.  Adds (or
   doesn't add) the initial identifying phrases, and the original file
   extension.
6. Processes the "Message" file.
7. If a "Message" file becomes unscrambled, deletes identifiers at the
   start of the file, and restores the original file extension.
8. Deletes specified key and/or original "Message" file(s).  Always
   deletes intermediate "Message" .CRP files.
9. Done; program automatically quits.

COMMENTS IN THE PROGRAM CODE WILL EXPLAIN THE MAIN CRYPTION ALGORITHMS
USED
*/////////////////////////////////////////////

/*
THIS  C  LANGUAGE SOURCE-CODE FILE CAN BE SUCCESSFULLY COMPILED INTO A
WORKING WINDOWS PROGRAM BY BORLAND (Turbo) C++ 4.52, BY BORLAND C++
BUILDER 5, BY MICROSOFT VISUAL C++ 6, AND BY OPEN WATCOM 1.2.  Other
compilers for Windows programs have not been tested.  Note that the
first of the two Borland compilers dates from the era when Windows
started to replace DOS widely, and Borland was starting to drop the
word "Turbo" from its application-development tools.  The others are
thorough-going Windows compilers, suitable even for Windows 2000/XP.
All four are fairly easily available -- for example, the Borland 4.52
compiler is often given away as part of a self-teaching C programming
package.  (And the Open Watcom compiler is a free download, although a
donation is requested).

There are no compiler-specific aspects to this source code.  As you
see it here, unchanged, any of those four compilers can crunch it into
a working program.  (Whether or not that remains true in the future,
after other workers have edited this code, remains to be seen.  :)

The exact steps to compile the program differ with each compiler, but
are similar enough to be described as follows:  Set up a Project named
CRYPTION, and use the Project Options Editor/Configuration-Tool to
delete ALL default files, such as "CRYPTION.RES" or "CRYPTION.DEF",
and ensure that the ONLY Project file is this one, CRYPTION.C -- you
may have to specify a C Project and not a C++ Project, and if you can
specify an EMPTY project do so.  Ensuring that this CRYPTION.C file is
the sole source-code file then becomes easy.  Note that this file is
compatible with pre-1999 ANSI  C  standards, EXCEPT for lots of usage
of pairs of ordinary slash marks  //  as comment-indicators.  (In 1999
the double-slash comment indicator became part of the ANSI standard
for the  C  programming language.)

BEWARE OF THE COMPILER/DEVELOPMENT-ENVIRONMENT REPLACING SPACES WITH
TABS!!!  THERE ARE NO TABS IN THIS FILE; NEARLY ALL INDENTATIONS HERE
ARE PAIRS OF SPACES.  The problem of the moment is that different
people prefer different tab-sizes, and much careful formatting at one
tab-size looks really ugly under almost any other.  These compilers
mostly offer built-in source-code-editors, along with options that
allow you to specify that tabs should not be used at all, and this is
recommended.  (Exception:  The Open Watcom compiler allows you to
specify your favorite text editor as part of its Integrated
Development Environment -- so that editor's own configuration must be
examined to eliminate tabs.)

After compiling, the executable file CRYPTION.EXE should successfully
work as described elsewhere herein.  However, if CRYPTION.EXE is
copied to another computer, where it was not compiled, it may be
necessary to copy certain other files that come with the compiler, and
to keep them together.  The short list:
  If compiled under Borland (Turbo) C++ 4.52, the file CW3215.DLL is
    required.
  If compiled under Borland C++ Builder 5, the number of required
    support-files can depend on a variety of things, such as whether
    or not the program was compiled for debugging.  You will discover
    which ones you need as you attempt to run a copy of CRYPTION.EXE
    on a computer that contains no compiler.  Note that Borland
    considers those files to be "redistributables" -- they are
    INTENDED to be copied along with .EXE files.
  If compiled under Microsoft Visual C++ 6, no other files are
    required.  Since this CRYPTION program was written for Windows,
    and since Microsoft is the monopolistic provider of the Windows
    Operating System, it figures that the Microsoft compiler has a
    "home team advantage" over competitor compilers.
  If compiled under Open Watcom 1.2, no other files are required.  The
    requested donation appears to have been earned!

Note that the CRYPTION program uses no obscure Windows functions, and
so is compatible with "WINE" under Linux.  Since this file is being
openly shared with the general public, with few restrictions, it is
expected that someone will quickly replace the Windows-specific code
with Linux-specific code, while hardly touching the program's
operational algorithms.  Various modifications will probably be
necessary if this program is used with another Operating System (for
example, a lot of backslash  \  symbols in Windows file names must
edited into regular slash  /  symbols under Linux or Unix).

Much of the commentary in this program is intended to help budding
  C  programmers.  Those who know this stuff can ignore it.

NOTE TO ADVANCED WINDOWS/C PROGRAMMERS:  Yes, this is known to be a
combination of ugly Windows code and reasonably elegant CRYPTION code.
Most of the original effort was put into the most important portions,
and it was not desired to waste a lot of time on part of a program
that (A) is expected to be superceded by a CALLER program (one that
keeps track of all encryption keys) and/or (B) is expected to be
subjected to  #ifdef  or commenting by workers who prefer Linux or
some other Operating System.
  What would you have done?
The Windows stuff merely needed to work smoothly, and indeed it nicely
does.  And the next-most-important thing was to swat all the bugs,
which didn't help the elegance of the Windows coding one bit.
Finally, if anyone wants to think of this as a kind of advertisement
of various skills, feel free to contact the original author through
his ISP, pinn.net.
  --Vernon Nemitz (vnemitz)   August, 2004
*/




// Header files list -- for those who don't know, these files give the
// compiler access to many "background" functions, variables, and
// constants, in a manner that is standardized, so that the "axle"
// doesn't have to be re-invented every time somebody writes a
// brand-new "wheel" program.
#include <windows.h>
#include <winbase.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <io.h>



// Error Codes: Out of Memory, Opening File, File Read, Linked List,
//              Defective Algorithm, Bad Data, File Write
#define CRP_ERR_OM 1
#define CRP_ERR_OF 2
#define CRP_ERR_FR 3
#define CRP_ERR_LL 4
#define CRP_ERR_DA 5
#define CRP_ERR_BD 6
#define CRP_ERR_FW 7
#define CRP_WM_QUIT 100
// That last one is not an error code; indicates user interrupting by
// pressing ESC key

// Other definitions
#define PROCESSOR_INT_SIZE_32
#define PROCESSOR_ENDIAN_TYPE_LITTLE
// Definitions like these, in conjuction with #ifdef/#endif clauses,
// allow a program to be customized.  Blocks of code surrounded by
// #ifdef and #endif will ONLY be compiled if a particular "label",
// like PROCESSOR_INT_SIZE_32, has been defined.  These two
// definitions ensure that the source code in this program gets
// compiled to an executable that is suitable for all processors
// compatible with the Intel 80386, to the hyperthreaded Pentium 4.
// The definitions are easily changed if some other processor is the
// intended destination of the compiled executable.


// Preprocessor macro
#define uli(x) (unsigned long int)x
// For those inexperienced with the  C  programming language, the
// purpose of this is to be lazy; it takes a lot less time to type
// uli(variable)  than to type (unsigned long int)variable -- and part
// of the compiler known as the preprocessor will conveniently convert
// all instances of one into the other, thanks to that #define
// statement.  The preprocessor even generalizes the conversion of
// uli() so it doesn't matter what variable-name is inside the
// parentheses.  THEN the main compiler will use the longer expression
// to convert the variable's value from any other integer-type (such
// as signed short, or char) to unsigned long int.  Minor joke on
// original author:  This macro was not needed quite as often as was
// anticipated, at the time it was declared here.

// And here is an alternate way to do the same thing, for all the
// common data types
#ifdef PROCESSOR_INT_SIZE_32
typedef signed char        S_08; // signed, 8 bits
typedef signed short int   S_16; // signed, 16 bits
typedef signed long int    S_32; // signed, 32 bits
typedef unsigned char      U_08; // unsigned, 8 bits
typedef unsigned short int U_16; // unsigned, 16 bits
typedef unsigned long int  U_32; // unsigned, 32 bits
#endif
// NOW THERE IS NO POSSIBLE CONFUSION
// With respect to type-conversions, usually called "casting", the way
// to do it is, for example, like this:  (U_32)variable  -- which you
// can see is equivalent to the  (unsigned long int)variable
// mentioned in the previous paragraph.  The obvious syntactic
// difference between  (U_32)variable  and  uli(variable)  means that
// the compiler never gets confused -- but both ways are now easy to
// type.

/*        SPECIAL NOTE REGARDING VARIABLE SIZES:
    In the  C  language, the  int  type is supposed to be the
"natural" size for the processor.  That is, a compiler for a 32-bit
/ processor will be designed so that simple  int  variables are 32-bit
variables.  In prior years, when 16-bit processors ruled,  C
compilers were made so easy-to-write  int  variables were 16-bit
variables.  This is actually the primary reason for creating the
typedefs above, to remove any uncertainty about sizes of declared
variables.  HOWEVER, BEWARE!  If you use the above typedefs on a
16-bit compiler, the  S_16  and U_16  types will actually be only 8
bits wide!  And the  S_32  and  U_32  types will actually be only 16
bits wide.  Fortunately, such compilers have mostly fallen by the
wayside over the years.  All four of the compilers specified
previously in this file will handle these typedefs as is desired and
expected.
    One aspect of the preceding is that there are concerns about the
future.  Already the phrase "long long int" is sometimes being used to
specify 64-bit data.  The  C  language does not really have a natural
way to accommodate ever-increasing data sizes, as the decades go by.
PERHAPS something like this will be agreed-upon, someday:  (1) Let
int  remain the natural data size for a processor -- and let the
compiler's documentation make it VERY clear what that size is!
(2) Let every usage of  long  specify a doubling of that size.
(3) Let every usage of  short  specify a halving of that size.
Yes, obviously the preceding typedefs break rule (2) because the
specified compilers for this program set the default size of an  int
to 32 bits, so "long int" above should not be needed, unless
specifying S_64 or U_64 data.  However, that was done mostly for the
benefit of the older Borland compiler, which evolved from a 16-bit
compiler, and has a chance of being confused about whether or not a
particular  int  is 32 bits.  Using  long  guarantees that the old
compiler will never be confused (and the other compilers don't have
those suggested Rules incorporated, so no problem).  But in the
future, should those suggested Rules be accepted and implemented, then
all that a program like this would need, if compiled for, say, a
128-bit processor which had some 256-bit abilities, is something like
this:

#ifdef PROCESSOR_INT_SIZE_128
typedef signed char                    S_08; // signed, 8 bits
typedef signed short short short int   S_16; // signed, 16 bits
typedef signed short short int         S_32; // signed, 32 bits
typedef signed short int               S_64; // signed, 64 bits
typedef signed int                     S128; // signed, 128 bits
typedef signed long int                S256; // signed, 256 bits
typedef unsigned char                  U_08; // unsigned, 8 bits
typedef unsigned short short short int U_16; // unsigned, 16 bits
typedef unsigned short short int       U_32; // unsigned, 32 bits
typedef unsigned short int             U_64; // unsigned, 64 bits
typedef unsigned int                   U128; // unsigned, 128 bits
typedef unsigned long int              S256; // unsigned, 256 bits
#endif

--AND, of course, that  #define PROCESSOR_INT_SIZE_32  above would
have to be changed.  Yet that would be the ONLY change, in this entire
program, for that other processor (Little-Endian/Big-Endian
controversy excepted, but that's a long comment for another place).
*/

// SPECIAL NOTE REGARDING "signed" DATA:  The key fact to ALWAYS
// remember, with respect to computer programs and computer
// programming, is that all data is represented by numbers, and
// THEREFORE there are many ways in which numbers can be used to
// represent data.  It is extremely important that Represenation
// #1 be consistently used, and not be confused with any other
// Representation.  In the particular case of "signed" data, it is
// first Decided that one single bit will represent a negative value
// -- but only if that bit is set.  For any "unsigned" data, it is
// Decided that that same bit will have no negative effect, even if
// set.  More specifically, consider the 8 bits inside a single byte
// of data:  Each bit has a particular numerical value if set, and
// these unsigned values are:  1, 2, 4, 8, 16, 32, 64, and 128.  Note
// that they can be added in any combination to yield results from 1
// to 255 (as well as Zero if none of the bits are set).  If we Decide
// that we want that byte to be able to accommodate negative numbers,
// then this "signed" byte has these bit-values:  1, 2, 4, 8, 16, 32,
// 64, and -128.  Now they can be added in any combination to yield a
// range of values from -128 to +127 (note that this is still a range
// of 256 different values).  The Rule for signed data is very simple
// for all data-sizes, and is always the same:  The largest-magnitude
// bit is negative if set.  All the other bits are always positive.
// So, for signed 16-bit (S_16) data, the biggest bit has the value of
// -32,768; for S_32 data, the biggest bit has the value of
// -2,147,483,648, and so on.



// Prepare a data structure suitable for many repeated
// parameter-groups
struct affect
{ S_32  skipno;       // Number of times to waste pseudorandom
                      //  calculations
  char algo;          // algorithm code E (encrypt) or D (decrypt)
  char pathname[50];  // limitation due to chosen window display
  S_16  dotloc;       // For location of period preceding filename
                      //  extension
  U_32 length;        // length of file-to-affect
  char kill;          // Y (yes) or N (no)
  char newname[50];   // Because files are renamed and not always
                      //  deleted
  struct affect *prev, *next; // Ensure link-pointers set NULL after
                              //  malloc()
}; // A linked list of these will accommodate many data files to
   //  process
// And what is a "linked list"?  It is a thing that depends on the
// fact that a variable can hold a number which is the memory-location
// (or "address") of some other variable.  Such address-holding
// variables are called "pointers", and the address of a structured
// grouping of variables is no different from the address of a single
// variable (both are just numbers).  So, inside each instance of this
// structure called "affect", there is a variable called "next" which
// can hold the address of another "affect" structure.  A simple rule
// to follow is that if "next" does NOT hold a known-to-be-valid
// address, then it should hold the value of NULL (zero).  That way
// one can follow the "next" pointer-links through every item on the
// list of mastdir structures, and know when the end has been reached.
// The comment above, regarding "malloc()", refers to the usage of
// that function to allocate memory to hold an "affect" structure.
// Such a just-allocated structure should be seen as LAST on a linked
// list, and so it is generally logical that its "next" pointer be set
// to NULL.  When ANOTHER "affect" structure gets some just-allocated
// memory, then the earlier structure's "next" pointer can be given
// the address of the new structure, while the new one's "next"
// pointer is set to NULL.  Naturally, the "prev" pointers work the
// same general way, only backward, each pointing at the previous
// "affect" structure in the linked list.  The FIRST structure's
// "prev" pointer must be NULL, is all....



// prepare a data structure suitable for division calculations
struct scratchpad
{ U_32 dvd; // divided (becomes remainder, which is divided again...)
  U_32 dvs; // divisor
}; // For lots and lots of division -- thousands of these are expected
   //  to get used
// Note that the preceding structure could be suitable for holding
// 64-bit numbers.  Some 32-bit compilers include a similar structure,
// because there are occasions when 64-bit numbers are greatly needed.
// Using this  scratchpad  structure will be somewhat unconventional
// though, because the two variables are not named "high" and "low".
// But it could still WORK, thanks to the availability of dynamic
// data-type casting.  Not to mention that some 32-bit compilers don't
// have any equivalent.  And, below, a specific reason for doing this
// is presented.


// Although included in winbase.h, the Borland C++ Builder 5 compiler
// somehow fails to fully recognize the WIN32_FIND_DATA structure.  It
// may be just a bug for which a patch is available.  A work-around is
// this renamed clone:
struct W_F_D    // Since this overall W_F_D structure will be typecast
{ U_32              Attribs;    // as a WIN_32_FIND_DATA when actually
  struct scratchpad CreateTime;   // used, the internal data types and
  struct scratchpad LastAccessed;    // names are irrelevant.  Windows
  struct scratchpad LastWritten;// just wants the correct total number
  U_32              FileSzHi;                             // of bytes.
  U_32              FileSzLo;     // This is the only varible WE need.
  U_32              Rsrvd0;
  U_32              Rsrvd1;
  FAR char          FilNam[MAX_PATH];
  FAR char          AltNam[14];
};
// Fortunately, no other work-arounds were needed, to get four
// different compilers to successfully process this file, with no
// editing needed by the user.  That is, even though the other three
// compilers don't need this structure, they can still accept it and
// use it and the result works fine.  On the other hand, this is to
// be expected when staying within the bounds of the ANSI standards
// for the  C  language.


// Prototypes (also known as "forward declarations") of subroutine
// functions in this file
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam,
                         LPARAM lParam);
S_32 ProcessMessages(void);
S_32 keycheck(void);
S_32 WorkAreaInit(void);
S_32 IndexToPrime(U_32 *dp);
U_32 Divide(struct scratchpad *sp, S_32 bits);
U_08 PseudoRandomize(U_08 uc);
S_32 KeyToPrimes(void);
S_32 AffectFiles(void); // uses struct affect *afflist declared below
/* For those who want to know what that section is all about, note
   that the compiler processes a source-code file like this one from
   start to finish, sequentially.  The compiler will complain if it
   encounters any phrase that it cannot recognize, and such phrases
   include the names of subroutine functions, if they are specified/
   declared/defined in the file AFTER any usage of them.  Since usage
   usually occurs in the "main" part of the program, one solution is
   to place all the subroutine functions/definitions near the start of
   the file, so that they are guaranteed to precede any usage of them.
   However, when there are many subroutines, someone who is editing
   such a file often has to hunt for the start of the main program,
   and there is an aura of untidiness about doing things that way.
   These prototypes are an alternative, a promise to the compiler that
   those functions will be found later on in the file.  Thus the main
   program can be located near the start of the file's executable
   code, and subroutine functions can be located in their logical
   place, at the rear.
*/


/*
Global Variables.  Programmers encounter many discussions regarding
these things.  In a really long program (multiple files) it may be
best to put them all in a structure, and have just one global
structure-pointer, with space for the structure malloc()'d.  Most of
the "static" variables in this program would probably get moved into
such a structure (they are essentially global, anyway).  However,
constant dereferencing of a structure, to get at the variables, slows
a program down.  This program needs to run as fast as possible --
which is why there are relatively few sub-functions (with associated
overhead in calling them frequently, not to mention stack-spasms as
space for local variables is constantly created/destroyed).  Still,
discussions continue, and the oldest-fashion way was chosen here.
*/
struct W_F_D    wfd;
HWND            hwnd;
FILE           *dskfil, *prmfil;
HFONT           hfont1, hfont2;
HANDLE          hPriorF, fil1, fil2;
HINSTANCE       previnst;
LPSTR           szParams;
RECT            rect;
char            eraser[100] = "                                  "
                              "                                 "
                              "                                 ",
                keynam[] = "                         "
                           "                         ", ch,
                keyfile[50], tmpstr[800], tadone[60], prm[50],
                del1, doit, proceed, *p, *q;
U_08           *ucMemBlk1, *ucMemBlk2, *ucMemBlk3, *ucMemBlk4, *ucp1,
               *ucp4, *by, bt, ModType[5], ModData[5];
U_08 skpd[7] = {1, 2, 3, 5, 7, 11, 13};
/* The table below is thoroughly explained in both the PRMPRESS.C and
   PIKPRIME.C files.  Here it is used to decompress the data in the
   COMPRESS.PRM file.  */
U_08 tbl[5761] =
      {16,  2,  4,  6,  2,  6,  4,  2,  4,  6,  6,  2,  6,  4,  2,  6,
        4,  6,  8,  4,  2,  4,  2,  4, 14,  4,  6,  2, 10,  2,  6,  6,
        4,  6,  6,  2, 10,  2,  4,  2, 12, 12,  4,  2,  4,  6,  2, 10,
        6,  6,  6,  2,  6,  4,  2,  6,  4, 14,  4,  2,  4,  6,  8,  6,
       10,  2,  4,  6,  2,  6,  6,  6,  4,  6,  2,  6,  4,  8, 10,  2,
       10,  2,  4,  2,  4,  6,  8,  4,  2,  4, 12,  8,  4,  2,  6,  4,
        6, 12,  2,  4,  2, 12,  6,  4,  6,  6,  6,  2,  6, 10,  2,  4,
        6,  2,  6,  6,  4,  2, 10,  2, 10,  2,  4,  6,  6,  2,  6,  6,
        4,  6,  8,  6,  4,  2,  6,  4,  6,  8,  4,  2,  6,  4,  8,  6,
        4,  8,  4,  6,  8, 10,  2, 10,  2,  6,  4,  2,  4,  2, 10,  2,
       10,  2,  4,  2,  4, 14,  4,  2,  4,  6,  6,  2,  6,  4,  8, 10,
        8,  4,  2,  4,  6,  8,  6,  4,  6,  6,  6,  2,  6,  6,  4,  2,
        4,  6,  2, 10,  2,  4,  2, 10,  2, 10,  2,  6,  4,  8,  6,  4,
        2,  4,  6,  6,  8,  4,  2,  6, 10,  8,  4,  2,  6,  4,  8, 10,
        6,  2,  4,  8,  6,  6,  4,  2,  4,  6,  2,  6,  4,  6,  2, 10,
       12,  2,  4,  2,  4,  6,  2,  6,  4,  2,  4, 12,  2,  6,  6, 10,
        6,  8,  4,  2,  4,  2,  4,  8,  6, 12,  4,  6,  2, 12,  4,  2,
        4,  6,  8,  4,  2,  4,  2, 12, 10,  2,  4,  2,  4,  6,  2, 10,
        2,  4,  6,  8,  6,  4,  2,  6,  4,  6,  8,  4,  6,  2,  4,  8,
        6,  4,  6,  2,  4,  6,  2,  6,  6,  4,  6,  6,  8,  6,  4,  2,
       10,  2, 10,  2,  4,  2, 10,  2,  6,  4,  2, 10,  6,  2,  6,  4,
        2,  6,  4,  6,  8,  6,  4,  2, 12, 10,  6,  2,  4,  6,  2, 12,
        4,  2,  4,  8,  6,  4,  2,  4,  2, 10,  2, 10,  6,  2,  4,  6,
        2,  6,  4,  2, 10,  6,  2,  6,  4, 12,  6,  8,  6,  4,  2,  4,
        8,  6,  4,  6,  2,  4,  6,  8,  6,  6,  4,  6,  2,  6,  4,  2,
        4,  2, 10, 12,  2,  4, 12,  2,  6,  4,  2,  4,  6,  6,  2, 12,
        6,  4, 18,  2,  4,  2,  4,  8,  6,  4,  6,  2,  4,  8,  6,  6,
        4,  2,  4,  6,  2,  6,  4,  2,  4, 12,  2, 12,  6,  4,  6,  2,
        6,  4,  6,  6,  6,  2,  6,  4,  2,  6,  4,  6,  8,  4,  2,  4,
        2,  4, 14,  4,  6,  2, 10,  2,  6,  6,  4,  2, 10,  2, 10,  2,
        4, 14, 10,  2,  4,  2,  4,  6,  2,  6, 10,  6,  6,  2, 10,  2,
        6,  4,  6,  8,  4,  2,  4,  6,  8,  6, 10,  2,  4,  6,  2,  6,
        6,  4,  2,  4,  6,  2,  6,  4,  2,  6, 10,  2, 10,  6,  2,  4,
        6,  8,  4,  2,  4, 12,  2,  6,  4,  2,  6,  4,  6, 12,  2,  4,
        2,  4,  8,  6,  4,  6,  2, 10,  2,  6, 10,  6,  6,  2,  6,  4,
        2,  4,  2, 10,  2, 12,  4,  6,  6,  2, 12,  4,  6,  6,  2,  6,
        4,  2,  6,  4, 14,  4,  2,  6,  4,  8,  6,  4,  6,  2,  4,  6,
        8,  6,  6, 10,  2,  6,  4,  6,  2, 10,  2, 10,  2,  4,  2,  4,
        8,  6,  4,  2,  4,  6,  6,  8,  4,  8,  4,  6,  8,  4,  2,  4,
        2, 12,  6,  4,  6,  6,  6,  2,  6,  6,  4,  2,  4,  6,  2,  6,
        6,  4,  2, 10,  2, 10,  2,  6,  4,  6,  2,  6,  4,  2,  4,  6,
       14,  4,  2,  6, 10,  8,  4,  2,  4,  2,  4,  8, 10,  8,  4,  8,
        6, 10,  2,  4,  6,  2,  6,  4,  6,  2, 10,  2, 10,  2,  4,  2,
        4,  6,  8,  4,  2,  4,  6,  6,  2,  6,  6,  6, 10,  8,  4,  2,
        4,  6,  8,  6,  4,  8,  4,  6,  2,  6,  6,  4,  2,  4,  6, 12,
        2,  4,  2, 10,  2, 10,  2,  4,  2,  4,  8, 10,  2,  4,  6,  8,
        6,  4,  2,  6,  4,  6,  8,  4,  8,  4,  8,  6,  4,  6,  2,  4,
        6,  2,  6,  6,  4,  6,  6,  2,  6,  6,  4,  2, 10, 12,  2,  4,
        2,  4,  6,  2,  6,  4,  2, 16,  2,  6,  4,  2, 10,  6,  8,  4,
        2,  4,  2, 12,  6, 10,  2,  4,  6,  2, 12,  4,  2,  4,  8,  6,
        4,  2,  4,  2, 12, 10,  6,  2,  4,  6,  2,  6,  4,  2,  4,  6,
        6,  2,  6,  4,  2, 10,  6,  8, 10,  2,  4,  8,  6,  4,  6,  2,
        4,  6,  2,  6,  6,  6,  4,  6,  8,  4,  2,  4,  2, 10, 12,  2,
        4,  2, 10,  2,  6,  4,  2,  4,  6,  6,  2, 10,  2,  6,  4, 14,
        6,  4,  2,  4,  8, 10,  6,  2,  4,  6,  2,  6,  6,  4,  2,  4,
        8,  6,  4,  2,  4, 12,  2, 12,  4,  2,  4,  6,  2,  6,  4,  2,
       10,  6,  2,  6,  4,  8,  4,  6,  8,  4,  2,  4,  2,  4, 14,  4,
        6,  2, 10,  8,  6,  4,  2,  4,  6,  2, 10,  2,  4,  2, 12, 10,
        2,  4,  6,  6,  2,  6,  4,  6,  6,  6,  2,  6,  6,  6,  4,  6,
       12,  2,  4,  6,  8,  6, 10,  2,  4,  8,  6,  6,  4,  2,  4,  6,
        2,  6,  4,  2,  6, 10,  2, 10,  2,  6,  4,  6,  8,  4,  6, 12,
        2,  6,  4,  2,  6,  4,  6, 12,  2,  4,  2,  4, 14,  4,  6,  2,
        4,  6,  2,  6, 10,  2, 10,  2,  6,  4,  2,  4, 12,  2, 10,  2,
        4,  6,  6,  2,  6,  6,  4,  6,  6,  2, 10,  2,  6,  4,  6,  8,
        4,  2,  6,  4,  8,  6,  4,  6,  2,  4,  6,  8,  6,  4,  2, 10,
        2,  6,  4,  2,  6, 10,  2, 10,  6,  2,  4,  8,  6,  4,  2,  4,
        6,  6,  2,  6,  4,  8,  4,  6,  8,  4,  2,  4,  2,  4,  8,  6,
        4,  6, 12,  2,  6,  6,  4,  6,  6,  2,  6,  4,  2,  4,  2, 10,
        2, 12,  6,  4,  6,  2, 10,  2,  4,  6,  6,  8,  4,  2,  6, 18,
        4,  2,  4,  2,  4,  8, 10,  6,  2,  4,  8,  6,  6,  6,  4,  6,
        2,  6,  4,  6,  2, 10,  2, 10,  2,  4,  2,  4,  6,  2,  6,  4,
        2,  4,  6,  6,  8,  6,  6,  4,  6,  8,  4,  2,  4,  2, 12,  6,
        4, 12,  6,  2,  6,  6,  4,  2,  4,  6,  8,  6,  4,  2, 10,  2,
       10,  2,  4,  2,  4,  6,  2, 10,  2,  4,  6,  8,  6,  4,  2,  6,
        4,  6,  8,  4,  6,  2,  4,  8,  6,  4,  8,  4,  6,  2,  6, 10,
        6,  6,  2,  6,  6,  4,  2, 10,  2, 10,  2,  4,  2,  4,  6,  8,
        4,  2, 10,  6,  2,  6,  4,  2,  6, 10,  8,  4,  2,  4, 14,  6,
        4,  6,  2,  4,  6,  2, 12,  4,  2,  4,  8, 10,  2,  4,  2, 10,
        2, 10,  6,  2,  4,  8,  6,  4,  2,  4,  6,  6,  2,  6,  4,  2,
       10,  6,  8,  6,  6,  4,  8,  6,  4,  6,  2,  4,  6,  2,  6,  6,
        6,  4,  6,  2,  6,  4,  2,  4,  2, 10, 12,  2,  4,  2, 10,  2,
        6,  4,  2,  4, 12,  2, 10,  2, 10, 14,  4,  2,  4,  2,  4,  8,
        6, 10,  2,  4,  6,  2, 12,  4,  2,  4,  6,  2,  6,  4,  2,  4,
       14, 12,  4,  2,  4,  6,  2,  6,  4,  2,  4,  6,  6,  2,  6,  4,
        2,  6,  4,  6,  8,  4,  6,  2,  4, 14,  4,  6,  2, 10,  2,  6,
        6,  4,  2,  4,  6, 12,  2,  4,  2, 12, 10,  2,  4,  2, 10,  2,
        6,  4,  6,  6,  6,  2,  6,  4,  2,  6,  4,  6,  8,  6,  4,  6,
        8, 16,  2,  4,  6,  2,  6,  6,  4,  2,  4,  8,  6,  4,  2,  6,
       10,  2, 10,  2,  4,  2,  4,  6,  8,  4,  2, 16,  2,  6,  4,  8,
        4,  6, 12,  2,  4,  2,  4,  8,  6,  4,  6,  2,  4,  6,  8, 10,
        2,  4,  6,  2,  6,  4,  2,  4,  2, 10,  2, 10,  2,  4,  6,  6,
        2,  6,  6,  4,  6,  6,  2,  6,  6,  6,  4,  6, 12,  2,  6,  4,
        8,  6,  4,  6,  2,  4, 14,  6,  4,  2, 10,  2,  6,  4,  2,  4,
        2, 10,  2, 10,  2,  6,  4,  8,  6,  4,  6,  6,  6,  2,  6,  4,
        8,  4,  6,  8,  4,  2,  4,  2,  4, 14,  4,  6,  6,  6,  2,  6,
        6,  4,  2, 10,  2,  6,  4,  2,  4, 12,  2, 10,  2,  6,  4,  6,
        2,  6,  6,  4,  6,  6, 12,  2,  6, 10,  8,  4,  2,  4,  2,  4,
        8, 10,  6,  2,  4,  8,  6,  6,  4,  2,  4,  6,  2,  6,  4,  8,
       10,  2, 10,  6,  2,  4,  6,  2,  6,  4,  2,  4,  6,  6,  2,  6,
        6,  6,  4,  6,  8,  4,  2,  4,  2,  4,  8,  6,  4,  8, 10,  2,
        6,  6,  4,  6,  6,  8,  4,  2,  4,  2, 10,  2, 12,  4,  2,  4,
        6,  2, 10,  2,  4,  6,  8,  6,  4,  2,  6,  4, 14,  4,  6,  2,
        4,  8,  6,  4,  6,  2,  4,  6,  2,  6,  6, 10,  6,  2,  6, 10,
        2, 10,  2, 10,  2,  4,  2,  4,  6,  2,  6,  4,  2, 10,  6,  8,
        4,  2,  6,  4,  6,  8,  4,  2,  4,  2, 12,  6,  4,  6,  6,  6,
        2, 12,  4,  2,  4,  8,  6,  6,  4,  2, 10,  2, 10,  6,  2,  4,
        6,  2,  6,  4,  2,  4,  6,  8,  6,  4,  2, 10,  6,  8,  6,  4,
        2,  4,  8,  6,  4,  8,  4,  6,  2,  6, 12,  4,  6,  2,  6,  4,
        2,  4,  2, 10, 12,  2,  4,  2, 10,  8,  4,  2,  4,  6,  6,  2,
       10,  2,  6, 18,  4,  2,  4,  6,  8,  6,  4,  6,  2,  4,  6,  2,
        6,  6,  4,  2,  4,  6,  2, 10,  2,  4, 12,  2, 12,  4,  2,  4,
        8,  6,  4,  2,  4,  6,  6,  2,  6,  4,  2,  6,  4,  6,  8,  4,
        2,  6,  4, 14,  4,  6,  2, 10,  2,  6,  6,  4,  2,  4,  6,  2,
       10,  2,  4,  2, 22,  2,  4,  2,  4,  6,  2,  6,  4,  6, 12,  2,
        6,  4,  2, 10,  6,  8,  4,  2,  4,  6,  8,  6, 10,  2,  4,  6,
        2, 12,  4,  2,  4,  6,  2,  6,  4,  2,  6, 12, 10,  2,  4,  2,
        4,  6,  8,  4,  2,  4, 12,  2,  6,  4,  2,  6,  4,  6, 12,  6,
        2,  4,  8,  6,  4,  6,  2,  4,  6,  2,  6, 10,  2,  4,  6,  8,
        4,  2,  4,  2, 10,  2, 10,  2,  4, 12,  2,  6,  6,  4,  6,  6,
        2,  6,  4,  2,  6,  4,  6,  8,  6,  6,  4,  8, 10,  6,  2,  4,
        6,  8,  6,  4,  2, 12,  6,  4,  2,  4,  2, 10,  2, 10,  2,  4,
        2,  4,  8,  6,  4,  2, 10,  6,  2,  6,  4,  8,  4,  6,  8,  4,
        2,  4,  2,  4,  8,  6,  4,  6,  6,  6,  8,  6,  4,  2,  4,  6,
        2,  6,  4,  2,  4,  2, 10,  2, 10,  2, 10,  6,  2,  6,  4,  2,
        4,  6,  6,  8,  6,  6, 10, 12,  2,  4,  2,  4,  8, 10,  6,  2,
        4,  8,  6,  6,  4,  2,  4,  6,  2,  6,  4,  6,  2, 10,  2, 10,
        2,  6,  4,  6,  2,  6,  4,  6,  6,  6,  2,  6,  6,  6,  4,  6,
        8,  4,  2,  4,  2,  4, 14,  4,  8,  4,  6,  2,  6,  6,  4,  2,
       10,  8,  4,  2,  4, 12,  2, 10,  2,  4,  2,  4,  6,  2, 12,  4,
        6,  8, 10,  2,  6,  4,  6,  8,  4,  6,  2,  4,  8,  6,  4,  6,
        2,  4,  6,  2,  6,  6,  4,  6,  6,  2,  6,  6,  6, 10,  2, 10,
        6,  2,  4,  6,  2,  6,  4,  2, 10,  6,  2,  6,  4,  2,  6,  4,
        6,  8,  4,  2,  4,  2, 12,  6,  4,  6,  2, 10,  2, 12,  4,  6,
        8,  6,  4,  2,  4,  2, 10,  2, 16,  2,  4,  6,  2, 10,  2,  4,
        6,  6,  2,  6,  4,  2, 10, 14,  6,  4,  2,  4,  8,  6,  4,  6,
        2,  4,  6,  2,  6,  6,  6,  4,  6,  2,  6,  4,  6,  2, 10, 12,
        2,  4,  2, 10,  2,  6,  4,  2,  4,  6,  6, 12,  2,  6,  4, 14,
        4,  2,  4,  2, 12,  6,  4,  6,  6,  6,  2,  6,  6,  4,  2,  4,
        6,  2,  6,  6,  4, 12,  2, 12,  4,  2,  4,  6,  2,  6,  4,  2,
        4,  6,  8,  6,  4,  2,  6,  4,  6,  8,  4,  2,  4,  2,  4, 14,
        4,  8, 10,  2,  6, 10,  2,  4,  6,  2, 10,  2,  4,  2, 12, 10,
        2,  4,  2,  4,  6,  8,  4,  6,  6,  6,  2,  6,  4,  2,  6, 10,
        8,  4,  2,  4,  6,  8,  6, 10,  2,  4,  6,  2,  6,  6,  4,  2,
        4,  6,  2, 10,  2,  6, 10,  2, 10,  2,  4,  2,  4, 14,  4,  2,
        4, 12,  2,  6,  4,  2,  6,  4,  6, 12,  2,  6,  4,  8,  6,  4,
        6,  2,  4,  6,  2,  6, 10,  2,  4,  6,  2,  6,  4,  2,  4,  2,
       10, 12,  2,  4,  6,  6,  2,  6,  6,  4, 12,  2,  6,  4,  2, 10,
        6,  8,  4,  2,  6,  4,  8,  6, 10,  2,  4,  6, 14,  4,  2, 10,
        2,  6,  4,  2,  4,  2, 12, 10,  2,  4,  2,  4,  8,  6,  4,  2,
        4,  6,  6,  2,  6,  4,  8,  4,  6,  8,  4,  6,  2,  4,  8,  6,
        4,  6,  6,  6,  2,  6,  6,  4,  2,  4,  6,  8,  4,  2,  4,  2,
       10,  2, 10,  2,  6, 10,  2,  6,  4,  2,  4,  6,  6,  8,  4,  2,
        6, 10,  8,  6,  4,  2,  4,  8, 10,  6,  2,  4,  8,  6,  6,  4,
        2,  4,  8,  6,  4,  6,  2, 10,  2, 10,  2,  4,  2,  4,  6,  2,
        6,  4,  2, 10,  6,  2,  6, 12,  4,  6,  8,  4,  2,  4,  2,  4,
        8,  6,  4,  8,  4,  6,  8,  6,  4,  2,  4,  6,  8,  4,  2,  4,
        2, 10,  2, 10,  2,  4,  6,  6,  2, 10,  2,  4,  6,  8,  6,  6,
        6,  4,  6, 12,  6,  2,  4,  8,  6,  4,  6,  2,  4,  8,  6,  6,
        4,  6,  6,  2,  6,  6,  4,  2, 10,  2, 10,  2,  6,  4,  6,  2,
        6,  4, 12,  6,  2,  6,  4,  2,  6,  4,  6,  8,  4,  2,  4,  2,
       18,  4,  6,  2,  4,  6,  2, 12,  4,  2, 12,  6,  4,  2,  4, 12,
        2, 10,  6,  2,  4,  6,  2,  6,  6,  4,  6,  6,  2, 10,  2, 10,
        6,  8,  6,  4,  2,  4,  8,  6,  4,  6,  2,  4,  6,  2,  6,  6,
        6,  4,  6,  2,  6,  4,  2,  6, 10, 12,  6,  2, 10,  2,  6,  4,
        2,  4,  6,  6,  2, 10,  2,  6,  4, 14,  4,  2,  4,  2,  4,  8,
        6,  4,  6,  2, 10,  2,  6,  6,  4,  6,  6,  2,  6,  4,  2,  4,
       12,  2, 12,  4,  2,  4,  6,  2, 10,  2,  4,  6,  6,  2,  6,  4,
        2,  6,  4, 14,  4,  2,  4,  2,  4, 14,  4,  6,  2, 10,  2,  6,
        6,  6,  4,  6,  2, 10,  6,  2, 12, 10,  2,  4,  2,  4,  6,  2,
        6,  4,  6,  6,  6,  8,  4,  2,  6,  4,  6,  8,  4,  2,  4, 14,
        6, 10,  6,  6,  2,  6,  6,  4,  2,  4,  6,  2,  6,  6,  6, 10,
        2, 10,  2,  4,  2,  4,  6,  8,  4,  2,  4, 14,  6,  4,  2,  6,
        4,  6, 12,  2,  4,  2,  4,  8,  6,  4,  8,  4,  6,  2,  6, 10,
        2,  4,  6,  2,  6,  4,  2,  4,  2, 10,  2, 10,  2,  4,  6,  6,
        8,  6,  4,  6,  6,  2,  6,  4,  2,  6, 10,  8,  4,  2, 10,  8,
        6,  4,  6,  2,  4,  6,  8,  6,  4,  2, 10,  2, 10,  2,  4,  2,
       10,  2, 10,  2,  4,  2,  4,  8,  6,  4,  2,  4,  6,  6,  2,  6,
        4,  8,  4,  6,  8,  4,  2,  6,  4,  8,  6,  4,  6,  6,  6,  2,
        6,  6,  4,  2,  4,  6,  2,  6,  4,  2,  4,  2, 10, 12,  2,  6,
        4,  6,  2,  6,  4,  2,  4, 12,  8,  4,  2, 16,  8,  4,  2,  4,
        2,  4,  8, 16,  2,  4,  8, 12,  4,  2,  4,  6,  2,  6,  4,  6,
        2, 12, 10,  2,  4,  2,  4,  6,  2,  6,  4,  2,  4,  6,  6,  2,
        6,  6,  6,  4,  6,  8,  4,  6,  2,  4,  8,  6,  4,  8,  4,  6,
        2,  6,  6,  4,  2,  4,  6,  8,  4,  2,  4,  2, 10,  2, 10,  2,
        4,  2, 10,  2, 10,  2,  4,  6,  8,  6,  4,  2,  6,  4,  6,  8,
       10,  2,  4,  8, 10,  6,  2,  4,  6,  2,  6,  6,  4,  6,  8,  6,
        6,  4,  2, 10,  2, 10,  2,  4,  2,  4,  6,  2,  6,  4,  2, 10,
        6,  2,  6,  4,  8,  4,  6,  8,  4,  2,  4,  2, 12,  6,  4,  6,
        2,  4,  6, 14,  4,  2,  4,  8,  6,  4,  2,  4,  2, 10,  2, 10,
        6,  6,  6,  2,  6,  4,  2,  4,  6,  6,  2,  6,  6, 10,  6, 14,
        4,  2,  4,  8,  6,  4,  6,  2,  4,  8,  6,  6,  6,  4,  6,  2,
        6,  4,  2,  4,  2, 10, 12,  2,  6, 10,  2,  6,  4,  6,  6,  6,
        2, 10,  2,  6,  4, 14,  4,  2,  4,  2,  4, 14,  4,  6,  2,  4,
        6,  2,  6,  6,  4,  2, 10,  2,  6,  4,  2,  4, 12,  2, 12,  4,
        2,  4,  6,  2,  6,  6,  4,  6,  6,  2, 10,  2,  6,  4,  6,  8,
        4,  2,  4,  2,  4, 14,  4,  6,  2, 10,  2,  6,  6,  4,  2,  4,
        6,  2, 10,  2,  6, 12, 10,  6,  2,  4,  6,  2,  6,  4,  6,  6,
        6,  2,  6,  4,  2,  6,  4,  6,  8,  4,  2,  4,  6,  8,  6, 10,
        2, 10,  2,  6,  6,  4,  6,  6,  2,  6,  4,  2,  6, 10,  2, 12,
        4,  2,  4,  6, 12,  2,  4, 12,  2,  6,  4,  2,  6,  4, 18,  2,
        4,  2,  4,  8,  6,  4,  6,  2,  4,  6,  2,  6, 12,  4,  6,  2,
        6,  4,  6,  2, 10,  2, 10,  2,  4,  6,  6,  2,  6,  6,  4,  6,
        6,  8,  4,  2,  6,  4,  6,  8,  4,  2,  6, 12,  6,  4,  6,  6,
        6,  8,  6,  4,  2, 10,  2,  6,  6,  4,  2, 10,  2, 10,  2,  4,
        2,  4,  8,  6,  4,  2,  4,  6,  8,  6,  4,  8,  4,  6,  8,  4,
        2,  4,  2,  4,  8,  6,  4, 12,  6,  2,  6, 10,  2,  4,  6,  2,
        6,  4,  2,  4,  2, 10,  2, 10,  2,  6,  4,  6,  8,  4,  2,  4,
        6,  6,  8,  4,  2,  6, 10,  8,  4,  2,  4,  6,  8, 10,  6,  2,
        4,  8,  6,  6,  4,  2,  4,  6,  2, 10,  6,  2, 10,  2, 10,  2,
        4,  2,  4,  8,  6,  4,  2,  4,  6,  6,  2,  6,  6,  6,  4,  6,
        8,  4,  2,  6,  4,  8,  6,  4,  8,  4,  6,  2,  6,  6,  4,  2,
        4,  6,  8,  4,  2,  4,  2, 10, 12,  2,  4,  2,  4,  6,  2, 10,
        2,  4, 14,  6,  4,  2, 10,  6,  8,  4,  6,  2,  4,  8,  6, 10,
        2,  4,  6,  2, 12,  4,  6,  6,  2,  6,  6,  4,  2, 12, 10,  2,
        4,  2,  4,  6,  2,  6,  4,  2, 10,  6,  2,  6,  4,  2,  6,  4,
        6,  8,  4,  6,  2, 12,  6,  4,  6,  2,  4,  6,  2, 12,  4,  2,
        4, 14,  4,  2,  4,  2, 10,  2, 10,  6,  2, 10,  2,  6,  4,  2,
        4,  6,  6,  2,  6,  4,  2, 10,  6,  8,  6,  4,  2,  4,  8, 10,
        6,  2,  4,  6,  2,  6,  6,  6,  4,  8,  6,  4,  2,  4,  2, 10,
       12,  2,  4,  2, 10,  2,  6,  4,  2, 10,  6,  2, 10,  8,  4, 14,
        4,  2,  4,  2,  4,  8,  6,  4,  6,  2,  4,  6,  8,  6,  4,  2,
        4,  6,  2,  6,  4,  2,  4, 12,  2, 12,  4,  6,  6,  2,  6,  4,
        2,  4,  6,  6,  2,  6,  6,  6,  4,  6, 12,  2,  4,  2,  4, 14,
        4,  6,  2, 12,  6,  6,  4,  2,  4,  6,  2, 10,  2,  4,  2, 12,
       10,  2,  6,  4,  6,  2,  6,  4,  6,  6,  6,  2,  6,  4,  2,  6,
        4,  6,  8,  4,  2,  4,  6, 14, 10,  2,  4,  6,  2,  6,  6,  4,
        2, 10,  2,  6,  4,  2, 16,  2, 10,  2,  4,  2,  4,  6,  8,  6,
        4, 12,  2, 10,  2,  6,  4,  6, 12,  2,  4,  2,  4,  8,  6,  4,
        6,  2,  4,  6,  2,  6, 10,  2,  4,  6,  2,  6,  4,  2,  6, 10,
        2, 10,  6,  6,  6,  2,  6,  6,  4,  6,  6,  2,  6,  4,  2,  6,
        4,  6,  8,  4,  2,  6,  4,  8,  6,  4,  6,  2, 10,  8,  6,  4,
       12,  2,  6,  4,  2,  4,  2, 10,  2, 12,  4,  2,  4,  8, 10,  2,
        4,  6,  6,  2,  6,  4,  8,  4, 14,  4,  2,  4,  2,  4,  8,  6,
        4,  6,  6,  6,  2,  6,  6,  6,  4,  6,  2,  6,  4,  6,  2, 10,
        2, 10,  2,  6,  4,  6,  2,  6,  4,  2,  4,  6,  6,  8,  4,  2,
        6, 10,  8,  4,  2,  4,  2, 12, 10,  6,  6,  8,  6,  6,  4,  2,
        4,  6,  2,  6, 10,  2, 10,  2, 10,  2,  4,  2,  4,  6,  2,  6,
        4,  2,  4,  6,  8,  6,  6,  6,  4,  6,  8,  4,  2,  4,  2,  4,
        8,  6,  4,  8,  4,  6,  2,  6, 10,  2,  4,  6,  8,  4,  2,  4,
        2, 10,  2, 10,  2,  4,  2,  4,  6, 12,  2,  4,  6,  8,  6,  4,
        2,  6, 10,  8,  4,  6,  6,  8,  6,  4,  6,  2,  4,  6,  2,  6,
        6,  4,  6,  6,  2, 12,  4,  2, 10,  2, 10,  2,  4,  2,  4,  8,
        6,  4,  2, 10,  6,  2,  6,  4,  2,  6,  4,  6,  8,  4,  2,  6,
       12,  6,  4,  6,  2,  4,  6,  2, 12,  4,  2,  4,  8,  6,  4,  2,
        4,  2, 10, 12,  6,  2,  4,  6,  2,  6,  4,  2,  4, 12,  2,  6,
        4,  2, 10,  6,  8,  6,  4,  2,  4,  8,  6, 10,  2,  4,  6,  2,
       12,  6,  4,  6,  2,  6,  4,  2,  4,  2, 22,  2,  4,  2, 10,  2,
        6,  4,  2,  4,  6,  6,  2, 10,  2,  6,  4, 14,  4,  6,  2,  4,
        8,  6,  4,  6,  2,  4,  6,  2,  6,  6,  4,  2,  4,  6,  8,  4,
        2,  4, 12,  2, 12,  4,  2, 10,  2,  6,  4,  2,  4,  6,  6,  2,
        6,  4,  2,  6,  4,  6,  8,  6,  4,  2,  4, 18,  6,  2, 10,  2,
        6,  6,  4,  2,  4,  8, 10,  2,  4,  2, 12, 10,  2,  4,  2,  4,
        6,  2,  6,  4, 12,  6,  2,  6,  4,  8,  4,  6,  8,  4,  2,  4,
        6,  8,  6, 10,  2,  4,  6,  8,  6,  4,  2,  4,  6,  2,  6,  4,
        2,  6, 10,  2, 10,  2,  4,  6,  6,  8,  4,  2,  4, 12,  2,  6,
        6,  6,  4,  6, 12,  2,  4,  2,  4,  8,  6,  4,  6,  2,  4,  8,
        6, 10,  2,  4,  6,  2,  6,  4,  2,  4,  2, 10,  2, 10,  2, 10,
        6,  2,  6, 10,  6,  6,  2,  6,  4,  2,  6,  4,  6,  8,  4,  2,
        6,  4, 14,  4,  6,  2,  4,  6,  8,  6,  4,  2, 10,  2,  6,  4,
        2,  4, 12,  2, 10,  2,  4,  2,  4,  8,  6,  6,  4,  6,  6,  2,
       10,  8,  4,  6,  8,  4,  2,  4,  2,  4,  8,  6,  4,  6,  6,  6,
        2,  6,  6,  4,  2,  4,  6,  2,  6,  4,  2,  6, 10,  2, 10,  8,
        4,  6,  2,  6,  4,  2,  4,  6,  6,  8,  4,  2,  6, 10,  8,  4,
        2,  4,  2,  4,  8, 10,  6,  2, 12,  6,  6,  4,  6,  6,  2,  6,
        4,  6,  2, 10,  2, 12,  4,  2,  4,  6,  2, 10,  2,  4,  6,  6,
        2,  6,  6,  6,  4, 14,  4,  2,  4,  2,  4,  8,  6,  4,  8,  4,
        6,  2,  6,  6,  6,  4,  6,  8,  4,  6,  2, 10,  2, 10,  2,  4,
        2,  4,  6,  2, 10,  2,  4,  6, 14,  4,  2,  6,  4,  6,  8,  4,
        6,  2, 12,  6,  4,  6,  6,  6,  2,  6,  6,  4,  6,  6,  2,  6,
        6,  4,  2, 10,  2, 10,  2,  4,  2,  4,  6,  2,  6,  4,  2, 10,
        8,  6,  4,  2,  6,  4,  6,  8,  4,  2,  4,  2, 12,  6,  4,  8,
        4,  6,  2, 16,  2,  4,  8,  6,  4,  2,  4,  2, 10,  2, 10,  6,
        2,  4,  6,  8,  4,  2,  4,  6,  6,  2,  6,  4,  2, 16,  8,  6,
        4,  6,  8,  6,  4,  6,  2,  4,  6,  2,  6,  6,  6,  4,  6,  2,
       10,  2,  4,  2, 10, 12,  2,  4,  2, 12,  6,  4,  2,  4,  6,  6,
        2, 10,  2,  6,  4, 14,  4,  2,  6,  4,  8,  6,  4,  6,  2,  4,
        6,  2,  6,  6,  4,  2,  4,  6,  2,  6,  4,  2,  4, 12, 14,  4,
        2,  4,  6,  2,  6,  4,  2,  4, 12,  2,  6,  4,  2, 10,  6,  8,
        4,  2,  4,  2,  4, 14, 10,  2, 10,  2, 12,  4,  2,  4,  6,  2,
       10,  2,  4,  2, 12, 10,  2,  4,  2,  4,  6,  2,  6,  4,  6,  6,
        6,  2,  6,  4,  2,  6,  4,  6,  8,  4,  6,  6,  8,  6, 10,  2,
        4,  6,  2,  6,  6,  4,  2,  4,  6,  8,  4,  2,  6, 10,  2, 10,
        2,  4,  2, 10,  8,  4,  2,  4, 12,  2,  6,  4,  2,  6,  4,  6,
       14,  4,  2,  4,  8, 10,  6,  2,  4,  6,  2,  6, 10,  2,  4,  8,
        6,  4,  2,  4,  2, 10,  2, 10,  2,  4,  6,  6,  2,  6,  6, 10,
        6,  2,  6,  4,  8,  4,  6,  8,  4,  2,  6,  4,  8,  6,  4,  6,
        2,  4,  6,  8,  6,  4,  2, 10,  2,  6,  4,  2,  4,  2, 10,  2,
       10,  2,  4,  6,  8,  6,  4,  2,  4,  6,  6,  2,  6, 12,  4,  6,
       12,  2,  4,  2,  4,  8,  6,  4,  6,  6,  8,  6,  6,  4,  2,  4,
        6,  2,  6,  4,  2,  4,  2, 10,  2, 10,  2,  6,  4,  6,  2,  6,
        4,  6,  6,  6,  8,  4,  2,  6, 10,  8,  4,  2,  4,  2,  4, 18,
        6,  2,  4,  8,  6,  6,  4,  2, 10,  2,  6,  4,  6, 12,  2, 10,
        2,  4,  2,  4,  6,  2,  6,  6,  4,  6,  6,  2, 12,  6,  4,  6,
        8,  4,  2,  4,  2,  4,  8,  6,  4,  8,  4,  6,  2,  6,  6,  4,
        2,  4,  6,  8,  4,  2,  6, 10,  2, 10,  6,  2,  4,  6,  2, 10,
        2,  4,  6,  8,  6,  4,  2,  6,  4,  6,  8,  4,  6,  2,  4,  8,
        6,  4,  6,  2, 10,  2,  6,  6,  4,  6,  6,  2,  6,  6,  4,  2,
       10,  2, 12,  4,  2,  4,  6,  2, 10,  2, 10,  6,  2,  6,  4,  2,
        6,  4, 14,  4,  2,  4,  2, 12,  6,  4,  6,  2,  4,  6,  2, 12,
        6,  4,  8,  6,  4,  6,  2, 10,  2, 10,  6,  2,  4,  6,  2,  6,
        4,  2,  4,  6,  6,  8,  4,  2, 10,  6,  8,  6,  4,  2, 12,  6,
        4,  6,  6,  6,  2,  6,  6,  6,  4,  6,  2,  6,  6,  4,  2, 10,
       12,  2,  4,  2, 10,  2,  6,  4,  2,  4,  6,  8, 10,  2,  6,  4,
       14,  4,  2,  4,  2,  4,  8,  6,  4,  8,  4,  6,  2,  6, 10,  2,
        4,  6,  2,  6,  4,  2,  4, 12,  2, 12,  4,  2,  4,  6,  8,  4,
        2,  4,  6,  6,  2,  6,  4,  2,  6, 10,  8,  4,  2,  4,  6, 14,
        4,  6,  2, 10,  2,  6,  6,  4,  2,  4,  6,  2, 10,  2,  4,  2,
       12, 10,  2,  4,  2,  4,  8,  6,  4,  6,  6,  6,  2,  6,  4,  2,
        6,  4,  6,  8,  4,  2, 10,  8,  6, 10,  2,  4,  6,  2,  6,  6,
        4,  2,  4,  6,  2,  6,  4,  2,  6, 10, 12,  2,  4,  2,  4,  6,
        8,  4,  2,  4, 12,  2,  6,  4,  2, 10,  6, 12,  2,  4,  2,  4,
        8,  6, 10,  2,  4,  6,  2, 16,  2,  4,  6,  2,  6,  4,  2,  4,
        2, 12, 10,  2,  4,  6,  6,  2,  6,  6,  4,  6,  6,  2,  6,  4,
        2,  6,  4,  6,  8,  4,  8,  4,  8,  6,  4,  6,  2,  4,  6,  8,
        6,  4,  2, 10,  8,  4,  2,  4,  2, 10,  2, 10,  2,  4,  2, 12,
        6,  4,  2,  4,  6,  6,  2,  6,  4,  8,  4,  6,  8,  6,  4,  2,
        4,  8, 10,  6,  6,  6,  2,  6,  6,  4,  2,  4,  8,  6,  4,  2,
        4,  2, 10,  2, 10,  2,  6,  4,  6,  2,  6,  4,  2, 10,  6,  8,
        4,  8, 10,  8,  4,  2,  4,  2,  4,  8, 10,  6,  2,  4, 14,  6,
        4,  2,  4,  6,  2,  6,  4,  6,  2, 10,  2, 10,  2,  4,  6,  6,
        2,  6,  4,  2,  4,  6,  6,  2,  6,  6,  6,  4,  6, 12,  2,  4,
        2,  4,  8,  6,  4,  8,  4,  8,  6,  6,  4,  2,  4,  6,  8,  4,
        2,  4,  2, 10,  2, 10,  2,  6,  4,  6,  2, 10,  6,  6,  8,  6,
        4,  2,  6,  4,  6,  8,  4,  6,  2,  4, 14,  4,  6,  2,  4,  6,
        2,  6,  6,  4, 12,  2,  6,  6,  4, 12,  2, 10,  2,  4,  2,  4,
        6,  2,  6,  6, 10,  6,  2, 10,  2,  6,  4,  6,  8,  4,  2,  4,
        2, 12,  6,  4,  6,  2,  4,  6,  2, 12,  4,  2,  4,  8,  6,  4,
        2,  6, 10,  2, 10,  6,  2,  4,  6,  2,  6,  4,  2,  4,  6,  6,
        2,  6,  4,  2, 10,  6,  8,  6,  4,  2,  4,  8,  6,  4,  6,  2,
       10,  2,  6,  6, 10,  6,  2,  6,  4,  2,  4,  2, 10, 14,  4,  2,
       10,  2, 10,  2,  4,  6,  6,  2, 10,  2,  6,  4, 14,  4,  2,  4,
        2,  4,  8,  6,  4,  6,  2,  4,  6,  2,  6,  6,  6,  4,  6,  2,
        6,  4,  6, 12,  2, 12,  4,  2,  4,  6,  2,  6,  4,  2,  4,  6,
        6,  8,  4,  2,  6,  4,  6,  8,  4,  2,  4,  2, 18,  4,  6, 12,
        2,  6,  6,  4,  2,  4,  6,  2, 12,  4,  2, 12, 10,  2,  4,  2,
        4,  6,  2,  6,  4,  6,  6,  8,  6,  4,  2,  6,  4,  6,  8,  4,
        2,  4,  6,  8,  6, 12,  4,  6,  2,  6, 10,  2,  4,  6,  2,  6,
        4,  2,  6, 10,  2, 10,  2,  4,  2,  4,  6,  8,  4,  2,  4, 12,
        2,  6,  4,  2,  6, 10, 12,  2,  4,  6,  8,  6,  4,  6,  2,  4,
        6,  2,  6, 10,  2,  4,  6,  2, 10,  2,  4,  2, 10,  2, 10,  2,
        4,  6,  8,  6,  6,  4,  6,  6,  2,  6,  4,  2,  6,  4,  6,  8,
        4,  2,  6,  4,  8,  6,  4,  6,  2,  4,  6,  8,  6,  4,  2, 10,
        2,  6,  4,  2,  4,  2, 10, 12,  2,  4,  2,  4,  8,  6,  4,  2,
        4, 12,  2,  6,  4, 12,  6,  8,  4,  2,  4,  2,  4,  8,  6, 10,
        6,  6,  2, 12,  4,  2,  4,  6,  2,  6,  4,  2,  4,  2, 12, 10,
        2,  6,  4,  6,  2,  6,  4,  2,  4,  6,  6,  8,  4,  2,  6, 10,
        8,  4,  6,  2,  4,  8, 10,  6,  2,  4,  8,  6,  6,  4,  2,  4,
        6,  8,  4,  6,  2, 10,  2, 10,  2,  4,  2, 10,  2,  6,  4,  2,
        4,  6,  6,  2,  6,  6,  6,  4,  6,  8,  6,  4,  2,  4,  8, 10,
        8,  4,  6,  2,  6,  6,  4,  2,  4, 14,  4,  2,  4,  2, 10,  2,
       10,  2,  4,  2,  4,  6,  2, 10,  2, 10,  8,  6,  4,  8,  4,  6,
        8,  4,  6,  2,  4,  8,  6,  4,  6,  2,  4,  6,  8,  6,  4,  6,
        6,  2,  6,  6,  4,  2, 10,  2, 10,  2,  4,  6,  6,  2,  6,  4,
        2, 10,  6,  2,  6,  6,  6,  4,  6, 12,  2,  4,  2, 12,  6,  4,
        6,  2,  4,  8, 12,  4,  2,  4,  8,  6,  4,  2,  4,  2, 10,  2,
       10,  8,  4,  6,  2,  6,  4,  6,  6,  6,  2,  6,  4,  2, 10,  6,
        8,  6,  4,  2,  4, 14,  4,  6,  2,  4,  6,  2,  6,  6,  6, 10,
        2,  6,  4,  2,  4, 12, 12,  2,  4,  2, 10,  2,  6,  6,  4,  6,
        6,  2, 10,  2,  6,  4, 14,  4,  2,  4,  2,  4,  8,  6,  4,  6,
        2,  4,  6,  2,  6,  6,  4,  2,  4,  6,  2,  6,  4,  2, 16,  2,
        0};
S_16              *qp;
S_32               NeedInfo, params, fpb, i, j, L, huminp, mastnum,
                  *lim, affnum = 1, affcou, status=0, WhichWay[2],
                   WorkSize, prmbar;
U_32              *ip, *is, *it;
size_t             fetched, big;
struct affect     *afflist = NULL, *affitem, *affprev, **affwalk;
struct scratchpad *LoadMaster, *ModCounter, *TypeSetter,
                  *RandomSkip, *WorkRegion;
// Note:  size_t  is a typedef like U_32, and happens to be the
//  same as U_32.



//////////////////////////////////////////////////////////////////////
// BEGIN:  WinMain is the primary/required starting point of any
// Windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR szCmdLine, int iCmdShow)
{ static char szAppName[] = "Cryption";
  MSG         msg;
  WNDCLASS    wndclass;

  previnst = hPrevInstance;    // Save to global to eliminate compiler
                               //  warning
  ucMemBlk1 = malloc(1100000); // Buffer for file input, modification,
                               //  and output
  ucMemBlk2 = malloc(525000);  // main work area, 65536 scratchpads,
                               //  8 bytes each
  ucMemBlk3 = malloc(600000);  // For the Index to the compressed-
                               //  primes data file
  ucMemBlk4 = malloc(4200000); // For sorting up to 65536 4-byte
                               //  numbers, quickly
  if((ucMemBlk1 == NULL) || (ucMemBlk2 == NULL) ||
     (ucMemBlk3 == NULL) || (ucMemBlk4 == NULL))
  { if(ucMemBlk1)
      free(ucMemBlk1);
    if(ucMemBlk2)
      free(ucMemBlk2);
    if(ucMemBlk3)
      free(ucMemBlk2);
    if(ucMemBlk4)
      free(ucMemBlk2);
    MessageBox(NULL, "NOT ENOUGH MEMORY!", "ERROR",
               MB_OK | MB_ICONSTOP);
    exit(CRP_ERR_OM); // exit code 1: Out of Memory
  }
  // Next critical step: ensure data file and index are available
  fetched = GetLogicalDrives();// Bitmap of available drives
                               //  1=A, 2=B, 4=C, 8=D, etc, 0=fail
  ch = 'C'; // here and below (i=4) skip Drive A and Drive B
  for(big=4; big; big<<=1) // Loop quits when bit shifted off end
                           //  and  i  becomes Zero
  { if((fetched & big) == big)
    { sprintf(tmpstr, "%c:\\PRIMES\\COMPRESS.PRM", ch);
      prmfil = fopen(tmpstr, "rb");
      if(prmfil != NULL)
      { fpb = 0; // initialize file-position-byte
        sprintf(tmpstr, "%c:\\PRIMES\\CMPRMDEX.QNT", ch);
        dskfil = fopen(tmpstr, "rb");
        break; // Quit for() loop regardless of existence of file,
               //  because have other file
    } } // Otherwise continue loop; assume compressed-prime file
        //  does not exist here; try next drive
    ch++; // 'D, 'E', etc
  }
  if((prmfil == NULL) || (dskfil == NULL))
  { MessageBox(NULL, "Files COMPRESS.PRM and CMPRMDEX.QNT are not\n"
                     "both available in a \\PRIMES directory.",
               "ERROR", MB_OK | MB_ICONSTOP);
    exit(CRP_ERR_OF); // using exit code 2: Opening File
  }
  fread(ucMemBlk1, 2, 143023, dskfil); // Load entire primes-data-
                                       //  Index file
  fclose(dskfil);     // close the file
  lim = (S_32 *)(ucMemBlk1 + 286046);
  ip = (U_32 *)ucMemBlk3;  // initialize Index pointer
  i = 0;
  for(qp=(S_16 *)ucMemBlk1; qp<(S_16 *)lim; )
  { i += *qp++;   // accumulate number of primes in this indexed block
    *ip++ = i;     // save the accumulations for later binary search
  }
/*It might be noted that the preceding calculations using the Index
  data file (and future calcs using the compressed Primes data file)
  are not subject to the Endian controversy.  This is because it is
  expected that the algorithms in PRMPRESS.C would have been compiled
  and executed to generate the files on the same computers that are
  going to use those files.  A problem is likely if, say, a Little
  Endian machine was used to generate the files, and a Big Endian
  machine was given a COPY of those files.  But that's not likely,
  mostly because you now know about it and can avoid it.
*/

  // Next up: Set four special scratchpads used to Control
  LoadMaster = (struct scratchpad *)(&ucMemBlk2[0]);  // the
  ModCounter = (struct scratchpad *)(&ucMemBlk2[8]);  // CRYPTION
  TypeSetter = (struct scratchpad *)(&ucMemBlk2[16]); // algorithm
  RandomSkip = (struct scratchpad *)(&ucMemBlk2[24]);
  WorkRegion = (struct scratchpad *)(&ucMemBlk2[32]); // Begin 64K
                                    // scratchpads, array-accessed
  // Those prior five lines are a way of telling the compiler that the
  // simple unorgainzed block of memory allocated for the ucMemBlk2
  // pointer (half-a-million bytes +) is going to be accessed as if it
  // was a huge array of scratchpad structures (each of which occupies
  // 8 bytes).  The first four are special-purpose scratchpads that
  // deserve their own names, which will control major aspects of the
  // CRYPTION process, as described elsewhere in this file.
  // "WorkRegion" is the name by which thousands of other scratchpads
  // can be accessed (specific examples are WorkRegion[15] and
  // WorkRegion[3749]) in that memory-block.  One of the best features
  // of the  C  programming language is something called "pointer
  // arithmetic".  Those references like "ucMemBlk2[24]" are
  // specifying particular numbers of bytes from the start of the
  // memory block, simply because ucMemBlk2 was declared as a "char"
  // pointer, and "char" variables occupy one byte each.  However,
  // since WorkRegion (and the others) are pointers to 8-byte
  // scratchpad structures, the compiler automatically knows to put
  // WorkRegion[193] 8 bytes after WorkRegion[192].  Thus while
  // WorkRegion[0] is located at ucMemBlk2[32], WorkRegion[1] is
  // located at ucMemBlk2[40], and WorkRegion[2] is located at
  // ucMemBlk2[48], and so on, for 65536 WorkRegion scratchpads, and
  // for 524288 bytes of memory in ucMemBlk2.
  tadone[0] = '\0';
  NeedInfo = 63;   // Binary 00111111 --flag-bits that will be cleared
                                                   // as info verified
  keyfile[0] = '\0';
  del1 = 'N';                     // default Don't Delete the Key File
  afflist = affitem = NULL;
  affwalk = &afflist; // get address of linked-list first-item pointer
                                                   // (currently NULL)
  affcou = 0;              // initialize count of items on linked list
  doit = ' ';
  proceed = ' ';
  szParams = szCmdLine;               // prepare to process parameters
  for(params=0; szParams[params]; params++)   // Use this loop to find
                                            // length of param-string,
    szParams[params] = (char)toupper(szParams[params]);    // ensuring
                                                          // uppercase
  //NOTE: Parsing stops at any failure point, or at NULL-terminator.
  // Insufficient acceptable parameters will result (later) in waiting
  // for human input.
  huminp = 1;// Assume missing or faulty params, so human input needed
  if(params)                        // if any length of parameter-info
  { ch = szParams[0];// Windows ensures first character is not a space
    if(ch == '"')// Validate required quotation mark for Key File Name
    { p = ++szParams;//Skip the open-quote and save start of File Name
      q = strchr(p, '"');         // look for the required close-quote
      if(q)                      // result of seeking must not be NULL
      { L = (int)(uli(q) - uli(p));//compute length of drive\path\name
        if(L && (L < 49))           //Key File Name must exist and not
                                                        // be too long
        { strncpy(keyfile, p, L);// copy the stuff between quote marks
          keyfile[L] = '\0';     // strncpy does not terminate string,
                                                           // so do it
          szParams += L;  // Skip filename (pointer now at close-quote
          while(' ' == (ch = *(++szParams)));     // 1-line loop: skip
                                       // current character and spaces
          if(ch == 'D')                      // check for optional 'D'
          { del1 = 'Y';           // Set flag to delete Key File after
                                               // successful operation
            while(' ' == (ch = *(++szParams))); // Same 1-line loop as
                                                 // above; skip spaces
          }     // If optional 'D' wasn't there, no problem continuing
          do   // BEGIN LOOP TO PARSE 4 PARAMS FOR EACH FILE TO AFFECT
          { if(isdigit(ch))           // A skip number is now required
            { huminp = 1;            // More params to process, assume
                                       // will need human input to fix
              affprev = affitem;               // Save current item as
                                               // about-to-be-previous
              *affwalk = malloc(sizeof(struct affect));     // reserve
                                      // some memory (sets 2 pointers)
              if(!*affwalk)                               // if failed
              { while(afflist)    // while an item on this list exists
                { affitem = afflist;          // save the current item
                  afflist = afflist->next;   // Get at a possible next
                                                 // item (may be NULL)
                  free(affitem);                // delete current item
                }
                MessageBox(NULL, "NOT ENOUGH MEMORY!", "ERROR",
                           MB_OK | MB_ICONSTOP);
                free(ucMemBlk1);
                free(ucMemBlk2);
                free(ucMemBlk3);
                free(ucMemBlk4);
                exit(CRP_ERR_OM);        // exit code 1: Out of Memory
              }// Program-flow passes this point only after successful
                                                  // memory allocation
              affcou++;   // count number of items on this linked list
              affitem = *affwalk;// get easy pointer to this list item
              affitem->prev = affprev;//set link to prior item on list
              afflist->prev = affitem;  // Set FIRST-item link to last
                                             // (current) item on list
              affprev = affitem->prev;// Refetch pointer, but at FIRST
                                                   // sets to NON-NULL
              affitem->next = NULL;    // Ensure new structure doesn't
                                                     // point anywhere
              affwalk = &(affitem->next);   // Get address of linklist
                                              // pointer for next loop
              affitem->dotloc = -1;      // Initialize in case no file
                                                          // extension
              affitem->kill = 'E'; // Initialize to Error in case loop
                                                        // quits early
              i = 0;                            // initialize a number
              do      // can do this at least once since ch is a digit
              { i = i * 10 + (ch - '0');    // Accumulate Skip Number;
                                     // convert digit's CHARACTER-CODE
              } while(isdigit(ch = *(++szParams)) && (i <= 999999));
                                                  //NOTE if i==999999,
                          // then next loop makes i nearly ten million
              affitem->skipno = i;             // save the skip number
              if((ch == ' ') || isdigit(ch))  // Did digit loop end at
                                                  // a space or digit?
                while((' ' == (ch = *(++szParams))) || isdigit(ch));
                                       // skip spaces or excess digits
              if((ch != 'D') && (ch != 'E'))   // Did that loop end at
                                           // required algorithm code?
                break;                      // end affwalk loop if not
              affitem->algo = ch;           // save the algorithm code
              while(' ' == (ch = *(++szParams)));//Skip any/all spaces
                                                     // that follow it
              if(ch != '"')        // Should now be at required quoted
                                                          // file name
                break;                      // end affwalk loop if not
              p = ++szParams;               // Skip the open-quote and
                                            // save start of File Name
              q = strchr(p, '"'); // look for the required close-quote
              if(q == NULL)                         // if wasn't there
                break;                             // end affwalk loop
              L = (int)(uli(q) - uli(p));         // Compute length of
                                                    // drive\path\name
              if((L < 1) || (L > 48))  // Key File Name must exist and
                                                    // not be too long
                break;                             // end affwalk loop
              q = affitem->pathname; // Get easy pointer to the copied
                                                    // pathfile string
              strncpy(q, p, L);  // Copy the stuff between quote marks
              q[L] = '\0';                     // terminate the string
              for(i=L-1; i>=0; i--)       // Walk backward through the
                                                           // filename
              { ch = q[i];
                if((ch == '\\') || (ch == ':'))
                  break;               // found marker before filename
                       // quit looping regardless of finding extension
                if((ch == '.') && (affitem->dotloc == -1))
                { affitem->dotloc = (S_16)i;       // Save location of
                                       // first-found extension-marker
                  break;             // no need to continue for() loop
              } }
              if(((i == -1) && (L > 44)) ||  // MUST HAVE ROOM IN FILE
                                              // NAME STRING TO EITHER
                  ((48 - i) < 4))           // REPLACE EXTENSION WITH,
                                                       // OR ADD, .CRP
                break;                             // end affwalk loop
              szParams += L;          // Skip filename (pointer now at
                                                        // close-quote
              while(' ' == (ch = *(++szParams)));//Skip any/all spaces
                                                     // that follow it
              if(!ch || (ch == ' ') || isdigit(ch))// String ended, or
                                               // have space or digit?
                affitem->kill = 'N';            // Default to NO KILL;
                                            // valid option is missing
              else if(ch != 'D')//anything else MUST be a D for delete
                break;  // keep the Error-marker and quit affwalk loop
              else
                affitem->kill = 'Y';      // have a D, so set YES KILL
              if(ch && !isdigit(ch))                  // if D or space
                while(' ' == (ch = *(++szParams)));     // Skip it and
                                           // any/all following spaces
              huminp = 0;               // Params accepted -- no human
                                                // input needed to fix
            }      // note huminp reset to 1 if another file-to-affect
            else
              break;            // nondigit where a digit was required
          } while(*szParams);      // need at least one to-affect file
  } } } }                     // continue parsing the parameter-string
  affitem = affprev = afflist; // Set pointers to start of linked list
                                                        // (if exists)
  affwalk = &afflist;                             // and this one, too

  if(!huminp)               // so far no errors requiring human input?
    doit = 'A';         // prepare for automatic-acceptance processing


// DONE PROCESSING PARAMETERS; TIME TO DO ORDINARY WINDOWS STUFF

// Prepare a couple of fixed fonts,
// only differece is that one is underlined
  hfont1 = CreateFont(0, 7, 0, 0, 0, 0, 0, 0, ANSI_CHARSET,
                      OUT_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS,
                      DEFAULT_QUALITY, (FIXED_PITCH | FF_MODERN),
                      "SimpleFixed"); // NO UNDERLINE
  hfont2 = CreateFont(0, 7, 0, 0, 0, 0, 1, 0, ANSI_CHARSET,
                      OUT_DEFAULT_PRECIS, CLIP_CHARACTER_PRECIS,
                      DEFAULT_QUALITY, (FIXED_PITCH | FF_MODERN),
                      "SimpleFixUN"); // UNDERLINED
/* (Copied from Language Reference)
CreateFont
 (int     nHeight,           // logical height of font (0=default)
  int     nWidth,            // logical average character width
                             // (0=default, using 7)
  int     nEscapement,       // angle of escapement (0=default)
  int     nOrientation,      // base-line orientation angle(0=default)
  int     fnWeight,          // font weight (0=default)
  DWORD   fdwItalic,         // italic attribute flag (0=False)
  DWORD   fdwUnderline,      // underline attribute flag (0=False)
  DWORD   fdwStrikeOut,      // strikeout attribute flag (0=False)
  DWORD   fdwCharSet,        // character set identifier, using
                             // ANSI_CHARSET
  DWORD   fdwOutputPrecision,// output precision, using default
  DWORD   fdwClipPrecision,  // clipping precision, using SOME
  DWORD   fdwQuality,        // output quality, using default
  DWORD   fdwPitchAndFamily, // pitch and family,
                             // using Fixed and no 'serif"
  LPCTSTR lpszFace);         // address of typeface name string
*/

// FINALLY READY TO CREATE A WINDOW FOR THIS PROGRAM
//wndclass.Size          = sizeof(wndclass);
  wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc   = WndProc;
  wndclass.cbClsExtra    = 0;
  wndclass.cbWndExtra    = 0;
  wndclass.hInstance     = hInstance;
  wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
  wndclass.lpszMenuName  = NULL;
  wndclass.lpszClassName = szAppName;
//wndclass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);// NOT USED
  RegisterClass(&wndclass);
  hwnd = CreateWindow(szAppName, "PRIMARY CRYPTION",
                      WS_CAPTION | WS_VISIBLE,
                      5, 5,
                      575, 280,
                      NULL, NULL, hInstance, NULL);
  ShowWindow(hwnd, iCmdShow);
  UpdateWindow(hwnd);
// Main Windows Program Loop; ends when the Quit message returns zero
  for(;;)
  { if(GetMessage(&msg, NULL, 0, 0))
    { TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    else
      break; // GetMessage pulled a WM_QUIT and returned zero; exit!
  }
// Windows programming is like a dance; the Operating System is
// willing to spend time executing your program-code as long as you
// let it take the "lead".  WINDOWS interacts with the user, and
// Windows will pass messages to your program, telling it what the
// user wants.  This tends to make your program a collection of
// disconnected blocks of code, each block waiting for the user to
// tell Windows to pass a message to it, to do its thing.  On the
// other hand, as long as Windows knows that your program is doing a
// GetMessage()/TranslateMessage()/DispatchMessage() loop, it doesn't
// matter WHERE your program does it.  (See the ProcessMessages()
// subroutine later on in the file.)  This means your program can do
// stuff without always waiting for Windows to give the go-ahead, and
// in fact the original author of the CRYPTION program once used such
// a trick to make a large, developed-for-a-decade, multi-megabyte
// pure-DOS program (the kind that wants total control of all
// operations of the computer) co-exist with the Windows paradigm, AS
// IF it had become an ordinary Windows program.  (Well, there was
// more to it than just that trick, but 90%+ of the original code did
// not need to be modified.)


// BEGIN ORGANIZED EXIT PROCESS
// CLEAN UP ALL ALLOCATED MEMORY
  free(ucMemBlk1);                                  // file I/O buffer
  free(ucMemBlk2);                                        // workspace
  free(ucMemBlk3);                         // prime-search/index table
  free(ucMemBlk4);                 // sorting are when preparing Index
      // To clean up the linked list, we use the starting "anchor" and
  while(afflist)  //  walk the list: while an item on this list exists
  { affitem = afflist;                        // save the current item
    afflist = afflist->next; // get a possible next item (may be NULL)
    free(affitem);                              // delete current item
  }
  if(prmfil != NULL)
    fclose(prmfil);                                  // close the file
  system("DEL .\\TMP*.CRP");                     // Clean up after any
                                        // abort-while-affecting-files
  return(msg.wParam);          // CRYPTION.EXE program terminates here
}; // PERSONAL PREFERENCE QUIRK of original author:  The  return
   // statement in  C  is not a function, and so the value returned,
   // msg.wParam  here, does not need to be surrounded by parentheses.
   // However, the  return  statement is LIKE a function-call -- such
   // as system() or free() above, where parentheses are mandatory --
   // in the sense that  return  can transmit a value elsewhere.
   // Thus, mostly for the sake of "aesthetic consistency" does the
   // original author prefer to associate parentheses with any  return
   // statement that transmits a value.  The compiler does not care,
   // and in some cases, such as when a complicated expression must be
   // evaluated to produce the return-value, parentheses often make
   // sense for that reason alone, to clarify something to the
   // compiler (or another human).  So using parentheses generally for
   // aesthetics means being consistent with the special case, also.



//////////////////////////////////////////////////////////////////////
// Critical Window Procedure: Windows passes User-Activity messages to
// it, for processing
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam,
                         LPARAM lParam)
{ // A function that uses a lot of local variables is often a function
  // that is taking a performance hit.  The computer has a special
  // place in its memory called the "stack" to which local variables
  // are typically added and removed as needed -- which is EVERY time
  // a function begins or ends.  Adding or removing a lot of local
  // variables, when a function is called many many times, can be
  // called a "stack-thrashing" time-wasting event.  What is an
  // alternative, when global variables are frowned-upon these days?
  // Well, a special type of local variable is called "static", which
  // is stored outside the stack, in a kind-of-global way, and
  // persists for as long as the overall program runs -- but it is
  // still accessed only by the function that declares it.  Static
  // variables are useful for remembering data in-between calls to the
  // function.  While some of that remembrance is needed here, in just
  // a few variables, what is needed more is the time savings that
  // comes with zero stack-thrashing.  So here all the local variables
  // are declared as static.
  static HDC         hdc;
  static PAINTSTRUCT ps;
  static COLORREF    oldcolr;
  static struct      affect *afftmp;
  static S_32        painting = 0, gathlen = 0, skip = -1, gotdat = 0;
  static S_32        dot, repaint, juset = 0, working = 0, ret;
  static char        algo = ' ', del2 = 'N', gather[50] = {' ','\0'},
                     dofile[50] = {'\0'}, sd1 = ' ',
                     savskp[50] = {'\0'}, savalg = ' ',
                     savdo[50] = {'\0'},
                     sd2 = ' ', d1 = ' ', alg = ' ', d2 = ' ';

  // The 'working' variable is set when all data entry has been
  // accepted and the program is beginning to do its CRYPTIONing.  It
  // is used to ignore all code associated with the data-entry
  // process, and to limit screen-displays to such things as a
  // progress bar.
  if(!working && (affitem == NULL))
  { *affwalk = malloc(sizeof(struct affect));   // Reserve some memory
                                                  // (sets 2 pointers)
    affitem = *affwalk;                           // set third pointer
    if(!affitem)         // if failed to allocate new linked-list item
    { MessageBox(NULL, "NOT ENOUGH MEMORY!", "ERROR",
                 MB_OK | MB_ICONSTOP);
      PostQuitMessage(CRP_ERR_OM);       // exit code 1: Out of Memory
      return(0);        // exit program in a way that cleans up memory
    }   // Below, set ->prev links to go backwards from latest item to
                                    // first -- which points to latest
    affitem->prev = affprev;     // Link to prior item (initially sets
                                           // FIRST list item to NULL)
    afflist->prev = affitem;      // Set FIRST item prior-link to last
                                                // (current) list item
    affprev = affitem->prev;      // Refetch pointer, except at FIRST,
                                             // where sets to NON-NULL
    affitem->next = NULL;
    affwalk = &(affitem->next);//Get address in case another list-item
                                                     // needs creating
    affitem->skipno = -1;     // Now initialize the ordinary variables
                                                   // in the structure
    affitem->algo = ' ';
    affitem->pathname[0] = '\0';
    affitem->dotloc = -1;
    affitem->length = 0;
    affitem->kill = ' ';
    affcou++;      // increment total count of these linked-list items
  }           // Later on, the Up-Arrow and Enter keys let the user to
         // sort-of-scroll through many data items, and this next code
     // fetches a small group that have been saved on the linked list.
  if(!working && (gotdat == 0))   // Pull file-to-affect data saved in
                                          // current linked-list item?
  { skip = affitem->skipno;
    algo = affitem->algo;
    strcpy(dofile, affitem->pathname);
    sd2 = del2 = affitem->kill;
    gather[0] = d2 = alg = savalg = ' ';    // erase other remembrance
                                                          // variables
    savskp[0] = savdo[0] = gather[1] = '\0';
    gathlen = 0;
    gotdat = 1;     // no need to repeat these assignments for a while
    if(huminp)                       // force stoppages if human input
    { if(skip > -1)
      { sprintf(gather, "%d", skip);
        gathlen = strlen(gather);
        strcat(gather, " ");
        skip = -1;
      }
      strcpy(savskp, gather);
      savalg = algo;
      algo = ' ';
      strcpy(gather, dofile);
      gathlen = strlen(gather);
      strcat(gather, " ");
      dofile[0] = '\0';
      strcpy(savdo, gather);
      del2 = ' ';
  } }

  GetClientRect(hwnd, &rect);    // Get rectangular screen region upon
                                       // which text will be displayed
  switch(iMsg)
  {/* case WM_CREATE:             // All initializations already done;
      return(0);                          // ignore WM_CREATE messages
  */


////
    case WM_KEYUP:     // Using this Message only to let us handle the
                                                       // up-arrow key
    case WM_CHAR:
      GetKeyNameText(lParam, keynam, 32);
      if(!strcmp(keynam, "Esc")) // quit
      { PostQuitMessage(0);
        return(0);
      } // Next line: Since every keystroke generates both WM_CHAR and
                                               // WM_KEYUP messages...
      if(strcmp(keynam, "Up") && (iMsg == WM_KEYUP))
        return(0);        // Need this to prevent duplicate-display of
                                                 // non-up-arrow keys!
      ch = (char)toupper((int)wParam);
      huminp = 1;      // For whatever reason, a keystroke means human
                                                 // input has occurred
      if(!working && !strcmp(keynam, "Up"))
      { for(i=1; i<64; i<<=1)    // Prepare to walk through six lowest
                                          // bits of NeedInfo variable
          if(!(NeedInfo & i)) // Each accepted data item is a zero-bit
                                                        // in NeedInfo
          { NeedInfo |= i;   // Setting that bit forces the item to be
                                                      // human-handled
            break;        // If any bit was set, must be last-accepted
                                                          // data item
          }
        juset = 1;  // Have just set some data (flag controls coloring
                                                 // of displayed text)
        if((i == 16) && (affprev != afflist->prev))   // DO WE NEED TO
                                             // CYCLE TO A PRIOR ITEM?
        { NeedInfo &= 239;      // clear that just-set bit-value of 16
          affitem = affprev;     // point at prior item on linked list
          affprev = affitem->prev;
          affnum--;              // indicate prior list-element number
          gotdat = 0;               // set flag to gather up that data
          SendMessage(hwnd, WM_CHAR, 0x0000000D, 0x001C0001);
                             // above, send an ENTER (go to algorithm)
          SendMessage(hwnd, WM_CHAR, 0x0000000D, 0x001C0001);
                            // above, send another (go to affect-file)
          SendMessage(hwnd, WM_CHAR, 0x0000000D, 0x001C0001);
                        // above, send another (highlights DeleteFile)
//        SendMessage(hwnd, WM_CHAR, 0x00000026, 0xC1480001);
                               // above, codes for UP-ARROW, if needed
          return(0);                 // exit current call to WndProc()
        }
        switch(i)
        { case 32:
            strcpy(gather, keyfile);     // Remember stuff when moving
                                          // up to prior editable item
            gathlen = strlen(gather);
            strcat(gather, " ");
            keyfile[0] = '\0';
            break;
          case 16:
            sd1 = del1;
            del1 = ' ';
            strcpy(savskp, gather);
            break;
          case 8:
            sprintf(gather, "%d", skip);
            gathlen = strlen(gather);
            strcat(gather, " ");
            skip = -1;
            break;
          case  4:
            savalg = algo;
            algo = ' ';
            strcpy(savdo, gather);
            break;
          case  2:
            strcpy(gather, dofile);
            gathlen = strlen(gather);
            strcat(gather, " ");
            dofile[0] = '\0';
            break;
          case  1:
            sd2 = del2;
            del2 = ' ';
        }
      }
      if(!strcmp(keynam, "Space"))
        L = 1;
      else
        L = strlen(keynam);
      if(((L == 1) || !strstr("Enter Up", keynam)) &&
              ((NeedInfo & 32) || ((NeedInfo & 8) &&
                                   !(NeedInfo & 16))
                                           // 32: bitflag for key file
                               || ((NeedInfo & 2) &&
                                  !(NeedInfo & 28))))
                                         // 8: bitflag for skip number
      { if(!strcmp(keynam, "Backspace") ||//2: bitflag, file to affect
           ((L == 1) && (strchr("1234567890", ch) ||
                         (((NeedInfo & 32) || !(NeedInfo & 8)) &&
                          strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ ;:\'`~!@"
                                 "#$%^&()_+-=.,[]{}_\\", ch)))))
        { if(gathlen && !strcmp(keynam, "Backspace"))
          { gather[gathlen--] = '\0';
            gather[gathlen] = ' ';
          }
          else if((L == 1) && ((gathlen < 7) ||
                               ((NeedInfo & 34) && (gathlen < 48))))
          { gather[gathlen++] = ch;
            gather[gathlen++] = ' ';
            gather[gathlen--] = '\0'; // Terminate string after space,
                                      // backup to replace space later
      } } }
      else if((L == 1) && ((NeedInfo & 16) ||
                           ((NeedInfo & 1) && !(NeedInfo & 14))))
                                       // 16: bitflag: delete key file
      { if((ch == 'Y') || (ch == 'N'))   // 1: bitflag for deletion of
                                                      // affected file
         if(NeedInfo & 16)
           d1 = ch;
         else
           d2 = ch;
      }
      else if((NeedInfo & 4) && (L == 1))            // 4: bitflag for
                                                     // De/En-cryption
      { if((ch == 'D') || (ch == 'E'))
          alg = ch;
      }
      else if(!working)
      { if(!NeedInfo)      // this is for the Accept/More question
        { if((doit == ' ') && (L == 1) &&
             ((ch == 'M') || ((ch == 'A') &&         // Accept or More
                              (affitem->next == NULL))))
            doit = ch;  // "More" will mean Continue to gather info on
                                             // another file-to-affect
        }
        else if(!strcmp("Enter", keynam))   // Everything else, except
                                                       // ENTER and UP
        { if(NeedInfo & 32)
          { strncpy(keyfile, gather, gathlen);
            keyfile[gathlen] = '\0';
          }
          else if((NeedInfo & 2) && !(NeedInfo & 60))
          { strncpy(dofile, gather, gathlen);
            dofile[gathlen] = '\0';
        } }
        else if(strcmp("Up", keynam))    // everything else, except UP
          break; // let default processing handle all other keystrokes
      }
      else
        break; // if CRYPTION is "working" then also ignore keystrokes
      InvalidateRect(hwnd, &rect, 0);   // Ensure when have a key, the
                                                  // window is updated
//    return(0);        // Every WndProc() "case" that is processed is
          // expected to return(0).  HOWEVER, this program gets better
            // results for Up-Arrow handling by letting each keystroke
                              // directly flow to the WM_Paint section

////
    case WM_PAINT:
      if(painting)
        return(0);
      painting = 1;            // multiple calls here will be rejected
      repaint = 0;      // this will be set only if we WANT to repaint
      hdc = BeginPaint (hwnd, &ps);
      SetBkColor(hdc, 0x00C0C0C0);            // reasonably light gray
      oldcolr = SetTextColor(hdc, 0x00000000); // black; DOING ONLY TO
                                                        // SET oldcolr
      hPriorF = SelectObject(hdc, hfont1);          // Fixed font, not
                                                         // underlined
      SetTextColor(hdc, 0x00008000);          // moderately dark green
      TextOut(hdc,                                   // device context
              1, 2,         // LOGICAL (not pixel) X and Y coordinates
              "THANK YOU, for choosing this data protection tool.",
              50);                // length of above string-to-display
      SetTextColor(hdc, oldcolr);                             // black
/*
NOTE: Because this CRYPTION program is a "lower level" program, it
does not have fancy Windows controls like edit boxes, nor does it call
the Windows Choose File dialog.  Here the user is expected to know the
standard DOS/Windows syntax for a file name, which is:  Drive letter
followed by a colon  :  followed by a backslash  \  followed by a
directory name OR by a file name.  If a directory name follows the
backslash, then another backslash must follow the directory name.
THAT backslash is followed by either another directory name (name of a
subdirectory, actually) or a file name.  Eventually, possibly after
several sub-subdirectory names and backslashes, the file name is
finally included.  Note that the filename itself is frequently in two
parts, with a period  .  separating the two parts.  The first part is
usually called the file name and the second part is called the
extension, but the combination of name and period and extension is
also often called the file name.  Fancy stuff like Windows dialogs
belongs to fancier programs, such as the future Controller Program
that will keep track of encryption keys and call this one with a
bunch of parameters.                     */
      SelectObject(hdc, hfont1);
      if(!*keyfile)
        SetTextColor(hdc, 0x0000FFFF);                       // yellow
      TextOut(hdc, 1, 30, "Drv:\\Pth\\KeyFile (any 8K+)?", 27);
      SetTextColor(hdc, oldcolr);       // Reset regardless of whether
                                                        // was changed
      TextOut(hdc, 205, 30, eraser, 49);   // Erase and reprint below;
                                                 // handles backspaces
      SelectObject(hdc, hfont2);
      if(NeedInfo & 32)
      { if(*keyfile)
        { strcpy(gather, keyfile);
          gathlen = strlen(gather);
          strcat(gather, " ");
        }
        else
          del1 = ' ';
        TextOut(hdc, 205, 30, gather, strlen(gather));
      }
      else if(*keyfile)
        TextOut(hdc, 205, 30, keyfile, strlen(keyfile));
      if(NeedInfo & 32)                 // begin gathering wanted data
      { if((!strcmp(keynam, "Enter")) || *keyfile)
        { strncpy(keyfile, gather, gathlen);
          keyfile[gathlen] = '\0';
          dskfil = fopen(keyfile, "rb");
          ucp1 = &ucMemBlk1[15000];   // Skip space big enough for any
                                                          // .PRM file
          if(dskfil &&                // if to-be-affected file exists
             (8300 <= (fetched = fread(ucp1, 1, 1080000, dskfil))) &&
                                                  // and is big enough
             (0 == keycheck())) // and has some moderately random data
          { fclose(dskfil);    // (to be reopened if actually PROCEED)
            NeedInfo &= 223;       // Clear Bit Five (6th from right),
                                                           // value 32
            gather[0] = ' ';  // Prepare these variables for next data
                                                     // to be gathered
            gather[1] = '\0';
            gathlen = 0;
            juset = 1;
          }
          else
          { if(dskfil)
              fclose(dskfil);
            sprintf(tmpstr, "This key file either cannot be found,\n"
                            "or is smaller than 8300 bytes, or\n"
                            "hasn't enough random data in it:\n%s",
                            keyfile);
            MessageBox(NULL, tmpstr, "ERROR",
                       MB_OK | MB_ICONEXCLAMATION);
            keyfile[0] = '\0';
            doit = ' ';
            huminp = 1;
            repaint = 1;
          }
          keynam[0] = '\0';
      } }
      if(!(NeedInfo & 32)) // Only do next data entry after prior line
                                                        // is accepted
      { SelectObject(hdc, hfont1);
        if(NeedInfo & 16)// Only want yellow question text when asking
                                                      // this question
          if((((del1 == ' ') && (d1 == ' ') && (sd1 == ' ')) ||
              !strcmp(keynam, "Up")) ||
             ((huminp == 1) && (juset == 1)))
            SetTextColor(hdc, 0x0000FFFF);                   // yellow
        TextOut(hdc, 1, 46,
                "Delete that file after successful processing (Y/N)?",
                51);
        SetTextColor(hdc, oldcolr);     // Reset regardless of whether
                                                        // was changed
        SelectObject(hdc, hfont2);
        if(sd1 != ' ')
          del1 = sd1;
        if(d1 != ' ')
          del1 = d1;
        sprintf(tmpstr, "%c", del1);
        TextOut(hdc, 373, 46, tmpstr, 1);
        if(NeedInfo & 16)              // ok to begin gathering data ?
        { if((del1 != ' ') && (((huminp == 0) || (juset == 0)) ||
                               !strcmp(keynam, "Enter")))
          { NeedInfo &= 239;       // Clear Bit Four (5th from right),
                                                           // value 16
            sd1 = ' ';
          }
          else
            juset = 0;
          d1 = ' ';
          keynam[0] = '\0';
      } }
      if(NeedInfo & 32)
      { SelectObject(hdc, hfont1);
        TextOut(hdc, 1, 46, eraser, 80); // Hide this line while prior
                                                        // line edited
      }
      if(!(NeedInfo & 48)) // Only display this data entry after prior
                                                 // lines are accepted
      { SelectObject(hdc, hfont1);
        sprintf(tmpstr,
                "======= INFO FOR FILE TO AFFECT:  #%d OF %d =======",
                affnum, affcou);
        SetTextColor(hdc, 0x00008000);        // moderately dark green
        TextOut(hdc, 1, 78, tmpstr, strlen(tmpstr));
        SetTextColor(hdc, oldcolr);
        if(NeedInfo & 8) // Only want yellow question text when asking
                                                      // this question
          if((skip == -1) &&
             (strcmp(keynam, "Enter") || (gathlen == 0)))
            SetTextColor(hdc, 0x0000FFFF);                   // yellow
        TextOut(hdc, 1, 94, "Extra randomizer 0-9999999:", 27);
        SetTextColor(hdc, oldcolr);     // Reset regardless of whether
                                                        // was changed
        TextOut(hdc, 205, 94, eraser, 80);  // Erase & reprint; cleans
                                        // up after Automatic displays
        SelectObject(hdc, hfont2);
        if(NeedInfo & 8)
        { if(skip > -1)
          { sprintf(gather, "%d", skip);
            gathlen = strlen(gather);
            strcat(gather, " ");
          }
          else
          { if(*savskp)
            { strcpy(gather, savskp);
              gathlen = strlen(gather) - 1;
              savskp[0] = '\0';
          } }
          TextOut(hdc, 205, 94, gather, strlen(gather));
        }
        else if(skip > -1)
        { sprintf(tmpstr, "%d", skip);
          TextOut(hdc, 205, 94, tmpstr, strlen(tmpstr));
        }
        if(NeedInfo & 8)               // ok to begin gathering data ?
        { i = strtol(gather, NULL, 10);// Get not-necessarily-finished
                                                      // numeric value
          affitem->skipno = i;               // save it on linked list
          if((!strcmp(keynam, "Enter") && (gathlen > 0)) ||
             (skip > -1))
          { skip = i;
            NeedInfo &= 247;      // Clear Bit Three (4th from right),
                                                            // value 8
            gather[0] = ' ';  // Prepare these variables for next data
                                                     // to be gathered
            gather[1] = '\0';
            gathlen = 0;
            juset = 1;
            keynam[0] = '\0';
      } } }
      if(NeedInfo & 16)
      { SelectObject(hdc, hfont1);
        TextOut(hdc, 1, 78, eraser, 69); // Hide this line while prior
                                                        // line edited
        TextOut(hdc, 1, 94, eraser, 80); // Hide this line while prior
                                                        // line edited
      }
      if(!(NeedInfo & 56)) // Only display this data entry after prior
                                                 // lines are accepted
      { SelectObject(hdc, hfont1);
        if(NeedInfo & 4) // Only want yellow question text when asking
                                                      // this question
        if((((algo == ' ') && (alg == ' ') && (savalg == ' ')) ||
                                         !strcmp(keynam, "Up")) ||
           ((huminp == 1) && (juset == 1)))
          SetTextColor(hdc, 0x0000FFFF);                     // yellow
        TextOut(hdc, 1, 110,
                "Use \"Encrypt\" or \"Decrypt\" algorithm (E/D)?",
                43);
        SetTextColor(hdc, oldcolr);     // Reset regardless of whether
                                                        // was changed
        SelectObject(hdc, hfont2);      // same fixed font, underlined
        if(savalg != ' ')
          algo = savalg;
        if(alg != ' ')                  //(alg == 'E') || (alg == 'D')
          algo = alg;
        sprintf(tmpstr, "%c", algo);
        TextOut(hdc, 317, 110, tmpstr, 1);
        if(NeedInfo & 4)
        { if((algo != ' ') && (((huminp == 0) || (juset == 0)) ||
                                     !strcmp(keynam, "Enter")))
          { NeedInfo &= 251;        // Clear Bit Two (3rd from right),
                                                            // value 4
            savalg = ' ';
            keynam[0] = '\0';
          }
          else
            juset = 0;
          alg = ' ';
          keynam[0] = '\0';
          affitem->algo = algo;                 // save on linked list
      } }
      if(NeedInfo & 8)
      { SelectObject(hdc, hfont1);
        TextOut(hdc, 1, 110, eraser, 80);// Hide this line while prior
                                                        // line edited
      }
      if(!(NeedInfo & 60)) // Only display this data entry after prior
                                                 // lines are accepted
      { SelectObject(hdc, hfont1);
        if(!*dofile)
          SetTextColor(hdc, 0x0000FFFF); // yellow
        TextOut(hdc, 1, 126, "Drive:\\Path\\File to affect?", 27);
        SetTextColor(hdc, oldcolr);     // Reset regardless of whether
                                                        // was changed
        TextOut(hdc, 205, 126, eraser, 49); // Erase & reprint; cleans
                                        // up after Automatic displays
        SelectObject(hdc, hfont2);
        if(*dofile)
        { strcpy(gather, dofile);
          gathlen = strlen(gather);
          strcat(gather, " ");
        }
        else
        { del2 = ' ';
          if(*savdo)
          { strcpy(gather, savdo);
            gathlen = strlen(gather) - 1;
            savdo[0] = '\0';
        } }
        if(!working && gathlen)
        { strncpy(affitem->pathname, gather, gathlen);    // Save even
                                        // partial name on linked list
          affitem->pathname[gathlen] = '\0';   // Terminate the copied
                                                             // string
        }
        TextOut(hdc, 205, 126, gather, strlen(gather));
        if(NeedInfo & 2)          // see if ok to begin gathering data
        { if((!strcmp(keynam, "Enter")) || *dofile)
          { strncpy(dofile, gather, gathlen);
            dofile[gathlen] = '\0';
            for(dot=-1, i=gathlen-1; i>=0; i--)//Walk backward through
                                                       // the filename
            { ch = dofile[i];
              if((ch == '\\') || (ch == ':'))
                break;   // found marker before filename; quit looping
              if((ch == '.') && (dot == -1))
              { dot = i;               // Save location of first-found
                                                   // extension-marker
                break;               // no need to continue for() loop
            } }
            if(((i == -1) && (gathlen > 44)) ||   // MUST HAVE ROOM IN
                                         // FILE NAME STRING TO EITHER
               ((48 - i) < 4)) // REPLACE EXTENSION WITH, OR ADD, .CRP
            { sprintf(tmpstr,
                    "This File-to-affect has too long a name:\n  %s\n"
             "There must be space to set the File Extension to .CRP\n"
               "-- AND that modified name must be acceptably short,\n"
                 "or it can't be specified as a file to unscramble!\n"
              "Try renaming file, or moving it to another directory.",
                      dofile);
              MessageBox(NULL, tmpstr, "ERROR",
                         MB_OK | MB_ICONEXCLAMATION);
              dofile[0] = '\0';
              doit = ' ';
              huminp = 1;
            }
            else       // Below, using FindFirstFile() and not fopen()
                                           // because want file length
            { j = 1;              // initialize this as a failure flag
              fil1 = FindFirstFile(dofile, (LPWIN32_FIND_DATA)&wfd);
                                                // seek file-to-affect
              i = GetLastError(); // double-check to be sure it exists
              if((fil1 != INVALID_HANDLE_VALUE) &&
                 (i != ERROR_PATH_NOT_FOUND))
              { affitem->length = wfd.FileSzLo;  // Save length of the
                                                      // file, 4GB max
                j = 0;
              }                      // Below, failed to open file, so
              else if((dot > -1) && !strcmp(".CRP", &(dofile[dot])))
                                     // if specified extension is .CRP
              { afftmp = afflist;           // Prepare to walk list of
                                                    // files-to-affect
                i = dot - 1;// Get length of drive\path\name up to the
                                                   // extension-marker
                while(afftmp != affitem)         // As long as current
                                       // linked-list-item not reached
                { j = strncmp(dofile, afftmp->pathname, i); // Compare
                                          // prior ACCEPTED file names
                  if(!j)   // A matching file was specified previously
                                                         // and saved?
                  { affitem->length = afftmp->length + 87;     // Copy
                      // length of the file, 4GB max, because that one
                    break;  // passed, and here-desired .CRP file will
                  }// be created from it (so end loop).  Note original
                   // file's length + 87 ("Cryptionite" identifier) is
                    // roughly the number of scrambled bytes, for that
                                   // currently-nonexistent .CRP file.
                  afftmp = afftmp->next;        // Else see about next
                                     // file-data saved on linked list
              } }
              FindClose(fil1);       // Release memory associated with
                                                    // FindFirstFile()
              if(!j)                        // if this file name is OK
              { NeedInfo &= 253;    // Clear Bit One (2nd from right),
                                                            // value 2
                gather[0] = ' ';   // Prepare these variables for next
                                                // data to be gathered
                gather[1] = '\0';
                gathlen = 0;
                affitem->dotloc = (S_16)dot;
                juset = 1;
              }
              else
              { sprintf(tmpstr,
                        "This file-to-affect cannot be found:\n%s",
                        dofile);
                MessageBox(NULL, tmpstr, "ERROR",
                           MB_OK | MB_ICONEXCLAMATION);
                dofile[0] = '\0';
                doit = ' ';
                huminp = 1;
            } }
            keynam[0] = '\0';
      } } }
      if(NeedInfo & 4)
      { SelectObject(hdc, hfont1);
        TextOut(hdc, 1, 126, eraser, 80);// Hide this line while prior
                                                        // line edited
      }
      if(!(NeedInfo & 62)) // Only display this data entry after prior
                                                 // lines are accepted
      { SelectObject(hdc, hfont1);
        if(NeedInfo & 1) // Only want yellow question text when asking
                                                      // this question
          if((((del2 == ' ') && (d2 == ' ') && (sd2 == ' ')) ||
                                       !strcmp(keynam, "Up")) ||
             ((huminp == 1) && (juset == 1)))
            SetTextColor(hdc, 0x0000FFFF);                   // yellow
        if((dot > -1) && !strcmp(".CRP", &(dofile[dot])))
                                     // if specified extension is .CRP
        { TextOut(hdc, 1, 142, eraser, 99);
          TextOut(hdc, 1, 142,
                 "Every specified .CRP file will always be replaced.",
                  50);
          SetTextColor(hdc, oldcolr);
          del2 = 'Y';           // ALWAYS delete "original" .CRP files
        }
        else
        { TextOut(hdc, 1, 142,
                "Delete that file after successful processing (Y/N)?",
                  51);
          SetTextColor(hdc, oldcolr);                         // black
          SelectObject(hdc, hfont2);
          if(sd2 != ' ')
            del2 = sd2;
          if(d2 != ' ')
            del2 = d2;
        }
        sprintf(tmpstr, "%c", del2);
        TextOut(hdc, 368, 142, tmpstr, 1);
        if(NeedInfo & 1)
        { if((del2 != ' ') && (((huminp == 0) || (juset == 0)) ||
                                      !strcmp(keynam, "Enter")))
          { NeedInfo &= 254;       // Clear Bit Four (5th from right),
                                                           // value 16
            sd2 = ' ';
          }
          else
            juset = 0;
          d2 = ' ';
          keynam[0] = '\0';
          affitem->kill = del2;                 // save on linked list
      } }
      if(NeedInfo & 2)
      { SelectObject(hdc, hfont1);
        TextOut(hdc, 1, 142, eraser, 80);// Hide this line while prior
                                                        // line edited
      }
      SelectObject(hdc, hfont1);
      if(!NeedInfo)                    // no other file info required?
      { if(!working && (affitem->next != NULL))
        { strcpy(tmpstr, "MORE TO SEE; PRESS M");
          doit = 'M';
        }
        else
        { strcpy(tmpstr, "ACCEPT / MORE (A/M)?");
          if(!huminp)                   // if automatically continuing
            doit = 'A';//for when all data has been presented/accepted
        }
        if(working || (proceed == ' '))
        { if(!working && (doit == ' '))
            SetTextColor(hdc, 0x0000FFFF);                   // yellow
          TextOut(hdc, 1, 174, tmpstr, 20);  // Display MORE TO SEE or
                                                     //  ACCEPT / MORE
          SetTextColor(hdc, oldcolr);
          SelectObject(hdc, hfont2);
          sprintf(tmpstr, "%c", doit);
          TextOut(hdc, 155, 174, tmpstr, 1);
          if(!working && (doit != ' '))// check for a previously-saved
                                                             // A or M
            proceed = doit;
      } }
      else
      { SelectObject(hdc, hfont1);
        TextOut(hdc, 1, 174, eraser, 25);     // Hide while prior line
                                                             // edited
      }
      SelectObject(hdc, hfont1);
      tmpstr[0] = '\0';
      strcpy(tadone, "Press");
      if(proceed != 'A')
      { if(proceed == 'M')
        { affnum++;                         // prepare new item number
          affprev = affitem; // Save current item as previous (becomes
                                       // previous, next line of code)
          affitem = affitem->next;
        }
        if(huminp)
        { if(!(NeedInfo & 32))
          { strcat(tadone, " up-arrow to edit prior entry,");
            doit = ' ';     // no auto-proceed if human entry required
          }
          sprintf(tmpstr, "%s ESC to exit program.", tadone);
        }
        else
          TextOut(hdc, 165, 174,
                  "  (autoproceeding with good-looking parameters)",
                  47);
      }
      else                                         // We are proceding
      { if(huminp)
          TextOut(hdc, 165, 174,
                  "-- OK, accepted inputs now being applied...", 43);
        else // Automatically proceeding ("autoproceeding" duplication
                                            // is for Window re-draws)
          TextOut(hdc, 165, 174,
                  "  (autoproceeding with good-looking parameters)",
                  47);
        strcpy(tmpstr,
         "Program automatically ends when done; Press ESC to abort.");
      }
      TextOut(hdc, 100, 238, eraser, 49);
      SetTextColor(hdc, 0x00FFFFFF);                          // white
      TextOut(hdc, 1, 238, tmpstr, strlen(tmpstr));
                          // tmpstr is one of 3 possible strings here:
                                         // Press ESC to exit program.
           // Press up-arrow to edit prior entry, ESC to exit program.
          // Program automatically ends when done; Press ESC to abort.
      if(!NeedInfo && (proceed == 'A') && (status > 0))
      { i = status / 100;            // extract type of status message
        j = ((status % 100) >> 1) + 1;     // Extract progress report:
                                                            // 1 to 50
        strcpy(tadone,
               "                                                   ");
                                                 // reset to 51 spaces
        strnset(tadone, '=', j);  // Create progress bar (overwrite up
                                                      // to 50 spaces)
        tadone[j] = '>';       // Make progress bar look like an arrow
                                         // (may overwrite 51st space)
         // note that null-terminator, after strcpy(), is not affected
        switch(i)
        { case 1:
            sprintf(tmpstr, "Initializing work area: [%s]", tadone);
            break;
          case  2:
            sprintf(tmpstr, "Gathering Control Primes: [%s]", tadone);
            break;
          case  3:
            j = (fetched - 108) >> 3;
            if(j > 65536)
              j = 65536;
            sprintf(tmpstr,
                    "Please be patient; pulling Primary Cryption Key,"
                    " up to %d prime numbers", j);    // Fetched is at
                                         // least 8300; 8300-108=8192;
               // 3 bit-shifts=division-by-8 (8192 bytes from Key File
                                                // yields 1024 primes)
            SetTextColor(hdc, 0x0000FFFF);                   // Yellow
            TextOut(hdc, 1, 190, tmpstr, strlen(tmpstr));   // Special
                                               // "be patient" message
            SetTextColor(hdc, oldcolr);
            sprintf(tmpstr, "Loaded %d Primes: [%s]", prmbar, tadone);
            break;
          case  4:
            TextOut(hdc, 1, 190, eraser, 99); // erase special message
            tmpstr[0] = '\0';
            sprintf(tmpstr, "Crypting File #%d of %d: [%s]",
                    affnum, affcou, tadone);
        }
        TextOut(hdc, 1, 206, eraser, 99);           // Erase any prior
                                                       // progress bar
        TextOut(hdc, 1, 206, tmpstr, strlen(tmpstr));   // (Re)Display
                                   // current message and progress bar
      }
      SetTextColor(hdc, oldcolr);
      SelectObject(hdc, hPriorF);
      EndPaint(hwnd, &ps);
      painting = 0;
      if(proceed == 'M')
      { proceed = ' ';
        gotdat = 0;
        NeedInfo |= 15;
        repaint = 1;                // WANT to repaint, to prepare for
                                                   // new data entries
      }
      if((proceed == 'A') && !working)
      { working = 1;
        PostMessage(hwnd, WM_COMMAND, 123456789, 987654321);
                                              // **** BEGIN TASK! ****
      }
      if(repaint)
      { InvalidateRect(hwnd, &rect, 0);      // The window must now be
                                                         // re-updated
        repaint = 0;
      }
      return(0);                                    // END OF WM_PAINT


////
    case WM_COMMAND:
      if((wParam == 123456789) && (lParam == 987654321))
      { if(0 < (ret = WorkAreaInit()))
        { PostQuitMessage(ret);      // any of several possible errors
          return(0);
        }
        if(0 < (ret = KeyToPrimes()))
        { PostQuitMessage(ret);      // any of several possible errors
          return(0);
        }
        if(0 < (ret = AffectFiles()))
        { PostQuitMessage(ret);      // any of several possible errors
          return(0);
        }
        PostQuitMessage(0);             // QUIT AUTOMATICALLY WHEN ALL
                                         // TESTING/PROCESSING IS DONE
        return(0);
      }
      break;                   // ignore all other WM_COMMAND messages



////

    case WM_DESTROY: // Clean-up work goes here, before ending overall
                                                 // conversion program
      PostQuitMessage(0);      // Note memory allocations freed at end
                                                       // of WinMain()
      return(0);        // Always return Zero from any Windows message
                                                          // processed
  }        // all Windows messages not handled in switch block must be
                                                    // processed below
  return(DefWindowProc(hwnd, iMsg, wParam, lParam));
};                                                 // END OF WndProc()



/********************************************************************/
// This semi-clone of the Main Windows Message-Handling Loop has the
// purpose of being available anywhere in this program, to process
// anything outstanding in the Message Queue.  That is, some of the
// other functions below may take a long time to do their things, and
// Windows might think the program is "Not Responding".  By placing
// calls to this function in appropriate places (during Progress-Bar
// handling, most likely), not only will Windows stay happy, but it
// also makes it easier for the user to abort the program by pressing
// the ESCape key.  NOTE:  When a large Key File is specified, such
// that more than ten thousand Primes will be pulled as the Primary
// CRYPTION Key, it does indeed take time to sort out those thousands
// of data items from random sequence, and then pull the primes from
// the main compressed-data file.  (IF YOU WANT REAL SPEED FOR THIS
// PART OF THE PROCESS, GET A "SOLID-STATE DISK" a.k.a. RAM DISK TO
// HOLD THE PRIMES DIRECTORY.)  If the user chooses to Abort, several
// seconds may pass before the CRYPTION program acknowledges it by
// quitting.  In a way this slow preparation work is good because the
// user is granted a reasonable chance to abort -- since the CRYPTION
// process itself is the very next thing that happens after loading
// all those Primes, and this process does depend on the speed of the
// computer, which can be quite fast.  There may not be any other
// equally good place to abort the CRYPTION program after all data has
// been accepted, especially if small files are to be scrambled
// (UNLESS very large Skip Numbers are chosen).  IN GENERAL, it may be
// preferable to use large Key Files only when you want to scramble
// very large data files, or perhaps a great many small files.  In
// those cases the time to load 65,000 primes for the Primary CRYPTION
// Key is OK because you know it's going to take a while, anyway, for
// the overall scrambling process to be completed.
S_32 ProcessMessages(void)
{ static MSG mesg;         // Make this multi-byte structure static so
                                           // doesn't go on the stack.
  S_32 ret = 0;//Initialize return-value-variable to Everything-is-OK.
                  // For the inexperienced, this assigment will happen
               // every time this function is called, because  ret  is
                   // NOT a "static" type of variable.  Assignments to
               // static variables (in their declaration statements at
                 // the start of a function) are only done once, after
                  // which the assignment-code is ignored in all later
                // calls to the function.  However, the assigned value
                   // is remembered in-between function calls, and the
                // body of the function can change it if desired (then
                      // the new value will be remembered, of course).
  while(!ret && PeekMessage(&mesg, NULL, 0, 0, PM_NOREMOVE))   // Seek
                              // anything in the Windows Message queue
  { if(GetMessage(&mesg, NULL, 0, 0))        // We arrive here ONLY if
                                      // PeekMessage() found something
    { TranslateMessage(&mesg);
      DispatchMessage(&mesg);
    }
    else // GetMessage pulled a WM_QUIT
    { PostQuitMessage(0);      // Must put it back in Messge Queue for
                                         // primary loop in WinMain()!
      ret = 1;      // Tell this while() loop AND the calling function
                                                           // to quit.
  } }         // Otherwise loop til processed all accumulated Messages
                                                       // in the Queue
  return(ret); // return-value  ret  will be 0 if no messages in Queue
};



S_32 keycheck(void)  // Let's try to get 90 bytes of reasonably random
                                             // data from the Key File
{ S_32 k;
  U_08 uc, *ucp2 = ucMemBlk1;  // Point at start of buffer loaded from
                                                           // Key File
     // Remember Key File data begins 15000 bytes into the buffer, and
                                      // that ucp1 points at its start
  for(i=0; i<100; i++)
    ucp2[i] = 0;         // Erase the first 100 bytes of the ucMemBlk1
                                                       // memory block
  for(i=0, j=0, uc=0; (i<(int)fetched)&&(j<90); i++)// Prepare to walk
                                    // length of fetched Key File data
  { uc ^= ucp1[i];          // Get a byte (or combine with another via
                                                      // Exclusive-Or)
  // This trick with Exclusive-Or means that the 90 bytes we save via
  // the ucp2 pointer will be rather unlike the data actually pulled
  // from the file.  More, since we are seeking ALL DIFFERENT bytes,
  // there is no telling what order they will be in.  That is, if a
  // pulled/combined byte has already been found, we keep pulling/
  // combining until something different pops out.  So, while a simple
  // text file like the U.S. Constitution may not look much like
  // random data, multiple Exclusive-Or operations between pulled
  // bytes will indeed create reasonable randomness.  (Later on, in
  // the main algorithm for using the Key File to select primes, bytes
  // pulled from the Key File will be combined with pseudorandom
  // numbers, so again even minimal randomness in the Key File will be
  // acceptable.)
    if(uc > 0)                              // for nonzero values only
    { for(k=0; k<j; k++)              // check previously saved values
        if(uc == ucp2[k])      // If current nonzero value has already
                                                         // been saved
          break;                      // consider it not random enough
      if(k == j) // if for() loop ended with no match of current value
      { ucp2[j++] = uc;                                     // save it
        uc = 0;                    // reset Exclusive-Or "accumulator"
  } } }                  // loop through as much of Key file as needed
  return(j < 90);          // Return value is zero if got 90 different
                                                        // byte values
};// Here is a place where parentheses with  return  make great sense,
// because they delimit a comparison-operation.  Parentheses force the
      // compiler to code an evaluation of the comparison, and yield a
    // guaranteed result of either Zero-for-"False" or One-for-"True".


S_32 WorkAreaInit(void)             // fill 4,725,000 bytes with zeros
{ char *r, *s, *t, *u, *v;
  S_32 x, y;

  p = (char *)(ucMemBlk4 + 525000);// Set pointer partway through this
                                                       // memory block
  q = p + 525000;     // set pointer partway through this memory block
  r = q + 525000;     // set pointer partway through this memory block
  s = r + 525000;     // set pointer partway through this memory block
  t = s + 525000;     // set pointer partway through this memory block
  u = t + 525000;     // set pointer partway through this memory block
  v = u + 525000;     // set pointer partway through this memory block
  for(status=100, x=0; x<525000; x+=10500, status+=2)
  { InvalidateRect(hwnd, &rect, 0);         // make window update-able
    PostMessage(hwnd, WM_PAINT, 0, 0); // Progress bar grows, based on
                                                             // status
    if(ProcessMessages())         // process ALL messages in the queue
      return(CRP_WM_QUIT);                        // assume user abort
    for(y=x; y<(x+10500); y++)
    { ucMemBlk2[y] = '\0';                    // 50 * 10,500 = 525,000
      ucMemBlk4[y] = '\0';                    // 50 * 10,500 = 525,000
      p[y] = '\0';                            // 50 * 10,500 = 525,000
      q[y] = '\0';                            // 50 * 10,500 = 525,000
      r[y] = '\0';                            // 50 * 10,500 = 525,000
      s[y] = '\0';                            // 50 * 10,500 = 525,000
      t[y] = '\0';                            // 50 * 10,500 = 525,000
      u[y] = '\0';                            // 50 * 10,500 = 525,000
      v[y] = '\0';   // 50 * 10,500 = 525,000; last of 4,200,000 bytes
  } }  // YES, the preceding could be written more efficiently and run
      //faster.  But this was also the first chance to experiment with
                                              // progress-bar code....
  it = (U_32 *)ucMemBlk3;        // Initialize Index Table pointer for
                                            // IndexToPrime() function
  WorkSize = 0;        // There are no ScratchPads prepared yet in the
                                             // WorkRegion (ucMemBlk2)
  WhichWay[0] = 0;// Set for Encryption Algorithm (code for Decryption
                                                    // Algorithm is 4)
  WhichWay[1] = 1;// Set for Encryption Algorithm (code for Decryption
                                                   // Algorithm is -1)
              // Now give the Control Scratchpads some default values,
                                                 // soon to be changed
  LoadMaster->dvd = 0x12345;// Just a number to be divided a few times
                                                   // (in hexadecimal)
  LoadMaster->dvs = 0x13531;    // This is a prime, 79153 in Base Ten;
                                                 // not used very long
  ModCounter->dvd = 1;        // Two bits at a time will be yielded by
                                                         // ModCounter
  ModCounter->dvs = 0x8000000;   // This division produces ZEROS for a
                                       // short time (2 modifications)
  TypeSetter->dvd = 30;     // Three bits at a time will be yielded by
                                                         // TypeSetter
  TypeSetter->dvs = 63;      // This division produces 011 110 011 110
                                 //  011 110 ...(til dvd/dvs replaced)
  RandomSkip->dvd = 1;        // Two bits at a time will be yielded by
                                                         // RandomSkip
  RandomSkip->dvs = 3;       // This division produces 01 01 01 01 ...
                                             // (til dvd/dvs replaced)
  // Above default values will allow the PseudoRandomize() function to
  // be called even while gathering the final data that will replace
  // these default values.  This lets us scramble the Key File data
  // even while fetching it, thereby practically guaranteeing we
  // always have pseudorandom Key data.  Again, that is the main
  // reason why only a minimal randomness test was performed by
  // function keycheck().
  return(0);
};
/* NOTE REGARDING EFFECTIVENESS OF THE CRYPTION ALGORITHMS:  While
   someone watching the flow of this code with a debugging tool could
   easily use the above initial information to construct a list of
   initial "scramble values" (values that affect key-file data), it
   remains to be seen if that information can actually help unscramble
   a given .CRP file.  See, the dilemma faced by a cryptanalyst is
   that the scramble-data used to affect that file did NOT directly
   come from these easily computed initial scramble values.  These
   values are merely used, along some of with those 90 "random" bytes
   found by the keycheck() function, to replace themselves with all
   new values -- and the cryptanalyst does not know what key file was
   used to obtain those 90 bytes.  THEN, those new values are used to
   generate all new pseudorandom numbers which are combined with
   (again unknown to the cryptanalyst) straight key-file data to
   select a thousand or more primes from the compressed primes data
   file -- and it is those primes that generate the scramble-data
   used to affect a Message file.  It seems likely that without
   knowing the key file, and even knowing that the scrambled data in
   the affected file always begins with "Data Protected From
   Snoopercomputers"..., there is no easy way to decide which
   GROUPINGS of primes-as-divisors and which numbers-as-dividends were
   used to generate the actually-used scamble-values. */






// Do binary search of Index for location of Nth prime, then fetch it
// from the COMPRESS.PRM file.  Parameter is a pointer to N;
// THIS FUNCTION REPLACES N WITH FOUND PRIME
S_32 IndexToPrime(U_32 *dp)
{ static U_32  N, hi, md, lo; // Static variables let the function run
                                                             // faster
/*
The Index to the COMPRESS.PRM file treats that file like 143023 blocks
of 720 bytes each (the last block is smaller).  The CMPRMDEX.QNT file
holds 143023 quantities of primes, each quantity being the number of
primes represented by the compressed data in one 720-byte block of the
file COMPRESS.PRM.  When the Index file was loaded, those quantites
were added up, and each subtotal was saved.  Therefore we now have in
memory an ever-increasing sequence of numbers, which we can use to
find the Nth prime.  N just needs to be no larger than the last value
in the sequence, which is the grand total number of primes that can be
accessed via COMPRESS.PRM (203,280,221).  The first thing this
function will do is ensure N is not too big.  Then it will conduct a
fast binary search to determine which 720-byte block inside
COMPRESS.PRM holds the desired Nth prime, and that compressed-data
block is of course immediately fetched.  The desired prime is then
quickly constructed using the Index value, N, and some of the elements
in the  tbl  array.
*/
  N = *dp;
  while(N > 203280221)      // Too big a value entered for finding Nth
                                                             // prime?
    N >>= 1;         // HALVE the value (ignore any odd-bit remainder)
  if(N < 7)
   *dp = skpd[N];         // These first primes are NOT represented in
                                                       // COMPRESS.PRM
  else
  { lo = 0;                                    // lowest Index element
    hi = 143022;                              // highest Index element
    md = hi >> 1;      // Prepare to do a binary search from middle of
                                                          // the Index
    while (lo != hi)
    { if(N < it[md])
        hi = md;       // Set new upper bound (this still might be the
                                                      // right block!)
      else if(N > it[md])
        lo = md + 1;// Set new lower bound (block following  md  might
                                                 // be the right one!)
      else
        break;    // Well, well,  cand  just happened to exactly match
                                                    // an Index entry!
      md = ((hi - lo) >> 1) + lo;  // Get new middle between hi and lo
                                 // (may equal untested lo if hi-lo=1,
                    //  but next loop then finds it or makes lo=md=hi)
    }
    lo = md * 720;     // Compute which block of compressed file holds
                                                              // our N
    fseek(prmfil, ((S_32)lo - fpb) , SEEK_CUR);   // Go to appropriate
                                                      // file location
    fpb = fread(tmpstr, 1, 720, prmfil);            // Load a block of
                                              // compressed-prime data
    fpb += lo;       // Set file-position-byte to current location for
                                                          // next seek
    ucp4 = tbl;                            // initialize table-pointer
    if(md > 0)                             // not the very first block
    { hi = it[(md - 1)]; // Fetch total number of primes preceding the
                                                      // fetched block
      md *= 30030;  // Initial computation for first possible prime in
                                                         // that block
      md++;      // Adjust for exactness:  first number represented by
                                                    // compressed data
      bt = 1;                                 // initialize bit-tester
    }
    else                                        // very first block...
    { hi = 6;            // Compressed-prime data starts at 7th prime;
                                            // ensure loop below works
      md = 17;
      bt = 2;                                 // initialize bit-tester
      ucp4++;                 // correct table pointer for first block
    }
    by = (U_08 *)tmpstr;  // Set byte-pointer to start of 720 items in
                                                             // buffer
    for(;;)                           // this loop guaranteed to break
    { if((*by & bt) == bt)                       // if this is a prime
        hi++;                               // count towards desired N
      if(hi >= N)
        break;                                    // exit if N reached
      md += *ucp4++;   // add a tbl entry to create new possible prime
      if(bt == 128) // check for last possible bit-value (in one byte)
      { bt = 1;                                    // reset bit-tester
        by++;                        // advance to next byte in buffer
      }
      else
        bt <<= 1;                       // double for next bit-to-test
    }     // when loop ends, variable  md  holds the desired Nth prime
    *dp = md;                                     // Replace N with it
  }
  return(0);                                              // no error!
};



// Divide using passed scratchpad pointer, to obtain some number of
// bits of result.  Since Base 2 is king, each division will yield one
// bit.  Most of the time this function will be used to obtain just
// two bytes, 16 bits, and often less.  NOTE: ENSURE (0 < .dvd) and
// (.dvd < .dvs) -- WHEN .dvs IS A PRIME>2, NEVER DIVIDES EVENLY!
U_32 Divide(struct scratchpad *sp, S_32 bits)
{ static U_32 ret;
  /*
  One of the keys to the CRYPTION program is the fact that this
  function operates on EXTERNAL data.  That modified data can be --
  and is -- simply retained until this function is called to operate
  on it some more.  Thus we do PART of an overall long division now --
  just a few bits of it -- some more bits later, some more bits still
  later still, and so on.  There will be up to 64K division-operations
  in progress!  That is how this program trades memory usage to obtain
  speed.  Only a relatively small amount of division is needed to
  obtain the pseudo-random numbers used for scrambling data, and it
  doesn't have to be re-done to get different pseudo-random numbers --
  because all the operations are held in memory, waiting for this: */
  ret = 0;                                  // initialize return value
  while(sp->dvd > sp->dvs)            // While divisor is smaller than
                                                      // to-be-divided
    sp->dvd >>= 1; // HALVE the dividend.   Here we do not care at all
                   // about keeping the thown-away lowest bit, because
                // we expect to be doing this only to convert a random
                    // 32-bit number down to the same magnitude of the
                // divisor-Prime -- and once done, will not need to be
                                     // done again to this ScratchPad.
  while(bits > 0)
  { ret <<= 1;      // For each bit counted in while() loop, prepare a
             // place to hold a One or a Zero (doubles ret by shifting
                  // all bits higher one position, "appending" a zero)
    if(sp->dvs > sp->dvd)//while divisor is greater than to-be-divided
      sp->dvd <<= 1;                       // double/redouble dividend
    /*    The two main steps in this loop are doing "long division" in
     Base Two, totally analogous to familiar Base Ten stuff.  Consider
     this Base Ten example:
           __0.009708_ <-appended zeros retained when can't subtract
       103 | 1.000     <-append and keep 2 zeros in quotient, but
              _927_    <-subtract after 3rd; nonzero put in quotient
                730    <-append a zero (multiply by Ten), but quotient
               _721_   <-gets a nonzero because we can subtract again
                  900  <-append/keep 1 more zero above
                 _824_ <-but 2nd appended zero allows subtraction
     Note in Base Ten each appended Zero means multiply-by-Ten, while
     in Base Two it means multiply-by-Two -- doubling, in other words.
     Also in Base Two, the only digit (and multiplier) besides Zero is
     ONE (not 9, 7 or 8 as above), which is why Base Two division can
     subtract without multiplying.                                  */
      // Below is the subtraction step; if ok-to-do, the Zero that was
       // appended to  ret  via bit-shift/doubling will be incremented
    if(sp->dvs < sp->dvd)    // TEST: is divisor smaller than dividend
                                                 // (can we subtract)?
    { sp->dvd -= sp->dvs;          // Division in Base Two consists of
     // subtracting the divisor from the (doubled/redoubled) dividend.
        // The remainder becomes new dividend for next division steps.
      ret++; // Obviously if no subtraction occurs, appended Zero will
                                                       // be unchanged
    }   // Ret is a partial quotient, the wanted string of bits, mixed
                                                     // Zeros and Ones
    bits--; /*    Each iteration of overall loop represents one bit in
    Base-Two division.  Since 16 or fewer bits are normally sought,
    next test exists for those rare occasions when we want to know
    that a prime's reciprocal-PERIOD is very long.  For these tests,
    dvs is set to the prime P, dvd is set to P-1, and the bits
    parameter is set to 100,020.  As it happens, when taking a
    reciprocal, the last division of a prime's period will always have
    a remainder of 1, while the MIDDLE division during the period will
    have a remainder of P-1 (this is a consequence of the two halves
    of a period adding their digits to a constant value).  So, by
    starting with a dividend of P-1 for dvd before calling this
    function, and seeking a constant of 1 as the current remainder...
    if a remainder of 1 appears before we countdown bits from 100,020
    to 20, then we know that the HALF-PERIOD is less than 100,000
    digits, and this is unacceptable for CRYPTION.  (Note 100,000
    loops are actually done quite quickly, since bit-shifts and
    subtractions are processed FAST.)  */
    if(bits > 20)   // Only do this test when wanting large quantities
                                                            // of bits
    { ret = 0;        // Prevent accidental return value of 0xFFFFFFFF
                                                       // by main loop
      if(sp->dvd == 1)
        return(0xFFFFFFFF);     // Let period-testing routine know the
                                           // divisor is unacceptable!
  } }
  return(ret);  // Note most return values will range 16 bits or less,
};                                                    // max of 0xFFFF



// The function processes one byte at a time only because files are
// measured in bytes.  Later, this might be modified to handle 32-bit
// or even 64-bit quantities, in which case the ModType and ModData
// arrays must be adjusted, and some tricky end-of-file stuff will be
// needed, too.
U_08 PseudoRandomize(U_08 uc)
{ static U_08 ch, sv, em, mn, kp; // Static variables speed a function
  static S_32 w, x, y, z;        // up by not needing to be recreated/
  static U_32 dat;     // destroyed every time the function is called.

  w = Divide(RandomSkip, 2);            // get a 2-bit number (0 to 3)
  if(w == 3)        // Prepare to convert 3 to 1  -- want w to be ONLY
              // for 0, 1 or 2 skips, averaging 1 (makes actually-used
    w = 1;                       // cryptioning data less predictable)
  kp = uc;            // Keep the value-to-randomize for the following
                                                      // do/while loop
  do     // DO-LOOP PURPOSE: pseudorandomly waste cryptioning-numbers;
                                   // w is a tiny internal Skip Number
  { uc = kp;        // Restore initial value of data-to-affect if this
                                                    // DO-loop repeats
    x = Divide(ModCounter, 2) + 1;  // Get a 2-bit number (0 to 3) and
                                         // convert it to range 1 to 4
    /* Now we reach the heart of the algorithm.  Basically, we will
    use ModCounter and Divide() to decide how many modifications will
    be made to the current byte, from two to five.  (If that seems
    strange because of above x having range 1 to 4, remember that ZERO
    is a counting value and will be used here, to access the first
    ModType and ModData array elements.  That is, counting both Zero
    and One represents two iterations.)  So two-to-five pseudo-random
    codes will be quantified by ModCounter.  Each of those codes will
    be generated by sending TypeSetter to Divide() for a 3-bit result,
    which will represent one of eight possible modifications to the
    data at uc.  These codes will be saved in the ModType array.
    Also, of course, more data is required DURING a modification, to
    actually cause the modification, and so LoadMaster will be sent to
    Divide() to obtain a 16-bit number.  This number will be used as
    an index into the main WorkRegion/array of 1K to 64K ScratchPads
    (65536 fits in 16 bits).  The selected ScratchPad is sent to
    Divide() for a byte of modification data, which will be saved in
    the ModData array.  Note that depending on Encryption or
    Decryption, the data arrays are filled either first-to-last or
    last-to-first.  Remember, CRYPTION is a NON-COMMUTATIVE process,
    so each Decryption step must be exactly the reverse of an
    Encryption step.  Thus the ModType and ModData arrays:  All the
    info needed to Encrypt or Decrypt a single byte is GATHERED in the
    same order, but STORED in opposite orders (based on WhichWay
    info).  Then data can be plucked from the arrays in first-to-last
    order, but because of the way it was stored, it will be USED in
    the correct order for the chosen Algorithm.  There is one slight
    complication, in that different fractions of the arrays are used,
    depending on ModCounter:  The last-to-first sequence-of-array-
    access has to be adjusted whenever fewer-than-five Modifications
    are done. */
    for(y=x,// Copy number of modifications, zero-based counting (note
           // comma operator) the adjustment to x is necessary because
                                   // the arrays start at element zero
        z=min(WhichWay[0],x);    // Get initial (first or last) access
                               // value for ModType and ModData arrays
           // Note: Since WhichWay[0] will be either 0 or 4, the min()
            // macro ensures the correct initial z for the ModType and
            // ModData arrays (range from 0 to 4).  Example: if x is 2
             // (actually meaning 3 Modifications), then z is set here
              // to either zero (Encryption value of WhichWay[0]) or 2
                                           // (when WhichWay[0] is 4).
        y>=0;         // Check for ending of this gather-mod-data loop
                                        // (in Example, y starts at 2)
        z+=WhichWay[1], // modify by +1 or -1, depending on Encryption
                                            // or Decryption Algorithm
                     // in Example, z is sequence 0, 1, 2 (Encryption)
                                            // or 2, 1, 0 (Decryption)
        y--) // (note comma operator above) Loop countdowner.  Example
               // y sequence is 2, 1, zero, and -1 -- which terminates
                                   // loop due to test for y>=0 above.
    { ModType[z] = (U_08)Divide(TypeSetter, 3);           // Get 3-bit
                                   // Modification Type, save in array
      dat = Divide(LoadMaster, 16); // Get a 16-bit number because max
                                           // value is 64K ScratchPads
      if(WorkSize)  // WorkSize is zero during the initial part of the
                                                // prep work, remember
        ch = (U_08)Divide(&(WorkRegion[(dat % WorkSize)]), 8);// The %
                         // (modulus) operation yields real ScratchPad
      else        // No ScratchPads available yet; and we still need 8
                                                  // pseudorandom bits
        ch = (U_08)(dat & 0x000000FF);    // Keep lowest 8 bits of the
                                               // 16-bit ScratchPad ID
      ModData[z] = ch;    // Save the data that will be used to modify
                                           // the byte in parameter uc
    }          // At end of loop we have quantity-x of stored Type and
                                                  // Modification info
    for(y=0; y<=x; y++)      // x ranges from 1 to 4 here, but 5 loops
                             // possible since counting starts at zero
    { ch = ModData[y];// Get Modification Data from just-filled array,
                                         // for this Modification Step
                // Below, (ch % 7) gets the remainder of division-by-7
                                             // (modulus: zero to six)
      sv = (U_08)((ch % 7) + 1);  // Some Modification Types only need
                                                   // values of 1 to 7
      em = (U_08)(8 - sv);    // The same Modification Types need this
                                                    // bit-count, also
      mn = ModType[y];   // Now get Type for current Modification from
                                                  // appropriate array
      if(WhichWay[1] > 0)               // Encryption Algorithm chosen
      { switch(mn)                   // Type Number ranges from 0 to 7
        { case 0: // About to do a LEFT ROTATION; only 7 possible mods
                                                 // to original value.
          case 1:     // (Eight rotations of a byte is full-circle, no
                                       // affect on data.  Prevented.)
            uc = (U_08)((uc << sv) + (uc >> em));    // Move some bits
            // left; this throws the rest away off the left end of the
               // byte, so we ALSO move the not-yet-thrown bits right,
                 // thus letting us combine the two sets of moved bits
            break;
          case 2:
          case 3:
            uc += ch;                // add; allow byte to odometerize
            break;
          case 4:
          case 5:
            uc -= ch;  // subtract; byte will odometerize as necessary
            break;
          case 6:
          case 7:
            uc ^= ch;  // modify using Exclusive-OR (flips a few bits)
        }
        if(mn & 1)               // if Modification Type 1, 3, 5, or 7
          uc = (U_08)(~uc);                      // ALSO FLIP ALL BITS
      }
      else                              // Decryption Algorithm chosen
      { if(mn & 1)               // if Modification Type 1, 3, 5, or 7
          uc = (U_08)(~uc);                     // FIRST FLIP ALL BITS
        switch(mn)                   // Type Number ranges from 0 to 7
        { case 0:// About to do a RIGHT ROTATION; only 7 possible mods
                                                 // to original value.
          case 1:        // (Eight rotations of a byte is full-circle,
                                    // no affect on data.  Prevented.)
            uc = (U_08)((uc >> sv) + (uc << em));    // Move some bits
              // right; this throws the rest away off the right end of
            // the byte, so we ALSO move the not-yet-thrown bits left,
                 // thus letting us combine the two sets of moved bits
            break;
          case 2:
          case 3:
            uc -= ch;  // subtract; byte will odometerize as necessary
            break;
          case 4:
          case 5:
            uc += ch;                // add; allow byte to odometerize
            break;
          case 6:
          case 7:
            uc ^= ch;  // modify using Exclusive-OR (flips a few bits)
    } } }
  } while(--w >= 0); // Immediate exit if w was 0, or repeat loop once
                                   // or twice (AVERAGE of one repeat)
  return(uc);  // Original value now scrambled two-to-five times, each
    // time being one of eight ways, and numbers causing those changes
}; // here-and-now were not necessarily obtained as consecutive to the
                // numbers that caused changes during the LAST call to
                                                  // PseudoRandomize()


/* About the KeyToPrimes() function
Uses the already-loaded KeyFile data in ucMemBlk1, along with
"fetched", to gather anywhere from 1K to 64K primes into the work area
at ucMemBlk2.  Two groups of primes will be loaded.  The first group
consists of only 4 primes, which are used for overall control of the
CRYPTION process.  These 4 primes will be pulled using those 90
different bytes, located at the start of ucMemBlk1, that were found/
saved when giving the key file a minimal test for randomness.  All we
need are 16 bytes, for 4 values of N in the Index to the primes -- but
we will actually use 32, to increase the randomness of those values.
These control primes must pass a special test, to ensure that the
reciprocal of each has a "half-period" of at least 100,000 digits.
The program will abort if it can't find 4 such primes using those 90
"random" bytes.  But that is expected to be a fairly low-probability
event, and if it happens, it is simple enough to choose a different
key file.  The second group of primes gathered will depend on
"fetched", which is basically the size of the key file, up to roughly
half of a megabyte (if no duplicate primes then about 524288 bytes
would suffice).  Eight bytes at a time will be pulled from the key
file, to be used to create an N to obtain one one prime for a
scratchpad in ucMemBlk2.  The miminum allowed key file size is 8300
bytes, so the "minimum" number of primes used for CRYPTION will be 1K
(loads quickly, and weeded-out duplicates will reduce that quantity).
The maximum is 64K.  In-between those quantities, the size of the Key
File will determine the security of the Message(s).  AND, the tail-end
of the Key File data is reserved, to allow ANOTHER replacement of the
four Control Primes, after the main prime-key-array has been gathered,
and prior to beginning any scrambling operations on the Message(s).
The only difference the file size makes, with respect to the actual
execution of the CRYPTION process to affect files, is the preparatory
time taken to load the primes (which can be minimized if the \PRIMES
directory is located on a large RAM disk, although some special
sorting is going to be done to more efficiently extract the primes
from COMPRESS.PRM).  But that is the only price to pay for greater
security.  In addition to specifying a thousand or more N-values for
selecting primes, a third group of numbers will be entirely generated
by one of the first 4 control primes.  This group will be equal in
quantity to the group loaded according to "fetched"; they will be the
dividends into which the scratchpad-primes are initially divided (no
reciprocals here, unless pseudorandomly happens!).  Finally, in
comparison to other and more standard encryption techniques, in which
the Key is described as being "56-bit" or "128-bit" or even
"2048-bit", the MINIMUM Key here is (if no duplicate primes)
65536-bit. */
S_32 KeyToPrimes(void)
{ U_08 uc, *ucp2 = ucMemBlk1; // Want a pointer with which to walk the
                                                        // data buffer
  S_32 a, b, c, d, x=-4, y=0, z=1;
  U_32 test, hold;
                    // below, this block for first four control-primes
  is = (U_32 *)ucMemBlk4;//Initialize Sorting and Prime Index pointers
  status = 200;         // for "Gathering Control Primes" progress bar
  InvalidateRect(hwnd, &rect, 0);           // make window update-able
  PostMessage(hwnd, WM_PAINT, 0, 0);        // show blank progress bar
  if(ProcessMessages())           // process ALL messages in the queue
    return(CRP_WM_QUIT);                          // assume user abort
    // Below, if had 90 "random" bytes from ucp2[0] to [89], then last
                                         // 64-bit data starts at [82]
  test = 0;
  while((z == 1) && (y < 83))      // Prepare to walk "random" numbers
                                           // grouping for values of N
  { for(a=0; ((a<4)&&(y<83)); a++, y++)
    { uc = *ucp2++;              // fetch a byte and increment pointer
      uc = PseudoRandomize(uc);       // "AFFECT" this byte, making it
                                            // somewhat more "random".
#ifdef PROCESSOR_ENDIAN_TYPE_LITTLE
      ((U_08 *)(&test))[a] = uc;  // Save the byte as part of a 32-bit
                                                             // number
#endif
#ifdef PROCESSOR_ENDIAN_TYPE_BIG
      ((U_08 *)(&test))[(3-a)] = uc;     // save the byte as part of a
                                                      // 32-bit number
#endif
      uc = *ucp2++;        // fetch another byte and increment pointer
      uc = PseudoRandomize(uc);       // "AFFECT" this byte, making it
      // somewhat more "random".  Note that in WorkAreaInit(),
      // initializations of LoadMaster, ModCounter, TypeSetter, and
      // RandomSkip ScratchPads were done just so these calls to
      // PseudoRandomize will work while using the KeyFile here to set
      // those ScratchPads!  This makes those initializations VERY
      // temporary!  Below, by taking the address of a variable and
      // using that address as an array-pointer, we can set any number
      // of bytes without referencing subunits of the variable (say a
      // struct).  HOWEVER, the order in which the bytes are put
      // together, to make a 32-bit number, is a sure sign of a
      // potential "Big-Endian/Little-Endian" conflict.  BEWARE!
#ifdef PROCESSOR_ENDIAN_TYPE_LITTLE
      ((U_08 *)(&test))[a] |= uc;// OR-combine with last byte, as part
                                                 // of a 32-bit number
#endif
#ifdef PROCESSOR_ENDIAN_TYPE_BIG
      ((U_08 *)(&test))[(3-a)] |= uc; // OR-combine with last byte, as
                                            // part of a 32-bit number
#endif // note using OR to combine bits to reduce chance of zero total
    }                           // loop for 4 bytes of a 32-bit number
    IndexToPrime(&test); // use Index to replace random N with a Prime
      // Next, can't have half-period of 100,000 if Prime is less than
                                                            // 200,000
    if(test > 200000)
    { WorkRegion[0].dvd = WorkRegion[0].dvs = test; // Copy test-Prime
                                          // to tmp dividend & divisor
      WorkRegion[0].dvd--;                      // set dividend to P-1
      if(0xFFFFFFFF != Divide(&WorkRegion[0], 100020)) // Seek 100,020
                                                  // pseudorandom bits
      { status += 25;//225, 250, 275, 200
        if(status == 300)        // if got here then prime passed test
          status = 299;// ensure Status Message Text remains the same!
        InvalidateRect(hwnd, &rect, 0);     // make window update-able
        PostMessage(hwnd, WM_PAINT, 0, 0);// Increment progress bar in
                                                      // four sections
        if(ProcessMessages())     // process ALL messages in the queue
          return(CRP_WM_QUIT);                    // assume user abort
        WorkRegion[x] = WorkRegion[0];  // Copy both Prime/Divisor and
                                         // current Remainder/Dividend
        // Note: Above test done with WorkRegion[0] to avoid affecting
        // default values of LoadMaster, ModCounter, TypeSetter, and
        // RandomSkip until we know that the new values pass the test
        x++; // LoadMaster is set when x=-4; increment for ModCounter,
                                          // TypeSetter and RandomSkip
        if(x == 0) // When finished replacing the defaults of all four
                                           // critical Control Primes,
          z = 0;      // set flag loop-exit; only other way is to fail
                                   // 80-odd attempts to set the four.
      }
      else   // bad prime! Had half-PERIOD of less than 100,000 digits
                                                        // in Base Two
      { y -= 7;     // Back up to re-use last 7 of 8 "random" bytes of
                 // those 90 (NOTE that when these are again passed to
        ucp2 -= 7;    // PseudoRandomize(), very different results are
    } }                                                     // likely.
    else         // bad prime!  (must be larger than 200,000 to have a
                                             // half-PERIOD of 100,000
    { y -= 7; // Back up to re-use last 7 of 8 "random" bytes of those
    // 90 (NOTE that when these are again passed to PseudoRandomize(),
      ucp2 -= 7;                 // very different results are likely.
    }
  }
  if(z == 1)                   // did not find four acceptable primes?
  { MessageBox(NULL, "QUITTING! Key File (randomly!) didn't contain "
                     "suitable data for picking one or\nmore of 4 "
                     "critical Control Primes.  (Very rare error -- "
                     "use another Key File)",
                     "ERROR", MB_OK | MB_ICONSTOP);
                        // This is indeed expected to be VERY rare....
    return(CRP_ERR_BD);                // using 6 as code for Bad Data
  }                         // NEXT UP: Fill the main WorkRegion area!
  lim = (S_32 *)(ucMemBlk1 + fetched - 108);
  z = (fetched - 108) >> 3;                // Key File size divided by
                                                  // 8-bytes-per-prime
  if(z > 65536)
    z = 65536;   // Fix upper limit.  This is kind of arbitrary.  Just
    // need more allocated memory for processing the Key File, and for
     // scratchpads, to allow an even bigger Key.  Of course, a bigger
                              // Key will also take longer to load....
  y = z / 50;           // number of primes per progress-bar increment
  b = y;              // set so initial display of progress bar occurs
  c = prmbar = 0;                        // initialize the bar counter
  for(status=300, x=0; ((x<z)&&(ucp1<(U_08*)lim)); x++) // For desired
                                 // primes, depending on Key File size
  { if(b == y)                 // if time for a progress bar increment
    { InvalidateRect(hwnd, &rect, 0);       // make window update-able
      PostMessage(hwnd, WM_PAINT, 0, 0);  // Progress bar grows, based
                                                          // on status
      if(ProcessMessages())       // process ALL messages in the queue
        return(CRP_WM_QUIT); // Assume user abort if ProcessMessages()
                                                   // returned nonzero
      b = 0;       // reset counter for next increment of progress bar
      status += 2;          // this is what the next increment will be
      if(status >= 400)   // ensure progress bar doesn't grow too much
        status = 399;
    }
    // Below, as previously indicated elsewhere, we are about to
    // SCRAMBLE bytes taken from the Key File, before using them to
    // select prime numbers from COMPRESS.PRM.  Here is a bit of extra
    // sneakiness, where we semirandomly specify either Encryption or
    // Decryption scrambling.
    uc = (U_08)Divide(TypeSetter, 1);    // Get one bit as Encryption/
                                                     //Decryption flag
    if(uc == 1)
    { WhichWay[0] = 0;                 // Set for Encryption Algorithm
      WhichWay[1] = 1;                 // Set for Encryption Algorithm
    }
    else
    { WhichWay[0] = 4;                 // Set for Decryption Algorithm
      WhichWay[1] = -1;                // Set for Decryption Algorithm
    }
    for(a=0; (a<4); a++)    // For 4 pairs of bytes per 32-bit number,
                                        // using current E/D algorithm
    { uc = *ucp1++;                  // fetch a byte from the Key File
      uc = PseudoRandomize(uc); // Make it more "random".  Notice that
      // inside the PseudoRandomize() function is:
      // WorkRegion[(dat %= WorkSize)]  --which lets us start using
      // the main ScratchPad array to scramble numbers as soon as even
      // one ScratchPad has been prepared.
  // Below, assemble the value  N  that will be used to fetch a prime;
                                           // also initialize dividend
#ifdef PROCESSOR_ENDIAN_TYPE_LITTLE
      ((U_08 *)(&WorkRegion[x].dvs))[a] = uc;//Save as part of divisor
                                                // for this ScratchPad
      uc = (U_08)Divide(ModCounter, 8);             // get 8 more bits
      ((U_08 *)(&WorkRegion[x].dvd))[a] = uc;       // Save as part of
                                       // dividend for this ScratchPad
#endif
#ifdef PROCESSOR_ENDIAN_TYPE_BIG
      ((U_08 *)(&WorkRegion[x].dvs))[(3-a)] = uc;   // Save as part of
                                        // divisor for this ScratchPad
      uc = (U_08)Divide(ModCounter, 8);             // get 8 more bits
      ((U_08 *)(&WorkRegion[x].dvd))[(3-a)] = uc;   // Save as part of
                                       // dividend for this ScratchPad
#endif
      uc = *ucp1++;            // fetch another byte from the Key File
      uc = PseudoRandomize(uc);              // Make it more "random".
      // Below, finish assembling the value  N  and dividend, using OR
#ifdef PROCESSOR_ENDIAN_TYPE_LITTLE
      ((U_08 *)(&WorkRegion[x].dvs))[a] |= uc;      // Save as part of
                                        // divisor for this ScratchPad
      uc = (U_08)Divide(ModCounter, 8);             // get 8 more bits
      ((U_08 *)(&WorkRegion[x].dvd))[a] |= uc;      // Save as part of
                                       // dividend for this ScratchPad
#endif // note using OR to combine bits to reduce chance of zero total
#ifdef PROCESSOR_ENDIAN_TYPE_BIG
      ((U_08 *)(&WorkRegion[x].dvs))[(3-a)] |= uc;  // Save as part of
                                        // divisor for this ScratchPad
      uc = (U_08)Divide(ModCounter, 8);             // get 8 more bits
      ((U_08 *)(&WorkRegion[x].dvd))[(3-a)] |= uc;  // Save as part of
                                       // dividend for this ScratchPad
#endif // note using OR to combine bits to reduce chance of zero total
    }
    big = WorkRegion[x].dvs;                                  // get N
    if(big < 256)
      big += 257;      // Ignore the lowest primes as having too-short
                                                            // periods
    while(big > 203280221)   // too big a value for finding Nth prime?
      big >>= 1;     // HALVE the value (ignore any odd-bit remainder)
    WorkRegion[x].dvs = big;           // put possibly-modified N back
    if(status <= 302)// For first 1/50 of scratchpads only, duplicates
                                                            // allowed
    { IndexToPrime(&WorkRegion[x].dvs); // Use Index to convert random
                                   // 32-bit number to a Prime divisor
      prmbar = WorkSize++;    // This ScratchPad is now ready for use!
         // Note that the first Divide() that is called to use it will
      b++; // cause its .dvd value to be repeatedly halved until it is
    }            // smaller than the .dvs value (the random .dvd value
                             // essentially becomes even more random).
    else     // SAVE IN ucMemBlk4 for sorting!  Two mutually exclusive
    {   // goals are (1) to access 49/50 of all the desired primes, in
        // COMPRESS.PRM as fast as possible (in order), and (2) retain
         // ALL the randomness associated with the first 1/50.  It can
                                                           // be done!
      if(!c)                                           // not yet set?
        c = x;                                  // SAVE THIS FOR LATER
      test = big / 194;            // compute a proportionate position
                                    // (203,280,221/1,050,000 = 193.6)
      if(!is[++test]) // Bump to avoid Slot Zero in ucMemBlk4 array of
                                        // 4,200,000 bytes; available?
      { is[test] = big;                                      // save N
        goto bmp;    // Despite being reviled,  goto  is sometimes the
      }  // best tool available.  GO TO incrementation of progress bar
              // ONLY when NO duplicate N is involved.  BASIC IDEA IS:
          // ucMemBlk4 HAS 1,050,000 SLOTS FOR < 65,000 RANDOM VALUES;
        //  NOTE THE ABOVE COMBINING  |=  PUSHES AVERAGE RANDOM NUMBER
                                                      // TO UPPER HALF
      else // slot full!
      { for(a=d=(S_32)test; (is[a]&&(a>1)); a--);    // Find open slot
                                   // preceding proportionate location
        for(; (is[d]&&(d<1049999)); d++);  // Find open slot following
                                             // proportionate location
        for(ip=&is[a]; ((big!=*ip)&&(ip<&is[d])); ip++);
                               // seek duplicate N if previously saved
        if(big != *ip)                      // for nonduplicate N only
        { if(is[a] ||        // if no open slot here, OR "here" is the
             ((((S_32)test - a) >= (d - (S_32)test)) &&// farther slot
                                     // from proportional position AND
              !is[d]))                       // the other slot is open
          { while(big < (hold = is[--d]))       // compare current and
                                                 // previously-saved N
              is[(d+1)] = hold;  // Move higher values upward in array
                                                           // of slots
            is[++d] = big;      // save current value in correct place
          }         // Since slots always outnumber the random values,
                                 // guaranteed to find one unoccupied,
          else //  and in this case the other side of the proportional
                                              // position is available
          { while((big > (hold = is[++a])) && hold) // compare current
                                                    // & prior-saved N
              is[(a-1)] = hold;  // move lower values (NOT 0) downward
                                                  // in array of slots
            is[--a] = big;      // save current value in correct place
          } // now the ucMemBlk4 buffer is becoming an array of sorted
                                     // values interspersed with Zeros
bmp:      if((x & 1) == 0)           // One bump of prmbar counter for
                                                // every-other N-value
          { prmbar++;            // bump count of loaded primes (LIE!)
            b++;          // bump counter responsible for progress bar
        } }
        else
          x--;                           // don't count this duplicate
  } } }
  a = big = 0;                  // set some counters to start of array
  while(a < 1050000)                        // walk the array of slots
  { if(0 < (hold = is[a++]))                    // get/test each value
    { is[(a-1)] = 0;      // erase the slot from which value was taken
      is[big++] = hold;    // Condense values so no interspersed Zeros
                                                             // remain
  } }       // now all the Zeros in the array FOLLOW the sorted values
  ip = (U_32 *)(ucMemBlk4 + 700000);      // This section of the array
                                             // guaranteed to be empty
  for(a=0; a<(S_32)big; a++)             // walk the sorted  N  values
  { test = is[a];                                           // get one
    IndexToPrime(&test);   // Find Nth prime, steadily forward through
                                                       // COMPRESS.PRM
    ip[a] = test;                                    // save the prime
    if((a & 1) == 1)                          // for every-other value
    { prmbar++;          // one bump of prmbar counter (lie some more)
      if(++b == y)             // if time for a progress bar increment
      { InvalidateRect(hwnd, &rect, 0);     // make window update-able
        PostMessage(hwnd, WM_PAINT, 0, 0);      // Progress bar grows,
                                                    // based on status
        if(ProcessMessages())     // process ALL messages in the queue
          return(CRP_WM_QUIT);                 // Assume user abort if
                                 // ProcessMessages() returned nonzero
        b = 0;     // reset counter for next increment of progress bar
        status += 2;        // this is what the next increment will be
        if(status >= 400) // ensure progress bar doesn't grow too much
          status = 399;
  } } }
      // LAST STEP: Put the primes into the WorkRegion[].dvs variables
                                              // AS IF NO SORTING DONE
  big--;        // decrement to highest-used slot in array of N-values
  for(WorkSize=c; WorkSize<x; WorkSize++)
  { test = WorkRegion[WorkSize].dvs;
    a = 0;                            // location of lowest N in array
    d = (S_32)big;                   // location of highest N in array
    c = d >> 1;    // Prepare to do a binary search from middle of the
                                                              // array
    while (a < d)
    { if(test < is[c])
        d = c - 1;    // Set new upper bound to possible correct array
                                                               // item
      else if(test > is[c])
        a = c + 1;//set new lower bound to possible correct array item
      else
        break; // Well, well,  test  just happened to exactly match an
                                                              // item!
      c = ((d - a) >> 1) + a;  // Get new middle between a and d; (may
          // equal untested a if d-a=1, but next loop then finds it or
    }                                                  // makes a=c=d)
    WorkRegion[WorkSize].dvs = ip[c];    // Use the array of primes to
                                                          // replace N
  }
  x=-4, y=0, z=1; // AND NOW TO REPLACE THE CONTROL PRIMES AGAIN!
  // This code block works with 108 BYTES reserved at the end of the
  // block of Key File data associated with the  fetched  variable,
  // much like the 90 bytes previously used.
  test = 0;
  { struct scratchpad sp;   // One cool thing about C is that wherever
          // there is a Left Brace, it is allowed to place a variable-
     // declaration there.  This can be handy to ensure that variables
    // needed for a particular block of code (until the matching Right
     // Brace) are available.  BUT doing this also has a price.  These
     // variables are always placed in an area known as The Stack, and
     // not only does it take extra time to put them there (and remove
            // them when done), accessing them can also be slower than
           // accessing global memory variables.  More, such variable-
    //declarations surrounded by code are not so obvious to the casual
       // eye as declarations at the start of a function (or at top of
      // prgram, global).  It can sometimes be annoying to try to find
        // them.  THIS declaration is the only one of its kind in this
           // program, partly so this comment could be written for the
     // benefit of a novice, and partly because this block of code was
      // copied from above, where  WorkRegion[0]  was specified.  THEN
     // WorkRegion[0]  was unoccupied and available for temporary use;
     // NOW it has been assigned a value that we want to retain.  So a
                           // new scratchpad is needed -- so declared!
    while((z == 1) && (y < 101))   // Prepare to walk "random" numbers
                                           // grouping for values of N
    {     // Below, as previously indicated elsewhere, we are about to
       // SCRAMBLE bytes taken from the Key File, before using them to
          // select prime numbers from COMPRESS.PRM.  Here is a bit of
             // extra sneakiness, where we semirandomly specify either
                               // Encryption or Decryption scrambling.
      uc = (U_08)Divide(TypeSetter, 1);  // Get one bit as Encryption/
                                                     //Decryption flag
      if(uc == 1)
      { WhichWay[0] = 0;               // Set for Encryption Algorithm
        WhichWay[1] = 1;               // Set for Encryption Algorithm
      }
      else
      { WhichWay[0] = 4;               // Set for Decryption Algorithm
        WhichWay[1] = -1;              // Set for Decryption Algorithm
      }
      for(a=0; ((a<4)&&(y<83)); a++, y++)
      { uc = *ucp1++;  // Fetch a byte from the Key File and increment
                                                            // pointer
        uc = PseudoRandomize(uc);     // "AFFECT" this byte, making it
                                            // somewhat more "random".
#ifdef PROCESSOR_ENDIAN_TYPE_LITTLE
        ((U_08 *)(&test))[a] = uc;// Save the byte as part of a 32-bit
                                                             // number
#endif
#ifdef PROCESSOR_ENDIAN_TYPE_BIG
        ((U_08 *)(&test))[(3-a)] = uc;   // save the byte as part of a
                                                      // 32-bit number
#endif
        uc = *ucp1++;     // Fetch another Key File byte and increment
                                                            // pointer
        uc = PseudoRandomize(uc);     // "AFFECT" this byte, making it
                                            // somewhat more "random".
          // Below, by taking the address of a variable and using that
        // address as an array-pointer, we can set any number of bytes
       // without referencing subunits of the variable (say a struct).
         // HOWEVER, the order in which the bytes are put together, to
                // make a 32-bit number, is a sure sign of a potential
                      // "Big-Endian/Little-Endian" conflict.  BEWARE!
#ifdef PROCESSOR_ENDIAN_TYPE_LITTLE
        ((U_08 *)(&test))[a] |= uc;   // OR-combine with last byte, as
                                            // part of a 32-bit number
#endif
#ifdef PROCESSOR_ENDIAN_TYPE_BIG
        ((U_08 *)(&test))[(3-a)] |= uc;  // OR-combine with last byte,
                                         // as part of a 32-bit number
#endif // note using OR to combine bits to reduce chance of zero total
      }                         // loop for 4 bytes of a 32-bit number
      IndexToPrime(&test);//use Index to replace random N with a Prime
      // Next, can't have half-period of 100,000 if Prime is less than
      if(test > 200000)                                     // 200,000
      { sp.dvd = sp.dvs = test;   // copy test-Prime to tmp dividend &
                                                            // divisor
        sp.dvd--;                               // set dividend to P-1
        if(0xFFFFFFFF != Divide(&sp, 100020))          // Seek 100,020
                                                  // pseudorandom bits
        { WorkRegion[x] = sp;   // Copy both Prime/Divisor and current
                                                 // Remainder/Dividend
                 // Note: Above test done with temporary  sp  to avoid
                // affecting default values of LoadMaster, ModCounter,
              // TypeSetter, and RandomSkip until we know that the new
                                               // values pass the test
          x++;//LoadMaster is set when x=-4; increment for ModCounter,
                                          // TypeSetter and RandomSkip
          if(x == 0)//When finished replacing the defaults of all four
                                           // critical Control Primes,
            z = 0;// set flag loop-exit; only other way is to fail 100
        }                                 // attempts to set the four.
        else // bad prime! Had half-PERIOD of less than 100,000 digits
                                                        // in Base Two
        { y -= 7;  // Back up to re-use last 7 of 8 bytes of those 108
          ucp1 -= 7;      // (NOTE that when these are again passed to
      } }     // PseudoRandomize(), very different results are likely.
      else       // bad prime!  (must be larger than 200,000 to have a
                                             // half-PERIOD of 100,000
      { y -= 7;    // Back up to re-use last 7 of 8 bytes of those 108
        ucp1 -= 7;        // (NOTE that when these are again passed to
      }       // PseudoRandomize(), very different results are likely.
    }
    if(z == 1)                 // did not find four acceptable primes?
    { MessageBox(NULL, "QUITTING! Key File didn't contain suitable "
                       "data for picking one or\nmore of 4 critical "
                       "Control Primes.  (Very rare error -- use "
                       "another Key File)",
                       "ERROR", MB_OK | MB_ICONSTOP);
                        // This is indeed expected to be VERY rare....
      return(CRP_ERR_BD);     // using 6 as code for Bad Data
  } }
  InvalidateRect(hwnd, &rect, 0);           // make window update-able
  PostMessage(hwnd, WM_PAINT, 0, 0);  // Progress bar ends (show final
                                            // count of loaded primes)
  if(ProcessMessages())           // process ALL messages in the queue
    return(CRP_WM_QUIT);     // Sssume user abort if ProcessMessages()
                                                   // returned nonzero
  return(0);                                              // no error!
};
/*SPECIAL NOTE REGARDING THE LITTLE-ENDIAN AND BIG-ENDIAN CONTROVERSY:
  The smallest unit of information is the bit, and the commonest next-
       small unit is the byte (a group of 8 bits).  Computer memory is
   typically organized as a huge array of bytes; for example, a 32-bit
processor can "address" an array of 4,294,967,296 memory locations.  A
    minor dilemma arises in that to GIVE a 32-bit processor 32 bits of
    data, four separate 8-bit bytes are required.  The original author
 of this document personally thinks that every memory address accessed
      by a 32-bit processor should have 32 bits of data sitting there,
  instead of 8, but that's a simplistic and controversial way to solve
   the "endian" controversy.  So, with the standard of only 8 bits per
        address, the needed four bytes typically come from 4 adjacent/
        consecutive addresses in the memory.  One will hold the "Least
 Significant" 8 bits -- values that can only range from 0 to 255.  And
 one byte will hold the "Most Significant" 8 bits -- values that range
  from 16,777,216 to 1,073,741,824 (not counting the possibly negative
    biggest bit) -- but which?  More specifically, imagine four memory
address numbers 10,000 through 10,003 (computers always start counting
 from Zero).  Will address 10,000 hold the Least Significant Byte, and
  10,003 hold the Most Significant Byte -- the Little-Endian way -- or
    vice-versa, the Big-Endian way?  Because both ways have some logic
behind them, both ways have been implemented in the computer industry,
                                  despite being mutually incompatible.
       What are those logical arguments, you ask?  Well, Little-Endian
supporters like the simple match-up between data-magnitude and memory-
 address.  Memory address 10,000, the first and least-magnitude of the
  four addresses, would hold the Least Significant Byte, as previously
  described.  On the other hand, the Big-Endian supporters look at the
 CONTENTS of the memory in sequence, and for them, it makes more sense
     for the Most Significant Byte to be first.  Here is an example of
              that; consider the number 1 Billion in 32 binary digits:
    00111011100110101100101000000000.  This is the conventional way to
    represent a large-ish number in Base Two.  Broken into a series of
 bytes, the same data is 00111011 10011010 11001010 00000000.  Suppose
      these bytes were placed into the memory in Little Endian format.
  Well, if you decided to "read" the contents of that memory in order,
  then you would end up with the following sequence: 00000000 11001010
  10011010 00111011.  It's bad enough that binary is not easy to read,
  but now sections of our 1 Billion are backwards (even while the bits
 in the individual bytes are still "forwards"!)!  Thus the Big-Endians
      choose to put the Most Significant Byte in the Least Significant
                                                       memory address.
      Heh, if "the convential way to represent a number" was REVERSED,
          then in common ordinary Base Ten we would write 1 Billion as
                  000,000,000,1 -- and in binary a similar reversal is
        00000000010100110101100111011100 -- so that is also a possible
solution to the controversy (the Little Endian way of putting sections
    of the number into memory would be completely consistent).  But is
     such a change of Convention likely?  NOT, any time soon!  Anyway,
  regardless of anyone's preferences, certain parts of this program do
      need to be able to work properly, so that a Message encoded by a
      Little Endian processor can be correctly decoded by a Big Endian
       processor (or vice-versa).  And that's the purpose for  #define
 PROCESSOR_ENDIAN_TYPE_LITTLE  earlier in this program; it lets us use
 #ifdef  blocks to tell the compiler which sections of code need to be
    compiled, to ensure that any Message data gets processed properly.
       Should this program be compiled on a big-endian processor, that
  #define statement is the ONLY thing in this entire program that must
be edited.  (CAUTION -- that claim has not been tested!  Other editing
                      may be needed if some mistake has been made!) */








// HERE is the main function that handles file extensions (including
// .CRP), opens files, works with the "Snoopercomputer/Cryptionite"
// strings, applies Encrypt/Decrypt algorithms via PseudoRandomize(),
// and deletes specified files (including old .CRP files) when done.
// Nonzero return values are error codes.
// Uses global    struct affect *afflist   --so no parameter needed
S_32 AffectFiles(void)
{ FILE *outfil;          // In order to not delete any files until all
             // processing is successful, need two FILE pointers here.
                     // Global dskfil will be used for the input-file.
  S_32 a, b;
  U_32 x=0, y, z;
  char work[60], ext[50];

  for(y=0, affitem=afflist, affnum=1;   affnum<=affcou;
      affnum++, affitem=affitem->next)
  { if(affitem == NULL)
    { sprintf(tmpstr, "QUITTING! Could not access internal "
                      "Files-to-Affect List!");
      MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
      return(CRP_ERR_LL);   // using 4 as code for Linked-List failure
    }
    z = y;                                      // save for comparison
    y += affitem->length;    // accumulate lengths of files to process
    if(z > y)                        // total rolled over 4 gigabytes?
      x++;                                         // carry to 64 bits
    z = y;
    y += affitem->skipno;//Also accumulate total wasted randomizations
                                            // (large skips take time)
    if(z > y)
      x++;                         // Carry any rollover to 64 bits --
                                     // TRY TO KEEP TOTAL WITHIN 100GB
  }   // Note minor flaw: Total does NOT account for "Snoopercomputer/
  // Cryptionite" recognition strings.  If completed loop then we know
     // afflist is in good shape and we can walk it again without fear

  // Now to divide a 64-bit number by 50, for the progress bar -- we
  // want result to fit in 32 bits!  (Perhaps I'm just being lazy
  // here, and should change all the (++x == y) below to 64-bit stuff)
  // BEST divide in Assembly Language, but cheap compilers often don't
  // support   asm   stuff, so....
  if(x >= 50)     // if exceeded 200GB (how likely is this, anyway???)
    y = 0xFFFFFFFF; // Set one Progress Bar increment after processing
       // every 4GB, but program will keep running even after Progress
      // Bar reaches its endpoint, because CRYPTION will try to finish
                                                  // all assigned work
  else
  { y = (y >> 1) + ((x & 1) << 31);        // First divide by two, via
                                                         // bit-shifts
    x >>= 1;                   // below, only need to divide by 25 now
    z = y;                                       // save, just in case
    y /= 25;
    if(x > 0)  // most of the time probably won't go farther than this
    {   // NOTE prior 200GB test, and bit-shift, ensures that x is its
                                    // own remainder-of-division-by-25
      x <<= 16;                       // shift to High Half of 32 bits
      x += (z >> 16);            // Combine with High Half of former y
                                           // (but make Low Half here)
      y = (x / 25) << 16; // Get integer quotient and shift it to High
                                                    // Half of 32 bits
      x = (x % 25) << 16;  // Get remainder of division-by-25; move to
                                               // High Half of 32 bits
      x += (z & 0x0000FFFF);  // Combine remainder with Low Quarter of
                                              // original 64-bit value
      y += (x / 25); // Combine shifted quotient with rest of computed
                                                           // quotient
  } }
  for(x=0, status = 400, affitem=afflist, affnum=1;
      (affnum<=affcou);   affnum++, affitem=affitem->next)
  { InvalidateRect(hwnd, &rect, 0);         // make window update-able
    PostMessage(hwnd, WM_PAINT, 0, 0);  // Show progress bar and File-
                                              // to-Affect Number info
    if(ProcessMessages())         // process ALL messages in the queue
      return(CRP_WM_QUIT);                        // assume user abort
    for(a=affitem->skipno; a>0; a--) // Since skipno is supposed to be
            // an irregular value, we gain some security by wasting an
    { PseudoRandomize(0);// irregular quantity of pseudorandomizations
      if(++x == y)     // NOTE x is NOT reset to zero at start of each
                                                     // File-to-Affect
      { status += 2;    // Progress-bar-incrementation could occur any
                                        // time, since x is constantly
        if(status >= 500) // incremented with each pseudorandomization
          status = 499; // make sure status stays within allowed range
        InvalidateRect(hwnd, &rect, 0);     // make window update-able
        PostMessage(hwnd, WM_PAINT, 0, 0);   // increment progress bar
        if(ProcessMessages())     // process ALL messages in the queue
          return(CRP_WM_QUIT);                    // assume user abort
        x = 0;        // reset counter for next progress bar increment
    } }
    if(affitem->algo == 'E')      // check the Algorithm code for this
                                                    // particular file
    { WhichWay[0] = 0;                 // Set for Encryption Algorithm
      WhichWay[1] = 1;                 // Set for Encryption Algorithm
    }
    else
    { WhichWay[0] = 4;                 // Set for Decryption Algorithm
      WhichWay[1] = -1;                // Set for Decryption Algorithm
    }
    dskfil = fopen(affitem->pathname, "rb");            // Read Binary
    if(dskfil == NULL)
    { sprintf(tmpstr, "QUITTING! Could not open File-to-Affect:\n%s",
              affitem->pathname);
      MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
      return(CRP_ERR_OF);    // using 2 as code for Opening File error
    }
    sprintf(work, ".\\TMP%d.CRP", affnum); // Create temporary file in
                                             // executable's directory
    outfil = fopen(work, "wb");                        // Write Binary
    if(outfil == NULL)
    { fclose(dskfil);
      sprintf(tmpstr,
              "QUITTING! Could not open Temporary Work File:\n%s",
              work);
      MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
      return(CRP_ERR_OF);    // using 2 as code for Opening File error
    }
    ext[0] = '\0';                // initialize a blank file extension
    ucp1 = ucMemBlk1;    // reset this pointer to start of file buffer
    z = min(200, affitem->length);  // Set z appropriately, in case of
                                                    // very short file
    if(z != fread(ucp1, 1, z, dskfil))    // Get file's start, perhaps
                               // only a Previously-Affected indicator
    { sprintf(tmpstr,
              "QUITTING! Could Not Load Initial Part of File:\n%s",
              affitem->pathname);
      MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
      fclose(dskfil);
      fclose(outfil);
      return(CRP_ERR_FR);       // using 3 as code for File Read error
    }
      // Below, check to see if file has previously been Affected, and
                                                 // do stuff if HASN'T
    if(strncmp((char *)ucp1, "DATA PROTECTED FROM SNOOPERCOMPUTERS "
                             "WITH CRYPTIONITE:  ", 56))
    { if(affitem->dotloc > -1)        // Did the file actually have an
                                   // Extension?  Below, copy it if so
        strcpy(ext, &(affitem->pathname[(affitem->dotloc + 1)]));
      sprintf(tmpstr, "DATA PROTECTED FROM SNOOPERCOMPUTERS WITH CRYP"
                      "TIONITE:  Data Protected From Snoopercomputers"
                      " With Cryptionite:  The Original File Extensio"
                      "n is %s.  ", ext);
                                 // put in main ID string (replace %s)
      // Purpose of the period after %s is to be a marker indicating
      // END of File Extension.  The original dotloc identification of
      // a file extension never includes a period.
      a = strlen(tmpstr);     // get length of just-constructed string
      memmove((ucp1 + a), ucp1, z);      // Move the initial file data
                                              // deeper into ucMemBlk1
      strncpy((char *)ucp1, tmpstr, a);      // Insert with no string-
                                                         // terminator
      z += a;  // get total length to put in outfil after Affecting it
    }  // Whether had it already, or just added the identifier string,
                                       // Affecting starts at ucp1[56]
    strcpy(ext, ".CRP");    // Set to CRYPTION-file extension, even if
                                                   // already was .CRP
    ucp1 += 56;       // Pointer arithmetic: skip   DATA PROTECTED ...
                                                 // (capitalized text)
    for(a=56; a<(int)z; a++)      // From   Data Protected   to end of
                                               // loaded start-of-file
    { *ucp1++ = PseudoRandomize(*ucp1);  // Affect appropriate part of
                                                 // this block of data
      if(y < 10000)
        y = 12000;
      if(++x == y)     // NOTE x is NOT reset to zero at start of each
                                                     // File-to-Affect
      { status += 2; // Since x increments across files, progress-bar-
                               // incrementation could occur any time.
        if(status >= 500)
          status = 499; // make sure status stays within allowed range
        InvalidateRect(hwnd, &rect, 0);     // make window update-able
        PostMessage(hwnd, WM_PAINT, 0, 0);   // increment progress bar
        if(ProcessMessages())     // process ALL messages in the queue
        { fclose(dskfil);
          fclose(outfil);
          return(CRP_WM_QUIT);                    // assume user abort
        }
        x = 0;        // reset counter for next progress bar increment
    } }
       // Below, check for RESTORED file (well, first part of it might
                                                   // now be restored)
    if(!strncmp((char *)ucMemBlk1, "DATA PROTECTED FROM SNOOPERCOMPUT"
                                   "ERS WITH CRYPTIONITE:  Data Prote"
                                   "cted From Snoopercomputers With C"
                                   "ryptionite:  The Original File Ex"
                                   "tension is ", 143))   // Remember,
    // Extension in text is followed by a marker-period and two spaces
    { for(a=143, b=1; ('.'!=(ext[b]=ucMemBlk1[a])); a++, b++);// Fetch
                                                 // Original Extension
      // Prior line is self-contained loop, exits after copying period
                                             // that follows Extension
      ext[b] = '\0';     // replace marker-period with null terminator
      ext[0] = '.';//prepend Extension-separator (note b started at 1)
      if(affitem->dotloc == -1)   // if no Extension in given filename
        affitem->dotloc = (S_16)strlen(affitem->pathname); // Set this
                                        // to where it would have been
      ucp1 = ucMemBlk1 + 145 + strlen(ext);  // Get buffer location of
                                        // start of original file data
      // Note about above 145: length up to Original File Extension is
      // 143, and 3 characters follow it (a period and two spaces), so
     // one might at first think that the 145 should be 146.  However,
      // variable ext includes an initial dot that was not part of the
     // stored Extension and so we have to account for it in the total
                            // length (most easily by specifying 145).
      z -= (ucp1 - ucMemBlk1);    // Get length of original data after
                                        // CRYPTION identifier removed
      memmove(ucMemBlk1, ucp1, z);  // Remove the CRYPTION identifier;
        // this is why we sought to load 200 bytes from start of file;
                                          // whole identifier is there
    }  // Next line either restores original file extension or sets it
                                                            // to .CRP
    strcpy(affitem->newname, affitem->pathname);  // copy current name
    strcpy(&(affitem->newname[affitem->dotloc]), ext); // Overwrite or
                                                   // append Extension
    if(z != fwrite(ucMemBlk1, 1, z, outfil))  // Save the initial data
                                            // to new (temporary) file
    { sprintf(tmpstr,
            "QUITTING! Could Not Save Initial Part of Work-File:\n%s",
              work);
      MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
      fclose(dskfil);
      fclose(outfil);
      return(CRP_ERR_FW);      // using 7 as code for File Write error
    } // Below, check to see if file has previously been Affected, and
                                                 // do stuff if HASN'T
    while(!feof(dskfil)) // Main loop to Affect data until end-of-file
                                                            // reached
    { z = fread(ucMemBlk1, 1, 524288, dskfil);    // Get huge chunk of
                                       // file, several whole clusters
      if((z != 524288) && !feof(dskfil))      // If file not ended and
                                        // didn't fetch what we wanted
      { sprintf(tmpstr, "QUITTING! Could Not Load Part of File:\n%s",
                affitem->pathname);
        MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
        fclose(dskfil);
        fclose(outfil);
        return(CRP_ERR_FR);     // using 3 as code for File Read error
      }
      ucp1 = ucMemBlk1;                        // reset moving pointer
      for(a=0; a<(int)z; a++)// From start to end of however-much data
                                                    // is in ucMemBlk1
      { *ucp1++ = PseudoRandomize(*ucp1);// Affect appropriate part of
                                                 // this block of data
        if(++x == y)   // NOTE x is NOT reset to zero at start of each
                                                     // File-to-Affect
        { status += 2;   // Since x increments across files, progress-
                            // bar-incrementation could occur any time
          if(status >= 500)
            status = 499;//make sure status stays within allowed range
          InvalidateRect(hwnd, &rect, 0);   // make window update-able
          PostMessage(hwnd, WM_PAINT, 0, 0); // increment progress bar
          if(ProcessMessages())   // process ALL messages in the queue
          { fclose(dskfil);
            fclose(outfil);
            return(CRP_WM_QUIT);                  // assume user abort
          }
          x = 0;      // reset counter for next progress bar increment
      } }   // loop til half-a-megabyte processed, or tail end of file
      if(z != fwrite(ucMemBlk1, 1, z, outfil))   // Save the processed
                                                              // block
      { sprintf(tmpstr,
                "QUITTING! Could Not Save Part of Work-File:\n%s",
                work);
        MessageBox(NULL, tmpstr, "ERROR", MB_OK | MB_ICONSTOP);
        fclose(dskfil);
        fclose(outfil);
        return(CRP_ERR_FW);    // using 7 as code for File Write error
    } }                           // loop til done Affecting this file
    fclose(dskfil);                         // Close the current files
    fclose(outfil);                    // in preparation for next loop
    rename(work, affitem->newname);  // MUST MOVE/RENAME TMP#.CRP FILE
   // TO ORIGINAL DIRECTORY NOW.  MUST BE AVAILABLE IN CASE ADDITIONAL
     // PROCESSING OF THE FILE IS SPECIFIED IN ONE OF THE NEXT LINKED-
   // LIST ITEMS.  THIS WILL OVERWRITE A PRIOR .CRP FILE IF CURRENT IS
       // STILL SCRAMBLED.  (But overwriting was described long ago in
                                                    // this Document.)
  }            // loop til done walking linked list, and Affecting all
                                                    // specified files
  // NOW DELETE SPECIFIED ORIGINAL FILES
  if(del1 == 'Y')
    remove(keyfile);
  for(affitem=afflist, affnum = 1;   affnum<=affcou;
      affnum++, affitem=affitem->next)
  { if((affitem->kill == 'Y') &&
       strcmp(affitem->pathname, affitem->newname))   // If both names
            // are the same, then they WILL both have .CRP extensions.
           // Above, the rename() has already overwritten the old .CRP
          //  file, and we certainly don't want to delete the new one.
      remove(affitem->pathname);    // DO remove() old file if 'Y' and
        // filename has changed.  In this case either new file is .CRP
  }                                        // or old file is restored.
  return(0);                                              // no error!
};


// END OF SOURCE CODE FOR CRYPTION.C,
// THE ORIGINAL WORK DONE BY VERNON NEMITZ

/* Final Remarks:
Some people may think a powerful encryption program to be too valuable
to give away, even if only in the shared manner as is described at the
 start of this program source file.  But -- is this really and truly a
    powerful encryption program?  The algorithms MUST be published, in
order for experts to make that determination.  Well, that means anyone
who learns the algorithms will be in a position to write an equivalent
     competing program.  It really isn't a terribly complicated thing,
after all.  OK, well, certainly algorithms are allowed to be patented,
     which would secure some protection against such competition for a
      reasonable time (think about the well-known RSA algorithm, which
       allowed one company to grow into prominence while enjoying such
  protection).  However, recall again that this algorithm has not been
proved! -- and patents can be expensive.  It would be kind of silly to
      invest all that money in something that could turn out to have a
   fundamental flaw.  So why not give it away, with no warranty of any
 kind?  Risk-takers who gamble on its security can at least be assured
  that their data will be protected UNTIL such a flaw is discovered --
 which may take a while.   Perhaps even a very long while...especially
                after others have a chance of improving the algorighm.
        -- Vernon Nemitz -- http://www.nemitz.net/vernon/vernon.htm */

 
To the best of our knowledge, the text on this page may be freely reproduced and distributed.
If you have any questions about this, please check out our Copyright Policy.

 

totse.com certificate signatures
 
 
About | Advertise | Bad Ideas | Community | Contact Us | Copyright Policy | Drugs | Ego | Erotica
FAQ | Fringe | Link to totse.com | Search | Society | Submissions | Technology
Hot Topics
Split Hard Drive???
computer crashed
Intel's Q6600
Unlock My Phone
opening a .iso file without writing it?
Closed Captioning Decoders
sharing broadband
where is most of my disk space being taken up?
 
Sponsored Links
 
Ads presented by the
AdBrite Ad Network

 

TSHIRT HELL T-SHIRTS