1 //////////////////////////////////////////////////////////////////////
2 // Critical Window Procedure: Windows passes User-Activity messages to
3 // it, for processing
4 LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam,
5 LPARAM lParam)
6 { // A function that uses a lot of local variables is often a function
7 // that is taking a performance hit. The computer has a special
8 // place in its memory called the "stack" to which local variables
9 // are typically added and removed as needed -- which is EVERY time
10 // a function begins or ends. Adding or removing a lot of local
11 // variables, when a function is called many many times, can be
12 // called a "stack-thrashing" time-wasting event. What is an
13 // alternative, when global variables are frowned-upon these days?
14 // Well, a special type of local variable is called "static", which
15 // is stored outside the stack, in a kind-of-global way, and
16 // persists for as long as the overall program runs -- but it is
17 // still accessed only by the function that declares it. Static
18 // variables are useful for remembering data in-between calls to the
19 // function. While some of that remembrance is needed here, in just
20 // a few variables, what is needed more is the time savings that
21 // comes with zero stack-thrashing. So here all the local variables
22 // are declared as static.
23 static HDC hdc;
24 static PAINTSTRUCT ps;
25 static COLORREF oldcolr;
26 static struct affect *afftmp;
27 static S_32 painting = 0, gathlen = 0, skip = -1, gotdat = 0;
28 static S_32 dot, repaint, juset = 0, working = 0, ret;
29 static char algo = ' ', del2 = 'N', gather[50] = {' ','\0'},
30 dofile[50] = {'\0'}, sd1 = ' ',
31 savskp[50] = {'\0'}, savalg = ' ',
32 savdo[50] = {'\0'},
33 sd2 = ' ', d1 = ' ', alg = ' ', d2 = ' ';
34
35 // The 'working' variable is set when all data entry has been
36 // accepted and the program is beginning to do its CRYPTIONing. It
37 // is used to ignore all code associated with the data-entry
38 // process, and to limit screen-displays to such things as a
39 // progress bar.
40 if(!working && (affitem == NULL))
41 { *affwalk = malloc(sizeof(struct affect)); // Reserve some memory
42 // (sets 2 pointers)
43 affitem = *affwalk; // set third pointer
44 if(!affitem) // if failed to allocate new linked-list item
45 { MessageBox(NULL, "NOT ENOUGH MEMORY!", "ERROR",
46 MB_OK | MB_ICONSTOP);
47 PostQuitMessage(CRP_ERR_OM); // exit code 1: Out of Memory
48 return(0); // exit program in a way that cleans up memory
49 } // Below, set ->prev links to go backwards from latest item to
50 // first -- which points to latest
51 affitem->prev = affprev; // Link to prior item (initially sets
52 // FIRST list item to NULL)
53 afflist->prev = affitem; // Set FIRST item prior-link to last
54 // (current) list item
55 affprev = affitem->prev; // Refetch pointer, except at FIRST,
56 // where sets to NON-NULL
57 affitem->next = NULL;
58 affwalk = &(affitem->next);//Get address in case another list-item
59 // needs creating
60 affitem->skipno = -1; // Now initialize the ordinary variables
61 // in the structure
62 affitem->algo = ' ';
63 affitem->pathname[0] = '\0';
64 affitem->dotloc = -1;
65 affitem->length = 0;
66 affitem->kill = ' ';
67 affcou++; // increment total count of these linked-list items
68 } // Later on, the Up-Arrow and Enter keys let the user to
69 // sort-of-scroll through many data items, and this next code
70 // fetches a small group that have been saved on the linked list.
71 if(!working && (gotdat == 0)) // Pull file-to-affect data saved in
72 // current linked-list item?
73 { skip = affitem->skipno;
74 algo = affitem->algo;
75 strcpy(dofile, affitem->pathname);
76 sd2 = del2 = affitem->kill;
77 gather[0] = d2 = alg = savalg = ' '; // erase other remembrance
78 // variables
79 savskp[0] = savdo[0] = gather[1] = '\0';
80 gathlen = 0;
81 gotdat = 1; // no need to repeat these assignments for a while
82 if(huminp) // force stoppages if human input
83 { if(skip > -1)
84 { sprintf(gather, "%d", skip);
85 gathlen = strlen(gather);
86 strcat(gather, " ");
87 skip = -1;
88 }
89 strcpy(savskp, gather);
90 savalg = algo;
91 algo = ' ';
92 strcpy(gather, dofile);
93 gathlen = strlen(gather);
94 strcat(gather, " ");
95 dofile[0] = '\0';
96 strcpy(savdo, gather);
97 del2 = ' ';
98 } }
99
100 GetClientRect(hwnd, &rect); // Get rectangular screen region upon
101 // which text will be displayed
102 switch(iMsg)
103 {/* case WM_CREATE: // All initializations already done;
104 return(0); // ignore WM_CREATE messages
105 */
106
107
108 ////
109 case WM_KEYUP: // Using this Message only to let us handle the
110 // up-arrow key
111 case WM_CHAR:
112 GetKeyNameText(lParam, keynam, 32);
113 if(!strcmp(keynam, "Esc")) // quit
114 { PostQuitMessage(0);
115 return(0);
116 } // Next line: Since every keystroke generates both WM_CHAR and
117 // WM_KEYUP messages...
118 if(strcmp(keynam, "Up") && (iMsg == WM_KEYUP))
119 return(0); // Need this to prevent duplicate-display of
120 // non-up-arrow keys!
121 ch = (char)toupper((int)wParam);
122 huminp = 1; // For whatever reason, a keystroke means human
123 // input has occurred
124 if(!working && !strcmp(keynam, "Up"))
125 { for(i=1; i<64; i<<=1) // Prepare to walk through six lowest
126 // bits of NeedInfo variable
127 if(!(NeedInfo & i)) // Each accepted data item is a zero-bit
128 // in NeedInfo
129 { NeedInfo |= i; // Setting that bit forces the item to be
130 // human-handled
131 break; // If any bit was set, must be last-accepted
132 // data item
133 }
134 juset = 1; // Have just set some data (flag controls coloring
135 // of displayed text)
136 if((i == 16) && (affprev != afflist->prev)) // DO WE NEED TO
137 // CYCLE TO A PRIOR ITEM?
138 { NeedInfo &= 239; // clear that just-set bit-value of 16
139 affitem = affprev; // point at prior item on linked list
140 affprev = affitem->prev;
141 affnum--; // indicate prior list-element number
142 gotdat = 0; // set flag to gather up that data
143 SendMessage(hwnd, WM_CHAR, 0x0000000D, 0x001C0001);
144 // above, send an ENTER (go to algorithm)
145 SendMessage(hwnd, WM_CHAR, 0x0000000D, 0x001C0001);
146 // above, send another (go to affect-file)
147 SendMessage(hwnd, WM_CHAR, 0x0000000D, 0x001C0001);
148 // above, send another (highlights DeleteFile)
149 // SendMessage(hwnd, WM_CHAR, 0x00000026, 0xC1480001);
150 // above, codes for UP-ARROW, if needed
151 return(0); // exit current call to WndProc()
152 }
153 switch(i)
154 { case 32:
155 strcpy(gather, keyfile); // Remember stuff when moving
156 // up to prior editable item
157 gathlen = strlen(gather);
158 strcat(gather, " ");
159 keyfile[0] = '\0';
160 break;
161 case 16:
162 sd1 = del1;
163 del1 = ' ';
164 strcpy(savskp, gather);
165 break;
166 case 8:
167 sprintf(gather, "%d", skip);
168 gathlen = strlen(gather);
169 strcat(gather, " ");
170 skip = -1;
171 break;
172 case 4:
173 savalg = algo;
174 algo = ' ';
175 strcpy(savdo, gather);
176 break;
177 case 2:
178 strcpy(gather, dofile);
179 gathlen = strlen(gather);
180 strcat(gather, " ");
181 dofile[0] = '\0';
182 break;
183 case 1:
184 sd2 = del2;
185 del2 = ' ';
186 }
187 }
188 if(!strcmp(keynam, "Space"))
189 L = 1;
190 else
191 L = strlen(keynam);
192 if(((L == 1) || !strstr("Enter Up", keynam)) &&
193 ((NeedInfo & 32) || ((NeedInfo & 8) &&
194 !(NeedInfo & 16))
195 // 32: bitflag for key file
196 || ((NeedInfo & 2) &&
197 !(NeedInfo & 28))))
198 // 8: bitflag for skip number
199 { if(!strcmp(keynam, "Backspace") ||//2: bitflag, file to affect
200 ((L == 1) && (strchr("1234567890", ch) ||
201 (((NeedInfo & 32) || !(NeedInfo & 8)) &&
202 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ ;:\'`~!@"
203 "#$%^&()_+-=.,[]{}_\\", ch)))))
204 { if(gathlen && !strcmp(keynam, "Backspace"))
205 { gather[gathlen--] = '\0';
206 gather[gathlen] = ' ';
207 }
208 else if((L == 1) && ((gathlen < 7) ||
209 ((NeedInfo & 34) && (gathlen < 48))))
210 { gather[gathlen++] = ch;
211 gather[gathlen++] = ' ';
212 gather[gathlen--] = '\0'; // Terminate string after space,
213 // backup to replace space later
214 } } }
215 else if((L == 1) && ((NeedInfo & 16) ||
216 ((NeedInfo & 1) && !(NeedInfo & 14))))
217 // 16: bitflag: delete key file
218 { if((ch == 'Y') || (ch == 'N')) // 1: bitflag for deletion of
219 // affected file
220 if(NeedInfo & 16)
221 d1 = ch;
222 else
223 d2 = ch;
224 }
225 else if((NeedInfo & 4) && (L == 1)) // 4: bitflag for
226 // De/En-cryption
227 { if((ch == 'D') || (ch == 'E'))
228 alg = ch;
229 }
230 else if(!working)
231 { if(!NeedInfo) // this is for the Accept/More question
232 { if((doit == ' ') && (L == 1) &&
233 ((ch == 'M') || ((ch == 'A') && // Accept or More
234 (affitem->next == NULL))))
235 doit = ch; // "More" will mean Continue to gather info on
236 // another file-to-affect
237 }
238 else if(!strcmp("Enter", keynam)) // Everything else, except
239 // ENTER and UP
240 { if(NeedInfo & 32)
241 { strncpy(keyfile, gather, gathlen);
242 keyfile[gathlen] = '\0';
243 }
244 else if((NeedInfo & 2) && !(NeedInfo & 60))
245 { strncpy(dofile, gather, gathlen);
246 dofile[gathlen] = '\0';
247 } }
248 else if(strcmp("Up", keynam)) // everything else, except UP
249 break; // let default processing handle all other keystrokes
250 }
251 else
252 break; // if CRYPTION is "working" then also ignore keystrokes
253 InvalidateRect(hwnd, &rect, 0); // Ensure when have a key, the
254 // window is updated
255 // return(0); // Every WndProc() "case" that is processed is
256 // expected to return(0). HOWEVER, this program gets better
257 // results for Up-Arrow handling by letting each keystroke
258 // directly flow to the WM_Paint section
259
260 ////
261 case WM_PAINT:
262 if(painting)
263 return(0);
264 painting = 1; // multiple calls here will be rejected
265 repaint = 0; // this will be set only if we WANT to repaint
266 hdc = BeginPaint (hwnd, &ps);
267 SetBkColor(hdc, 0x00C0C0C0); // reasonably light gray
268 oldcolr = SetTextColor(hdc, 0x00000000); // black; DOING ONLY TO
269 // SET oldcolr
270 hPriorF = SelectObject(hdc, hfont1); // Fixed font, not
271 // underlined
272 SetTextColor(hdc, 0x00008000); // moderately dark green
273 TextOut(hdc, // device context
274 1, 2, // LOGICAL (not pixel) X and Y coordinates
275 "THANK YOU, for choosing this data protection tool.",
276 50); // length of above string-to-display
277 SetTextColor(hdc, oldcolr); // black
278 /*
279 NOTE: Because this CRYPTION program is a "lower level" program, it
280 does not have fancy Windows controls like edit boxes, nor does it call
281 the Windows Choose File dialog. Here the user is expected to know the
282 standard DOS/Windows syntax for a file name, which is: Drive letter
283 followed by a colon : followed by a backslash \ followed by a
284 directory name OR by a file name. If a directory name follows the
285 backslash, then another backslash must follow the directory name.
286 THAT backslash is followed by either another directory name (name of a
287 subdirectory, actually) or a file name. Eventually, possibly after
288 several sub-subdirectory names and backslashes, the file name is
289 finally included. Note that the filename itself is frequently in two
290 parts, with a period . separating the two parts. The first part is
291 usually called the file name and the second part is called the
292 extension, but the combination of name and period and extension is
293 also often called the file name. Fancy stuff like Windows dialogs
294 belongs to fancier programs, such as the future Controller Program
295 that will keep track of encryption keys and call this one with a
296 bunch of parameters. */
297 SelectObject(hdc, hfont1);
298 if(!*keyfile)
299 SetTextColor(hdc, 0x0000FFFF); // yellow
300 TextOut(hdc, 1, 30, "Drv:\\Pth\\KeyFile (any 8K+)?", 27);
301 SetTextColor(hdc, oldcolr); // Reset regardless of whether
302 // was changed
303 TextOut(hdc, 205, 30, eraser, 49); // Erase and reprint below;
304 // handles backspaces
305 SelectObject(hdc, hfont2);
306 if(NeedInfo & 32)
307 { if(*keyfile)
308 { strcpy(gather, keyfile);
309 gathlen = strlen(gather);
310 strcat(gather, " ");
311 }
312 else
313 del1 = ' ';
314 TextOut(hdc, 205, 30, gather, strlen(gather));
315 }
316 else if(*keyfile)
317 TextOut(hdc, 205, 30, keyfile, strlen(keyfile));
318 if(NeedInfo & 32) // begin gathering wanted data
319 { if((!strcmp(keynam, "Enter")) || *keyfile)
320 { strncpy(keyfile, gather, gathlen);
321 keyfile[gathlen] = '\0';
322 dskfil = fopen(keyfile, "rb");
323 ucp1 = &ucMemBlk1[15000]; // Skip space big enough for any
324 // .PRM file
325 if(dskfil && // if to-be-affected file exists
326 (8300 <= (fetched = fread(ucp1, 1, 1080000, dskfil))) &&
327 // and is big enough
328 (0 == keycheck())) // and has some moderately random data
329 { fclose(dskfil); // (to be reopened if actually PROCEED)
330 NeedInfo &= 223; // Clear Bit Five (6th from right),
331 // value 32
332 gather[0] = ' '; // Prepare these variables for next data
333 // to be gathered
334 gather[1] = '\0';
335 gathlen = 0;
336 juset = 1;
337 }
338 else
339 { if(dskfil)
340 fclose(dskfil);
341 sprintf(tmpstr, "This key file either cannot be found,\n"
342 "or is smaller than 8300 bytes, or\n"
343 "hasn't enough random data in it:\n%s",
344 keyfile);
345 MessageBox(NULL, tmpstr, "ERROR",
346 MB_OK | MB_ICONEXCLAMATION);
347 keyfile[0] = '\0';
348 doit = ' ';
349 huminp = 1;
350 repaint = 1;
351 }
352 keynam[0] = '\0';
353 } }
354 if(!(NeedInfo & 32)) // Only do next data entry after prior line
355 // is accepted
356 { SelectObject(hdc, hfont1);
357 if(NeedInfo & 16)// Only want yellow question text when asking
358 // this question
359 if((((del1 == ' ') && (d1 == ' ') && (sd1 == ' ')) ||
360 !strcmp(keynam, "Up")) ||
361 ((huminp == 1) && (juset == 1)))
362 SetTextColor(hdc, 0x0000FFFF); // yellow
363 TextOut(hdc, 1, 46,
364 "Delete that file after successful processing (Y/N)?",
365 51);
366 SetTextColor(hdc, oldcolr); // Reset regardless of whether
367 // was changed
368 SelectObject(hdc, hfont2);
369 if(sd1 != ' ')
370 del1 = sd1;
371 if(d1 != ' ')
372 del1 = d1;
373 sprintf(tmpstr, "%c", del1);
374 TextOut(hdc, 373, 46, tmpstr, 1);
375 if(NeedInfo & 16) // ok to begin gathering data ?
376 { if((del1 != ' ') && (((huminp == 0) || (juset == 0)) ||
377 !strcmp(keynam, "Enter")))
378 { NeedInfo &= 239; // Clear Bit Four (5th from right),
379 // value 16
380 sd1 = ' ';
381 }
382 else
383 juset = 0;
384 d1 = ' ';
385 keynam[0] = '\0';
386 } }
387 if(NeedInfo & 32)
388 { SelectObject(hdc, hfont1);
389 TextOut(hdc, 1, 46, eraser, 80); // Hide this line while prior
390 // line edited
391 }
392 if(!(NeedInfo & 48)) // Only display this data entry after prior
393 // lines are accepted
394 { SelectObject(hdc, hfont1);
395 sprintf(tmpstr,
396 "======= INFO FOR FILE TO AFFECT: #%d OF %d =======",
397 affnum, affcou);
398 SetTextColor(hdc, 0x00008000); // moderately dark green
399 TextOut(hdc, 1, 78, tmpstr, strlen(tmpstr));
400 SetTextColor(hdc, oldcolr);
401 if(NeedInfo & 8) // Only want yellow question text when asking
402 // this question
403 if((skip == -1) &&
404 (strcmp(keynam, "Enter") || (gathlen == 0)))
405 SetTextColor(hdc, 0x0000FFFF); // yellow
406 TextOut(hdc, 1, 94, "Extra randomizer 0-9999999:", 27);
407 SetTextColor(hdc, oldcolr); // Reset regardless of whether
408 // was changed
409 TextOut(hdc, 205, 94, eraser, 80); // Erase & reprint; cleans
410 // up after Automatic displays
411 SelectObject(hdc, hfont2);
412 if(NeedInfo & 8)
413 { if(skip > -1)
414 { sprintf(gather, "%d", skip);
415 gathlen = strlen(gather);
416 strcat(gather, " ");
417 }
418 else
419 { if(*savskp)
420 { strcpy(gather, savskp);
421 gathlen = strlen(gather) - 1;
422 savskp[0] = '\0';
423 } }
424 TextOut(hdc, 205, 94, gather, strlen(gather));
425 }
426 else if(skip > -1)
427 { sprintf(tmpstr, "%d", skip);
428 TextOut(hdc, 205, 94, tmpstr, strlen(tmpstr));
429 }
430 if(NeedInfo & 8) // ok to begin gathering data ?
431 { i = strtol(gather, NULL, 10);// Get not-necessarily-finished
432 // numeric value
433 affitem->skipno = i; // save it on linked list
434 if((!strcmp(keynam, "Enter") && (gathlen > 0)) ||
435 (skip > -1))
436 { skip = i;
437 NeedInfo &= 247; // Clear Bit Three (4th from right),
438 // value 8
439 gather[0] = ' '; // Prepare these variables for next data
440 // to be gathered
441 gather[1] = '\0';
442 gathlen = 0;
443 juset = 1;
444 keynam[0] = '\0';
445 } } }
446 if(NeedInfo & 16)
447 { SelectObject(hdc, hfont1);
448 TextOut(hdc, 1, 78, eraser, 69); // Hide this line while prior
449 // line edited
450 TextOut(hdc, 1, 94, eraser, 80); // Hide this line while prior
451 // line edited
452 }
453 if(!(NeedInfo & 56)) // Only display this data entry after prior
454 // lines are accepted
455 { SelectObject(hdc, hfont1);
456 if(NeedInfo & 4) // Only want yellow question text when asking
457 // this question
458 if((((algo == ' ') && (alg == ' ') && (savalg == ' ')) ||
459 !strcmp(keynam, "Up")) ||
460 ((huminp == 1) && (juset == 1)))
461 SetTextColor(hdc, 0x0000FFFF); // yellow
462 TextOut(hdc, 1, 110,
463 "Use \"Encrypt\" or \"Decrypt\" algorithm (E/D)?",
464 43);
465 SetTextColor(hdc, oldcolr); // Reset regardless of whether
466 // was changed
467 SelectObject(hdc, hfont2); // same fixed font, underlined
468 if(savalg != ' ')
469 algo = savalg;
470 if(alg != ' ') //(alg == 'E') || (alg == 'D')
471 algo = alg;
472 sprintf(tmpstr, "%c", algo);
473 TextOut(hdc, 317, 110, tmpstr, 1);
474 if(NeedInfo & 4)
475 { if((algo != ' ') && (((huminp == 0) || (juset == 0)) ||
476 !strcmp(keynam, "Enter")))
477 { NeedInfo &= 251; // Clear Bit Two (3rd from right),
478 // value 4
479 savalg = ' ';
480 keynam[0] = '\0';
481 }
482 else
483 juset = 0;
484 alg = ' ';
485 keynam[0] = '\0';
486 affitem->algo = algo; // save on linked list
487 } }
488 if(NeedInfo & 8)
489 { SelectObject(hdc, hfont1);
490 TextOut(hdc, 1, 110, eraser, 80);// Hide this line while prior
491 // line edited
492 }
493 if(!(NeedInfo & 60)) // Only display this data entry after prior
494 // lines are accepted
495 { SelectObject(hdc, hfont1);
496 if(!*dofile)
497 SetTextColor(hdc, 0x0000FFFF); // yellow
498 TextOut(hdc, 1, 126, "Drive:\\Path\\File to affect?", 27);
499 SetTextColor(hdc, oldcolr); // Reset regardless of whether
500 // was changed
501 TextOut(hdc, 205, 126, eraser, 49); // Erase & reprint; cleans
502 // up after Automatic displays
503 SelectObject(hdc, hfont2);
504 if(*dofile)
505 { strcpy(gather, dofile);
506 gathlen = strlen(gather);
507 strcat(gather, " ");
508 }
509 else
510 { del2 = ' ';
511 if(*savdo)
512 { strcpy(gather, savdo);
513 gathlen = strlen(gather) - 1;
514 savdo[0] = '\0';
515 } }
516 if(!working && gathlen)
517 { strncpy(affitem->pathname, gather, gathlen); // Save even
518 // partial name on linked list
519 affitem->pathname[gathlen] = '\0'; // Terminate the copied
520 // string
521 }
522 TextOut(hdc, 205, 126, gather, strlen(gather));
523 if(NeedInfo & 2) // see if ok to begin gathering data
524 { if((!strcmp(keynam, "Enter")) || *dofile)
525 { strncpy(dofile, gather, gathlen);
526 dofile[gathlen] = '\0';
527 for(dot=-1, i=gathlen-1; i>=0; i--)//Walk backward through
528 // the filename
529 { ch = dofile[i];
530 if((ch == '\\') || (ch == ':'))
531 break; // found marker before filename; quit looping
532 if((ch == '.') && (dot == -1))
533 { dot = i; // Save location of first-found
534 // extension-marker
535 break; // no need to continue for() loop
536 } }
537 if(((i == -1) && (gathlen > 44)) || // MUST HAVE ROOM IN
538 // FILE NAME STRING TO EITHER
539 ((48 - i) < 4)) // REPLACE EXTENSION WITH, OR ADD, .CRP
540 { sprintf(tmpstr,
541 "This File-to-affect has too long a name:\n %s\n"
542 "There must be space to set the File Extension to .CRP\n"
543 "-- AND that modified name must be acceptably short,\n"
544 "or it can't be specified as a file to unscramble!\n"
545 "Try renaming file, or moving it to another directory.",
546 dofile);
547 MessageBox(NULL, tmpstr, "ERROR",
548 MB_OK | MB_ICONEXCLAMATION);
549 dofile[0] = '\0';
550 doit = ' ';
551 huminp = 1;
552 }
553 else // Below, using FindFirstFile() and not fopen()
554 // because want file length
555 { j = 1; // initialize this as a failure flag
556 fil1 = FindFirstFile(dofile, (LPWIN32_FIND_DATA)&wfd);
557 // seek file-to-affect
558 i = GetLastError(); // double-check to be sure it exists
559 if((fil1 != INVALID_HANDLE_VALUE) &&
560 (i != ERROR_PATH_NOT_FOUND))
561 { affitem->length = wfd.FileSzLo; // Save length of the
562 // file, 4GB max
563 j = 0;
564 } // Below, failed to open file, so
565 else if((dot > -1) && !strcmp(".CRP", &(dofile[dot])))
566 // if specified extension is .CRP
567 { afftmp = afflist; // Prepare to walk list of
568 // files-to-affect
569 i = dot - 1;// Get length of drive\path\name up to the
570 // extension-marker
571 while(afftmp != affitem) // As long as current
572 // linked-list-item not reached
573 { j = strncmp(dofile, afftmp->pathname, i); // Compare
574 // prior ACCEPTED file names
575 if(!j) // A matching file was specified previously
576 // and saved?
577 { affitem->length = afftmp->length + 87; // Copy
578 // length of the file, 4GB max, because that one
579 break; // passed, and here-desired .CRP file will
580 }// be created from it (so end loop). Note original
581 // file's length + 87 ("Cryptionite" identifier) is
582 // roughly the number of scrambled bytes, for that
583 // currently-nonexistent .CRP file.
584 afftmp = afftmp->next; // Else see about next
585 // file-data saved on linked list
586 } }
587 FindClose(fil1); // Release memory associated with
588 // FindFirstFile()
589 if(!j) // if this file name is OK
590 { NeedInfo &= 253; // Clear Bit One (2nd from right),
591 // value 2
592 gather[0] = ' '; // Prepare these variables for next
593 // data to be gathered
594 gather[1] = '\0';
595 gathlen = 0;
596 affitem->dotloc = (S_16)dot;
597 juset = 1;
598 }
599 else
600 { sprintf(tmpstr,
601 "This file-to-affect cannot be found:\n%s",
602 dofile);
603 MessageBox(NULL, tmpstr, "ERROR",
604 MB_OK | MB_ICONEXCLAMATION);
605 dofile[0] = '\0';
606 doit = ' ';
607 huminp = 1;
608 } }
609 keynam[0] = '\0';
610 } } }
611 if(NeedInfo & 4)
612 { SelectObject(hdc, hfont1);
613 TextOut(hdc, 1, 126, eraser, 80);// Hide this line while prior
614 // line edited
615 }
616 if(!(NeedInfo & 62)) // Only display this data entry after prior
617 // lines are accepted
618 { SelectObject(hdc, hfont1);
619 if(NeedInfo & 1) // Only want yellow question text when asking
620 // this question
621 if((((del2 == ' ') && (d2 == ' ') && (sd2 == ' ')) ||
622 !strcmp(keynam, "Up")) ||
623 ((huminp == 1) && (juset == 1)))
624 SetTextColor(hdc, 0x0000FFFF); // yellow
625 if((dot > -1) && !strcmp(".CRP", &(dofile[dot])))
626 // if specified extension is .CRP
627 { TextOut(hdc, 1, 142, eraser, 99);
628 TextOut(hdc, 1, 142,
629 "Every specified .CRP file will always be replaced.",
630 50);
631 SetTextColor(hdc, oldcolr);
632 del2 = 'Y'; // ALWAYS delete "original" .CRP files
633 }
634 else
635 { TextOut(hdc, 1, 142,
636 "Delete that file after successful processing (Y/N)?",
637 51);
638 SetTextColor(hdc, oldcolr); // black
639 SelectObject(hdc, hfont2);
640 if(sd2 != ' ')
641 del2 = sd2;
642 if(d2 != ' ')
643 del2 = d2;
644 }
645 sprintf(tmpstr, "%c", del2);
646 TextOut(hdc, 368, 142, tmpstr, 1);
647 if(NeedInfo & 1)
648 { if((del2 != ' ') && (((huminp == 0) || (juset == 0)) ||
649 !strcmp(keynam, "Enter")))
650 { NeedInfo &= 254; // Clear Bit Four (5th from right),
651 // value 16
652 sd2 = ' ';
653 }
654 else
655 juset = 0;
656 d2 = ' ';
657 keynam[0] = '\0';
658 affitem->kill = del2; // save on linked list
659 } }
660 if(NeedInfo & 2)
661 { SelectObject(hdc, hfont1);
662 TextOut(hdc, 1, 142, eraser, 80);// Hide this line while prior
663 // line edited
664 }
665 SelectObject(hdc, hfont1);
666 if(!NeedInfo) // no other file info required?
667 { if(!working && (affitem->next != NULL))
668 { strcpy(tmpstr, "MORE TO SEE; PRESS M");
669 doit = 'M';
670 }
671 else
672 { strcpy(tmpstr, "ACCEPT / MORE (A/M)?");
673 if(!huminp) // if automatically continuing
674 doit = 'A';//for when all data has been presented/accepted
675 }
676 if(working || (proceed == ' '))
677 { if(!working && (doit == ' '))
678 SetTextColor(hdc, 0x0000FFFF); // yellow
679 TextOut(hdc, 1, 174, tmpstr, 20); // Display MORE TO SEE or
680 // ACCEPT / MORE
681 SetTextColor(hdc, oldcolr);
682 SelectObject(hdc, hfont2);
683 sprintf(tmpstr, "%c", doit);
684 TextOut(hdc, 155, 174, tmpstr, 1);
685 if(!working && (doit != ' '))// check for a previously-saved
686 // A or M
687 proceed = doit;
688 } }
689 else
690 { SelectObject(hdc, hfont1);
691 TextOut(hdc, 1, 174, eraser, 25); // Hide while prior line
692 // edited
693 }
694 SelectObject(hdc, hfont1);
695 tmpstr[0] = '\0';
696 strcpy(tadone, "Press");
697 if(proceed != 'A')
698 { if(proceed == 'M')
699 { affnum++; // prepare new item number
700 affprev = affitem; // Save current item as previous (becomes
701 // previous, next line of code)
702 affitem = affitem->next;
703 }
704 if(huminp)
705 { if(!(NeedInfo & 32))
706 { strcat(tadone, " up-arrow to edit prior entry,");
707 doit = ' '; // no auto-proceed if human entry required
708 }
709 sprintf(tmpstr, "%s ESC to exit program.", tadone);
710 }
711 else
712 TextOut(hdc, 165, 174,
713 " (autoproceeding with good-looking parameters)",
714 47);
715 }
716 else // We are proceding
717 { if(huminp)
718 TextOut(hdc, 165, 174,
719 "-- OK, accepted inputs now being applied...", 43);
720 else // Automatically proceeding ("autoproceeding" duplication
721 // is for Window re-draws)
722 TextOut(hdc, 165, 174,
723 " (autoproceeding with good-looking parameters)",
724 47);
725 strcpy(tmpstr,
726 "Program automatically ends when done; Press ESC to abort.");
727 }
728 TextOut(hdc, 100, 238, eraser, 49);
729 SetTextColor(hdc, 0x00FFFFFF); // white
730 TextOut(hdc, 1, 238, tmpstr, strlen(tmpstr));
731 // tmpstr is one of 3 possible strings here:
732 // Press ESC to exit program.
733 // Press up-arrow to edit prior entry, ESC to exit program.
734 // Program automatically ends when done; Press ESC to abort.
735 if(!NeedInfo && (proceed == 'A') && (status > 0))
736 { i = status / 100; // extract type of status message
737 j = ((status % 100) >> 1) + 1; // Extract progress report:
738 // 1 to 50
739 strcpy(tadone,
740 " ");
741 // reset to 51 spaces
742 strnset(tadone, '=', j); // Create progress bar (overwrite up
743 // to 50 spaces)
744 tadone[j] = '>'; // Make progress bar look like an arrow
745 // (may overwrite 51st space)
746 // note that null-terminator, after strcpy(), is not affected
747 switch(i)
748 { case 1:
749 sprintf(tmpstr, "Initializing work area: [%s]", tadone);
750 break;
751 case 2:
752 sprintf(tmpstr, "Gathering Control Primes: [%s]", tadone);
753 break;
754 case 3:
755 j = (fetched - 108) >> 3;
756 if(j > 65536)
757 j = 65536;
758 sprintf(tmpstr,
759 "Please be patient; pulling Primary Cryption Key,"
760 " up to %d prime numbers", j); // Fetched is at
761 // least 8300; 8300-108=8192;
762 // 3 bit-shifts=division-by-8 (8192 bytes from Key File
763 // yields 1024 primes)
764 SetTextColor(hdc, 0x0000FFFF); // Yellow
765 TextOut(hdc, 1, 190, tmpstr, strlen(tmpstr)); // Special
766 // "be patient" message
767 SetTextColor(hdc, oldcolr);
768 sprintf(tmpstr, "Loaded %d Primes: [%s]", prmbar, tadone);
769 break;
770 case 4:
771 TextOut(hdc, 1, 190, eraser, 99); // erase special message
772 tmpstr[0] = '\0';
773 sprintf(tmpstr, "Crypting File #%d of %d: [%s]",
774 affnum, affcou, tadone);
775 }
776 TextOut(hdc, 1, 206, eraser, 99); // Erase any prior
777 // progress bar
778 TextOut(hdc, 1, 206, tmpstr, strlen(tmpstr)); // (Re)Display
779 // current message and progress bar
780 }
781 SetTextColor(hdc, oldcolr);
782 SelectObject(hdc, hPriorF);
783 EndPaint(hwnd, &ps);
784 painting = 0;
785 if(proceed == 'M')
786 { proceed = ' ';
787 gotdat = 0;
788 NeedInfo |= 15;
789 repaint = 1; // WANT to repaint, to prepare for
790 // new data entries
791 }
792 if((proceed == 'A') && !working)
793 { working = 1;
794 PostMessage(hwnd, WM_COMMAND, 123456789, 987654321);
795 // **** BEGIN TASK! ****
796 }
797 if(repaint)
798 { InvalidateRect(hwnd, &rect, 0); // The window must now be
799 // re-updated
800 repaint = 0;
801 }
802 return(0); // END OF WM_PAINT
803
804
805 ////
806 case WM_COMMAND:
807 if((wParam == 123456789) && (lParam == 987654321))
808 { if(0 < (ret = WorkAreaInit()))
809 { PostQuitMessage(ret); // any of several possible errors
810 return(0);
811 }
812 if(0 < (ret = KeyToPrimes()))
813 { PostQuitMessage(ret); // any of several possible errors
814 return(0);
815 }
816 if(0 < (ret = AffectFiles()))
817 { PostQuitMessage(ret); // any of several possible errors
818 return(0);
819 }
820 PostQuitMessage(0); // QUIT AUTOMATICALLY WHEN ALL
821 // TESTING/PROCESSING IS DONE
822 return(0);
823 }
824 break; // ignore all other WM_COMMAND messages
825
826
827
828 ////
829
830 case WM_DESTROY: // Clean-up work goes here, before ending overall
831 // conversion program
832 PostQuitMessage(0); // Note memory allocations freed at end
833 // of WinMain()
834 return(0); // Always return Zero from any Windows message
835 // processed
836 } // all Windows messages not handled in switch block must be
837 // processed below
838 return(DefWindowProc(hwnd, iMsg, wParam, lParam));
839 }; // END OF WndProc()
840
841
842
843 /********************************************************************/
844 // This semi-clone of the Main Windows Message-Handling Loop has the
845 // purpose of being available anywhere in this program, to process
846 // anything outstanding in the Message Queue. That is, some of the
847 // other functions below may take a long time to do their things, and
848 // Windows might think the program is "Not Responding". By placing
849 // calls to this function in appropriate places (during Progress-Bar
850 // handling, most likely), not only will Windows stay happy, but it
851 // also makes it easier for the user to abort the program by pressing
852 // the ESCape key. NOTE: When a large Key File is specified, such
853 // that more than ten thousand Primes will be pulled as the Primary
854 // CRYPTION Key, it does indeed take time to sort out those thousands
855 // of data items from random sequence, and then pull the primes from
856 // the main compressed-data file. (IF YOU WANT REAL SPEED FOR THIS
857 // PART OF THE PROCESS, GET A "SOLID-STATE DISK" a.k.a. RAM DISK TO
858 // HOLD THE PRIMES DIRECTORY.) If the user chooses to Abort, several
859 // seconds may pass before the CRYPTION program acknowledges it by
860 // quitting. In a way this slow preparation work is good because the
861 // user is granted a reasonable chance to abort -- since the CRYPTION
862 // process itself is the very next thing that happens after loading
863 // all those Primes, and this process does depend on the speed of the
864 // computer, which can be quite fast. There may not be any other
865 // equally good place to abort the CRYPTION program after all data has
866 // been accepted, especially if small files are to be scrambled
867 // (UNLESS very large Skip Numbers are chosen). IN GENERAL, it may be
868 // preferable to use large Key Files only when you want to scramble
869 // very large data files, or perhaps a great many small files. In
870 // those cases the time to load 65,000 primes for the Primary CRYPTION
871 // Key is OK because you know it's going to take a while, anyway, for
872 // the overall scrambling process to be completed.
873 S_32 ProcessMessages(void)
874 { static MSG mesg; // Make this multi-byte structure static so
875 // doesn't go on the stack.
876 S_32 ret = 0;//Initialize return-value-variable to Everything-is-OK.
877 // For the inexperienced, this assigment will happen
878 // every time this function is called, because ret is
879 // NOT a "static" type of variable. Assignments to
880 // static variables (in their declaration statements at
881 // the start of a function) are only done once, after
882 // which the assignment-code is ignored in all later
883 // calls to the function. However, the assigned value
884 // is remembered in-between function calls, and the
885 // body of the function can change it if desired (then
886 // the new value will be remembered, of course).
887 while(!ret && PeekMessage(&mesg, NULL, 0, 0, PM_NOREMOVE)) // Seek
888 // anything in the Windows Message queue
889 { if(GetMessage(&mesg, NULL, 0, 0)) // We arrive here ONLY if
890 // PeekMessage() found something
891 { TranslateMessage(&mesg);
892 DispatchMessage(&mesg);
893 }
894 else // GetMessage pulled a WM_QUIT
895 { PostQuitMessage(0); // Must put it back in Messge Queue for
896 // primary loop in WinMain()!
897 ret = 1; // Tell this while() loop AND the calling function
898 // to quit.
899 } } // Otherwise loop til processed all accumulated Messages
900 // in the Queue
901 return(ret); // return-value ret will be 0 if no messages in Queue
902 };
903
904
905
906 S_32 keycheck(void) // Let's try to get 90 bytes of reasonably random
907 // data from the Key File
908 { S_32 k;
909 U_08 uc, *ucp2 = ucMemBlk1; // Point at start of buffer loaded from
910 // Key File
911 // Remember Key File data begins 15000 bytes into the buffer, and
912 // that ucp1 points at its start
913 for(i=0; i<100; i++)
914 ucp2[i] = 0; // Erase the first 100 bytes of the ucMemBlk1
915 // memory block
916 for(i=0, j=0, uc=0; (i<(int)fetched)&&(j<90); i++)// Prepare to walk
917 // length of fetched Key File data
918 { uc ^= ucp1[i]; // Get a byte (or combine with another via
919 // Exclusive-Or)
920 // This trick with Exclusive-Or means that the 90 bytes we save via
921 // the ucp2 pointer will be rather unlike the data actually pulled
922 // from the file. More, since we are seeking ALL DIFFERENT bytes,
923 // there is no telling what order they will be in. That is, if a
924 // pulled/combined byte has already been found, we keep pulling/
925 // combining until something different pops out. So, while a simple
926 // text file like the U.S. Constitution may not look much like
927 // random data, multiple Exclusive-Or operations between pulled
928 // bytes will indeed create reasonable randomness. (Later on, in
929 // the main algorithm for using the Key File to select primes, bytes
930 // pulled from the Key File will be combined with pseudorandom
931 // numbers, so again even minimal randomness in the Key File will be
932 // acceptable.)
933 if(uc > 0) // for nonzero values only
934 { for(k=0; k<j; k++) // check previously saved values
935 if(uc == ucp2[k]) // If current nonzero value has already
936 // been saved
937 break; // consider it not random enough
938 if(k == j) // if for() loop ended with no match of current value
939 { ucp2[j++] = uc; // save it
940 uc = 0; // reset Exclusive-Or "accumulator"
941 } } } // loop through as much of Key file as needed
942 return(j < 90); // Return value is zero if got 90 different
943 // byte values
944 };// Here is a place where parentheses with return make great sense,
945 // because they delimit a comparison-operation. Parentheses force the
946 // compiler to code an evaluation of the comparison, and yield a
947 // guaranteed result of either Zero-for-"False" or One-for-"True".
948
949
950 S_32 WorkAreaInit(void) // fill 4,725,000 bytes with zeros
951 { char *r, *s, *t, *u, *v;
952 S_32 x, y;
953
954 p = (char *)(ucMemBlk4 + 525000);// Set pointer partway through this
955 // memory block
956 q = p + 525000; // set pointer partway through this memory block
957 r = q + 525000; // set pointer partway through this memory block
958 s = r + 525000; // set pointer partway through this memory block
959 t = s + 525000; // set pointer partway through this memory block
960 u = t + 525000; // set pointer partway through this memory block
961 v = u + 525000; // set pointer partway through this memory block
962 for(status=100, x=0; x<525000; x+=10500, status+=2)
963 { InvalidateRect(hwnd, &rect, 0); // make window update-able
964 PostMessage(hwnd, WM_PAINT, 0, 0); // Progress bar grows, based on
965 // status
966 if(ProcessMessages()) // process ALL messages in the queue
967 return(CRP_WM_QUIT); // assume user abort
968 for(y=x; y<(x+10500); y++)
969 { ucMemBlk2[y] = '\0'; // 50 * 10,500 = 525,000
970 ucMemBlk4[y] = '\0'; // 50 * 10,500 = 525,000
971 p[y] = '\0'; // 50 * 10,500 = 525,000
972 q[y] = '\0'; // 50 * 10,500 = 525,000
973 r[y] = '\0'; // 50 * 10,500 = 525,000
974 s[y] = '\0'; // 50 * 10,500 = 525,000
975 t[y] = '\0'; // 50 * 10,500 = 525,000
976 u[y] = '\0'; // 50 * 10,500 = 525,000
977 v[y] = '\0'; // 50 * 10,500 = 525,000; last of 4,200,000 bytes
978 } } // YES, the preceding could be written more efficiently and run
979 //faster. But this was also the first chance to experiment with
980 // progress-bar code....
981 it = (U_32 *)ucMemBlk3; // Initialize Index Table pointer for
982 // IndexToPrime() function
983 WorkSize = 0; // There are no ScratchPads prepared yet in the
984 // WorkRegion (ucMemBlk2)
985 WhichWay[0] = 0;// Set for Encryption Algorithm (code for Decryption
986 // Algorithm is 4)
987 WhichWay[1] = 1;// Set for Encryption Algorithm (code for Decryption
988 // Algorithm is -1)
989 // Now give the Control Scratchpads some default values,
990 // soon to be changed
991 LoadMaster->dvd = 0x12345;// Just a number to be divided a few times
992 // (in hexadecimal)
993 LoadMaster->dvs = 0x13531; // This is a prime, 79153 in Base Ten;
994 // not used very long
995 ModCounter->dvd = 1; // Two bits at a time will be yielded by
996 // ModCounter
997 ModCounter->dvs = 0x8000000; // This division produces ZEROS for a
998 // short time (2 modifications)
999 TypeSetter->dvd = 30; // Three bits at a time will be yielded by
1000 // TypeSetter
1001 TypeSetter->dvs = 63; // This division produces 011 110 011 110
1002 // 011 110 ...(til dvd/dvs replaced)
1003 RandomSkip->dvd = 1; // Two bits at a time will be yielded by
1004 // RandomSkip
1005 RandomSkip->dvs = 3; // This division produces 01 01 01 01 ...
1006 // (til dvd/dvs replaced)
1007 // Above default values will allow the PseudoRandomize() function to
1008 // be called even while gathering the final data that will replace
1009 // these default values. This lets us scramble the Key File data
1010 // even while fetching it, thereby practically guaranteeing we
1011 // always have pseudorandom Key data. Again, that is the main
1012 // reason why only a minimal randomness test was performed by
1013 // function keycheck().
1014 return(0);
1015};
1016/* NOTE REGARDING EFFECTIVENESS OF THE CRYPTION ALGORITHMS: While
1017 someone watching the flow of this code with a debugging tool could
1018 easily use the above initial information to construct a list of
1019 initial "scramble values" (values that affect key-file data), it
1020 remains to be seen if that information can actually help unscramble
1021 a given .CRP file. See, the dilemma faced by a cryptanalyst is
1022 that the scramble-data used to affect that file did NOT directly
1023 come from these easily computed initial scramble values. These
1024 values are merely used, along some of with those 90 "random" bytes
1025 found by the keycheck() function, to replace themselves with all
1026 new values -- and the cryptanalyst does not know what key file was
1027 used to obtain those 90 bytes. THEN, those new values are used to
1028 generate all new pseudorandom numbers which are combined with
1029 (again unknown to the cryptanalyst) straight key-file data to
1030 select a thousand or more primes from the compressed primes data
1031 file -- and it is those primes that generate the scramble-data
1032 used to affect a Message file. It seems likely that without
1033 knowing the key file, and even knowing that the scrambled data in
1034 the affected file always begins with "Data Protected From
1035 Snoopercomputers"..., there is no easy way to decide which
1036 GROUPINGS of primes-as-divisors and which numbers-as-dividends were
1037 used to generate the actually-used scamble-values. */
1038
1039
1040
1041
1042
1043// Do binary search of Index for location of Nth prime, then fetch it
1044// from the COMPRESS.PRM file. Parameter is a pointer to N;
1045// THIS FUNCTION REPLACES N WITH FOUND PRIME
1046S_32 IndexToPrime(U_32 *dp)
1047{ static U_32 N, hi, md, lo; // Static variables let the function run
1048 // faster
1049/*
1050The Index to the COMPRESS.PRM file treats that file like 143023 blocks
1051of 720 bytes each (the last block is smaller). The CMPRMDEX.QNT file
1052holds 143023 quantities of primes, each quantity being the number of
1053primes represented by the compressed data in one 720-byte block of the
1054file COMPRESS.PRM. When the Index file was loaded, those quantites
1055were added up, and each subtotal was saved. Therefore we now have in
1056memory an ever-increasing sequence of numbers, which we can use to
1057find the Nth prime. N just needs to be no larger than the last value
1058in the sequence, which is the grand total number of primes that can be
1059accessed via COMPRESS.PRM (203,280,221). The first thing this
1060function will do is ensure N is not too big. Then it will conduct a
1061fast binary search to determine which 720-byte block inside
1062COMPRESS.PRM holds the desired Nth prime, and that compressed-data
1063block is of course immediately fetched. The desired prime is then
1064quickly constructed using the Index value, N, and some of the elements
1065in the tbl array.
1066*/
1067 N = *dp;
1068 while(N > 203280221) // Too big a value entered for finding Nth
1069 // prime?
1070 N >>= 1; // HALVE the value (ignore any odd-bit remainder)
1071 if(N < 7)
1072 *dp = skpd[N]; // These first primes are NOT represented in
1073 // COMPRESS.PRM
1074 else
1075 { lo = 0; // lowest Index element
1076 hi = 143022; // highest Index element
1077 md = hi >> 1; // Prepare to do a binary search from middle of
1078 // the Index
1079 while (lo != hi)
1080 { if(N < it[md])
1081 hi = md; // Set new upper bound (this still might be the
1082 // right block!)
1083 else if(N > it[md])
1084 lo = md + 1;// Set new lower bound (block following md might
1085 // be the right one!)
1086 else
1087 break; // Well, well, cand just happened to exactly match
1088 // an Index entry!
1089 md = ((hi - lo) >> 1) + lo; // Get new middle between hi and lo
1090 // (may equal untested lo if hi-lo=1,
1091 // but next loop then finds it or makes lo=md=hi)
1092 }
1093 lo = md * 720; // Compute which block of compressed file holds
1094 // our N
1095 fseek(prmfil, ((S_32)lo - fpb) , SEEK_CUR); // Go to appropriate
1096 // file location
1097 fpb = fread(tmpstr, 1, 720, prmfil); // Load a block of
1098 // compressed-prime data
1099 fpb += lo; // Set file-position-byte to current location for
1100 // next seek
1101 ucp4 = tbl; // initialize table-pointer
1102 if(md > 0) // not the very first block
1103 { hi = it[(md - 1)]; // Fetch total number of primes preceding the
1104 // fetched block
1105 md *= 30030; // Initial computation for first possible prime in
1106 // that block
1107 md++; // Adjust for exactness: first number represented by
1108 // compressed data
1109 bt = 1; // initialize bit-tester
1110 }
1111 else // very first block...
1112 { hi = 6; // Compressed-prime data starts at 7th prime;
1113 // ensure loop below works
1114 md = 17;
1115 bt = 2; // initialize bit-tester
1116 ucp4++; // correct table pointer for first block
1117 }
1118 by = (U_08 *)tmpstr; // Set byte-pointer to start of 720 items in
1119 // buffer
1120 for(;;) // this loop guaranteed to break
1121 { if((*by & bt) == bt) // if this is a prime
1122 hi++; // count towards desired N
1123 if(hi >= N)
1124 break; // exit if N reached
1125 md += *ucp4++; // add a tbl entry to create new possible prime
1126 if(bt == 128) // check for last possible bit-value (in one byte)
1127 { bt = 1; // reset bit-tester
1128 by++; // advance to next byte in buffer
1129 }
1130 else
1131 bt <<= 1; // double for next bit-to-test
1132 } // when loop ends, variable md holds the desired Nth prime
1133 *dp = md; // Replace N with it
1134 }
1135 return(0); // no error!
1136};
1137
1138
1139// Divide using passed scratchpad pointer, to obtain some number of
1140// bits of result. Since Base 2 is king, each division will yield one
1141// bit. Most of the time this function will be used to obtain just
1142// two bytes, 16 bits, and often less. NOTE: ENSURE (0 < .dvd) and
1143// (.dvd < .dvs) -- WHEN .dvs IS A PRIME>2, NEVER DIVIDES EVENLY!
1144U_32 Divide(struct scratchpad *sp, S_32 bits)
1145{ static U_32 ret;
1146 /*
1147 One of the keys to the CRYPTION program is the fact that this
1148 function operates on EXTERNAL data. That modified data can be --
1149 and is -- simply retained until this function is called to operate
1150 on it some more. Thus we do PART of an overall long division now --
1151 just a few bits of it -- some more bits later, some more bits still
1152 later still, and so on. There will be up to 64K division-operations
1153 in progress! That is how this program trades memory usage to obtain
1154 speed. Only a relatively small amount of division is needed to
1155 obtain the pseudo-random numbers used for scrambling data, and it
1156 doesn't have to be re-done to get different pseudo-random numbers --
1157 because all the operations are held in memory, waiting for this: */
1158 ret = 0; // initialize return value
1159 while(sp->dvd > sp->dvs) // While divisor is smaller than
1160 // to-be-divided
1161 sp->dvd >>= 1; // HALVE the dividend. Here we do not care at all
1162 // about keeping the thown-away lowest bit, because
1163 // we expect to be doing this only to convert a random
1164 // 32-bit number down to the same magnitude of the
1165 // divisor-Prime -- and once done, will not need to be
1166 // done again to this ScratchPad.
1167 while(bits > 0)
1168 { ret <<= 1; // For each bit counted in while() loop, prepare a
1169 // place to hold a One or a Zero (doubles ret by shifting
1170 // all bits higher one position, "appending" a zero)
1171 if(sp->dvs > sp->dvd)//while divisor is greater than to-be-divided
1172 sp->dvd <<= 1; // double/redouble dividend
1173 /* The two main steps in this loop are doing "long division" in
1174 Base Two, totally analogous to familiar Base Ten stuff. Consider
1175 this Base Ten example:
1176 __0.009708_ <-appended zeros retained when can't subtract
1177 103 | 1.000 <-append and keep 2 zeros in quotient, but
1178 _927_ <-subtract after 3rd; nonzero put in quotient
1179 730 <-append a zero (multiply by Ten), but quotient
1180 _721_ <-gets a nonzero because we can subtract again
1181 900 <-append/keep 1 more zero above
1182 _824_ <-but 2nd appended zero allows subtraction
1183 Note in Base Ten each appended Zero means multiply-by-Ten, while
1184 in Base Two it means multiply-by-Two -- doubling, in other words.
1185 Also in Base Two, the only digit (and multiplier) besides Zero is
1186 ONE (not 9, 7 or 8 as above), which is why Base Two division can
1187 subtract without multiplying. */
1188 // Below is the subtraction step; if ok-to-do, the Zero that was
1189 // appended to ret via bit-shift/doubling will be incremented
1190 if(sp->dvs < sp->dvd) // TEST: is divisor smaller than dividend
1191 // (can we subtract)?
1192 { sp->dvd -= sp->dvs; // Division in Base Two consists of
1193 // subtracting the divisor from the (doubled/redoubled) dividend.
1194 // The remainder becomes new dividend for next division steps.
1195 ret++; // Obviously if no subtraction occurs, appended Zero will
1196 // be unchanged
1197 } // Ret is a partial quotient, the wanted string of bits, mixed
1198 // Zeros and Ones
1199 bits--; /* Each iteration of overall loop represents one bit in
1200 Base-Two division. Since 16 or fewer bits are normally sought,
1201 next test exists for those rare occasions when we want to know
1202 that a prime's reciprocal-PERIOD is very long. For these tests,
1203 dvs is set to the prime P, dvd is set to P-1, and the bits
1204 parameter is set to 100,020. As it happens, when taking a
1205 reciprocal, the last division of a prime's period will always have
1206 a remainder of 1, while the MIDDLE division during the period will
1207 have a remainder of P-1 (this is a consequence of the two halves
1208 of a period adding their digits to a constant value). So, by
1209 starting with a dividend of P-1 for dvd before calling this
1210 function, and seeking a constant of 1 as the current remainder...
1211 if a remainder of 1 appears before we countdown bits from 100,020
1212 to 20, then we know that the HALF-PERIOD is less than 100,000
1213 digits, and this is unacceptable for CRYPTION. (Note 100,000
1214 loops are actually done quite quickly, since bit-shifts and
1215 subtractions are processed FAST.) */
1216 if(bits > 20) // Only do this test when wanting large quantities
1217 // of bits
1218 { ret = 0; // Prevent accidental return value of 0xFFFFFFFF
1219 // by main loop
1220 if(sp->dvd == 1)
1221 return(0xFFFFFFFF); // Let period-testing routine know the
1222 // divisor is unacceptable!
1223 } }
1224 return(ret); // Note most return values will range 16 bits or less,
1225}; // max of 0xFFFF
|