How to protect final program when distributing? License keys?

In the prototype stage you can have a count to protect the program but what do you do when you hand over the program to others? You’ve given an install file so potentially they can share that installer with anyone.

I wrote some articles and did a video for the temporary process Compile a program for install for distribution & Setting up install files to share for prototyping with security and the video:

https://www.youtube.com/watch?v=zVqk-KoufP0

So if you’d planned a fees based on 3-5 people usage of a bespoke program and it was used by 20 pax then you could feel that you’d have had a different fee structure in place for that many people.

So how do you make an installer that only installs once in this case?

I can’t think of any obvious way, so I think you have to have the key in the program itself.

I found this forum discussion thought provoking. I quite liked the time sensitive key, for use within 2 weeks, and people can request new licenses.

This article is interesting on stack overflow too. Validating via a remote server was one suggestion. And along these lines they could email you to get license sent with a mailto:….

First run request for Key.

So the program, on first run, should pop-up a box asking for the Serial Key.

This key can then be matched against a list of keys within a file somewhere that it needs to loop through. (This could be done in a 2nd script/program (but you’d need for the first program to check the file was there and stop if it wasn’t) If Key matches one in list then activates and deletes that key from the list

NO- WON’T WORK- As setup package has same stuff in it from beginning.!!! So next install has all the Keys , so same key can be used again. Needs to be Time Sensitive on Keys –

License sums to a number

in this video (https://www.youtube.com/watch?v=_5VOABeCv3U) the validation for the License is if all the added values in the number are divisible by 7 with no remainder. It still has the issue of once you have a license key that is valid you can share it around.

License Install Scripts with embedded key

Maybe another way to do it is to give them fist install script for program, then another License script? How do you make that a one off run ? Again compiled, so they could use it again and again. There is this article that generates a Key from input: Using VB to Create & Check License Keys. There is program you can download to generate key.

This will create a key that you can embed in your .exe file. If it matches then you are fine, but again, once you have given correct data it can be used over and over, Licencee: JBlogs, Serial#:123, Keycode:abc… and software activated. Thy just pass those details on to others.

Email with PC ID and create a key- this has to be held outside compiled script

Run a script and it gets a mac address that then sends an email to you. You then email back with key to use. So every time program runs it sends you a request email, you have control on who can install.

One method for a program was for you to send an email to program supplier for a key. This was asked for after the install and it got the mac address of the pc. They then created a key that was associated with a specific pc. So the key was only valid on a specific PC. So you could install as many times as you liked on one PC.

As you are creating a unique key that you are giving after the program has been sent to a user, you cannot have the full key embedded in the program as you are using post install information to generate the rest of the key, so this needs to be installed in a file on their pc that it can be checked against.

So the validation can have part of the key embedded in the compiled script and part in an external read/write file.

So key: ProgKeyInCompiledExe: 1234 + PostGeneratedKey: 3456 key: 1234+3456

A Unique ID as part of check process

I think I start to see a way forward.

You need something unique from the user or the users PC, then that can be added to the combination of the validation process.

When someone puts the info in say Name: J.Iijit and you have given them Serial :4321 , this gets written to file and in that file you get the userName login, say “Rhonda”. So 3 parts to key -1/ Name, 2/ Serial & 3/UserName

So once you try to use that on a different PC you need to login as “Rhonda” is logged in then program will run with the above License add-in info of Name: J.Iijit and Serial :4321

So for people who want to login as “Rhonda” for the program on lots of PC’s it’ll work. A bit irritating

AHK variables that can be gathered that are specific to a certain PC & user, see AHK Documentation and look up “A_“:

A_ComputerName, A_UserName, A_IPAddress1 through 4 (this may occur on all pc’s in an office, so may stop external use)

So you could combine the PC ID in the validation process.

You still need to send that information back to program distributor so that a Serial Key can be associated with a specific computer & a specific user.

So you need a License Request email a mailto: that includes computer name and user login for the person using the program. This may need to be encrypted.

Process

Inside main program start by:

  1. finding comp & userName & encrypting them
  2. Storing in FileTemp.ini with the ProjectId (name, Ver, date)
  3. Checking License-compile and compare against hidden Alma.ini
  4. If they match then go to program and run
  5. If NOT match then MessageBox says NO VALID License and asks you to put correct License in
  6. New Pop-up GUI asks you to 1/Install key & press OK button or 2/Request Button to Request a License

If you put Correct serial Number (License key then you run the program again and it takes you straight to program.

If you request a License this sends an email to Software Supplier who will generate a Serial Number for you

Main Script

This is the main executable that you run:

/*
Name: RunShell.ahk
This is a setup for Adding & checking a License for a program

Steps: 
On first Run -
1/ - Read comp name & username
2/ -store in FileTemp.ini encrypted
3/ -check to see if valid licence
4/ If match- then run program
5/ if not, put in key
6/ If no key then email to request License 

*/
;-----------------------Setup -----------------------------
#NoEnv
#SingleInstance, Force
SetWorkingDir %A_ScriptDir%
;-----------------------Include libraries -----------------------------
#Include %A_ScriptDir%\Notify.ahk
#Include %A_ScriptDir%\E13.ahk

;------------------Package ID ----------------------
PackageId = ShareFile_v2_20211026
NgSplit=av7x

;-----------------------Files & Locations -----------------------------

Alma = AlmaMater.ini
;------------------Read Comp & User Names & Write to file ----------------------

comp= %A_ComputerName%
user= %A_UserName%

sendx:= Rot13(comp)  ; encrypting function 
underx:=Rot13(user) ; encrypting function 

IniWrite,%PackageId% , FileTemp.ini, p, PackageId
IniWrite,%sendx% , FileTemp.ini, c, cee
IniWrite, %underx%, FileTemp.ini, d, dee

IniRead, zed, %Alma%, serial, serialId
IniRead, why, %Alma%, other, B1

Timeframe = %NgSplit%%why%*%sendx%*%underx%   ; %why% 2nd part of  key, held in the Alma.ini file
;msgbox, %Timeframe%
 

msgbox ,%zed% ** %Timeframe%   ; message box to check to see if tke license keys match- can comment out on main program

If (zed != Timeframe)  ; This compares keys - if not valid, then you have pop-up to all licence
{
 
 MsgBox, No Valid License for %PackageId%`n`n Please install correct License Key after you close this Message Box`n`n If you don't have a License then press Request Button in next Message Box
Run,  PC&UerInfoLicenceInstall.ahk 

ExitApp
}else {


   MsgBox, Program Start 
   
   ;PUT YOUR MAI N PROGRAM HERE BETWEEN BRACKETS

;------These for Notify popup class-----------------
Text:= "Run Shell Licence Started"
Background1=0x456789   ; a bluey color 
Color=0xFFFFFF ; white;
Title = Shell Licence ;This is my TITLE
TitleFont="Tahoma"
TitleColor= 0xFFFFFF ; white
TitleSize=20
Size=12 ;text height
Time= 3000 ;3000
Icon =145 ;297or145  tick,132 "x", 278 blue circle exclamation , 234 orange triangle exclamation; 220 no way,211 question in blue circle
IconSize =30

;------------------INITIATE INSTANCE OF NOTIFY ----------------------
Notify:=Notify()
;------------------NOTIFY POPUP  STARTING THE PROGRAM ----------------------
Notify().AddWindow(Text,{Size:Size,Icon:Icon "," Ico,IconSize:IconSize,Title:Title,TitleColor:TitleColor,TitleFont:TitleFont,TitleSize:TitleSize,Background:Background1,Color:Color,Time:Time}) ;Flash:1000,

sleep,3000  ; this is only here to make sure notify is displayed for the duration before exit

ExitApp
}

No Valid License Script

If the license check is false then you need to ask for a License and get them to fill in info. You do not really need the email address in the request box gui, that could be removed as I do not use that information anywhere.

;Name:PC&UerInfoLicenceInstall.ahk 
#NoEnv
#SingleInstance, force
;-----------------------Files & Locations -----------------------------
Alma = AlmaMater.ini
;-----------------------Files & Locations -----------------------------
Gui, Add, Text,, EmailAddress:
Gui, Add, Text,, License Code:
Gui, Add, Edit, vEmailAddress ym  ; The ym option starts a new column of controls.
Gui, Add, Edit, vLicense_Code
Gui, Add, Button, default, OK  ; The label ButtonOK (if it exists) will be run when the button is pressed.
Gui, Add, Button,x+25+m , REQUEST  ; The label ButtonOK (if it exists) will be run when the button is pressed.
Gui , Font , S10
Gui, add,text, xs+5 ys+80, If you do not have a License Code`nPress Request Button above`nTo send email to request one 
Gui, Show,w200 h140, License Add
return  ; End of auto-execute section. The script is idle until the user does something.

ButtonOK:
Gui, Submit  ; Save the input from the user to each control's associated variable.
MsgBox You entered "%EmailAddress% %License_Code%".

if (EmailAddress !="") {
if (License_Code !=""){
 
IniWrite, %EmailAddress%, %Alma%, name, nameId
IniWrite, %License_Code%, %Alma%, serial, serialId
}
}

ExitApp


ButtonREQUEST:
Gui, Cancel  ; Save the input from the user to each control's associated variable.
run,       LicenseRequest.ahk

ExitApp

Request License email

The Request button uses a mailto setup (note save file encode as UTF-8-BOM if you want to use emoji’s in email):

;Name:
LicenseRequest.ahk


#SingleInstance, Force
SendMode Input
SetWorkingDir, %A_ScriptDir%

IniRead, PackageId, FileTemp.ini, p, PackageId
IniRead, c, FileTemp.ini, c, cee
IniRead, d, FileTemp.ini, d, dee
;----------------------------
em1= [email protected]
Subj= ?️License Request-RunShell ?️

Bod= Requesting License for.`%0APackage:%PackageId%*%c%*%d% `%0A Thank you
Run, mailto:%em1%?&subject=%Subj%&body=%Bod%       
;----------------------------
ExitApp

This has encrypted Computer name and UserName in the request and they form part of the Serial number that you will return to them. via email

Ini Files

There are 2 .ini files, one is temporary and one is hidden

;Name: FileTemp.ini
[p]
PackageId=ShareFile_v2_20211026
[c]
cee =QRFXGBC-VXTMQ
[d]
dee=rixol

The hidden file where the License code is stored is

;Name: Alma.ini
[name]
[email protected]
[serial]
serialId=av7x0x456789*QRFXGBC-VXTMQ*rixol  
[other]   ; this is 2nd part of key for License 
B1=0x456789

Encryption

I’d been playing with this code previously, when I found an Encryption bookmarklet, and I found this article on it at Rosetta Code which has a link to the AutoHotKey script here . I used it as a library file and used it to encrypt computer name and user name.

This is a very simple encryption , in English alphabet 26 letters, this shifts each letter along by 13- then for deEncryption it shifts letters along by 13 again back to their starting letter. So a one way encrypt/decrypt, so you don’t have to use a reversal script. Just run the same script twice over the original text to get back to the original.It only affects letters and does nothing with numbers or symbols.

You would locate this file somewhere hidden so that it would not be easy to see the encryption process. you could always substitute the encryption code at a later date if you found people were able to break the License code.

/*
;Name: E13.ahk
;For testing
Str0=Hello, This is a sample text with 1 2 3 or other [email protected]#$^&*()-_=
; Str1 runs function Rot13(string) over Str0
Str1 := Rot13(Str0)
; Str2 runs function Rot13(string) over Str1 to convert it back again
Str2 := Rot13(Str1)
; Msg box displays Str0 "`n" Str1 "`n" Str2
MsgBox % Str0 "`n" Str1 "`n" Str2
*/
; This is function that does the work 
Rot13(string) 
{
  Loop Parse, string
  {
    char := Asc(A_LoopField)
    ; o is 'A' code if it is an uppercase letter, and 'a' code if it is a lowercase letter
    o := Asc("A") * (Asc("A") <= char && char <= Asc("Z")) + Asc("a") * (Asc("a") <= char && char <= Asc("z"))
    If (o > 0)
    {
      ; Set between 0 and 25, add rotation factor, modulus alphabet size
      char := Mod(char - o + 13, 26)
      ; Transform back to char, upper or lower
      char := Chr(char + o)
    }
    Else
    {
      ; Non alphabetic, unchanged
      char := A_LoopField
    }
    rStr .= char
  }
  Return rStr
}

Install Files

Installable File (no Dialogue install) & NSIS Script for the file

Methods for the process

So in the above process I’ve used the following methods:

  1. Joining different variables to make the key
  2. Using Computer ID as part of the key – so it only runs on that computer with that key
  3. Using UserName as part of the key – so it only runs when that userName is logged in
  4. Part of Key is in compiled program
  5. Part of Key is in .ini file that is located in different part of the computer
  6. Key to be requested so that it can be generated by software provider who can keep tabs on how many licenses issued
  7. An encryption process is used to conceal/obfuscate some of the information
  8. Install process of Program onto PC is without display windows so you don’t see where files are being installed (run without a dialogue box)

I did note that the beginning of the key does look the same as the first part is the fixed key in the PC.

  1. You could further mix things up by chopping the information up into smaller pieces and shifting their location in the key- so stripping and recombining the parts of the key
  2. Use a more complex encryption algorithms
  3. Use 2 or more encryption algorithms

And many more methods that would be beyond my humble skills

Maybe sending info to a server to generate a key or to check a key on the server. This could be a pain if you had no internet access.

How to break it- vulnerabilities

After making the key, there are aspects that are easy to glean from the setup.

You could go looking for the hidden files and start to dissect the License key. The way you’d do this is look at the readable text in the .EXE compiled AHK files to see the original code. They show how key is constructed. I did try and make this a little unclear, but its not too hard to unravel.

In the FileTemp.ini you can see the information there, looking by the size of the values you could begin to see that they may have some relevance to the ID of the pc and user, as the License Key does not work on other installs on other computers. Also thinking about unique identifiers and what they could be.

End Comment

This has been an interesting exercise and fun to do. The issues round a robust key that was specific enough that sharing it would not be easy took a little bit of research.

I did not want to get into massive research on the topic of cryptography , I just wanted something simple to setup and run that was within my coding skills.

I also wanted to think through from first principles as to what is a logical method of doing this. So I wasn’t trying for the ultimate, rather just the practical.

It ended up being quite easy to code as I’d got the basic process sorted from the count process for proto-typing.

Breaking it down into separate activities helped as well. So send email was one process, install license a 2nd process, then the main process calling these sub processes ata specific time and in a specific order.