Code Encryption

Oct 13, 2020

Code encryption is a security measure that completely hides the internal structure of a method, thereby preventing the code from being revealed. Code encryption is one of the most valid protections when it comes to hiding the code. In this article, we will explain how code encryption can help protect your assemblies better and realize a feature-based licensed application.

At the moment, the feature MSIL Code Encryption is available with the Enterprise and Company editions for all application and software components running at least on .NET Framework 2.0 or any .NET platform ranging from .NET Core 3.1 to .NET 7. This feature is not available on .NET Standard, Xamarin or Mono Framework.

This example uses the Babel Licensing library Babel.License.dll. The Babel Licensing library is a software component that allows you to add licensing features to your software applications. This library is included in the Babel Obfuscator Company license, which means that customers who purchase this license have access to the Babel.License.dll component as part of their license. However, if you have the Babel Obfuscator Enterprise edition, you can also access a demo version of the Babel.License.dll component. This demo version provides limited features of the full component, allowing you to test the licensing functionality of your software.

If you look at a method inside a .NET assembly editor like dnSpy, you can almost see the original source code. Code encryption replaces the original method code with a single call to the Babel compiler, which compiles and executes the original method in a secure environment that completely hides the original code from any inspection tool. Consider the following method:

        public static void CreateLicense()
        {
            RSASignature rsa = RSASignature.CreateFromKeyFile("Keys.snk");
            string publicKey = rsa.ExportKeys(true);
            rsa.GenerateKeyInfo = true;

            string licenseKey = new XmlLicense()
                .WithUniqueId()
                .ForAssembly(typeof(Program).Assembly)
                .WithField("app", "s3cret P@sswOrD")
                .WithTrialDays(10)
                .SignWith(rsa)
                .ToReadableString();

            File.WriteAllText(LicenseFileName, licenseKey);
        }

The dnSpy tool can reconstruct the source code using only the assembly binary.

Once code encryption is enabled, the original source code of the method is replaced by a call to a Babel Compiler. As a result, the original code is completely gone. The Babel compiler transforms the source code of the method into a bytecode that is executed by the Babel Virtual Machine. By using code encryption, it becomes extremely difficult to reverse-engineer the code, as the original source code is no longer present in the software. This provides an additional layer of security to the software, making it harder for attackers to access sensitive information or intellectual property.

During the obfuscation process, the Babel Compiler replaces the original method code with instructions specifically generated for the Babel Virtual Machine. These instructions are then encrypted, making it much harder for potential attackers to reverse engineer or analyze the code. This encrypted code can only be executed by the Babel Runtime, which is included with the software.

One practical application of this feature is the creation of feature-based licenses. A feature-based license can contain either the encrypted code or a password to decrypt the code, allowing the user to access only the features for which they have purchased a license.

To better show how code encryption works consider the following .NET Console application, which generates and validate an XML license file with Babel Licensing. The example uses encrypted code with a password, which enables the creation of a license that contains the password required to decrypt the code and run the application.

To specify which code should be encrypted with a password, you can use either the Obfuscation attribute or an XML rule. In this example, the Obfuscation attribute is used for simplicity.

    // Encrypted code
    // This code is encrypted using a password sored inside the license file
    [Obfuscation(Feature = "msil encryption:Source=app;Internal=true;Password=s3cret P@sswOrD", Exclude = false)]
    class Application
    {
        public static void Run()
        {
            Console.WriteLine("Encrypted code running...");
            var lic = LicenseManager.License;

            if (lic.IsTrial)
            {
                var trial = lic.Restrictions.OfType<TrialRestriction>().FirstOrDefault();
                Console.WriteLine("Trial time left: {0:dd} days {0:hh} hours", trial.TimeLeft);
            }
        }
    }

The attribute is applied to the Application class making Babel use MSIL Code Encryption on every method inside the class. The feature string contains some MSIL Code Encryption feature properties we need to set so that babel can tag any encrypted method with a name (Source), keep the encrypted data internal to the assembly (Internal), and finally define a password for encrypting code.

msil encryption:Source=app;Internal=true;Password=s3cret P@sswOrD

The password will be used to encrypt all the methods inside the class. Without the password needed to decrypt and compile methods tagged with “app” source, the application cannot run. Now we need a mechanism to access the password when Babel Virtual Machine needs to execute the encrypted method. At runtime, when any method of the class Application is called, the Babel Virtual Machine will take over and issue a request to get the password for decrypting the method called. The receipt of the request is a method defined inside the assembly having the following declaration:

        [Obfuscation(Feature = "msil encryption get password", Exclude = false)]
        internal static string GetEncryptionPassword(string source)
        {
            return LicenseManager.License.Fields.First(item => item.Name == source).Value;
        }

It is crucial to have the method declared as internal or public, otherwise, Babel Virtual Machine will not be able to access the method. In this example, we will use a license file field to store the password. The field name will be the same tag name assigned to the encrypted method. The license file plays a central role in providing the decryption password. The advantages are that the application cannot run without the license file. You can extend the concept by encrypting different parts of your application using unique source tags and passwords. Partitioning the application this way will allow you to make feature-based licenses where every field is tied to a specific application functionality that cannot run without the proper password and license.

The complete source code of the discussed example is available to download here: CodeEncryption.zip. To build the solution, copy your Company license file inside the solution folder, then rebuild the Release configuration.

Pin It on Pinterest

Share This