Any questions? Ask us: support@enigmaprotector.com

Help

Tutorials

Creating key generators of Enigma projects for automatic registrar ShareIt!

This tutorial will explain how to generate custom keys generator for the own projects protected with Enigma Protector. Enigma Protector itself has possibility to generate registration keys (through the simple keygen or License Manager) but this requires manual generation, it would be the best to automate this operation. So, we will create custom keys generator and send it to shareit team. Shareit will execute this keygen after successful order and show registration key to the user immediately after purchasing.

All the examples described below are written in Delphi (shareit SDK does not provide us C examples, but anyway, it can be rewritten in C too).

Creating Registration Keys Generator with embeded constants
Creating Registration Keys Generator that loads settings from the project file
Generating Time Limited Keys
Generating Hardware Locked Keys
Send Keygen to ShareIt!
Some missed words FYI

Creating Registration Keys Generator with embeded constants

Keys Generator is just simple executable file that is able to generate registration keys. For keys generation keygen uses special library keygen.dll (it may be found in the installation package of Enigma). Please note, all the projects created in Enigma Protector are unique (because some secure constants that use for keys generating are unique) and it is impossible to make keygen for the any external files protected with Enigma.

The registration keys generator requires few unique constants that are placed in your project file. These constant are unique for every project created in Enigma, probability of its duplication is almost zero. This generation method embeds unique constants into compiled project. The following code illustrates the key generator routine:

function Enigma_GenerateRegistrationKey(ARegistrationName : string) : string;
var
  kg : TKeyGenParams;
  key_buf : array [0..2047] of char;
  dwresult : Cardinal;
begin
  // Clear buffer
  FillChar(kg, sizeof(kg), #0);
  // Get this information from your project file
  kg.KeyMode := RM_512;
  kg.KeyBase := RB_32;
  kg.KeyWithHyphens := true;
  kg.PublicKey  := '0201B810DA4A1ADD4351378790A98138533067CP4S86R7D8THS45GBCVUM635EPRQRMYRP3DAA5DUPZ6ABDSFP7F5AC' +
                   'P7ERGH4A7Y6B6NW6NMMBZF83WVER9Y4MMBNLBQDKR7KFVLGLV067CFDQC' +
                   'WCHGQVVRN24DECEPBL96YJQJTVDCRTNQG3E4WW4GK4GQ5X5L5H88D3XYH' +
                   'CBRBNASPD3P5CNYFKFHBCSDHHD6WPTCC4XVSM5S88067C2JSTCMVT48C8' +
                   'HC7SHKGTFJBM28P6XTBCNWHMV6J6KN6W5Q9TQLVR285U6GVCAAUTZLRTP' +
                   'SRGDQ742B4742XF4MACRR747YDP5FZZ9D';
  kg.PrivateKey := '00C98B2SF9UBJA605AJX53GJFXJV8UH4A6PY2L6CV4MAMV7V3ERRVY99Y' +
                   '72V2P77Z2J3KBPGWR3WXKG5GF9Z6CKXJHY5VUMBTQ66H2MRZPCU00DLFJ' +
                   '675JTTTNEK00DLFJ675JTTTNEK';
  kg.EncryptedConstant := 2113444489;
  // Clear key buffer
  FillChar(key_buf, sizeof(key_buf), #0);
  kg.Key := @key_buf;
  // Set key buffer size
  kg.KeyLen := sizeof(key_buf);
  // Set registration user info
  kg.RegInfo := pointer (ARegistrationName);
  kg.RegInfoLen := length(ARegistrationName);
  // Use key expiration
  kg.UseKeyExpiration := true;
  kg.ExpirationYear := 2010;
  kg.ExpirationMonth := 1;
  kg.ExpirationDay := 1;
  // Do not use hardware id
  kg.UseHardwareLocking := false;
  // This key should decrypt #2 and #6 sections
  kg.EncryptedSections[1] := true;
  kg.EncryptedSections[5] := true;

  dwresult := KG_GenerateRegistrationKey(@kg);
  if dwresult = EP_NO_ERROR then
  begin
    Result := pchar(kg.Key);
  end else
  begin
    // Generate error message
    case dwresult of
      EP_ERROR_UNKNOWN                 : Result := 'EP_ERROR_UNKNOWN                ';
      EP_ERROR_KEYBUFFEREMPTY          : Result := 'EP_ERROR_KEYBUFFEREMPTY         ';
      EP_ERROR_KEYBUFFERISLESS         : Result := 'EP_ERROR_KEYBUFFERISLESS        ';
      EP_ERROR_REGINFOEMPTY            : Result := 'EP_ERROR_REGINFOEMPTY           ';
      EP_ERROR_REGINFOTOOLARGE         : Result := 'EP_ERROR_REGINFOTOOLARGE        ';
      EP_ERROR_PRIVATEKEYISNOTSET      : Result := 'EP_ERROR_PRIVATEKEYISNOTSET     ';
      EP_ERROR_PUBLICKEYISNOTSET       : Result := 'EP_ERROR_PUBLICKEYISNOTSET      ';
      EP_ERROR_PRIVATEKEYISINVALID     : Result := 'EP_ERROR_PRIVATEKEYISINVALID    ';
      EP_ERROR_PUBLICKEYISINVALID      : Result := 'EP_ERROR_PUBLICKEYISINVALID     ';
      EP_ERROR_KEYMODEISINVALID        : Result := 'EP_ERROR_KEYMODEISINVALID       ';
      EP_ERROR_KEYBASEISINVALID        : Result := 'EP_ERROR_KEYBASEISINVALID       ';
      EP_ERROR_CURRENTDATEISINVALID    : Result := 'EP_ERROR_CURRENTDATEISINVALID   ';
      EP_ERROR_EXPIRATIONDATEISINVALID : Result := 'EP_ERROR_EXPIRATIONDATEISINVALID';
      EP_ERROR_KEYISINVALID            : Result := 'EP_ERROR_KEYISINVALID           ';
      EP_ERROR_HARDWAREID              : Result := 'EP_ERROR_HARDWAREID             ';
      EP_ERROR_HARDWAREBUFFEREMPTY     : Result := 'EP_ERROR_HARDWAREBUFFEREMPTY    ';
      EP_ERROR_HARDWAREIDINVALIDFORKEY : Result := 'EP_ERROR_HARDWAREIDINVALIDFORKEY';
      EP_ERROR_PROJECTFILENOTFOUND     : Result := 'EP_ERROR_PROJECTFILENOTFOUND    ';
      EP_ERROR_INVALIDPROJECTFILE      : Result := 'EP_ERROR_INVALIDPROJECTFILE     ';
      else Result := 'Unknown error';
    end;
  end;
end;

Now, let's explain every code string:

FillChar(kg, sizeof(kg), #0); - clear memory buffer structure that uses for generating registration keys
kg.KeyMode := RM_512; - type of the keys length/safety. Enigma Protector supports few types of key safety RSA 512 (RM_512), RSA 768 (RM_768), RSA 1024 (RM_1024), RSA 2048 (RM_2048), RSA 3076 (RM_3076), RSA 4096 (RM_4096), to understand what value you should use there - open your project file in Enigma and go to "REGISTRATION FEATURES" - "Common" panel and find there "Registration key safety/length" field, it shows what value you should use. For example, if you are using RSA 1024 keys, then use RM_1024 constant for KeyMode parameter.
kg.KeyBase := RB_32; - output type of registration keys. There are 5 output types for registration keys:

Key Base Value Key Symbols Example
Base 2 RB_2 01

0111101100110111000111100110101011101000
1101010100111000100110000000011011111001
0000101100011001101001000011000101101010

Base 8 RB_8 01234567 6683343532254367337887327776473815464631
Base 16 RB_16 ABCDEF1234567890 960F4A566A1FCEDD491837CAC9E6F5
Base 32 RB_32 ABCDEFGHJKLMNPQRSTUVWXYZ 2..9 8T8TB8TC8ZJWHKT49JXCA3R9
Base 64 RB_64 A..Z a..z 0..9 += VbwprHrqTQ=qv7YUXdn+

Please note that key output base is defined into your project file, to know what base you should use for keys generating - open your project file in Enigma and go to "REGISTRATION FEATURES" - "Common" panel and find there "Registration key output base" field, it shows what value you should use. For example, if you are using Base 32, then use RB_32 constant for KeyBase parameter.

kg.KeyWithHyphens := true; - allows to add hyphens to the key (example of the key with hyphens 9S7FN3- AHLSFU-9FE929-TPGTQS).
kg.PublicKey  := '0201B810DA4A1ADD4351378790A98138533067CP4S86R7D8THS45GBCVUM635EPRQRMYRP3DAA5DUPZ6ABDSFP7F5AC' +
                 'P7ERGH4A7Y6B6NW6NMMBZF83WVER9Y4MMBNLBQDKR7KFVLGLV067CFDQC' +
                 'WCHGQVVRN24DECEPBL96YJQJTVDCRTNQG3E4WW4GK4GQ5X5L5H88D3XYH' +
                 'CBRBNASPD3P5CNYFKFHBCSDHHD6WPTCC4XVSM5S88067C2JSTCMVT48C8' +
                 'HC7SHKGTFJBM28P6XTBCNWHMV6J6KN6W5Q9TQLVR285U6GVCAAUTZLRTP' +
                 'SRGDQ742B4742XF4MACRR747YDP5FZZ9D';
kg.PrivateKey := '00C98B2SF9UBJA605AJX53GJFXJV8UH4A6PY2L6CV4MAMV7V3ERRVY99Y' +
                 '72V2P77Z2J3KBPGWR3WXKG5GF9Z6CKXJHY5VUMBTQ66H2MRZPCU00DLFJ' +
                 '675JTTTNEK00DLFJ675JTTTNEK';
- Public and Private Keys. These unique keys are placed in the project file. How to extract these keys from project file? Go through the following steps:

  • Open project file in notepad (project file with the .enigma extension). Enigma project file is just xml file with the all necessary settings.
  • Find there the following branch: EnigmaProject - RegistrationFeatures - Constants. Constants branch contains all necessary unique constants. Now, take a look at the KeyMode parameter (described above), and remember key mode digits. Then, find in Constants branch that describes your KeyMode (for example, if you are using KeyMode = RM_1024 (~RSA 1024) then find Mode1024 branch in project file), in the necessary Mode get your Public and Private Keys.

kg.EncryptedConstant := 2113444489; - one more unique constant that is using for encryption/decryption of crypted sections (note: this value has integer type, not a string!). Get it from project file, in EnigmaProject - RegistrationFeatures - Constants branch, EncryptedConstant value.
FillChar(key_buf, sizeof(key_buf), #0); - fill out key memory buffer. In this buffer will be placed registration keys. Remember, size of key buffer must be at least 2048 bytes. Of course, size of buffer may be less, it depends on KeyBase and KeyMode, for example, KeyBase = RB_2 and KeyMode = RM_4096 give you a key about 2000 symbols length, but KeyBase = RB_64 and KeyMode = RM_512 - 20 symbols.
kg.Key := @key_buf; - set pointer of the key buffer to the key generation struct.
kg.KeyLen := sizeof(key_buf); - define a size of the key buffer. If the size of key buffer will be less than required then keygen function will return an error.
kg.RegInfo := pointer(ARegistrationName); - set pointer of the registration name buffer.
kg.RegInfoLen := length(ARegistrationName); - define a length of registration name buffer in bytes.
kg.UseKeyExpiration := false; - if this value if true then generated registration keys should have expiration date. Otherwise key is not time limited.
kg.UseHardwareLocking := false; - set it to true if the key is generating for the particular hardware id. In our example key is not locked to hardware id.
kg.EncryptedSections[1] := true;
kg.EncryptedSections[5] := true;
- set the crypted sections that should be decrypted with the current key.
dwresult := KG_GenerateRegistrationKey(@kg); - call key generation function. Function returns integer result.
if dwresult = EP_NO_ERROR then
begin
  Result := pchar(kg.Key);
end else
begin
  // Generate error message
  case dwresult of
  EP_ERROR_UNKNOWN : Result := 'EP_ERROR_UNKNOWN ';
  EP_ERROR_KEYBUFFEREMPTY : Result := 'EP_ERROR_KEYBUFFEREMPTY ';
  EP_ERROR_KEYBUFFERISLESS : Result := 'EP_ERROR_KEYBUFFERISLESS ';
  EP_ERROR_REGINFOEMPTY : Result := 'EP_ERROR_REGINFOEMPTY ';
  EP_ERROR_REGINFOTOOLARGE : Result := 'EP_ERROR_REGINFOTOOLARGE ';
  EP_ERROR_PRIVATEKEYISNOTSET : Result := 'EP_ERROR_PRIVATEKEYISNOTSET ';
  EP_ERROR_PUBLICKEYISNOTSET : Result := 'EP_ERROR_PUBLICKEYISNOTSET ';
  EP_ERROR_PRIVATEKEYISINVALID : Result := 'EP_ERROR_PRIVATEKEYISINVALID ';
  EP_ERROR_PUBLICKEYISINVALID : Result := 'EP_ERROR_PUBLICKEYISINVALID ';
  EP_ERROR_KEYMODEISINVALID : Result := 'EP_ERROR_KEYMODEISINVALID ';
  EP_ERROR_KEYBASEISINVALID : Result := 'EP_ERROR_KEYBASEISINVALID ';
  EP_ERROR_CURRENTDATEISINVALID : Result := 'EP_ERROR_CURRENTDATEISINVALID ';
  EP_ERROR_EXPIRATIONDATEISINVALID : Result := 'EP_ERROR_EXPIRATIONDATEISINVALID';
  EP_ERROR_KEYISINVALID : Result := 'EP_ERROR_KEYISINVALID ';
  EP_ERROR_HARDWAREID : Result := 'EP_ERROR_HARDWAREID ';
  EP_ERROR_HARDWAREBUFFEREMPTY : Result := 'EP_ERROR_HARDWAREBUFFEREMPTY ';
  EP_ERROR_HARDWAREIDINVALIDFORKEY : Result := 'EP_ERROR_HARDWAREIDINVALIDFORKEY';
  EP_ERROR_PROJECTFILENOTFOUND : Result := 'EP_ERROR_PROJECTFILENOTFOUND ';
  EP_ERROR_INVALIDPROJECTFILE : Result := 'EP_ERROR_INVALIDPROJECTFILE ';
  else Result := 'Unknown error';
end;
- get an error code, if there is not any error, key generating fucntion returns EP_NO_ERROR value and kg.Key buffer contains generated key.

Download sources

Creating Registration Keys Generator that loads settings from the project file

This kind of keys generator is similar as above but does not require defining of unique constants and key parameters (Private and Public Keys, EncryptedConstant, KeyBase and KeyMode). Keys generation routine reads all parameters from the project file automatically. Take a look at the code below. Note, here we are using KG_GenerateRegistrationKeyFromProject instead of KG_GenerateRegistrationKey (as in previous example) and KG_GenerateRegistrationKeyFromProject requires define a project file name. Simply, you may use my compiled example, just place there own project file.

function Enigma_GenerateRegistrationKey(ARegistrationName : string) : string;
var
  kg : TKeyGenParams;
  key_buf : array [0..2047] of char;
  dwresult : Cardinal;
begin
  // Clear buffer
  FillChar(kg, sizeof(kg), #0);
  // Get this information from your project file
  kg.KeyWithHyphens := true;
  // Clear key buffer
  FillChar(key_buf, sizeof(key_buf), #0);
  kg.Key := @key_buf;
  // Set key buffer size
  kg.KeyLen := sizeof(key_buf);
  // Set registration user info
  kg.RegInfo := pointer(ARegistrationName);
  kg.RegInfoLen := length (ARegistrationName);
  // Use key expiration
  kg.UseKeyExpiration := true;
  kg.ExpirationYear := 2010;
  kg.ExpirationMonth := 1;
  kg.ExpirationDay := 1;
  // Do not use hardware id
  kg.UseHardwareLocking := false;
  // This key should decrypt #2 and #6 sections
  kg.EncryptedSections[1] := true;
  kg.EncryptedSections[5] := true;
  dwresult := KG_GenerateRegistrationKeyFromProject('project.enigma', @kg);
  if dwresult = EP_NO_ERROR then
  begin
    Result := pchar(kg.Key);
  end else
  begin
    // Generate error message
    case dwresult of
      EP_ERROR_UNKNOWN                 : Result := 'EP_ERROR_UNKNOWN                ';
      EP_ERROR_KEYBUFFEREMPTY          : Result := 'EP_ERROR_KEYBUFFEREMPTY         ';
      EP_ERROR_KEYBUFFERISLESS         : Result := 'EP_ERROR_KEYBUFFERISLESS        ';
      EP_ERROR_REGINFOEMPTY            : Result := 'EP_ERROR_REGINFOEMPTY           ';
      EP_ERROR_REGINFOTOOLARGE         : Result := 'EP_ERROR_REGINFOTOOLARGE        ';
      EP_ERROR_PRIVATEKEYISNOTSET      : Result := 'EP_ERROR_PRIVATEKEYISNOTSET     ';
      EP_ERROR_PUBLICKEYISNOTSET       : Result := 'EP_ERROR_PUBLICKEYISNOTSET      ';
      EP_ERROR_PRIVATEKEYISINVALID     : Result := 'EP_ERROR_PRIVATEKEYISINVALID    ';
      EP_ERROR_PUBLICKEYISINVALID      : Result := 'EP_ERROR_PUBLICKEYISINVALID     ';
      EP_ERROR_KEYMODEISINVALID        : Result := 'EP_ERROR_KEYMODEISINVALID       ';
      EP_ERROR_KEYBASEISINVALID        : Result := 'EP_ERROR_KEYBASEISINVALID       ';
      EP_ERROR_CURRENTDATEISINVALID    : Result := 'EP_ERROR_CURRENTDATEISINVALID   ';
      EP_ERROR_EXPIRATIONDATEISINVALID : Result := 'EP_ERROR_EXPIRATIONDATEISINVALID';
      EP_ERROR_KEYISINVALID            : Result := 'EP_ERROR_KEYISINVALID           ';
      EP_ERROR_HARDWAREID              : Result := 'EP_ERROR_HARDWAREID             ';
      EP_ERROR_HARDWAREBUFFEREMPTY     : Result := 'EP_ERROR_HARDWAREBUFFEREMPTY    ';
      EP_ERROR_HARDWAREIDINVALIDFORKEY : Result := 'EP_ERROR_HARDWAREIDINVALIDFORKEY';
      EP_ERROR_PROJECTFILENOTFOUND     : Result := 'EP_ERROR_PROJECTFILENOTFOUND    ';
      EP_ERROR_INVALIDPROJECTFILE      : Result := 'EP_ERROR_INVALIDPROJECTFILE     ';
      else Result := 'Unknown error';
    end;
  end;
end;


Download sources

Generating Time Limited Keys

To generate time limited registration keys, we need to enable UseKeyExpiration property and setup key expiration date.
This example shows how to set fixed expiration date. The keys generated with such expiration date will expire at 01/01/2010 (DD/MM/YYYY)
kg.UseKeyExpiration := true;
kg.ExpirationYear := 2010;
kg.ExpirationMonth := 1;
kg.ExpirationDay := 1;

Download Example

If there is need to setup variable expiration date, it can be done very simply too. Such keys will expire after 1 year from key creation date.
kg.UseKeyExpiration := true;
kg.ExpirationYear := YearOf(Now) + 1;
kg.ExpirationMonth := MonthOf(Now);
kg.ExpirationDay := DayOf(Now);

Download Example

Or the same example but with using of GetSystemTime Windows API.
kg.UseKeyExpiration := true;
GetSystemTime(lpSystemTime);
kg.ExpirationYear := lpSystemTime.wYear + 1;
kg.ExpirationMonth := lpSystemTime.wMonth;
kg.ExpirationDay := lpSystemTime.wDay;

Download Example

Generating Hardware Locked Keys

When the key should be locked to particular Hardware ID we need to get user's Hardware ID before generating key. How to get it? As I always promise to software developers to avoid cracking of their work - never distribute full functional version. The best way to avoid cracking is distributing of functions limited DEMO version, that does not require registration, but for registered user - FULL version of the program which should have registration. So, let's think you have two versions of your program:

  • DEMO version, this version has restricted functionality (for example, some functions are not available as in full version) and it is placed in your site. Anybody can download it and decide - purchase it or no.
  • FULL version, this version requires registration by means registration name and key, it has full functionality and you send this version to registered users ONLY.

Now return to keygen, we should get user's hardware id before the user purchases and get full version. In this case we need to mechasim that returns user's hardware id, for this purpose we can protect DEMO version with the same project file as a full version (we need this because DEMO version should return same hardware id as full version, this possible only by protecting DEMO with the same project as FULL version), plus, this DEMO should show hardware id (hardware id may be shown by means Enigma API EP_RegHardwareID, or embed Enigma's registration dialog, take a look at the REGISTRTAION FEATURES - Registration Dialog panel in Enigma).
Usual purchasing dialog of shareit does not support entering of hardware id, but we can configure it! There are 2 special unnamed fields that we can enable in purchasing dialog, its are ADDITIONAL1 and ADDITIONAL2. In the shareit control we need to enable ADDITIONAL1 field and set it's text - Hardware ID. This field should be required. After this, we made possibility to enter hardware id to the shareit purchasing dialog.
In the keygen we setup that key should be hardware locked and hardware id is placed in the ADDITIONAL1 field.
kg.UseHardwareLocking := true; - key should be hardware locked.
kg.HardwareID := pointer(HardwareId); - set pointer to the hardware id string.

Finally, how it works:

  • User gets DEMO version of your application (protected with the same project as FULL version).
  • User decided to purchase you software and is going to the shareit purchasing page.
  • Shareit asked user to enter own hardware id. User opens DEMO version (that shows hardware it), and copy-paste it.
  • Shareit gets this hardware id and uses it for generating registration key.
  • Then we should let user know where to get FULL version. For example, this information we may setup in shareit control panel, this information will be shown to user after successful purchasing together with the registration key.
  • User downloads/installs/run FULL version, it asks for registration name and key, user enters the registration name that was entered in shareit purchasing dialog and registration key that was generated with our keygen.
  • Everything is done and everything is automated!

Download Example

Send Keygen to ShareIt!

After keygen for the project has been created we have to send it to shareit support team and ask to enable this keygen for our account. Email address on that should be sent email is authors@shareit.com I will explain a little what should contain this email:

  • Information about your shareit account (how is account owner, account number).
  • Few words that we are asking about adding keygen and unique shareit numbers of the software(s) for that this keygen will work.
  • Attached keygen: keygen.exe (example.exe), keygen.dll (and project.enigma if you are using generation with project file).
  • Need to explain what files keygen is using: keygen.dll (and project.enigma if you are using generation with project file).
  • What encoding can be used for keys generating. For now, keygen does NOT support UTF-8 encoding.

When shareit team replies that keygen was applied, just for testing (to be sure that all is working well) make a test order from the shareit control panel.

Some missed words FYI

In the previous topic I wrote that UTF-8 is not supported, really, it can be done! You may send input parameter RegInfo for keygen.dll not as ansi string like were using in the above examples, but in wide char mode (unicode), remember, RegInfoLen should be in 2 times greater for unicode string than length if ansi, it is due to ansi string uses one byte for one symbol conversion but unicode - 2 bytes per each symbol. Then, key check function EP_RegCheckAndSaveKey, or EP_RegCheckKey should have RegName parameter in unicode style too.
Second idea, I explain how to generate registration key as string, but shareit gives us possibility to generate text files with the key also.
All of the examples are using crypted sections, but if you do not need to use it - eliminate these strings from the keygen, remember, if you use crypted sections for the key - it becomes larger.

Downloads:
Simple Keygen
Keygen from Project File
Keygen with Expiration Date 1
Keygen with Expiration Date 2
Keygen with Expiration Date 3
Keygen with Hardware ID

If you have any suggestions/comments you may post it in out support forum Forum: Automatic Keygen for Shareit!
This article is written for educational purposes only. The author does not carry any warranties/liability for using this information.
Author: Vladimir Sukhov
Date: 3 March 2009