Lizenzgebundene Codeverschlüsselung
Machen Sie eine geschützte Funktion kryptografisch von einer gültigen Lizenz abhängig, indem Sie das Passwort der Codeverschlüsselung in der Lizenz selbst ablegen.
Eine boolesche Lizenzprüfung wie if (!IsLicensed) return; lässt sich leicht herauspatchen. Dieses Beispiel
zeigt ein stärkeres Muster: Die sensible Methode wird mit der
Codeverschlüsselung von Babel Obfuscator verschlüsselt, und das Passwort, das die Babel Virtual
Machine (BVM) zu ihrer Ausführung braucht, steht gar nicht in der Binärdatei. Es liegt, selbst verschlüsselt, in einer
signierten und hardwaregebundenen Babel-Lizenz. Die Lizenzprüfung zu entfernen genügt nicht: Ohne
gültige Lizenz gibt es kein Passwort, und ohne das Passwort lässt sich die verschlüsselte Methode weder
rekonstruieren noch ausführen.
Codebeispiel
git clone https://github.com/babelfornet/license-bound-encryption-console-example.gitDas Projekt ist eine plattformübergreifende .NET-Konsolenanwendung mit zwei Teilen: SecureApp, die
lizenzierte Anwendung, deren sensible Methode codeverschlüsselt ist, und LicenseGenerator, ein
Tool auf Herstellerseite, das signierte Lizenzen ausstellt. Die Version des Babel-Pakets ist zentral in
Directory.Build.props festgelegt, sodass das Beispiel die Version verwenden kann, die zu Ihrem Feed passt.
Die geschützte Methode
Das zu schützende geistige Eigentum ist eine einzige Methode. Das Attribut [Obfuscation] weist
Babel an, ihren Rumpf zu verschlüsseln und ihn in der Assembly (internal=true) unter dem Quellnamen
core abzulegen, mit einem Passwort, das beim Build verwendet wird:
[Obfuscation(Feature = "msil encryption:internal=true;source=core;password=C0re-Pr0tect!on-K3y", Exclude = false)]
public static long Compute(int a, int b)
{
long acc = 0;
for (int i = 1; i <= b; i++)
acc += (long)a * i;
return acc + 42;
}Die Codeverschlüsselung ist nur im Release-Build eingeschaltet und über eine
MSBuild-Eigenschaft in SecureApp.csproj auf die sensible Klasse begrenzt:
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<MsilEncryption Condition="'$(MsilEncryption)' == ''">SecureApp\.Secret::.*</MsilEncryption>
<BabelWarningsAsErrors>W00000</BabelWarningsAsErrors>
</PropertyGroup>Die Codeverschlüsselung läuft nur in der Konfiguration Release. Die Zeile BabelWarningsAsErrors macht
aus der Warnung W00000 des Evaluierungsmodus einen Fehler, sodass eine ungeschützte Assembly nie
versehentlich ausgeliefert werden kann.
Wo das Passwort liegt
Beim Build wird die Methode mit dem Passwort C0re-Pr0tect!on-K3y verschlüsselt. Zur Laufzeit
fragt die BVM die Anwendung über einen Hook get password nach diesem Passwort, bevor sie die
Methode ausführen kann. Statt einen fest codierten Wert zurückzugeben, validiert der Hook die Lizenz und liest das
Passwort aus ihr:
[Obfuscation(Feature = "msil encryption get password")]
internal static string GetSourcePassword(string source)
{
var license = Validate();
// The code password is carried by the license as an encrypted field.
var field = license.Fields.FirstOrDefault(f => f.Name == source)
?? throw new InvalidOperationException($"License does not grant source '{source}'.");
// Decrypt the field with the vendor secret to recover the real code password.
return field.Value.Decrypt(Secrets.FieldSecret);
}Validate() verwendet den eingebetteten öffentlichen RSA-Schlüssel, um die Signatur der Lizenz zu prüfen, und erzwingt
jede Einschränkung, einschließlich der Hardwarebindung:
public static ILicense Validate()
{
var manager = new StringLicenseManager
{
SignatureProvider = RSASignature.FromKeys(PublicKey)
};
return manager.Validate(File.ReadAllText(LicenseFilePath), typeof(Program));
}Die Lizenz ausstellen
Der LicenseGenerator auf Herstellerseite signiert eine Lizenz, die an die Assembly SecureApp und an
den aktuellen Rechner gebunden ist und das Codepasswort als verschlüsseltes Feld enthält. Das Passwort
erscheint daher nie im Klartext, weder in der Binärdatei noch in der Lizenzdatei:
string encryptedPassword = Secrets.CodePassword.Encrypt(Secrets.FieldSecret);
var license = new StringLicense()
.ForAssembly(assemblyFullName)
.WithUniqueId("SECURE-")
.WithHardwareKey(HardwareId.Create().ToMachineKey())
.WithField(Secrets.Source, encryptedPassword)
.LicensedTo("Demo Customer", "demo@example.com", "ACME Corp");
string serial = license.SignWith(signature).ToReadableString("ASCII");Der LicenseGenerator und der private RSA-Schlüssel (keys.pem) dienen nur der Demonstration. In
der Produktion stellt der Hersteller oder der
Babel Licensing Service die Lizenz aus, und der private Schlüssel wird
offline aufbewahrt. Mit der Anwendung wird nur der öffentliche Schlüssel ausgeliefert.
Ausführen
# Build the app in Release — this is when Babel encrypts Secret.Compute.
dotnet build src/SecureApp/SecureApp.csproj -c Release
# Generate a signed, machine-locked license.
dotnet run --project src/LicenseGenerator
# Deploy the license next to the app and run it.
cp SecureApp.lic src/SecureApp/bin/Release/net8.0/
dotnet src/SecureApp/bin/Release/net8.0/SecureApp.dllMit einer gültigen Lizenz läuft die geschützte Methode:
License OK : SECURE-8CCC8
Licensed to : Demo Customer
Bound to machine: ADSQH-89GGJ-J7CJY-3FQFK-DF48H
Protected computation Secret.Compute(7, 5) = 147
The encrypted method ran: the license unlocked the code.Wenn Sie SecureApp.lic entfernen oder manipulieren oder die Anwendung auf einem anderen Rechner ausführen, ist das Ergebnis
mehr als eine freundlichere Fehlermeldung: Der verschlüsselte Code kann schlicht nicht ausgeführt werden.
License INVALID : Invalid license signature
Protected computation blocked: Invalid license signature
Without a valid license the encrypted code cannot be decrypted or executed.Warum dies stärker ist
Weil das Passwort aus einer signierten Lizenz stammt, gewinnt ein Angreifer nichts, wenn er den
Validierungscode aus der Assembly entfernt: Die BVM hat weiterhin kein Passwort für die Quelle core, und
Secret.Compute bleibt ein undurchsichtiger, verschlüsselter Blob. Die Signatur verhindert, dass eine Lizenz gefälscht wird,
und die Hardwarebindung verhindert, dass eine rechtmäßige Lizenz auf einem anderen Rechner wiederverwendet wird. Dieselbe Technik
liegt dem Beispiel Funktionsbasierte Lizenzen und
den vom Hersteller gehosteten Lizenzvorlagen zugrunde, bei denen der Babel Licensing Service
das verschlüsselte Feld liefert und nicht ein lokaler Generator.