Trial Serial License

Trial licenses allow software vendors to offer time-limited trial versions of their applications to potential customers.

In this article, we will explore the concept of Trial Serial Licenses and demonstrate its implementation through a sample console application. The provided code showcases how to create a trial license that expires after a certain number of days and limits the number of runs allowed. Additionally, it demonstrates the usage of encryption techniques to protect sensitive code that is only executed if the license is valid. By understanding the Trial Serial License model and examining the accompanying code, developers can gain valuable insights into leveraging Babel Licensing for implementing trial versions of their software products.

Code Example

To access the code for the TrialLicense project and explore it further, you can clone the repository from GitHub using the following command:

git clone https://github.com/babelfornet/trial-license-string-console-example.git

The TrialLicense project provides a practical demonstration of implementing a trial license system using Babel Licensing within a console application. By cloning the repository, you will have access to the complete source code, allowing you to delve into the implementation details, examine the different components, and explore the functionalities of the trial licensing system.

Once you have built the solution in the Debug configuration, run the obfuscate.babel project file inside the solution folder using the Babel UI to protect the application and encrypt the code. The password-encrypted code can only be executed with a valid serial which contains the password to decrypt and access the code.

To start the application, double-click on the "TrialLicense.exe" file located inside the Debug folder. This will initiate the execution of the application.

Trial License Generation

The following code is responsible for generating a trial license serial:

string hardwareKey = HardwareId.Create().ToMachineKey();

var sign = (RSASignature)Pem.ReadSignature("Keys.pem");

var lic = new StringLicense()       // Create a new string license
   .ForAssembly(Assembly.GetExecutingAssembly()) // The license is for this assembly
   .WithUniqueId()                 // Unique ID for the license
   .WithHardwareKey(hardwareKey)   // Lock to the current machine
   .WithTrialDays(2)               // Give 2 days trial
   .WithMaximumRunCount(3)         // Allow 3 runs
   .WithField("source1", "p@ssw0rd1".Encrypt("!sEcr3tp@sswOrD!"))  // Set the encrypted code password            
   .SignWith(sign);                // Sign the license with the private key

// Convert the license object to an ASCII string
string serial = lic.ToReadableString("ASCII");

Here's a breakdown of its functionality:

  1. HardwareId.Create().ToMachineKey() generates a hardware-specific key that uniquely identifies the current machine. This key is used to lock the trial license to the current machine.

  2. (RSASignature)Pem.ReadSignature("Keys.pem") reads the RSA private key from the "Keys.pem" file. This key is used to sign the license and validate its authenticity.

  3. new StringLicense() creates a new instance of the StringLicense class, representing the trial license.

  4. .ForAssembly(Assembly.GetExecutingAssembly()) specifies that the license is associated with the current assembly.

  5. .WithUniqueId() generates a unique identifier for the license.

  6. .WithHardwareKey(hardwareKey) locks the license to the current machine by associating it with the hardware key generated at point 1.

  7. .WithTrialDays(2) sets the trial period to 2 days, indicating that the license will expire after this duration.

  8. .WithMaximumRunCount(3) sets the maximum number of runs allowed for the trial version to 3.

  9. .WithField("source1", "p@ssw0rd1".Encrypt("!sEcr3tp@sswOrD!")) adds a field named "source1" to the license and sets its value to an encrypted password. This password will be used to decrypt specific code execution when the license is valid.

  10. .SignWith(sign) signs the license with the RSA private key obtained in step 2, ensuring its integrity and authenticity.

  11. lic.ToReadableString("ASCII") converts the license object into an ASCII string representation.

  12. The resulting license serial is stored inside the registry, along with the public key used for validation.

This code demonstrates the process of generating a trial license serial, including securing it with encryption and storing it in the registry. The trial license can be validated using the corresponding public key to ensure its authenticity and enforce trial restrictions, such as trial duration and run limits.

Trial License Validation

The following code snippet demonstrates a practical implementation of this process. It utilizes Babel Licensing to perform the trial serial validation.

using var reg = Registry.CurrentUser.OpenSubKey(RegistryKey);
string serial = Convert.ToString(reg?.GetValue("Serial"));

// Get the public key from the key to validate the license signature
string publicKey = Convert.ToString(reg?.GetValue("Key")).Decrypt("pk_p@sswOrd");

var manager = new StringLicenseManager();

// The public key is used to validate the license signature
manager.SignatureProvider = RSASignature.FromKeys(publicKey);

// Validate the serial
// A license object is returned if the serial is valid and all license restrictions are met
Babel.Licensing.ILicense license = manager.Validate(serial);

Console.WriteLine("Serial {0} is valid", license.Id);
var trial = license.Restrictions.OfType<TrialRestriction>().FirstOrDefault();

if (trial != null)
{
   Console.WriteLine("Trial time left: {0}", trial.TimeLeft);
   Console.WriteLine("Runs left: {0}", trial.RunCountLeft);
}

Here, the public key used to validate the license signature is retrieved from the registry. The value associated with the "Key" key is obtained, and the "pk_p@sswOrd" decryption password is used to decrypt the stored value.

An instance of the StringLicenseManager class is created to manage the license validation process. The SignatureProvider property of the manager is set to an RSASignature object created from the retrieved public key. This sets up the manager to use the public key for validating the license signature.

Babel.Licensing.ILicense license = manager.Validate(serial);

The manager.Validate(serial) method is called to validate the license. The license serial stored in the serial variable is passed as an argument. If the serial is valid and meets all the license restrictions, a license object implementing the Babel.Licensing.ILicense interface is returned. It represents the validated license.

Finally, the remaining trial time and the number of runs left are then printed to the console.

Overall, this code validates a license serial by retrieving the serial and public key from the registry, configuring the license manager with the public key, and calling the validation method. It then displays the validation result and any relevant license information, such as trial time and run count, if applicable.

Execution of Encrypted Code

The provided code segment showcases the execution of encrypted code and how it can be retrieved using Babel Obfuscator. Let's examine how this code operates:

Firstly, there are two methods involved:

[Obfuscation(Feature = "msil encryption get password", Exclude = false)]
internal static string GetEncryptedCodePassword(string source)
{
    return EncryptedGetEncryptedCodePassword(source);
}

[Obfuscation(Feature = "msil encryption", Exclude = false)]
private static string EncryptedGetEncryptedCodePassword(string source)
{
    using var reg = Registry.CurrentUser.OpenSubKey(RegistryKey);
    string serial = Convert.ToString(reg?.GetValue("Serial"));

    // Get the public key from the key to validate the license signature
    string publicKey = Convert.ToString(reg?.GetValue("Key")).Decrypt("pk_p@sswOrd");

    var manager = new StringLicenseManager();

    // The public key is used to validate the license signature
    manager.SignatureProvider = RSASignature.FromKeys(publicKey);

    // Validate the serial
    // A license object is returned if the serial is valid and all license restrictions are met
    Babel.Licensing.ILicense license = manager.Validate(serial);

    // Reuse the same secret used to decrypt the code password
    return license.Fields.First(item => item.Name == source).Value.Decrypt("!sEcr3tp@sswOrD!");
}

The GetEncryptedCodePassword method serves as an entry point to retrieve the encrypted code password. It calls the EncryptedGetEncryptedCodePassword method, passing a source value as a parameter. The purpose of this method is to extract the encrypted code password associated with the provided source from the license. Please refer to Babel Obfuscator Code Encryption to learn more about encrypted code with a password.

Inside EncryptedGetEncryptedCodePassword, the following steps occur:

  1. The code retrieves the license serial and the corresponding public key from the registry.

  2. The public key is decrypted using the password "pk_p@sswOrd".

  3. A StringLicenseManager instance is created to validate the license using the decrypted public key.

  4. The license is validated by passing the serial to the Validate method of the manager.

  5. If the serial is valid and meets all license restrictions, a license object is returned.

  6. The encrypted code password associated with the specified source is retrieved from the license fields.

  7. Finally, the encrypted password is decrypted using the secret "!sEcr3tp@sswOrD!" and returned.

Furthermore, Babel Obfuscator is used to obfuscate and encrypt the code. The obfuscation features used are:

  1. For the ExecuteEncryptedCode method:

[Obfuscation(Feature = "msil encryption:source=source1;password=p@ssw0rd1;internal=true", Exclude = false)]
private void ExecuteEncryptedCode()
{
    Console.WriteLine("Encrypted code running");
}

The msil encryption feature is applied with the specified source ("source1"), encryption password ("p@ssw0rd1"), and internal set to true. This obfuscation ensures that the code within this method is encrypted and protected.

By combining these components, the encrypted code password can be retrieved from the license using Babel Obfuscator. The validated password allows for the decryption and execution of the encrypted code within the ExecuteEncryptedCode method, providing a secure and controlled execution environment for sensitive code sections.

Last updated