Simple copy protection done right :)



  • Hi everybody,

    inspired by @Lindon's remarkable efforts to wrap a copy protection system into the user preset system, I decided to make a example project that uses an intermediate file in the app data folder for checking whether the plugin is authorised correctly.

    I slapped this together in about 30 minutes, so if you spot anything stupid let me know, but this project should get the most people started with a really simple copy protection scheme.

    https://github.com/christophhart/hise_tutorial/tree/master/SimpleCopyProtection



  • @Christoph-Hart make it a valid Javascript file by pretending
    I think that should read prepending 🙂



  • @Christoph-Hart You are awesome, thank you!!



  • @d-healey make a pull request 😉



  • World's fastest copy protection creating process (in 30 min.). Speedart 🙂 🙂



  • @Christoph-Hart thanks so much!



  • Light speed!!! Thanks !!!! 🙂



  • @Christoph-Hart said in Simple copy protection done right 🙂:

    Hi everybody,

    inspired by @Lindon's remarkable efforts to wrap a copy protection system....

    remarkable only in the level of doofus inability to work things out by me really....



  • "we use the Engine.dumpAsJSON() method to just store their entered serial to a file which is loaded every time the plugin is instanciated."

    The only additional thing I usually do is obfuscate this "number" - put it at random spots in a inside a 60 digit sequence - 9's complement - that sort of stuff... but that might be a little paranoid on my part.



  • @Lindon

    The only additional thing I usually do is obfuscate this "number"

    What purpose does that serve?



  • @d-healey it makes me feel good....☺

    Actually I dont store all the numbers in the interface - I use an formula to calc if the entered numbers are valid or not...Kontakt is so much easier to hack the (KSP) code so including the numbers was never really an option. HISE not so much of a problem. One more win for HISE...



  • @Lindon Any good hacker can hack everything. If you don't use advanced challenge system (that requires taking machine ID and checks / registers online status...etc) they can hack everything including live serial generation formula system... So, this Serial protection with formula system has the same risks with "Simple Copy Protection" solution...



  • @orange That's not the point of this.



  • @d-healey So, this Serial protection with formula system has the same risks with "Simple Copy Protection" solution...



  • @orange said in Simple copy protection done right 🙂:

    @d-healey So, this Serial protection with formula system has the same risks with "Simple Copy Protection" solution...

    This is not designed to be a super secure copy restriction system, it is designed as a sharing deterrent for regular none techy users.



  • @d-healey Yes I am saying the same thing 😉



  • Actually I dont store all the numbers in the interface - I use an formula to calc if the entered numbers are valid or not...Kontakt is so much easier to hack the (KSP) code so including the numbers was never really an option. HISE not so much of a problem. One more win for HISE...

    Yes, if you come up with a way to validate serials without storing strings in the binary, you solve a few issues of this approach:

    • if you run out of serials, you have to reencode the plugin (or choose a big enough serial amount in the first place)
    • smaller footprint and compile time (creating more than a few thousand strings will defer the plugin start for your user)

    There aren't too much security features in HISEScript, but you can use one of these tricks:

    • create the sum (poor man's hash) of the string character values and make sure it matches a rule you define.
    • disallow certain characters
    • any kind of cheap encryption algorithm should be enough.

    This function can be used to create a "hash" from a string:

    const var s = "ABCD";
    
    var x = 0;
    
    inline function createHash(text)
    {
        local sum = 0;
        
        for(i = 0; i < text.length; i++)
        {
            sum += text.charCodeAt(i);
        }
        
        return sum;
    }
    
    x = createHash(s);
    


  • with hise 1.6 it crash
    hise 2.00 nothing to see in the interface.

    "Interface:! onControl could not be parsed!"

    normal ?



  • @staiff in
    Use the latest (updated today) HISE version.
    Use Authorisation.js code with Content.makeFrontInterface like below. Also don't forget to include("Serials.js") to make the function check. All of the UI elements will be activated. I tried and compiled a plugin, it works likea charm. It creates "RegistrationInfo.js" in User presets main folder. Interface code example is this;

    Content.makeFrontInterface(600, 500);
    
    
    include("Serials.js");
    
    
    
    namespace Authorisation
    {
        const var SerialInput = Content.getComponent("SerialInput");
        const var Description = Content.getComponent("Description");
        const var SerialStateLabel = Content.getComponent("SerialStateLabel");
        const var AuthorisationDialogue = Content.getComponent("AuthorisationDialogue");
        const var GlobalMute = Synth.getMidiProcessor("GlobalMute");
        
        /** Checks if the serial input is valid and stores the result if successful. */
        inline function onSubmitButtonControl(component, value)
        {
            if(!value) // Just execute once
                return;
        
            local v = SerialInput.getValue();
            Console.print(v);
    	
            // Checks if it's in the input
            if(serials.Data.contains(v))
            {
                Console.print("Serial number found");
            
                local data = 
                {
                    "Serial": v
                };
            
                // Stores the file to the hard drive. In HISE it will be the project folder
                // but in the compiled plugin it will use the parent directory to the 
                // user preset directory (which is usually the app data folder).
                Engine.dumpAsJSON(data, "../RegistrationInfo.js");
                
                setValidLicense(true);
            }
            else
            {
                Console.print("Invalid serial number");
                Description.set("text", "Invalid serial number. The number you supplied does not match");
                
                setValidLicense(false);
            }
        };
    
        Content.getComponent("SubmitButton").setControlCallback(onSubmitButtonControl);
    
    
        inline function setValidLicense(isValid)
        {
            // Do whatever you want to do here. I suggest a MIDI muter...
            GlobalMute.setAttribute(0, 1 - isValid);
        
            if(isValid)
            {
                // Change this to any other visual indication...
                SerialStateLabel.set("bgColour", Colours.greenyellow);
                AuthorisationDialogue.set("visible", false);
            }
            else
            {
                SerialStateLabel.set("bgColour", Colours.red);
                AuthorisationDialogue.set("visible", true);
            }
        }
    
        inline function checkOnLoad()
        {
            // Clear the input
            SerialInput.set("text", "");
            
            // Load the serial from the stored file
            local pData = Engine.loadFromJSON("../RegistrationInfo.js");
            Console.print("Checking serial");
        
            if(pData)    
            {
                local v = pData.Serial;
                Console.print("Restored serial: " + v);
            
                if(serials.Data.contains(v))
                {
                    setValidLicense(true);
                    return;
                }
            }
        
            setValidLicense(false);
        }
    
        // Call this on startup
        checkOnLoad();
    
    }
    


  • Yes you need today's HISE version, I changed the behaviour of the Engine.loadJSON() method to return undefined instead of throwing an error (which will be the default case if the file wasn't written yet).


 

2
Online

400
Users

1.3k
Topics

9.4k
Posts