HISE Logo Forum
    • Categories
    • Register
    • Login

    build failed with copy protection enabled

    Scheduled Pinned Locked Moved Bug Reports
    15 Posts 5 Posters 1.2k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ustkU
      ustk
      last edited by

      I see that it dynamic_cast the frontend proc, does it mean it shouldn't be enabled for Hise but only for frontend build?

      Can't help pressing F5 in the forum...

      1 Reply Last reply Reply Quote 0
      • Christoph HartC
        Christoph Hart @ustk
        last edited by

        @ustk You don't need to define those preprocessors when building HISE, just put them in your project_info.xml. HISE itself has a dedicated "development" unlocker class.

        So basically the procedure is:

        1. Define USE_SCRIPT_COPY_PROTECTION (add it as ExtraDefinition) (you actually don't need to define the other one, it gets defined automatically when you define.
        2. Create a RSA key file (Tools -> Create RSA Key, then Save to file). This is important and the build process will fail without this step. The public key will be embedded into HISE, the private key must lie on your server that generates the key file.
        3. Use the script unlocker class and its methods (I'll probably need to make a minimal example project here, as there might be a few things that are not self explanatory), but basically you create an instance, then ask unlocker.isUnlocked() and if not, call your server and fetch a key file that you then apply with unlocker.writeKeyFile().
        ustkU 2 Replies Last reply Reply Quote 3
        • ustkU
          ustk @Christoph Hart
          last edited by ustk

          @christoph-hart Much clearer, thanks! I'll see if I can get on with the productCheckFunction once the first bit works

          Can't help pressing F5 in the forum...

          Christoph HartC 1 Reply Last reply Reply Quote 0
          • Christoph HartC
            Christoph Hart @ustk
            last edited by

            @ustk You don't need to define that function, the default will just compare the product name against the one in your key file (I removed the version number as default check), so unless you want some custom checks (eg. invalidate license key files with version upgrades, etc), leave that one alone :)

            ustkU 1 Reply Last reply Reply Quote 1
            • ustkU
              ustk @Christoph Hart
              last edited by

              @christoph-hart Ok so I get weird things... Maybe you could just add a minimal project in the tutorial repo?

              Can't help pressing F5 in the forum...

              1 Reply Last reply Reply Quote 3
              • Matt_SFM
                Matt_SF
                last edited by

                @Christoph-Hart would be nice indeed ! +1 🙂

                Develop branch
                Win10 & VS17 / Ventura & Xcode 14. 3

                1 Reply Last reply Reply Quote 0
                • ustkU
                  ustk @Christoph Hart
                  last edited by

                  @Christoph-Hart So I finally got the unlocker to work. I'm not yet ready to create the file server side, so for now I fake it in Hise using a dummy license file.
                  Though something seems weird with the license system, but chances are it is me not understanding.

                  When a license file is created, it is created from the RSA pair (that is the same for all instances/installation).
                  So what prevent anyone to share the file? I don't imagine it is the non-crypted part, but the crypted part that should contain customer info. But how do you decrypt it? I tried several thing including online tools using the RSA pair with no luck...

                  Can't help pressing F5 in the forum...

                  Christoph HartC 1 Reply Last reply Reply Quote 0
                  • Christoph HartC
                    Christoph Hart @ustk
                    last edited by

                    @ustk The license file embeds a machine identification so it can only be used on the system that created the file. Your responsibility on the server side is to write a method that takes this information and returns a key file. We're using it in the current project and the activation function looks more or less like this:

                    inline function activationAttempt()
                    {	
                    	local parameters = {};
                    	
                    	parameters.email = Content.getComponent("emailInput").get("text");
                    	parameters.machineID = FileSystem.getSystemId();
                    	parameters.version = Engine.getVersion();
                    	parameters.OS = Engine.getOS();
                    	parameters.productID = "Our Funky Product";
                    	parameters.serial = Content.getComponent("serialInput").get("text");
                    	
                            // Your server must implement this function and either return an error string or the encrypted key file using the same RSA key as embedded into the plugin
                    	Server.callWithPOST("activate", parameters, onServerActivate);
                    	
                    	return false;
                    }
                    
                    function onServerActivate(status, obj)
                    {
                    	if(status != 200)
                    	{
                                   // obj is an error string
                    		Console.print(obj);
                    	}
                    	else
                    	{
                                    // obj is the key file content
                    		unlocked = ul.writeKeyFile(obj);
                    		
                    		if(unlocked)
                    		{
                    			Console.print("Nice");
                    		}
                    		else
                    		{
                    			Console.print("SUPER CRITICAL ERROR. WHY");
                    		}
                    	}
                    }
                    

                    The beauty of this is you don't need to decrypt anything manually, this is done all by the system (the public RSA key for decrypting the content gets mangled into the plugin binary).

                    ustkU 1 Reply Last reply Reply Quote 1
                    • ustkU
                      ustk @Christoph Hart
                      last edited by ustk

                      @Christoph-Hart Easier than I thought, so it is already working :)
                      Well, still the server side to to create the license file, which is not a small rock to move...

                      Can't help pressing F5 in the forum...

                      Christoph HartC 1 Reply Last reply Reply Quote 0
                      • Christoph HartC
                        Christoph Hart @ustk
                        last edited by Christoph Hart

                        @ustk I've posted a PHP snipped on the JUCE forum which you can use as starting point:

                        <?php
                        /** PHP script that creates an unlock file for the Tracktion Marketplace Status. */
                        /** Variables */
                        $PRODUCT_ID = "YOUR PRODUCT";
                        $EMAIL = "YOUR EMAIL";
                        $USER = "YOUR NAME";
                        $DATE = date("j M Y g:i:sa");
                        $MACHINE = "BYPASS";
                        $TIME = dec2hex(round(microtime(true)*1000));
                        
                        $PRIVATE_KEY_PART_1 = "742ccf57e16f84bb"; // These are stupid 64bit keys for developing, but it should run with big keys too...
                        $PRIVATE_KEY_PART_2 = "ae4337057c0e3f6f";
                        
                        header('Content-Description: File Transfer');
                        header('Content-Type: text/plain');
                        header('Content-Disposition: attachment; filename='.$PRODUCT_ID.'.licence');
                        header('Content-Transfer-Encoding: UTF-8');
                        header('Expires: 0');
                                
                        /** Helper Functions */
                        function dec2hex($number)
                        {
                            $hexvalues = array('0','1','2','3','4','5','6','7',
                                       '8','9','a','b','c','d','e','f');
                            $hexval = '';
                             while($number != '0')
                             {
                                $hexval = $hexvalues[bcmod($number,'16')].$hexval;
                                $number = bcdiv($number,'16',0);
                            }
                            return $hexval;
                        }
                        
                        include ('Math/BigInteger.php');  // get this from: phpseclib.sourceforge.net
                        function applyToValue ($message, $key_part1, $key_part2)
                        {
                            $result = new Math_BigInteger();
                            $zero  = new Math_BigInteger();
                            $value = new Math_BigInteger (strrev ($message), 256);
                            $part1 = new Math_BigInteger ($key_part1, 16);
                            $part2 = new Math_BigInteger ($key_part2, 16);
                            while (! $value->equals ($zero))
                            {
                                $result = $result->multiply ($part2);
                                list ($value, $remainder) = $value->divide ($part2);
                                $result = $result->add ($remainder->modPow ($part1, $part2));
                            }
                            return $result->toHex();
                        }
                        
                        // Create the comment section
                        echo "Keyfile for ", $PRODUCT_ID, "\n";
                        echo "User: ", $USER, "\n";
                        echo "Email: ", $EMAIL, "\n";
                        echo "Machine numbers: ", "\n";
                        echo "Created: ", $DATE, "\n";
                        echo "\n";
                        // Create the XML 
                        $dom = new DOMDocument("1.0", "utf-8");
                        $root = $dom->createElement("key");
                        $dom->appendChild($root);
                        $root->setAttribute("user", $USER);
                        $root->setAttribute("email", $EMAIL);
                        $root->setAttribute("mach", $MACHINE);
                        $root->setAttribute("app", $PRODUCT_ID);
                        $root->setAttribute("date", $TIME);
                        $XML_STRING = $dom->saveXML();
                        $ENCRYPTED_XML = "#" . applyToValue($XML_STRING, $PRIVATE_KEY_PART_1, $PRIVATE_KEY_PART_2);
                        $XML_DATA = chunk_split($ENCRYPTED_XML, 70);
                        echo $XML_DATA;
                        ?>
                        

                        But if anyone is motivated to do a .js version (or whatever server language is the cool kid as we speak), it might be better than this ugly hack.

                        ustkU 1 Reply Last reply Reply Quote 2
                        • ustkU
                          ustk @Christoph Hart
                          last edited by

                          @Christoph-Hart Yeah thanks, I remember you posted this on the Juces forum, thanks!

                          Can't help pressing F5 in the forum...

                          1 Reply Last reply Reply Quote 0
                          • P
                            parabuh
                            last edited by

                            Hey, any of you managed to write working code in node?

                            I'm not good in backend but I made something like this

                            import {create} from 'xmlbuilder2'
                            import bigInt from 'big-integer'
                            
                            const PRODUCT_ID = "PRODUCT NAME"
                            const EMAIL = "user@example.com"
                            const USER = "user"
                            const MACHINE = "XXXXXXX"
                            
                            
                            class RSAKey {
                                constructor(key) {
                                    const keys = key.split(',');
                            
                                    this.k1 = this.toHex(keys[0])
                                    this.k2 = this.toHex(keys[1])
                                }
                            
                                toHex(str) {
                                    let result = '';
                                    for (let i = 0; i < str.length; i++) {
                                        result += str.charCodeAt(i).toString(16);
                                    }
                                    return result;
                                }
                            
                                applyToValue(message) {
                            
                                    let result = bigInt.zero
                                    const zero = bigInt.zero
                                    const value = bigInt(message, 256)
                                    const key1 = bigInt(this.k1)
                                    const key2 = bigInt(this.k2)
                            
                                    result = key2.multiply(result);
                                    const {quotient, remainder} = value.divmod(key2)
                                    result = result.add(remainder.modPow(key1, key2))
                            
                                    return result.toString(16);
                                }
                            }
                            
                            const root = create({version: '1.0'})
                                .ele('key')
                                .att("user", USER)
                                .att("email", EMAIL)
                                .att("mach", MACHINE)
                                .att("app", PRODUCT_ID)
                            
                            
                            const xml = root.end()
                            
                            const rsa = new RSAKey('2c69e2b65085061fc4ecc0f48523d1cf8ae55e1ea2aa111cef8d766273d5850539914c0e48ce199904611ec7a6eff1bf167f5aa70bf05e03213945a3538b81fd,6f08b6c7c94c8f4f6c4fe2634cd98c86db3d6b4c96a92ac856e1a7f62195cc8e6b17a6c7c50ee2b8bfb59e7e3dffd752917d328e52019f337488beac3f545b5f');
                            
                            const result = rsa.applyToValue(rsa.toHex(xml))
                            console.log(result)
                            
                            process.exit(0)
                            

                            Everything seems be ok and I can generate key but is much shorten than this fake one generated in hise.

                            Christoph HartC 1 Reply Last reply Reply Quote 0
                            • Christoph HartC
                              Christoph Hart @parabuh
                              last edited by

                              @parabuh Have you compared the output with the PHP snippet I posted above? I don't know node.js but I think if you just recreate the PHP thingie you should be able to compare and match the outputs of those two.

                              It obviously depends on the external libraries for big integers and XML creation that you use and how they handle bit order and whatnot.

                              1 Reply Last reply Reply Quote 0
                              • S
                                Sawer
                                last edited by

                                Hello @ustk
                                How is this whole method works?
                                Just want to understand the RSA using a dummy License in the plugin.
                                I'm trying to create just a a demo to get an understanding of how this whole thing works, but there's no documentation and as well as I'm not getting fulfilling inputs here in the forum.
                                Seems like this method is more effective than the simple copy protection.
                                Any help is appreciated

                                1 Reply Last reply Reply Quote 0
                                • ustkU ustk referenced this topic on
                                • First post
                                  Last post

                                28

                                Online

                                1.7k

                                Users

                                11.8k

                                Topics

                                102.5k

                                Posts