home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / FLXKEY10.ZIP / FLXKEY.DOC < prev    next >
Encoding:
Text File  |  1992-10-01  |  26.7 KB  |  834 lines

  1.  
  2.  
  3.  
  4.                       FlxKey 1.0  :  Registration-key Unit
  5.                       for Borland's Turbo Pascal 4.0 - 6.0
  6.  
  7.                         Copyright 1992 by Guy McLoughlin
  8.                               All Right Reserved.
  9.  
  10.                          Released as Shareware, 01/10/92.
  11.  
  12.  
  13.  
  14.      DESCRIPTION
  15.      ===========
  16.  
  17.           FlxKey is an easy to use Turbo Pascal unit, that enables you
  18.           to create encrypted user-registration keys for your programs.
  19.  
  20.           To make the whole process as "painless" as possible, FlxKey
  21.           performs all the encryption, decryption, and error-checking
  22.           for you.
  23.  
  24.           The FlxKey unit comes pre-compiled in four .TPU files: one
  25.           for Turbo Pascal 4.0 (FLX40TPU.ZIP), one for Turbo Pascal 5.0
  26.           (FLX50TPU.ZIP), one for Turbo Pascal 5.5 (FLX55TPU.ZIP), and
  27.           one for Turbo Pascal 6.0 . (FLX60TPU.ZIP)
  28.  
  29.           Also included are several sample programs, each demonstrating
  30.           a different method of using the FlxKey unit.
  31.  
  32.  
  33.  
  34.      PUTTING FLX TO WORK
  35.      ===================
  36.  
  37.           There are only two routines to call within the FlxKey unit:
  38.  
  39.             CreateFlxKey - Creates an encrypted registration-key
  40.                            based on the data you pass to it.
  41.  
  42.             ReadFlxKey   - Reads/decodes/error-checks an encrypted
  43.                            registration-key, and returns the key's
  44.                            data.
  45.  
  46.           Both of these routines will return an error-code number, which
  47.           your program can use to determine it's best course of action.
  48.  
  49.  
  50.  
  51.      CREATING A REGISTRATION-KEY
  52.      ===========================
  53.  
  54.           Before you can use the CreateFlxKey routine you must:
  55.  
  56.             1- Place the name of the FlxKey unit in your program's
  57.                "uses" declaration.
  58.  
  59.                ie:   uses
  60.                        Crt,
  61.                        FlxKey;
  62.  
  63.  
  64.                                     Page 1
  65.  
  66.  
  67.  
  68.  
  69.             2- Declare a "FlxRec" variable, used to pass the data you
  70.                want to encrypt into the registration key.
  71.  
  72.                ie:   type
  73.                        FlxRec = record
  74.                                   FirstName : st20;
  75.                                   LastName  : st30;
  76.                                   Address1  : st30;
  77.                                   Address2  : st30;
  78.                                   Address3  : st30;
  79.                                   AppName   : st20;
  80.                                   Version   : word;
  81.                                   Serial    : longint;
  82.                                   Date      : longint;
  83.                                   Access    : word;
  84.                                 end;
  85.                      var
  86.                        TempKeyRec : FlxRec;
  87.  
  88.             3- Declare two encryption-code string variables, to be used
  89.                to encrypt the registration key. These strings can be
  90.                from 1 character to 100 characters in length, though I
  91.                would recommend using at least 10 characters for each
  92.                encryption string.
  93.  
  94.                ie:   var
  95.                        Ecode1,
  96.                        Ecode2 : string[100];
  97.  
  98.                      or
  99.  
  100.                      var
  101.                        Ecode1,
  102.                        Ecode2 : st100;
  103.  
  104.             4- Declare a word-type variable to hold the error-code
  105.                returned by CreateFlxKey.
  106.  
  107.                ie:   var
  108.                        ErrorCode : word;
  109.  
  110.             5- Declare a path/filename string variable, that will be
  111.                used to pass the name of the encrypted registration-key
  112.                file you want to create.
  113.  
  114.                ie:   var
  115.                        RegKeyName : string[79];
  116.  
  117.                      or
  118.  
  119.                      var
  120.                        RegKeyName : st79;
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.                                     Page 2
  129.  
  130.  
  131.  
  132.  
  133.             6- Assign your data to the "FlxRec" variable.
  134.  
  135.                To assign data to the "TempKeyRec" you declared earlier,
  136.                you could code something like this:
  137.  
  138.               (* TempKeyRec is our "FlxRec" type variable.            *)
  139.                with TempKeyRec do
  140.                  begin
  141.  
  142.               (* Assign the firstname, lastname, and address of the   *)
  143.               (* user this key is being created for.                  *)
  144.                    FirstName := 'John';
  145.                    LastName  := 'Smith';
  146.                    Address1  := '1234 AnyPlace Road,';
  147.                    Address2  := 'BigCity, BigPlace,';
  148.                    Address3  := 'BigCountry, BigZip';
  149.  
  150.               (* Assign the name of your amazing program that this    *)
  151.               (* key belongs to.                                      *)
  152.                    AppName   := 'Amazing Program';
  153.  
  154.               (* Assign the version number of your program. For       *)
  155.               (* example, the number below could be used to represent *)
  156.               (* version 3.10 of your software.                       *)
  157.                    Version   := 310;
  158.  
  159.               (* Assign the serial number of the registration-key you *)
  160.               (* are creating for this user.                          *)
  161.                    Serial    := 1234567890;
  162.  
  163.               (* This is the date that will be stored in the          *)
  164.               (* encrypted registration-key, in standard Turbo Pascal *)
  165.               (* packed "datetime" format. If you set this variable   *)
  166.               (* to zero, the CreateFlxKey routine will automatically *)
  167.               (* stamp it with the current date/time.                 *)
  168.                    Date      := 0;
  169.  
  170.               (* This is the user-access level that you are assigning *)
  171.               (* to this user. From 0 to 65,535.                      *)
  172.                    Access    := 1234
  173.                  end;
  174.  
  175.             7- Assign the path/filename to the encrypted registration-
  176.                key you want to create.
  177.  
  178.                ie:   RegKeyName := 'AMAZPROG.KEY';
  179.  
  180.                      or
  181.  
  182.                      RegKeyName := 'C:\AP-KEYS\AMAZPROG.KEY';
  183.  
  184.             8- Assign data to the two the two encryption-code strings
  185.                that you want to use to encrypt the registration-key.
  186.                This is a very crucial step in the process, that will
  187.                be covered in more detail when we look at "embedding"
  188.                random encryption-codes into your programs.
  189.  
  190.  
  191.  
  192.                                     Page 3
  193.  
  194.  
  195.  
  196.  
  197.                For now we will assign two simple encryption-code strings,
  198.                to be used for demonstration purposes.
  199.  
  200.                ie:   Ecode1 := 'Apple';
  201.                      Ecode2 := 'Orange';
  202.  
  203.           ...Now that you've created all the variables necessary, and
  204.           assigned data to them, you can call "CreateFlxKey" to create
  205.           the encrypted registration key.
  206.  
  207.                ie:  CreateFlxKey(TempKeyRec, Ecode1, Ecode2,
  208.                                  RegKeyName, ErrorCode);
  209.  
  210.           ...If this call was successful, the ErrorCode variable should
  211.           be equal to zero, and you should now find a new file on your
  212.           disk called "AMAZPROG.KEY".
  213.  
  214.  
  215.  
  216.      CHECKING FOR ERRORS
  217.      ===================
  218.  
  219.           ...Ok, so what happens when the ErrorCode variable does not
  220.           equal zero? Here is an explanation of how to interpret the
  221.           ErrorCode variable.
  222.  
  223.           The ErrorCode number is a "word" type variable, where the "low"
  224.           byte is used to store a FlxKey error, and the "hi" byte is used
  225.           to store a standard Turbo Pascal "ioresult" type error.
  226.  
  227.           Normally you would first check the "low" byte of the ErrorCode
  228.           variable, to determine if the error was a FlxKey error or a
  229.           standard Turbo Pascal "ioresult" type error. To check this you
  230.           could:
  231.  
  232.             AND it with the value of 255, which will give us only the
  233.             "low" byte of the variable.
  234.  
  235.               ie:  LowByte := (ErrorCode AND 255);
  236.  
  237.             Use the standard Turbo Pascal function called "Lo".
  238.  
  239.               ie:  LowByte := lo(ErrorCode);
  240.  
  241.  
  242.           Here is a list of the FlxKey errors that could occur in
  243.           the "low" byte:
  244.  
  245.             0  : No errors.
  246.             1  : Error! One or more encryption-code strings is blank.
  247.             2  : Error! Filename string for registration-key is blank.
  248.             3  : Error! Registration-key is CORRUPT. Data is INVALID.
  249.            16  : Error! Standard Turbo Pascal "ioresult" type error.
  250.  
  251.           If there was an "ioresult" error, then you can check the "hi"
  252.           byte of the "ErrorCode" variable to determine what the error
  253.           was.
  254.  
  255.  
  256.                                     Page 4
  257.  
  258.  
  259.  
  260.  
  261.           To check the "hi" byte of the ErrorCode variable you could
  262.           either:
  263.  
  264.             Use the standard Turbo Pascal "SHR" operator to shift the
  265.             "hi" byte down to the "low" byte position.
  266.  
  267.               ie:  HiByte := (ErrorCode SHR 8);
  268.  
  269.             Use the standard Turbo Pascal function called "Hi".
  270.  
  271.               ie:  HiByte := hi(ErrorCode);
  272.  
  273.           Check in your Turbo Pascal manuals, to determine the meaning
  274.           of this "hi" byte error. (ie: See "RunTime Errors")
  275.  
  276.           To see a complete program listing to create an encrypted
  277.           registration-key, take a look at the sample program called
  278.           "MAKEKEY1.PAS".
  279.  
  280.  
  281.  
  282.      READING THE DATA STORED IN AN ENCRYPTED REGISTRATION-KEY
  283.      ========================================================
  284.  
  285.           Before you can use the ReadFlxKey routine you must perform
  286.           almost the identical steps you did to create the encrypted
  287.           registration-key:
  288.  
  289.             1- Place the name of the FlxKey unit in your program's
  290.                "uses" declaration.
  291.  
  292.                ie:   uses
  293.                        Crt,
  294.                        FlxKey;
  295.  
  296.             2- Declare a "FlxRec" variable, used to pass the data you
  297.                want to encrypt into the registration key.
  298.  
  299.                ie:   var
  300.                        TempKeyRec : FlxRec;
  301.  
  302.             3- Declare two encryption-code string variables, to be used
  303.                to encrypt the registration-key. These strings can be
  304.                from 1 character to 100 characters in length, though I
  305.                would recommend using at least 10 characters for each
  306.                encryption string.
  307.  
  308.                ie:   var
  309.                        Ecode1,
  310.                        Ecode2 : string[100];
  311.  
  312.                      or
  313.  
  314.                      var
  315.                        Ecode1,
  316.                        Ecode2 : st100;
  317.  
  318.  
  319.  
  320.                                     Page 5
  321.  
  322.  
  323.  
  324.  
  325.             4- Declare a word-type variable to hold the error-code number
  326.                returned by CreateFlxKey.
  327.  
  328.                ie:   var
  329.                        ErrorCode : word;
  330.  
  331.             5- Declare a word-type variable to hold the difference in
  332.                days between the current date and the date stored within
  333.                the registration-key.
  334.  
  335.                ie:   var
  336.                        DaysOld : word;
  337.  
  338.             6- Declare a path/filename string variable. This will be used
  339.                to pass the name of the encrypted registration-key file you
  340.                want to create.
  341.  
  342.                ie:   var
  343.                        RegKeyName : string[79];
  344.  
  345.                      or
  346.  
  347.                      var
  348.                        RegKeyName : st79;
  349.  
  350.             7- Assign the path/filename to the encrypted registration-key
  351.                you want to read the data from.
  352.  
  353.                ie:   RegKeyName := 'AMAZPROG.KEY';
  354.  
  355.                      or
  356.  
  357.                      RegKeyName := 'C:\AP-KEYS\AMAZPROG.KEY';
  358.  
  359.             8- Assign the IDENTICAL two encryption-codes that you used
  360.                to create the registration-key. (If these two encryption-
  361.                codes are not identical to the ones used to create the
  362.                registration-key, the data returned by the ReadFlxKey
  363.                routine will be completely corrupt.)
  364.  
  365.                ie:   Ecode1 := 'Apple';
  366.                      Ecode2 := 'Orange';
  367.  
  368.           ...Now that you've created all the variables necessary, and
  369.           entered the required data, you can now call "ReadFlxKey" to
  370.           obtain the data stored within the encrypted registration-key.
  371.  
  372.                ie:  ReadFlxKey(Ecode1, Ecode2, RegKeyName,
  373.                                TempKeyRec, DaysOld, ErrorCode);
  374.  
  375.           ...If this call was successful, the ErrorCode variable should
  376.           be equal to zero, and you should now find the data from the
  377.           registration-key in the "TempKeyRec" variable. The "DaysOld"
  378.           variable will also indicate the difference in days between the
  379.           current date and the date stored inside the registration-key.
  380.  
  381.  
  382.  
  383.  
  384.                                     Page 6
  385.  
  386.  
  387.  
  388.  
  389.           The ErrorCode variable that ReadFlxKey returns, is handled in
  390.           exactly the same manner as the "CreateFlxKey" routine, with the
  391.           FlxKey error stored in the "low" byte and the standard Turbo
  392.           Pascal "ioresult" type error stored in the "hi" byte.
  393.  
  394.           Here is a list of the FlxKey errors that could occur in the
  395.           "low" byte:
  396.  
  397.             0  : No errors.
  398.             1  : Error! One or more encryption-code strings is blank.
  399.             2  : Error! Filename string for registration-key is blank.
  400.             3  : Error! Registration-key is CORRUPT. Data is INVALID.
  401.            16  : Error! Standard Turbo Pascal "ioresult" type error.
  402.  
  403.           Check in your Turbo Pascal manuals, to determine the meaning
  404.           of this "hi" byte error. (ie: See "RunTime Errors")
  405.  
  406.           To see a complete program listing to read an encrypted
  407.           registration-key, take a look at the sample program called
  408.           "READKEY1.PAS".
  409.  
  410.  
  411.  
  412.      "EMBEDDING" THE TWO ENCRYPTION-CODE STRINGS
  413.      ===========================================
  414.  
  415.           ...One of the main problems with creating a program that
  416.           utilizes encrypted registration-keys, is where do you
  417.           store the two encryption-code strings?
  418.  
  419.           If you simply use an assignment statement for these two
  420.           strings, it may be quite easy for someone to look at your
  421.           .EXE and determine what their values are.
  422.  
  423.           For example here is a "hex-mode" display of the compiled
  424.           "READKEY1.EXE" sample program:
  425.  
  426.        30 01 04 02 01 00 66 02-EE 00 66 02 8A 05 66 02  ................
  427.        05 41 70 70 6C 65 06 4F-72 61 6E 67 65 09 44 45  .Apple.Orange...
  428.        4D 4F 31 2E 4B 45 59 2E-20 45 72 72 6F 72 21 20  ................
  429.  
  430.           ...As you can see, the two encryption-strings "Apple" and
  431.           "Orange" are clearly visible.
  432.  
  433.           ...OK, how about if we make these two encryption strings into
  434.           "typed constants"?
  435.           (A "typed constant" is basically a variable that is assigned
  436.            it's data at "compile-time", instead of "run-time".)
  437.  
  438.                ie:   const
  439.                        Ecode1 : st100 = 'Apple';
  440.                        Ecode2 : st100 = 'Orange';
  441.  
  442.           ...Again it is quite easy to determine what the encryption-
  443.           string values are. Here is a "hex-mode" display from an .EXE
  444.           that uses this method:
  445.  
  446.  
  447.  
  448.                                     Page 7
  449.  
  450.  
  451.  
  452.  
  453.        00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
  454.        00 00 05 41 70 70 6C 65-00 00 00 00 00 00 00 00  ...Apple........
  455.        00 00 00 00 00 00 00 00-06 4F 72 61 6E 67 65 00  .........Orange.
  456.        00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
  457.  
  458.           ...So what can you do?
  459.  
  460.           One part of the solution is to use "random" encryption-code
  461.           strings. These are strings that contain randomly generated
  462.           data, and are MUCH harder to find than a simple alphabetical
  463.           string.
  464.  
  465.           Here are the steps required to create "random" encryption-code
  466.           strings:
  467.  
  468.             1- Clear the encryption-code string variables.
  469.  
  470.                  fillchar(Ecode1, sizeof(Ecode1), 0);
  471.                  fillchar(Ecode2, sizeof(Ecode2), 0);
  472.  
  473.             2- Set the length byte for both of these encryption-code
  474.                strings:
  475.  
  476.               (* Set the length byte to 20 characters.                *)
  477.                  Ecode1[0] := #20;
  478.                  Ecode2[0] := #20;
  479.  
  480.             3- Call the standard Turbo Pascal "Randomize" function to
  481.                ensure that the data will be random.
  482.  
  483.                  randomize;
  484.  
  485.             4- Assign random data to each of the encryption-code strings.
  486.  
  487.                for Index := 1 to 20 do
  488.                  begin
  489.                    Ecode1[Index] := chr(random(256));
  490.                    Ecode2[Index] := chr(random(256))
  491.                  end;
  492.  
  493.           ...The second part of the solution is to use the "fake"
  494.           procedure method of linking these two encryption-strings
  495.           directly into a compiled program's "code segment".
  496.  
  497.           By placing these two "random" encryption strings into the
  498.           "code segment", it becomes MUCH harder to detect both the
  499.           location of the encryption-code strings, and which bytes
  500.           belong to them.
  501.  
  502.           Here are the steps required to using the "fake" procedure
  503.           method of linking these two encryption-code strings into
  504.           your program's "code" segment:
  505.  
  506.             1- Create two random encryption-code strings, as shown
  507.                earlier.
  508.  
  509.  
  510.  
  511.  
  512.                                     Page 8
  513.  
  514.  
  515.  
  516.  
  517.             2- Write these two encryption strings to disk.
  518.  
  519.                To see a complete program listing that will create
  520.                two "random" encryption-code strings, and then write
  521.                them to disk, take a look at the sample program called
  522.                "RANDCODE.PAS".
  523.  
  524.             3- Use the standard Turbo Pascal "BINOBJ.EXE" utility,
  525.                to convert the encryption-code string data from "binary"
  526.                file format to "object" file format. For example here
  527.                is a sample DOS command line to use this utility:
  528.  
  529.                  (A)      (B)        (C)       (D)
  530.                BINOBJ  ECODE1.DAT  ECODE1.OBJ  Ecode1Data
  531.  
  532.                  A : This is the name of the Turbo Pascal utility.
  533.  
  534.                  B : This is the name of the "binary" file we want to
  535.                      convert.
  536.  
  537.                  C : This is the name of the "object" file we want to
  538.                      create.
  539.  
  540.                  D : This is the "public" name for the "fake" procedure
  541.                      that we want to create.
  542.  
  543.                Take a look at the sample "batch" file called
  544.                "DAT2OBJ.BAT", for an example of how to use the
  545.                Turbo Pascal "BINOBJ.EXE" utility.
  546.  
  547.             4- Declare two encryption-string pointer variables.
  548.  
  549.               (* Declare a 20 character string-type.                  *)
  550.                type
  551.                  st20     = string[20];
  552.  
  553.               (* Declare a 20 character string pointer-type.          *)
  554.                  st20Ptr = ^st20;
  555.  
  556.               (* Declare two encryption-code string pointer variables.*)
  557.                var
  558.                  Ecode1ptr,
  559.                  Ecode2ptr : st20Ptr;
  560.  
  561.             5- Link the encryption-code string data (in "object" file
  562.                format) into your program, as a "fake" procedure. For
  563.                example:
  564.  
  565.               (* Declare the following two procedures as "FAR".       *)
  566.  
  567.                {$F+}
  568.  
  569.               (* "Fake" procedure that contains first encryption-code *)
  570.               (* string.                                              *)
  571.  
  572.                procedure Ecode1Data; external;
  573.                {$L ECODE1.OBJ}
  574.  
  575.  
  576.                                     Page 9
  577.  
  578.  
  579.  
  580.  
  581.               (* "Fake" procedure that contains second encryption-code*)
  582.               (* string.                                              *)
  583.  
  584.                procedure Ecode2Data; external;
  585.                {$L ECODE2.OBJ}
  586.  
  587.               (* Turn off "FAR" declaration.                          *)
  588.  
  589.                {$F-}
  590.  
  591.             6- Assign the encryption-string pointers to the two "fake"
  592.                procedures. For example:
  593.  
  594.               (* Assign the encryption-code string pointers to their  *)
  595.               (* data.                                                *)
  596.  
  597.                Ecode1ptr := addr(Ecode1Data);
  598.                Ecode2ptr := addr(Ecode2Data);
  599.  
  600.             7- Call the FlxKey routine by "de-refferencing" ( ^ ) the two
  601.                encryption-code string pointers.
  602.  
  603.                CreateFlxKey(TempKeyRec, Ecode1Ptr^, Ecode2Ptr^, RegKeyName,
  604.                             ErrorCode);
  605.  
  606.                ReadFlxKey(Ecode1Ptr^, Ecode2Ptr^, RegKeyName, TempKeyRec,
  607.                           DaysOld, ErrorCode);
  608.  
  609.           To demonstrate this whole "embedded" encryption-code process,
  610.           try out the sample programs in the following order:
  611.  
  612.             1- Compile and run the "RANDCODE.PAS" sample program
  613.                to create the two "random" encryption-code strings,
  614.                and save them in "binary" file format.
  615.                (ie: ECODE1.DAT, ECODE2.DAT)
  616.  
  617.             2- Run the "DAT2OBJ.BAT" batch-file to convert the
  618.                encryption-code data from "binary" file format to
  619.                "object" file format. (ie: ECODE1.OBJ, ECODE2.OBJ)
  620.  
  621.                *** NOTE: The "BINOBJ.EXE" utility must either be in
  622.                          the same directory, or be in a "pathed"
  623.                          directory.
  624.  
  625.             3- Compile and run the "MAKEKEY2.PAS" sample program to
  626.                create a sample encrypted registration-key file called
  627.                "DEMO2.KEY".
  628.  
  629.             4- Compile and run the "READKEY2.PAS" sample program to
  630.                read the sample encrypted registration-key file called
  631.                "DEMO2.KEY".
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.                                     Page 10
  641.  
  642.  
  643.  
  644.  
  645.      CREATING A "PASSWORD" REGISTRATION-KEY
  646.      ======================================
  647.  
  648.           Another way to use the FlxKey unit is to create encrypted
  649.           "password" registration-keys.
  650.  
  651.           With this sort of registration-key, the end-user has to
  652.           enter a "password" to be able to use your program.
  653.  
  654.           The process to create an encrypted "password" registration-
  655.           key is very similar to creating a standard encrypted
  656.           registration-key.
  657.  
  658.           The only difference is that ONLY one of the encryption-code
  659.           strings is "embedded" in your compiled program. The second
  660.           encryption-code string is the "password" string that the user
  661.           must enter, to use your program.
  662.  
  663.           ...To demonstrate how the whole "password" encryption-key
  664.           process works, try out the two sample programs:
  665.  
  666.             MAKEKEY3.PAS - Create an encrypted "password" registration-
  667.                            key. (ie: DEMO3.KEY)
  668.  
  669.             READKEY3.PAS - Read an encrypted "password" registration-key.
  670.                            (ie: DEMO3.KEY)
  671.  
  672.  
  673.  
  674.      NOTES ON USING THE FLXKEY UNIT
  675.      ==============================
  676.  
  677.           ...One of the main design features of the FlxKey unit is that
  678.           it will rarely ever produce the same encrypted registration-
  679.           key twice. Even when using the identical user-data.
  680.  
  681.           For example: If you run one of the sample "MakeKey" programs
  682.           several times using the same user-data, a unique encrypted
  683.           registration-key will be produced each time. Yet each of these
  684.           unique registration-keys will still produce the identical user-
  685.           data when read using the ReadFlxKey routine.
  686.  
  687.           ...Remember to always keep a secure copy of the encryption-code
  688.           strings that your program passes to the FlxKey routines.
  689.  
  690.           ...If you lose these encryption-code strings, there is NO
  691.           alternative method of creating/reading compatible encrypted
  692.           registration-keys.
  693.  
  694.           ...The source-code to the FlxKey unit is NOT available. I feel
  695.           that it would compromise the security of the registration-keys
  696.           that the FlxKey unit generates if I released the source-code.
  697.  
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.                                     Page 11
  705.  
  706.  
  707.  
  708.  
  709.      SUPPORT FOR REGISTERED FLXKEY USERS
  710.      ===================================
  711.  
  712.           Registered users may contact me through one of the following
  713.           Networks:
  714.  
  715.               DEVNET  Pascal Conference
  716.               ILINK   Pascal Conference
  717.               NANET   Pascal Conference
  718.               RIME    Pascal Conference
  719.               UN'INET Pascal Conference
  720.  
  721.           ...Or by writing me using "snail" mail:
  722.  
  723.              Guy McLoughlin,
  724.              P.O. Box 519, Station A,
  725.              Toronto, Ontario,
  726.              Canada  M5W 1E4
  727.  
  728.  
  729.  
  730.      HOW TO REGISTER THE FLXKEY UNIT
  731.      ===============================
  732.  
  733.           FlxKey is distributed as a "shareware" unit, which enables
  734.           you to try it out before you decide if you want to purchase
  735.           the registered version of it.
  736.  
  737.           The registered version of the FlxKey unit will perform
  738.           identically to the "shareware" version, but will NOT
  739.           contain the FlxKey message with the ten second delay.
  740.           (It will also use up 3.5K less space in your programs.)
  741.  
  742.           To register the FlxKey unit, send $15.00 in the form of
  743.           check or money-order to:
  744.  
  745.  
  746.              Guy McLoughlin,
  747.              P.O. Box 519, Station A,
  748.              Toronto, Ontario,
  749.              Canada  M5W 1E4
  750.  
  751.  
  752.           Registered FlxKey users will be able to purchase future
  753.           upgrades of the FlxKey unit for 1/3 the cost of the initial
  754.           registration fee.
  755.  
  756.  
  757.  
  758.      LEGAL DETAILS
  759.      =============
  760.  
  761.           The "shareware" version of the FlxKey unit may be freely
  762.           distributed ONLY in it's original un-modified format.
  763.           This would include the full documentation, compiled
  764.           "shareware" .TPUs, and sample programs. These files are
  765.           Copyright 1992 by Guy McLoughlin, All Rights Reserved.
  766.  
  767.  
  768.                                     Page 12
  769.  
  770.  
  771.  
  772.  
  773.           The author assumes no responsibility for any damage or
  774.           loss caused by the use of the FlxKey unit, or the support
  775.           files that accompany it.
  776.  
  777.           Turbo Pascal is registered trademark of Borland International.
  778.  
  779.  
  780.  
  781.  
  782.  
  783.  
  784.  
  785.  
  786.  
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.                                     Page 13
  833.  
  834.