home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / Digital Money™ Dev Kit / DM Development / routines you may want.c < prev    next >
Encoding:
Text File  |  1995-04-11  |  11.8 KB  |  497 lines  |  [TEXT/KAHL]

  1.  
  2. // ****************************************************************
  3. //
  4. // Copyright 1995 Digital Money, Inc.
  5. // You may use this source code in your own applications.
  6. //
  7. // *******************************************************************
  8. //
  9. // Supplemental routines for use with Digital Money AutoPay Module.
  10. // These routines were written for Think C 5.0
  11. // but should be immediately useable with other C environments.
  12.  
  13. // Feel free to use these routines in you own applications.
  14. // See the AutoPay manual, Chapter 4, for more information.
  15.  
  16. // This file uses ANSI routines.
  17.  
  18. // Updated April 5, 1995.
  19. // *******************************************************************
  20.  
  21. // *******************************
  22. // THINGS YOU NEED TO PERSONALIZE:
  23. // *******************************
  24.  
  25. // Personalize the following three strings:
  26.  
  27. #define kTheCryptoKey         "Put your crypto key here!"
  28. #define kYourProgramName     "YourProgramNameHere"
  29. #define kOwnerResource        'xYxn'                    // This should match your 
  30.                                                     // application's owner resource
  31.                                                     // If you don't know what this is,
  32.                                                     // choose a random 4-char string.
  33. #include <Folders.h>
  34. #include <Files.h>
  35. #include <Script.h>
  36.  
  37. // The keyType structure. See the description below.
  38.  
  39. typedef struct
  40. {
  41.     char            name[60];
  42.     char            verificationCode[60];
  43.     char            serialNumber[30];
  44. }    keyType;
  45.  
  46. // *******************
  47. // Function prototypes
  48. // *******************
  49.  
  50. OSErr         readKeyFromDisk         (keyType *key);
  51. OSErr         writeKeyToDisk             (keyType *key);
  52. Boolean     isProgramRegistered     (void);
  53. char         *myEncrypt                (char *inputString, char *cryptoKey);
  54. OSErr         saveProgramAsRegistered (char *theName);
  55. OSErr         saveSerialNumber         (char *theSerialNumber);
  56.  
  57.  
  58. Boolean isProgramRegistered (void)
  59. {
  60.     keyType        theKey;
  61.     char        cryptoKey[50], whatItShouldBe[80];
  62.     OSErr        iErr;
  63.     
  64.     // EXPLANATION:
  65.     //
  66.     // This is a pretty straightforward locking/unlocking mechanism that you can use
  67.     // in your program to see whether a program has been registered (i.e. payed for)
  68.     // or not.
  69.     
  70.     // A brief description follows, but for more details, you should see
  71.     // your AutoPay Developer's Manual.
  72.     
  73.     // What happens is this. The program opens a "key file" which is stored
  74.     // in the preferences folder. The Key File has three components:
  75.     
  76.     //         The registration name :    the name of the user who paid for program
  77.     
  78.     //      The verification code :    a special code that is specific to
  79.     //                                  to the registration name. This proves the
  80.     //                                registration name hasn't been tampered with.
  81.                                     
  82.     //        The serial number        
  83.     
  84.     
  85.     
  86.     iErr=readKeyFromDisk(&theKey);
  87.     
  88.     if (iErr)
  89.     {
  90.         // add your own error handling here if desired
  91.     }
  92.     
  93.     if (strlen((char*)theKey.name)==0)
  94.     {
  95.         // Either the key file doesn't exist or the name has been tampered
  96.         // with. So treat this as an unregistered copy.
  97.         
  98.         return (false);
  99.     }
  100.     
  101.     // A name *does* exist. Now the program looks at the verification code. 
  102.     // There is some, *unobvious* cryptographic relationship between the name and
  103.     // the verification code, but only you as the developer knows it. This stops
  104.     // hackers from examining an officially registered copy of your app and figuring
  105.     // out how to write a "correct" result string based on a seed string of his choice.
  106.     
  107.     if (strlen((char*)theKey.verificationCode)==0)
  108.     {
  109.         return (false);
  110.     }
  111.         
  112.     strcpy(cryptoKey,kTheCryptoKey);
  113.     
  114.     // Feed the name into the encryption routine to find out what the
  115.     // verification code *should* be. Then see if it's a match.
  116.     
  117.     strcpy((char*)&whatItShouldBe, myEncrypt((char*)&theKey.name,cryptoKey) );
  118.     if ( strcmp    (
  119.             whatItShouldBe,                    // If the resultString is
  120.             &theKey.verificationCode        // identical to what you'd expect to get
  121.                 ) == 0 )                     // given your program's cryptoKey,
  122.                                         
  123.         {    
  124.             return(true);                    // then this is a valid, registered copy
  125.         }
  126.     else
  127.         {
  128.             return(false);                    // ...otherwise it isn't
  129.         }
  130. }
  131.  
  132. OSErr saveSerialNumber (char *theSerialNumber)
  133. {
  134.     keyType theKey;
  135.     
  136.  
  137.     readKeyFromDisk(&theKey);
  138.     strcpy((char*)&theKey.serialNumber,theSerialNumber);
  139.     writeKeyToDisk(&theKey);
  140. }
  141.  
  142.  
  143.     
  144. OSErr saveProgramAsRegistered (char *theName)
  145. {
  146.     OSErr     iErr;
  147.     keyType theKey;
  148.     char     *theResult;
  149.     char    cryptoKey[50];
  150.     
  151.     // First the program stores the name string in the appropriate place.
  152.     
  153.     iErr=readKeyFromDisk(&theKey);
  154.     if (iErr)
  155.         return (iErr);
  156.         
  157.     // Next it stores the Verification Code, which is encrypted based on your
  158.     // cryptoKey. See the Digital Money manual for more information.
  159.     
  160.     strcpy(cryptoKey,kTheCryptoKey);
  161.     strcpy ((char*)&theKey.verificationCode, myEncrypt(theName,cryptoKey) );
  162.     
  163.     strcpy((char*)&theKey.name,theName);
  164.     iErr=writeKeyToDisk(&theKey);
  165.     if (iErr)
  166.         return (iErr);
  167.         
  168. }
  169.  
  170.  
  171. char *myEncrypt(char *inputString, char *cryptoKey)
  172. {
  173.     long     numCharsInInput;
  174.     int        cryptoCharToUse,i;
  175.     char    charToAdd;
  176.     char    *outputString;
  177.     
  178.     // Given an input string and a cryptoKey (know only to you)
  179.     // this routiner spits out an encrypted version of the input
  180.     // string. Later, you'll be able to compare say, a user's name
  181.     // and it's encrypted version to make sure the user's name hasn't been
  182.     // tampered with.
  183.     
  184.     outputString=NewPtr(strlen(inputString)+1);
  185.     
  186.     numCharsInInput=strlen(inputString);
  187.     cryptoCharToUse=0;
  188.     *outputString='\0';
  189.     
  190.     for (i=0; i<=numCharsInInput-1; i++)
  191.     {
  192.         
  193.         charToAdd=(inputString[i]^cryptoKey[cryptoCharToUse])+28; // ^ is exclusive OR
  194.         
  195.         charToAdd=charToAdd%33; // the remainder of the number after divided by 33
  196.         charToAdd=32+charToAdd;
  197.         outputString[i]=charToAdd;
  198.         
  199.         cryptoCharToUse++;
  200.         if (cryptoCharToUse>strlen(cryptoKey)-1)
  201.             cryptoCharToUse=0;
  202.     }
  203.  
  204.     outputString[i]='\0'; // make sure the output string is terminated with a null
  205.     
  206.     return (outputString);
  207. }
  208.  
  209.  
  210.  
  211. OSErr readKeyFromDisk (keyType *key)
  212. {
  213.  
  214.     OSErr    myErr;
  215.     short    myVRef, i;
  216.     long    myDirID;
  217.     FSSpec    mySpec;
  218.     char    myName[25];
  219.     int        myRef;
  220.     Handle    myHandle;
  221.     int        myRefNum, version;
  222.     long    len;
  223.     long    myLen[6];
  224.     
  225.     // find the "key" file in the system
  226.     
  227.     strcpy(myName,kYourProgramName);
  228.     strcat(myName," Key");
  229.     
  230.     // The "key file" will be stored in the Preferences folder 
  231.     // within the System folder
  232.     
  233.     myErr=FindFolder(kOnSystemDisk,kPreferencesFolderType,kDontCreateFolder, &myVRef, &myDirID);
  234.     
  235.     if (myErr==noErr)
  236.         myErr=FSMakeFSSpec(myVRef, myDirID, CtoPstr(myName), &mySpec);
  237.  
  238.     // If no "key file" exists, return a null key.
  239.     // This will happen the first time the user wants to register.
  240.     
  241.     if (myErr==fnfErr)
  242.     {
  243.         key->name[0]='\0';
  244.         key->verificationCode[0]='\0';
  245.         key->serialNumber[0]='\0';
  246.         return(noErr);
  247.     }
  248.     
  249.     if (myErr==noErr)
  250.         myRefNum=FSpOpenDF(&mySpec, fsRdWrPerm, &myRef);
  251.     else if (myErr!=eofErr) return(myErr);                    // error check
  252.  
  253.     
  254.     myErr=SetFPos(myRef, fsFromStart,0);
  255.     
  256.     if ((myErr!=noErr) && (myErr!=eofErr))
  257.          return(myErr);                                        // error check
  258.     
  259.     // Check the version number of the key file.
  260.     // This really has no use now, but may or may not come in handy in
  261.     // in the future, if you ever decide to change the file format of
  262.     // the key file.
  263.     
  264.     len=2;
  265.     if (myErr==noErr)
  266.     {
  267.         myErr=FSRead(myRef, &len, &version);
  268.     }
  269.     if (version!=1)
  270.         myErr=eofErr; // if this is not version 1, just pretend file doesn't exist
  271.     
  272.     len=sizeof(*key);    
  273.     
  274.     if (myErr==noErr)
  275.     {
  276.         myErr=FSRead(myRef, &len, key);
  277.     }
  278.     
  279.     
  280.     if ((myErr) && (myErr!=eofErr)) return(myErr);         // error check
  281.  
  282.     FSClose(myRef);
  283.     
  284.     return(noErr);
  285.       
  286. }
  287.  
  288. OSErr writeKeyToDisk (keyType *key)
  289. {
  290.     OSErr    myErr;
  291.     short    myVRef, i;
  292.     long    myDirID;
  293.     FSSpec    mySpec;
  294.     char    myName[25];
  295.     int        myRef,scrapInt;
  296.     int        myRefNum, myVol;
  297.     long    len,fLength=0;
  298.  
  299.     strcpy(myName,kYourProgramName);
  300.     strcat(myName," Key");
  301.  
  302.     myErr=FindFolder(kOnSystemDisk,kPreferencesFolderType,kDontCreateFolder, &myVRef, &myDirID);
  303.     
  304.     if (myErr==noErr)
  305.         myErr=FSMakeFSSpec(myVRef, myDirID, CtoPstr(myName), &mySpec);
  306.  
  307.     if (myErr==fnfErr)
  308.     {
  309.         myErr= FSpCreate(&mySpec, kOwnerResource, 'pref', smSystemScript);
  310.         fLength=0;
  311.     }
  312.     
  313.     if (myErr==noErr)
  314.         myRefNum=FSpOpenDF(&mySpec, fsRdWrPerm, &myRef);
  315.     
  316.     
  317.     if (myErr==noErr)
  318.     {
  319.         myErr=SetFPos(myRef, fsFromStart, 0);        // write at beginning
  320.     }
  321.     
  322.     // Write the version number of the key file
  323.     // for future upgrade capability. This is version 1.
  324.     
  325.     len=2;
  326.     scrapInt=1;
  327.     if (myErr==noErr)
  328.     {
  329.         myErr= FSWrite (myRef, &len, &scrapInt);
  330.         fLength+=len;
  331.     }
  332.     
  333.     // write the actual key data structure
  334.     
  335.     len=sizeof(*key);
  336.     if (myErr==noErr)
  337.     {
  338.         myErr= FSWrite (myRef, &len, key);
  339.         fLength+=len;
  340.     }
  341.  
  342.     myErr=SetEOF(myRef, fLength);
  343.     if (myErr) return(myErr);
  344.     
  345.     if (myErr==noErr)
  346.     {
  347.         myErr=GetVRefNum(myRef, &myVol);                // find volume file is on
  348.     }
  349.     
  350.     if (myErr==noErr)
  351.     {
  352.         FSClose(myRef);
  353.         myErr=FlushVol(nil, myVol);                        // ... and flush it
  354.         if (myErr) return(myErr);
  355.     }
  356.       
  357.     return(myErr);
  358. }
  359.  
  360.  
  361. /********************************/
  362. //        drawSplashScreen        //
  363. /*******************************/
  364.  
  365. void drawSplashScreen (int whichColorPictToUse, int whichBWPictToUse)
  366. {
  367.  
  368.     GrafPtr        oldPort;
  369.     Boolean        userReacts, hasColor=false;
  370.     SysEnvRec    sysEnv;
  371.     Rect        r,winRect,textBox;
  372.     PicHandle    thePict;
  373.     int         screenWidth,screenHeight,pictWidth,pictHeight,winLeft,winTop;
  374.     WindowPtr    window;
  375.     short        oldFont,oldSize,curPnMode;
  376.     EventRecord    event;
  377.     keyType        theKey;
  378.     char        output[100];
  379.     
  380.     #define        SysEnvironsTrap            0xA090
  381.     #define        UnknownTrap                0xA89F
  382.  
  383.     GetPort(&oldPort);
  384.     
  385.     // First check to see if the computer has color display or not.
  386.     // This will help us decide whether to draw the color picture
  387.     // or the B&W picture.
  388.     
  389.     if ((long)NGetTrapAddress(SysEnvironsTrap, OSTrap) != (long)NGetTrapAddress(UnknownTrap, ToolTrap))
  390.     {
  391.         SysEnvirons(1, &sysEnv);
  392.         
  393.         // Check graphic's device depth    
  394.         if ((*((*((GDHandle)GetGDevice()))->gdPMap))->pixelSize > 1)    
  395.         {
  396.             hasColor = sysEnv.hasColorQD;                        // Does it have color?        
  397.         }
  398.     }
  399.         
  400.     if (hasColor)
  401.         thePict=GetPicture(whichColorPictToUse);        
  402.     else
  403.         thePict=GetPicture(whichBWPictToUse);
  404.  
  405.     r = (*thePict)->picFrame;
  406.     
  407.     pictWidth = r.right - r.left;        // calculate width of picture
  408.     pictHeight = r.bottom - r.top;        // calculate height of picture
  409.     
  410.     
  411.     screenWidth =(screenBits.bounds).right;        // calculate width of screen
  412.     screenHeight =(screenBits.bounds).bottom;    // calculate height of screen
  413.     
  414.     // Center the splash window on the screen:
  415.     
  416.     winLeft=(screenWidth/2)-(pictWidth/2);
  417.     winTop=(screenHeight/2)-(pictHeight/2);
  418.     SetRect(&winRect,winLeft,winTop,winLeft+pictWidth,winTop+pictHeight);
  419.     
  420.     // make a new, temporary window, just big enough to hold your
  421.     // splash screen picture
  422.     window = NewWindow(nil,&winRect,"\p",true,plainDBox,(WindowPtr)-1,false,0);
  423.     
  424.     SetPort(window);
  425.     DrawPicture( thePict,  &(window->portRect) );
  426.     
  427.     // Now draw your text ON TOP OF the picture.
  428.     
  429.     
  430.     TextFont(applFont);
  431.     TextFace(bold);
  432.     
  433.     readKeyFromDisk(&theKey);
  434.     
  435.     if (!isProgramRegistered())
  436.     {
  437.         
  438.         strcpy(output,"This program is not registered.\rYou can register immediately with Digital Money™.\rSee the Apple menu.");
  439.         
  440.         // You may want to change the coordinates where the text box is overlaid
  441.         // on picture window:
  442.         
  443.         TextSize(11);
  444.         SetRect(&textBox,window->portRect.left+2,window->portRect.bottom-80,window->portRect.right-2,window->portRect.bottom-30);
  445.         TextBox(output,strlen(output),&textBox,teJustLeft);
  446.     
  447.     }
  448.     else
  449.     {
  450.  
  451.         sprintf(output,"This copy is registered to %s.",(char*)&theKey.name);
  452.     
  453.         TextMode(srcBic); // reverse out the text you're about to draw
  454.         
  455.         // You may want to change the coordinates where the text is
  456.         // "reversed out" of window:
  457.         
  458.         MoveTo(2,window->portRect.bottom-45);
  459.         TextSize(10);
  460.         DrawText(output,0,strlen(output));
  461.         if (strlen((char*)&theKey.serialNumber))
  462.         {
  463.             sprintf(output,"Serial Number %s",(char*)&theKey.serialNumber);
  464.             MoveTo(2,window->portRect.bottom-30);
  465.         }
  466.     }
  467.     
  468.     SelectWindow(window);
  469.     
  470.     
  471.     // wait for the user to click the mouse or hit a key...
  472.     
  473.     userReacts=false;
  474.     do
  475.     {
  476.         if (WaitNextEvent(everyEvent, &event, 20, nil))
  477.         {    
  478.             switch (event.what)
  479.             {    
  480.                 case mouseDown:
  481.                 case keyDown:
  482.                 case autoKey:    
  483.                     userReacts=true;
  484.                     break;
  485.                 default:
  486.                     userReacts=false;
  487.                     break;
  488.             }
  489.         }
  490.     }
  491.     while (!userReacts);
  492.     
  493.     HideWindow(window);
  494.     DisposeWindow(window);
  495.     ReleaseResource(thePict);
  496. }    
  497.