Skip to Content
Nueva versión 12 disponible 🎉
ObfuscatorCifrado de códigoCifrado de código vinculado a la licencia

Cifrado de código vinculado a la licencia

El cifrado de código vinculado a la licencia es una variante del código protegido por contraseña en la que la contraseña que desbloquea un método cifrado no es una constante fija incluida en la compilación, sino un valor leído de la licencia del cliente en tiempo de ejecución.

El método protegido sigue distribuyéndose dentro del ensamblado ofuscado, pero su código permanece cifrado hasta que una licencia válida aporta la contraseña correcta. Así, una función sensible o premium solo se ejecuta para los usuarios cuya licencia la autoriza, mientras que el resto de la aplicación sigue funcionando con normalidad para todos los demás.

Este es el patrón que Babel Obfuscator usa internamente para restringir sus propias funciones con licencia. Se apoya en el cifrado de código habitual que ya conoce: no hay nada nuevo que instalar, solo hay que escribir una regla y un pequeño hook.

Cómo funciona

  1. Marcar el código que se va a proteger. Una regla XML (o el atributo Obfuscation) selecciona los métodos o los tipos que se cifran y les asigna un nombre de origen y una contraseña, manteniendo el código cifrado dentro del ensamblado (Internal = true).
  2. Proporcionar un hook de obtención de contraseña. Un método marcado con [Obfuscation(Feature = "msil encryption get password")] recibe el nombre del origen y devuelve la contraseña de ese origen leyendo un campo de la licencia cargada.
  3. Ejecutar. Cuando se llama por primera vez al método protegido, la máquina virtual de Babel (BVM) invoca el hook para obtener la contraseña del origen. Si la licencia contiene el campo esperado, el método se descifra y se ejecuta; si el campo falta o el valor es incorrecto, el descifrado falla y el método no puede ejecutarse, de modo que la función queda bloqueada en la práctica.

Solo los métodos que coinciden con una regla que tiene un <Source> quedan vinculados a la licencia. Los métodos cifrados con --msilencryption sin más (sin origen) se desbloquean desde el propio ensamblado y siguen ejecutándose sin licencia, por lo que la aplicación sin licencia continúa funcionando: solo se retienen las funciones restringidas por la licencia.

Cifrar el código

Añada una regla que cifre el código sensible y lo vincule a un origen con nombre y a una contraseña:

<Rule name="encrypt premium" feature="msil encryption" exclude="false"> <Target>Methods</Target> <Pattern>ACME.Premium::*</Pattern> <Properties> <Source>premium</Source> <Password>Xa9!k2$LpQ7r</Password> <Internal>true</Internal> </Properties> <Description>Encrypt the premium feature, unlocked by the license.</Description> </Rule>

Lo mismo puede expresarse en línea con el atributo Obfuscation:

[Obfuscation(Feature = "msil encryption:internal=true;source=premium;password=Xa9!k2$LpQ7r", Exclude = false)] internal class Premium { public string Run() => "premium result"; }

El <Password> que define en tiempo de compilación debe coincidir con el valor que el hook de obtención de contraseña devuelve para ese origen en tiempo de ejecución. En un diseño vinculado a la licencia el hook lee ese valor de la licencia, así que guarde el mismo valor en el campo de la licencia que emite para sus clientes.

Leer la contraseña de la licencia

Declare un único hook que asocie un nombre de origen con la contraseña guardada en la licencia. El ejemplo siguiente usa Babel Licensing para buscar una función con licencia y devolver su valor:

[Obfuscation(Feature = "msil encryption get password")] internal static string GetSourcePassword(string source) { var license = LicenseManager.Instance.License; var feature = license.Features.FirstOrDefault(f => f.Name == source); if (feature == null) throw new ApplicationException($"feature '{source}' is not licensed"); return Encoding.UTF8.GetString(feature.Data); }

En tiempo de ejecución la BVM llama a GetSourcePassword("premium"); el hook devuelve la contraseña almacenada en la licencia del cliente, y el método premium se descifra y se ejecuta.

El hook debe ser accesible para el código que Babel inyecta, así que declárelo public o internal. Si lo deja como private o protected, Babel lo amplía automáticamente a internal durante la ofuscación (nunca lo hace público), para que el código inyectado pueda llamarlo.

Para ver una implementación completa y ejecutable, con la clase LicenseManager y la forma de emitir licencias por edición, consulte el ejemplo Licencias basadas en funciones.

Funciona con todos los métodos de entrega de licencias

Como el hook se limita a leer del objeto de licencia cargado, el cifrado de código vinculado a la licencia no depende de cómo llega esa licencia a la aplicación. Funciona sin cambios con todos los métodos de entrega de Babel Licensing:

Sea cual sea la modalidad que elija, una vez que su código de gestión de licencias ha validado y cargado la licencia, el hook de obtención de contraseña puede leer el campo que necesita y la función protegida se desbloquea.

¿Prefiere mantener el código cifrado completamente fuera del ensamblado principal? Combine este patrón con Archivos de código externos para desplegar el método cifrado junto con la licencia.

Last updated on