Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

SW copy protection


  • Please log in to reply
305 replies to this topic
Murp-e
  • Members
  • 531 posts
  • Last active: Sep 27 2011 11:44 AM
  • Joined: 12 Jan 2007
Understood. I think it's important to make this type of solution as accessible as possible. If you come up with a good GUI solution I think you should include that in your post with the rest of the internal library. A seasoned coder can remove blocks of code just as easily as he can add it.

Looking forward to reaping the fruits of your work!

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
I agree.
I will work on something.

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
Ok,

Here is a first version of the GUI for Software Protection.
I have decided to keep things separated, so the original include library is still needed.
Save the original library as SWProtect-Internal.ahk, then save this file with any name you want (I use SWProtect-GUI.ahk) and run it.

Again, not thoroughly tested, but seem to be working nicely. Need to sleep now, so if anyone is having problems using it, post your problem here and if anyone has suggestions, also.

Thanks to Laszlo for making it possible and to tic for the mental support :)

Although it is written in the code's header, the usage is simple:
Call SWP_CheckRegistration( "AppName", "DeveloperEmail" )
The rest is done for you.



;-------------------------------------------------------------------------------
;
; Software Protection Library - GUI Implementation 0.10
;
; This library contains a simple set of GUI functions to allow easy 
; implementation of a software protection, using a registration code and a 
; computer fingerprint.
; 
; Requires: SWProtect-Internal.ahk
; 
; Original Code:        Laszlo Hars <www.Hars.US>
; Library/GUI Version:  Icarus
;
; AutoHotkey Forum Thread:
; http://www.autohotkey.com/forum/viewtopic.php?t=5763&postdays=0&postorder=asc&start=0
;
; USAGE:
;   1. Include this file in your script
;   2. In your loading sequence, call 
;      SWP_CheckRegistration( "AppName", "DeveloperEmail" )
;
;   *. You should also change the 8 secret keys in the main GUI function 
;      ( SWP_CheckRegistration ) - see the second line SWP_Initialize()
;
; TODO:
;   - See if there is a way to use less global variables
;   - See if there is a way to avoid using a fixed GUI ID (currently, 20) and
;     instead pass it as an optional parameter. The reason why this is not 
;     implemented like this is because we need to have 20GuiEscape: labels
;   - Make a separate KeyGen so that the AHK developer can get a computer ID
;     from the user and instantly generate a key.
;
;-------------------------------------------------------------------------------
#Include SWProtect-Internal.ahk

;-------------------------------------------------------------------------------
; TESTER - Comment or delete this tester when including the file
;

#SingleInstance Force
SetWorkingDir %A_ScriptDir%

; Use this snippet (NOT in your program) to generate a key for a user
; *** TODO: A KeyGen function

;SWP_Initialize( 0x81645732, 0x19573549 )
;Fingerprint := "d964e5ee60da7687"      ; the one received from the user
;Key := SWP_GenerateKey( "Icarus", "[email protected]", Fingerprint )
;Clipboard := Key
;MsgBox 64,Copied to Clipboard, License key was copied to the clipboard.



; Add this in your loading sequence
SWP_CheckRegistration( "My Application", "[email protected]" )     
Msgbox Registration OK - The program continues here`n`n`n`n`n`n`n`n



ExitApp

;
; END OF TESTER
;-------------------------------------------------------------------------------




;-------------------------------------------------------------------------------
; Main GUI Function
;-------------------------------------------------------------------------------
SWP_CheckRegistration( appName, developerEmail, iniFilename="Reg.ini" ) {
    Global SWP_AppName, SWP_IniFilename, SWP_DeveloperEmail, SWP_LicenseOK
    
    ; Init the globals
    SWP_Initialize( 0x81645732, 0x19573549 )    ; May be called with up to 8 secret keys
    
    SWP_AppName        := appName
    SWP_IniFilename    := iniFilename
    SWP_DeveloperEmail := developerEmail
    SWP_LicenseOK      := false
    
    If( Not FileExist( iniFilename ) ) {
        SWP_ShowRegisterDialog( appName )
        Loop 
            If( SWP_LicenseOK )     ; Loop will be broken by a valid license
                Break

    }
    Else {                          ; File exists, read registration data and validate
        SWP_ReadRegFile( iniFilename )
    }

    Sleep 1000          ; This is here since the Reload in SWP_ReadRegFile
                        ; seem to still give the application to continue running
                        ; before it actually reloads.
                        ; Deleteing this launches the "The program continues"
                        ; msgbox
                        ; *** TODO: Can be fixed?
}

;-------------------------------------------------------------------------------
; Other GUI Functions (you should generally avoid calling these functions)
;-------------------------------------------------------------------------------

SWP_ShowRegisterDialog( appName ) {
    Global SWP_GuiID        ; *** TODO: See if there is a way to have a dynamically 
                            ; created 20GuiEscape labels, so we can pass GuiID as
                            ; an optional parameter to the function

    Global SWP_AppName, SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key
    
    SWP_GuiID := 20
    GuiID := SWP_GuiID
    
    Gui %GuiID%:Margin, 10, 10

    ; Top introduction text
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, x10 y10 w352 h22 center, %appName% is not registered.
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Text, xp y+0 wp hp center, Please enter your registration details:

    ; Text labels
    Gui %GuiID%:Add, Text, xp y+15 w135 h22 right section, % "Name/Company: "
    Gui %GuiID%:Add, Text, xp y+2  wp   hp  right        , % "Email Address: "
    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Registration Code: "
    
    ; Edit fields
    Gui %GuiID%:Add, Edit, xs+137 ys  wp+64 hp vSwpGuiVal_Name
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Email
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Key
    Gui %GuiID%:Add, Groupbox, xs ys-20 w352 h102
    
    ; Buttons
    Gui %GuiID%:Add, Button, xs  y+10 w168 h24 gSWP_RegisterDialogGetKey    , &Get a Registration Key
    Gui %GuiID%:Add, Button, x+2 yp   w90  h24 gSWP_RegisterDialogCancel    , E&xit
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Button, x+2 yp   w90  h24 default gSWP_RegisterDialogOk, Register
    
    Gui %GuiID%:Show, w372, %appName% Registration
}

20GuiEscape:
20GuiClose:
SWP_RegisterDialogCancel:
    ExitApp 
Return

SWP_RegisterDialogOk:
    Gui %SWP_GuiID%:Submit, NoHide
    If( SwpGuiVal_Name = "" or SwpGuiVal_Email = "" or SwpGuiVal_Key = "" ) 
        MsgBox 16,Invalid Registration, Invalid Registration.`nPlease check your input.`t
    Else If( Not SWP_IsUserAuthenticated( SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key ) ) {
        MsgBox 16,Invalid Registration, Invalid Registration.`nPlease check your input.`t
    }
    Else {
        ; Registration ok, write to ini file and exit happily
        IniWrite %SwpGuiVal_Name%, %SWP_IniFilename%, Registration, Name
        IniWrite %SwpGuiVal_Email%, %SWP_IniFilename%, Registration, Email
        IniWrite %SwpGuiVal_Key%, %SWP_IniFilename%, Registration, Key
        MsgBox 64,Registration Accepted, Your registration was accepted and saved.`t`nThank you for using %SWP_AppName%.
        SWP_LicenseOK := true
        Gui %SWP_GuiID%:Destroy
    }   
Return

SWP_RegisterDialogGetKey:
    SWP_ShowGetKeyDialog()
Return

SWP_ShowGetKeyDialog() {
    Global SWP_GuiID, SWP_AppName, SwpGuiVal_Fingerprint, SwpGuiButton_Ok
        ,SWP_DeveloperEmail

    ; Destroy
    Gui %SWP_GuiID%:Destroy
    
    ; Then rebuild
    SwpGuiVal_Fingerprint := SWP_GetPcFingerprint()
    
    GuiID := SWP_GuiID
    Gui %GuiID%:Margin, 10, 10

    ; Middle box
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Text, x20   y20  w332  h44 center section, Please send us this Computer ID together with your name and email address.
    Gui %GuiID%:Font, s12 bold
    Gui %GuiID%:Add, Edit, xp+10 y+2  wp-20 h24 r1 ReadOnly center vSwpGuiVal_Fingerprint, %SwpGuiVal_Fingerprint%
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, xp    y+2  wp    h24 center, Send to %SWP_DeveloperEmail%
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Groupbox, xs-10 ys-15 w352 h128
    
    ; Buttons
    Gui %GuiID%:Add, Button, xs-10  y+10 w90 h24 gSWP_RegisterDialogCancel  , E&xit
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Button, x+2 yp w259  h24 default vSwpGuiButton_Ok gSWP_GetDialogOk, Copy to Clipboard && Exit  
    
    GuiControl %GuiID%:Focus, SwpGuiButton_Ok       ; To avoide the selection of the fingerprint
    
    Gui %GuiID%:Show, w372, %SWP_AppName% Registration
}

SWP_GetDialogOk:
    Gui %SWP_GuiID%:Submit
    Clipboard := "Computer ID: " SwpGuiVal_Fingerprint
    MsgBox 64,Copied to Clipboard, Your Computer ID was copied to the clipboard.`nPlease send it along with your name and email address to`t`n%SWP_DeveloperEmail%.
    ExitApp
Return


SWP_ReadRegFile( iniFilename ) {
    Global SWP_LicenseOK
    IniRead Name, %iniFilename%, Registration, Name
    IniRead Email, %iniFilename%, Registration, Email
    IniRead Key, %iniFilename%, Registration, Key
    If( Not SWP_IsUserAuthenticated( Name, Email, Key ) ) {
        MsgBox 16,Invalid Registration, Your registration details seem to be invalid.`t`n
        FileDelete %iniFilename%
        Reload
    }
    SWP_LicenseOK := true
}



tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
good work, but in order to make this useful it would need to:

Not include the username and email in with the TEA, as then the person could just apply for another key with a different username.

Also write a similar TEA decryptor, so that the collected details as the unique PC ID (fingerprint) could be sent encrypted to a php script online in the form of:

<!-- w -->www.mywebsite.com/registration/<!-- w -->%fingerprint%

then the php script could convert this ID into the key and imediately send the key back and activate the product. Inside this key, the program would have an end date to stop working (15 day, 30 etc). The php script would also add the ID to a database, and then in future if that ID requests a new key then they will be denied (so will query the database whether it already exists) although.....

PCdata = %COMPUTERNAME%%HOMEPATH%%USERNAME%%PROCESSOR_ARCHITECTURE%%PROCESSOR_IDENTIFIER%
    PCdata = %PCdata%%PROCESSOR_LEVEL%%PROCESSOR_REVISION%%A_OSType%%A_OSVersion%%Language%

should not be used, but something much simpler, with only 2 variables, as if the user changes any of those on the system, the the user could just change a single variable and then get a new key.

so the only thing i see that i would need is to perhaps make it so the php script can decode the TEA of the fingerprint, and then recode it to turn it into the key ( i would need help on this.....if i had it in ahk then that would get me started)

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Very nice. :!:
Posted Image

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

write a similar TEA decryptor, so that the collected details as the unique PC ID (fingerprint) could be sent encrypted to a php script

(1) You cannot decrypt a hash or a Message Authentication Code. TEA is used in CBC-MAC mode, where the output is shorter than the input, so there is no unique inverse.
(2) The copy protection scheme was designed, so that the PC fingerprint does not reveal any private information, like username or home path. It is not only a privacy issue, but also liability: should anybody break in to the target machine, whoever received the PC fingerprint earlier will be the first suspects.
(3) The algorithm should be public, so the user trusts the program not spying out his secrets.

the program would have an end date to stop working (15 day, 30 etc).

We discussed it earlier in the Forum. It would be useful, but the user can always reset the system clock to fool your time verification. Additional steps are necessary, like using a trusted clock source, detecting changes in the system clock, recording heart bit signal of the script, etc.

[…]should not be used, but something much simpler, with only 2 variables

Two variables don't provide enough copy protection, nor privacy. An illegitimate user or a curious colleague can just guess their values (dictionary attack).

You are using a different threat model, with different goals. In general, it is not a good idea to "optimize" a security system: you are better off starting from scratch with clearly stated goals and attack scenarios, you want to protect against.

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
thanks for your help....

(1) You cannot decrypt a hash or a Message Authentication Code. TEA is used in CBC-MAC mode, where the output is shorter than the input, so there is no unique inverse.


hah! yes i knew this, dont know why i thought otherwise (temporary insanity)

You are using a different threat model, with different goals. In general, it is not a good idea to "optimize" a security system: you are better off starting from scratch with clearly stated goals and attack scenarios, you want to protect against.


you are right, but i feel that this method could still be used....instead of sending the TEA of your ID across, just use a simple hash, that can be reconstructed by the php script, and then create the TEA, send it back as your key, and if it doesnt match, then the program doesnt work.

I do know that the system clock could just be put back, but the alternatives are too much trouble. i had attempted to store null strings within the exe to show its "age" but this always led me to corrupt exes (worked for other files). I was thinking of making some form of encryption of my own concoction, but will see, perhaps if i write it laszlo then you could comment on it and say how secure you feel it is....

thanks again for your insight

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
Ok,

I have corrected a minor bug in the internal library and added a keygen to the GUI library (more details in the code - revision history at the end)

I am reposting the two libraries together here, for convenience:

Save as SWProtect-Internal.ahk
;-------------------------------------------------------------------------------
;
; Software Protection Library 0.11
;
; This library contains a set of functions to generate a registration key
; based on a user fingerprint.
; To be used separately or together with the GUI library - SWProtect-GUI.ahk
; 
; Original Code:    Laszlo Hars <www.Hars.US>
; Library Version:  Icarus
;
; Original proof of concept by Laszlo, taken from AutoHotkey Forum at
; http://www.autohotkey.com/forum/viewtopic.php?t=5763&postdays=0&postorder=asc&start=0
;
;
; Functions in this version
; 
;   SWP_Initialize( [ secret1, secret 2, ... , secret 8 ] )
;   Fingerprint := SWP_GetPcFingerprint()
;   UserOK      := SWP_IsUserAuthenticated( username, email, key )
;   Key         := SWP_GenerateKey( username, email, fingerprint )
;
;-------------------------------------------------------------------------------


;-------------------------------------------------------------------------------
; TESTER - Comment or delete this tester when including the file
;

/*

; Initialize the required globals
;----------------------------------------
SWP_Initialize()        ; May be called with up to 8 secret keys


; Get a hardware fingerprint
;----------------------------------------
Fingerprint := SWP_GetPcFingerprint()
MsgBox 32,,Your computer ID is`n%Fingerprint%


; Generate a license key for this user
;----------------------------------------
Username    := "Icarus"
Email       := "[email protected]"
Key         := SWP_GenerateKey( Username, Email, Fingerprint )
MsgBox 32,,Your registration details are:`nUser:`t%Username%`nEmail:`t%Email%`nKey:`t%Key%


; Check if a user's registration code is ok
;----------------------------------------
;Key := "some invalid key by the user"                      ; Uncomment to test
UserOK      := SWP_IsUserAuthenticated( Username, Email, Key )
If( UserOK )
    MsgBox 32,OK,User is authenticated
Else
    MsgBox 16,INVALID,User is NOT authenticated`n%Username%`n%Email%`n%Key%
    
    
Return


*/

;
; END OF TESTER
;-------------------------------------------------------------------------------




;-------------------------------------------------------------------------------
; API Functions
;-------------------------------------------------------------------------------
;  
; SWP_Initialize( [ secret1, secret 2, ... , secret 8 ] )
; Fingerprint := SWP_GetPcFingerprint()
; UserOK      := SWP_IsUserAuthenticated( username, email, key )
; Key         := SWP_GenerateKey( username, email, fingerprint )
;
;-------------------------------------------------------------------------------
SWP_Initialize( mk0=0x11111111, mk1=0x22222222, mk2=0x33333333, mk3=0x44444444
    ,ml0=0x12345678, ml1=0x12345678, mm0=0x87654321, mm1=0x87654321 ) {
    
    Global

    k0 := mk0                  ; 128-bit secret key (example)
    k1 := mk1
    k2 := mk2
    k3 := mk3
    
    l0 := ml0                  ; 64- bit 2nd secret key (example)
    l1 := ml1
    
    m0 := mm0                  ; 64- bit 3rd secret key (example)
    m1 := mm1

}


SWP_GetPcFingerprint() {
    PCdata = %COMPUTERNAME%%HOMEPATH%%USERNAME%%PROCESSOR_ARCHITECTURE%%PROCESSOR_IDENTIFIER%
    PCdata = %PCdata%%PROCESSOR_LEVEL%%PROCESSOR_REVISION%%A_OSType%%A_OSVersion%%Language%

    Fingerprint := XCBC(Hex(PCdata,StrLen(PCdata)), 0,0, 0,0,0,0, 1,1, 2,2)
    Return Fingerprint
}

SWP_GenerateKey( username, email, fingerprint ) {
    Global k0,k1,k2,k3,l0,l1,m0,m1
    
    If( not k0 ) {
        MsgBox 16,Error,Error in SWP_GenerateKey - values are not initialized.`nPlease call SWP_Initialize() first.
        Return false
    }
        
    Together = %username%%email%%fingerprint%
    Auth := XCBC(Hex(Together,StrLen(Together)), 0,0, k0,k1,k2,k3, l0,l1, m0,m1)
    Return Auth
}


SWP_IsUserAuthenticated( username, email, key ) {
    Global k0,k1,k2,k3,l0,l1,m0,m1
    
    If( not k0 ) {
        MsgBox 16,Error,Error in SWP_IsUserAuthenticated - values are not initialized.`nPlease call SWP_Initialize() first.
        Return false
    }

    Fingerprint := SWP_GetPcFingerprint()
    Together = %username%%email%%Fingerprint%

    AuthData := XCBC(Hex(Together,StrLen(Together)), 0,0, k0,k1,k2,k3, l0,l1, m0,m1)
    
    Return Key=AuthData
}




;-------------------------------------------------------------------------------
; Internal Functions by Laszlo
;-------------------------------------------------------------------------------

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TEA cipher ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Block encryption with the TEA cipher
; [y,z] = 64-bit I/0 block
; [k0,k1,k2,k3] = 128-bit key
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TEA(ByRef y,ByRef z, k0,k1,k2,k3)
{                                   ; need  SetFormat Integer, D
   s = 0
   d = 0x9E3779B9
   Loop 32                          ; could be reduced to 8 for speed
   {
      k := "k" . s & 3              ; indexing the key
      y := 0xFFFFFFFF & (y + ((z << 4 ^ z >> 5) + z  ^  s + %k%))
      s := 0xFFFFFFFF & (s + d)  ; simulate 32 bit operations
      k := "k" . s >> 11 & 3
      z := 0xFFFFFFFF & (z + ((y << 4 ^ y >> 5) + y  ^  s + %k%))
   }
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; XCBC-MAC ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; x  = long hex string input
; [u,v] = 64-bit initial value (0,0)
; [k0,k1,k2,k3] = 128-bit key
; [l0,l1] = 64-bit key for not padded last block
; [m0,m1] = 64-bit key for padded last block
; Return 16 hex digits (64 bits) digest
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

XCBC(x, u,v, k0,k1,k2,k3, l0,l1, m0,m1)
{
   Loop % Ceil(StrLen(x)/16)-1   ; full length intermediate message blocks
      XCBCstep(u, v, x, k0,k1,k2,k3)

   If (StrLen(x) = 16)              ; full length last message block
   {
      u := u ^ l0                   ; l-key modifies last state
      v := v ^ l1
      XCBCstep(u, v, x, k0,k1,k2,k3)
   }
   Else {                           ; padded last message block
      u := u ^ m0                   ; m-key modifies last state
      v := v ^ m1
      x = %x%100000000000000
      XCBCstep(u, v, x, k0,k1,k2,k3)
   }
   Return Hex8(u) . Hex8(v)         ; 16 hex digits returned
}

XCBCstep(ByRef u, ByRef v, ByRef x, k0,k1,k2,k3)
{
   StringLeft  p, x, 8              ; Msg blocks
   StringMid   q, x, 9, 8
   StringTrimLeft x, x, 16
   p = 0x%p%
   q = 0x%q%
   u := u ^ p
   v := v ^ q
   TEA(u,v,k0,k1,k2,k3)
}

Hex8(i)                             ; 32-bit integer -> 8 hex digits
{
   format = %A_FormatInteger%       ; save original integer format
   SetFormat Integer, Hex
   i += 0x100000000                 ; convert to hex, set MS bit
   StringTrimLeft i, i, 3           ; remove leading 0x1
   SetFormat Integer, %format%      ; restore original format
   Return i
}

Hex(ByRef b, n=0)                   ; n bytes data -> stream of 2-digit hex
{                                   ; n = 0: all (SetCapacity can be larger than used!)
   format = %A_FormatInteger%       ; save original integer format
   SetFormat Integer, Hex           ; for converting bytes to hex

   m := VarSetCapacity(b)
   If (n < 1 or n > m)
       n := m
   Loop %n%
   {
      x := 256 + *(&b+A_Index-1)    ; get byte in hex, set 17th bit
      StringTrimLeft x, x, 3        ; remove 0x1
      h = %h%%x%
   }
   SetFormat Integer, %format%      ; restore original format
   Return h
}


;-------------------------------------------------------------------------------
; Revision History
;-------------------------------------------------------------------------------
/*

    0.11  2007 09 04
        - Fixed  : IsUserAuthenticated returned -1 in case of an uninitialized
                   globals, now returning false.
        
    0.10  2007 09 03
        - First version



*/


GUI Library - save as SWProtect-GUI.ahk
;-------------------------------------------------------------------------------
;
; Software Protection Library - GUI Implementation 0.11
;
; This library contains a simple set of GUI functions to allow easy 
; implementation of a software protection, using a registration code and a 
; computer fingerprint.
; 
; Requires: SWProtect-Internal.ahk
; 
; Original Code:        Laszlo Hars <www.Hars.US>
; Library/GUI Version:  Icarus
;
; AutoHotkey Forum Thread:
; http://www.autohotkey.com/forum/viewtopic.php?t=5763&postdays=0&postorder=asc&start=0
;
; USAGE 1:
;   1. Include this file in your script
;   2. In your loading sequence, call SWP_Initialize() then
;      SWP_CheckRegistration( "AppName", "DeveloperEmail" )
;      to check/ask for a valid registration.
;
; USAGE 2:
;   1. Include this file in a new script
;   2. Call SWP_Initialize() then SWP_ShowKeyGen() to activate a KeyGen dialog
;
; TODO:
;   - See if there is a way to use less global variables
;   - See if there is a way to avoid using a fixed GUI ID (currently, 20) and
;     instead pass it as an optional parameter. The reason why this is not 
;     implemented like this is because we need to have 20GuiEscape: labels
;
;-------------------------------------------------------------------------------
#Include SWProtect-Internal.ahk

;-------------------------------------------------------------------------------
; TESTER - Comment or delete this tester when including the file
;
/*

#SingleInstance Force
SetWorkingDir %A_ScriptDir%

; USAGE 1: Add this in a separate file, to have your own keygen
;-------------------------
;SWP_Initialize( 0x81645732, 0x19573549 )   ; Up to 8 secret keys, 
;SWP_ShowKeyGen()
;Return
;-------------------------


; USAGE 2: Add this in your loading sequence to check/ask for a valid registration
;-------------------------
SWP_Initialize( 0x81645732, 0x19573549 )    ; Up to 8 secret keys, 
SWP_CheckRegistration( "My Application", "[email protected]" )     
;-------------------------



Msgbox The program continues here`n`n`n`n`n`n`n`n
Return

*/
;
; END OF TESTER
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; Main GUI Function
;-------------------------------------------------------------------------------

SWP_CheckRegistration( appName, developerEmail, iniFilename="Reg.ini" ) {
;
; Checks for the existence of a valid registration file.
; If registration is valid, it will return the control to the caller, otherwise
; it will show a registration GUI (with an option to the user to ask for a 
; registration key) and will only resume normal operation if a valid 
; registration code is entered.
;
; When a valid key is entered, the registration details will be saved in an INI
; file (default: Reg.ini) so that next time this function is called, it will be
; able to find the registration code on its own.
;
;-------------------------------------------------------------------------------
    Global SWP_AppName, SWP_IniFilename, SWP_DeveloperEmail, SWP_LicenseOK
    
    SWP_AppName        := appName
    SWP_IniFilename    := iniFilename
    SWP_DeveloperEmail := developerEmail
    SWP_LicenseOK      := false
    
    If( Not FileExist( iniFilename ) ) {
        SWP_ShowRegisterDialog( appName )
        Loop 
            If( SWP_LicenseOK )     ; Loop will be broken by a valid license
                Break

    }
    Else {                          ; File exists, read registration data and validate
        SWP_ReadRegFile( iniFilename )
        Sleep 1000      ; This is here since the Reload in SWP_ReadRegFile
                        ; seem to still give the application to continue running
                        ; before it actually reloads.
                        ; Deleteing this launches the "The program continues"
                        ; msgbox
                        ; *** TODO: Can be fixed?

    }

}

SWP_ShowKeyGen() {
;
; This function shows a simple generator for registration numbers.
; Once the user has sent you his Computer ID, use this function to generate
; a valid registration key for this user+computer.
;
; The proper use of this function, is to create a separate ahk code, including
; this library, then calling this function.
;
; Note that you need to call SWP_Initialize with the same seed keys as in your
; SWP_CheckRegistration function BEFORE you call this function.
;
;-------------------------------------------------------------------------------
    Global SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key, SwpGuiVal_Fingerprint
        ,SWP_GuiID
    
    SWP_GuiID := 20
    GuiID := SWP_GuiID
    
    Gui %GuiID%:Margin, 10, 10

    ; Top introduction text
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, x10 y10 w352 h22 center, Please enter user details:
    Gui %GuiID%:Font, s10 norm

    ; Text labels
    Gui %GuiID%:Add, Text, xp y+15 w135 h22 right section, % "Name/Company: "
    Gui %GuiID%:Add, Text, xp y+2  wp   hp  right        , % "Email Address: "
    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Computer ID: "
    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Key: "
    
    ; Edit fields
    Gui %GuiID%:Add, Edit, xs+137 ys  wp+64 hp vSwpGuiVal_Name
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Email
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Fingerprint
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp readonly center vSwpGuiVal_Key
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Groupbox, xs ys-20 w352 h126
    
    ; Buttons
    Gui %GuiID%:Add, Button, xs  y+10 w109   h24 gSWP_RegisterDialogCancel  , E&xit
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Button, x+2    yp   wp+20 hp  default gSWP_KeygenGenerate  , &Generate
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Button, x+2    yp   wp-20 h24 gSWP_KeygenOk, &Copy && Exit  
    
    Gui %GuiID%:Show, w372, Registration Key Generator
}

;-------------------------------------------------------------------------------
; Other GUI Functions (you should generally avoid calling these functions)
;-------------------------------------------------------------------------------

SWP_ShowRegisterDialog( appName ) {
    Global SWP_GuiID        ; *** TODO: See if there is a way to have a dynamically 
                            ; created 20GuiEscape labels, so we can pass GuiID as
                            ; an optional parameter to the function

    Global SWP_AppName, SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key
    
    SWP_GuiID := 20
    GuiID := SWP_GuiID
    
    Gui %GuiID%:Margin, 10, 10

    ; Top introduction text
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, x10 y10 w352 h22 center, %appName% is not registered.
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Text, xp y+0 wp hp center, Please enter your registration details:

    ; Text labels
    Gui %GuiID%:Add, Text, xp y+15 w135 h22 right section, % "Name/Company: "
    Gui %GuiID%:Add, Text, xp y+2  wp   hp  right        , % "Email Address: "
    Gui %GuiID%:Add, Text, xp Y+2  wp   hp  right        , % "Registration Code: "
    
    ; Edit fields
    Gui %GuiID%:Add, Edit, xs+137 ys  wp+64 hp vSwpGuiVal_Name
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Email
    Gui %GuiID%:Add, Edit, xp     y+2 wp    hp vSwpGuiVal_Key
    Gui %GuiID%:Add, Groupbox, xs ys-20 w352 h102
    
    ; Buttons
    Gui %GuiID%:Add, Button, xs  y+10 w168 h24 gSWP_RegisterDialogGetKey    , &Get a Registration Key
    Gui %GuiID%:Add, Button, x+2 yp   w90  h24 gSWP_RegisterDialogCancel    , E&xit
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Button, x+2 yp   w90  h24 default gSWP_RegisterDialogOk, Register
    
    Gui %GuiID%:Show, w372, %appName% Registration
}

20GuiEscape:
20GuiClose:
SWP_RegisterDialogCancel:
    ExitApp 
Return

SWP_RegisterDialogOk:
    Gui %SWP_GuiID%:Submit, NoHide
    If( SwpGuiVal_Name = "" or SwpGuiVal_Email = "" or SwpGuiVal_Key = "" ) 
        MsgBox 16,Invalid Registration, Invalid Registration.`nPlease check your input.`t
    Else If( Not SWP_IsUserAuthenticated( SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Key ) ) {
        MsgBox 16,Invalid Registration, Invalid Registration.`nPlease check your input.`t
    }
    Else {
        ; Registration ok, write to ini file and exit happily
        IniWrite %SwpGuiVal_Name%, %SWP_IniFilename%, Registration, Name
        IniWrite %SwpGuiVal_Email%, %SWP_IniFilename%, Registration, Email
        IniWrite %SwpGuiVal_Key%, %SWP_IniFilename%, Registration, Key
        MsgBox 64,Registration Accepted, Your registration was accepted and saved.`t`nThank you for using %SWP_AppName%.
        SWP_LicenseOK := true
        Gui %SWP_GuiID%:Destroy
    }   
Return

SWP_RegisterDialogGetKey:
    SWP_ShowGetKeyDialog()
Return

SWP_ShowGetKeyDialog() {
    Global SWP_GuiID, SWP_AppName, SwpGuiVal_Fingerprint, SwpGuiButton_Ok
        ,SWP_DeveloperEmail

    ; Destroy
    Gui %SWP_GuiID%:Destroy
    
    ; Then rebuild
    SwpGuiVal_Fingerprint := SWP_GetPcFingerprint()
    
    GuiID := SWP_GuiID
    Gui %GuiID%:Margin, 10, 10

    ; Middle box
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Text, x20   y20  w332  h44 center section, Please send us this Computer ID together with your name and email address.
    Gui %GuiID%:Font, s12 bold
    Gui %GuiID%:Add, Edit, xp+10 y+2  wp-20 h24 r1 ReadOnly center vSwpGuiVal_Fingerprint, %SwpGuiVal_Fingerprint%
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Text, xp    y+2  wp    h24 center, Send to %SWP_DeveloperEmail%
    Gui %GuiID%:Font, s10 norm
    Gui %GuiID%:Add, Groupbox, xs-10 ys-15 w352 h128
    
    ; Buttons
    Gui %GuiID%:Add, Button, xs-10  y+10 w90 h24 gSWP_RegisterDialogCancel  , E&xit
    Gui %GuiID%:Font, s10 bold
    Gui %GuiID%:Add, Button, x+2 yp w259  h24 default vSwpGuiButton_Ok gSWP_GetDialogOk, Copy to Clipboard && Exit  
    
    GuiControl %GuiID%:Focus, SwpGuiButton_Ok       ; To avoide the selection of the fingerprint
    
    Gui %GuiID%:Show, w372, %SWP_AppName% Registration
}

SWP_GetDialogOk:
    Gui %SWP_GuiID%:Submit
    Clipboard := "Computer ID: " SwpGuiVal_Fingerprint
    MsgBox 64,Copied to Clipboard, Your Computer ID was copied to the clipboard.`nPlease send it along with your name and email address to`t`n%SWP_DeveloperEmail%.
    ExitApp
Return


SWP_ReadRegFile( iniFilename ) {
    Global SWP_LicenseOK
    IniRead Name, %iniFilename%, Registration, Name
    IniRead Email, %iniFilename%, Registration, Email
    IniRead Key, %iniFilename%, Registration, Key
    SWP_LicenseOK := false
    If( Not SWP_IsUserAuthenticated( Name, Email, Key ) ) {
        MsgBox 16,Invalid Registration, Your registration details seem to be invalid.`t`n
        FileDelete %iniFilename%
        Reload
    }
    SWP_LicenseOK := true
}

SWP_KeygenGenerate:
    Gui %SWP_GuiID%:Submit, NoHide
    SwpGuiVal_Key := SWP_GenerateKey( SwpGuiVal_Name, SwpGuiVal_Email, SwpGuiVal_Fingerprint )
    GuiControl ,%SWP_GuiID%:,SwpGuiVal_Key,%SwpGuiVal_Key%
Return

SWP_KeygenOK:
    Gui %SWP_GuiID%:Submit, NoHide
    Clipboard = 
        ( LTRIM
            -----------------------------------
            Username: %SwpGuiVal_Name%
            Email:    %SwpGuiVal_Email%
            Key:      %SwpGuiVal_Key%
            -----------------------------------
        )
    Gui %SWP_GuiID%:Destroy

Return


;-------------------------------------------------------------------------------
; Revision History
;-------------------------------------------------------------------------------
/*

    0.11  2007 09 04
        - Added  : Keygen
        - Changed: Initialize function (secret seeds) now needs to be called
          separately prior to calling any of the other main GUI functions.
          This is done to allow different key generation for every software
          you develop.
          If this is not a requirement, the Initialize function can be put
          back into the two main GUI functions (only make sure you are using
          the same seeds)
        
    0.10  2007 09 03
        - First version



*/





Rajat
  • Members
  • 1904 posts
  • Last active: Jul 17 2015 07:45 AM
  • Joined: 28 Mar 2004
really good work there Laszlo and Icarus.
thanks for sharing.

MIA

CleanNews.in : Bite sized latest news headlines from India with zero bloat


Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
Laszlo,

The values of the 8 secret keys - can they all be in the range of
0x00000000 to 0xffffffff

or is there a difference between the first four and the last four?

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
For my purposes I would use something like this. This isnt exactly what I would use, this is just 25 mins of mucking around to see what it would look like, as obviously if you wanted to decrypt then you would do it from the file etc....
So if Laszlo can help me a bit more on getting the CPU values with that crazy machine code :) then I would use only 2 variables and no need to encrypt the username and email


SetBatchLines -1
StringCaseSense Off
AutoTrim Off

k1 := 0x00000000                 	; 128-bit secret key
k2 := 0x11111111
k3 := 0x22222222               	        ; choose wisely!
k4 := 0x33333333
k5 := 0x44444444              		; starting counter value


Gui, 1: Add, Text, x10 y10 w60 r1 -Multi -Wrap, Name
Gui, 1: Add, Edit, x+10 w210 r1 -Multi -Wrap vUserName
Gui, 1: Add, Text, x10 y+10 w60 r1 -Multi -Wrap, Email
Gui, 1: Add, Edit, x+10 w210 r1 -Multi -Wrap vEmail

Gui, 1: Add, Text, x10 y+20 w60 r1 -Multi -Wrap, Hash
Gui, 1: Add, Edit, x10 y+5 w280 r8 vEncDec, %COMPUTERNAME%`n%HOMEPATH%`n%USERNAME%`n%PROCESSOR_ARCHITECTURE%`n%PROCESSOR_IDENTIFIER%`n%PROCESSOR_LEVEL%`n%PROCESSOR_REVISION%`n%A_OSType%`n%A_OSVersion%`n%Language%
Gui, 1: Add, Button, x10 y+50 w75 gENCRYPT, Encode
Gui, 1: Add, Button, x+5 yp+0 w75 gDECRYPT, Decode
Gui, 1: Add, Button, x+50 yp+0 w75 gWRITE, Write...
Gui, 1: Show, w300 h300, XTEA
Return

;#############################################################################################################

WRITE:
Gui, 1: Submit, NoHide
FileDelete, hash.txt
FileAppend, %Name%`n, hash.txt
FileAppend, %Email%`n`n, hash.txt
FileAppend, %EncDec%, hash.txt
Return

ENCRYPT:
encrypt = 1
decrypt = 0
GoSub, EncryptDecrypt
Return

DECRYPT:
decrypt = 1
encrypt = 0
GoSub, EncryptDecrypt
Return

;#############################################################################################################

EncryptDecrypt:
Gui, 1: Submit, NoHide

i = 9
p = 0
L =
   
Loop % StrLen(EncDec)
{
    i++
    If i > 8
	{
		u := p
		v := k5
		p++
		TEA(u,v, k1,k2,k3,k4)
		Stream9(u,v)
		i = 0
	}
		
    StringMid c, EncDec, A_Index, 1
    a := Asc(c)
	
    If a between 32 and 126
    {
		If encrypt = 1
		{
			a += s%i%
			IfGreater a, 126, SetEnv, a, % a-95
			c := Chr(a)
		}
		If decrypt = 1	
		{
			a -= s%i%
			IfLess a, 32, SetEnv, a, % a+95
			c := Chr(a)
		}
    }
		
	L = %L%%c% 
}
GuiControl,, EncDec, %L%
Return

;#############################################################################################################

TEA(ByRef y,ByRef z,k0,k1,k2,k3) ; (y,z) = 64-bit I/0 block
{                                ; (k0,k1,k2,k3) = 128-bit key
   IntFormat = %A_FormatInteger%
   SetFormat Integer, D          ; needed for decimal indices
   s := 0
   d := 0x9E3779B9
   Loop 32
   {
      k := "k" . s & 3           ; indexing the key
      y := 0xFFFFFFFF & (y + ((z << 4 ^ z >> 5) + z  ^  s + %k%))
      s := 0xFFFFFFFF & (s + d)  ; simulate 32 bit operations
      k := "k" . s >> 11 & 3
      z := 0xFFFFFFFF & (z + ((y << 4 ^ y >> 5) + y  ^  s + %k%))
   }
   SetFormat Integer, %IntFormat%
   y += 0
   z += 0                        ; Convert to original ineger format
}

Stream9(x,y)                     ; Convert 2 32-bit words to 9 pad values
{                                ; 0 <= s0, s1, ... s8 <= 94
   Local z                       ; makes all s%i% global
   s0 := Floor(x*0.000000022118911147) ; 95/2**32
   Loop 8
   {
      z := (y << 25) + (x >> 7) & 0xFFFFFFFF
      y := (x << 25) + (y >> 7) & 0xFFFFFFFF
      x  = %z%
      s%A_Index% := Floor(x*0.000000022118911147)
   }
}


David55
  • Guests
  • Last active:
  • Joined: --
Hi,

this is my key generator script (the beginning) i'm still using the first script made by Laszlo, see below...

my question: do i need to change the values of the keys k0,k1...,L0,L1..,m0,m1 to get a unique key generator??

means that i have to change it in the code implemented script also to the same keys??

does it means that i can change k0 = 0x11111111 to k0 = 0x98472210 and all the other kes as i wish??



; AutoHotkey Version: 1.0.39+
; Language: English
; Platform: Win2000/XP
; Author: Laszlo Hars
; Function: SW copy protection

k0 = 0x11111111 ; 128-bit secret key (example)
k1 = 0x22222222
k2 = 0x33333333
k3 = 0x44444444

l0 = 0x12345678 ; 64- bit 2nd secret key (example)
l1 = 0x12345678

m0 = 0x87654321 ; 64- bit 3rd secret key (example)
m1 = 0x87654321

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
You don't need a key generator, one particular key is as good as an other. Even if it is not secret, CBC-MAC is not invertible. If you replace TEA with a hash function from the Windows CSP, you have no place from keys, either.

David55
  • Guests
  • Last active:
  • Joined: --
Laszlo, but if i don't change the key, anyone who has the key generator (from your first code) can make a key for the software to work. that is the reason i asked if i need to change them all.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
You just choose one secret key. You can use it forever. No need for a fancy key generator.