Subscription License with Encrypted Pro Code
A time-limited subscription license with a grace period, where the subscription-only code is protected with Babel Obfuscator Code Encryption.
Subscriptions need two behaviors that a plain expiry date does not give you: a grace period so paying customers are not cut off the instant a renewal is late, and enforcement that cannot be bypassed by editing a config file. This example does both, and ties the premium (“pro”) functionality to the subscription with Code Encryption: the pro method only runs while the subscription — including its grace window — is valid, because the Babel Virtual Machine gets its decryption password from the license.
Code Example
git clone https://github.com/babelfornet/subscription-license-console-example.gitProSuite is a console application with a free basic feature and an encrypted pro feature;
LicenseGenerator mints subscription licenses with configurable duration and grace.
Two Dates: Renewal and Hard Cutoff
The license carries two dates:
- the engine-enforced
ExpireDate, set to the end of the grace period (the hard cutoff), and - a soft
subscription-endfield marking when renewal is due.
DateTime subscriptionEnd = now.AddDays(days); // soft end — renewal due
DateTime hardCutoff = subscriptionEnd.AddDays(grace); // engine-enforced end of grace
var license = new StringLicense { ExpireDate = hardCutoff };
license
.ForAssembly(assemblyFullName)
.WithUniqueId("SUBSCR-")
.WithHardwareKey(HardwareId.Create().ToMachineKey())
.WithField(Secrets.SubscriptionEndField, subscriptionEnd.ToString("O"))
.WithField(Secrets.ProSource, Secrets.ProPassword.Encrypt(Secrets.FieldSecret))
.LicensedTo("Demo Customer", "demo@example.com", "ACME Corp");Babel Licensing rejects the license automatically once ExpireDate has passed, so the hard
cutoff needs no code of its own. The application only has to distinguish active from in
grace, which it does by comparing the soft subscription-end field to the current time:
var now = DateTime.UtcNow;
if (subEnd.HasValue && now > subEnd.Value)
{
int graceDaysLeft = (int)Math.Ceiling(((license.ExpireDate ?? now) - now).TotalDays);
return new SubscriptionStatus(SubscriptionState.Grace, subEnd, graceDaysLeft,
$"Subscription lapsed — grace period active ({graceDaysLeft} day(s) left). Please renew.");
}The Encrypted Pro Feature
The pro method is encrypted; its password comes from the license through the get password
hook. That is what ties the encrypted code to the subscription: while the license validates
(active or in grace) the hook returns the password and the method runs; once the hard cutoff
passes, Validate() throws and the hook can no longer supply the password.
[Obfuscation(Feature = "msil encryption:internal=true;source=pro;password=Pr0-Su1te-2026-K3y", Exclude = false)]
public static string Forecast(double[] series) { /* premium analytics */ }
[Obfuscation(Feature = "msil encryption get password")]
internal static string GetSourcePassword(string source)
{
var license = Validate(); // throws once past the end of grace
var field = license.Fields.FirstOrDefault(f => f.Name == source)
?? throw new InvalidOperationException($"License does not grant source '{source}'.");
return field.Value.Decrypt(Secrets.FieldSecret);
}Running It
# Build in Release — Babel encrypts Pro.Forecast.
dotnet build src/ProSuite/ProSuite.csproj -c Release
# Mint a subscription license: active for 30 days, 7-day grace.
dotnet run --project src/LicenseGenerator -- --days 30 --grace 7
cp ProSuite.lic src/ProSuite/bin/Release/net8.0/
dotnet src/ProSuite/bin/Release/net8.0/ProSuite.dllRe-mint the license to walk through every state:
dotnet run --project src/LicenseGenerator -- --days -2 --grace 7 # lapsed, in grace
dotnet run --project src/LicenseGenerator -- --expired # past grace| State | Condition | Pro feature |
|---|---|---|
| Active | before the subscription end | runs |
| Grace | past the subscription end, before the hard cutoff | runs, with a renewal warning |
| Expired | past the hard cutoff | locked — the BVM cannot decrypt it |
Past the grace period the application proves the point by trying to call the pro method anyway:
Subscription expired: License expired
Basic average: 13.63
Pro forecast is locked. Renew your subscription to restore access.
(proof) encrypted Pro.Forecast blocked: License expiredFor recurring billing, the same license is normally issued and renewed by the Babel Licensing Service, which can shorten the validity window and push renewals automatically. The offline file license shown here is the simplest way to demonstrate the active / grace / expired transitions.
keys.pem and the passwords in the sample are for demonstration only. Keep the RSA private key
offline and issue licenses from the vendor side; only the public key ships with the application.