Implement A Rudimentary Licensing Solution?



  • Hi,

    There are several sources on licensing, including, but not limited to the following:

    1. R21 Github Example
    2. General Theories in this thread

    They somehow require a server or a license file. I don't want any of that. LOL

    Is it possible to check for the first 11 digits of the license?

    I was thinking of doing something like

    approved_license_serial = []
    
    if user_license in approved_license_serial:
        # Register Plugin
    else: 
        #Pass
    

    The problem is I can't retrieve the 11 digits reliably.
    For example, my true 11 digits is 14004030666 (Correct me if I'm wrong but there is no harm posting this since they would require the other values).

    When I execute the c4d.GeGetSerialInfo(), all I get is
    {'city': '', 'street': '', 'name': 'Rebenrio Traje', 'country': '', 'licenseId': 'e5ae5e5a-2a77-4b89-a6d6-c16316856b1e', 'organization': ''}

    I can't find the 14004030666 figure on the dictionary so I can't perform the check.

    Is there a way around this?

    Regards,
    Ben



  • Hi,

    why do you need the license key in prior to R21 style? The license model changed with R21 and all that fancy-shmancy Maxon account stuff. You are also using the old license interface. The R21 license interface is c4d.GetGeneralLicensingInformation and the c4d.ExportLicenses, but the main product serial in them will be the same.

    Cheers,
    zipit



  • @zipit

    Thanks for the response.

    RE: why do you need the license key in prior to R21 style
    Chances are some user will have a version prior R21. That's why I didn't use the commands introduced in R21.
    The plugin I'm working on is a rigging/animation workflow. And most of the people I know within that workflow (i.e. not in the mograph field) is not really on the latest version.



  • Hi,

    but you are R21 if I am not mistaken, so why would you expect to retrieve some old style serial? If you want to support older versions of Cinema, use the old interface. The format of the returned serial data does not really matter, since you are going to hash it anyways unless you have something very special in mind.

    Cheers,
    zipit



  • Hi @zipit

    RE: why would you expect to retrieve some old style serial? & If you want to support older versions of Cinema, use the old interface
    So I guess you want me to perform different test for pre R21 and R21+?
    I'm a user before R21, so I might be missing something out.

    Anyhow, I tried running the c4d.GeGetSerialInfo(c4d.SERIALINFO_CINEMA4D) in R20, which gives me
    {'city': XXXX, 'name': 'Rebenrio Traje', 'country': XXXX, 'street': 'Damosa', XXXX: 'Freelance', 'nr': '14004030666'}

    The last entry now matches my 11 first digits, which I can perform a direct comparison.

    For R21, again, it gives me,
    {'city': '', 'street': '', 'name': 'Rebenrio Traje', 'country': '', 'licenseId': 'e5ae5e5a-2a77-4b89-a6d6-c16316856b1e', 'organization': ''}

    Does this mean for R20 users, I'll ask for first 11 digits?
    And for R21+ users, I'll ask for licenseId?

    Is this assessment correct?

    RE: since you are going to hash it
    Correct me if I'm wrong, hashing means I'd have to generate a separate license/key file.
    If that's the case, I don't want to hash them.
    I just want a direct comparison of the first 11 digit serial with the code in my plugin.
    Basically, I want to hard code their 11 digit serial in my plugin.



  • @bentraje

    One way or another you will need to provide the users of your plugin with a license key. Be it as a separate file, or a simple string of text which they enter into the personalization panel (R20 and earlier).
    I take it you read through the links you provided in your first post, especially the "How does licensing basically work?" (from Part 1 of the 5 part series at https://developers.maxon.net/?p=623).
    Reading the 11 digits (R20 and earlier) is fine, but you need to compare it to something ... As such, if you are not providing a license key as file or as text string, how will you be able to compare? Are you going to hardcode the user's 11 digits? And thus update this in the code for every single user?



  • @C4DS

    RE: Are you going to hardcode the user's 11 digits? And thus update this in the code for every single user?
    Yes yes. You read me right :)
    I want to hardcode them and update the code for every single user.
    BTW, by update, I meant updating the list of the allowed license in the file. Not necessarily separate plugin for each user.

    That's what I meant by "rudimentary".
    I don't expect large users for my plug-in.

    With that said, will my implementation be feasible (i.e. the plugin will not open if it doesn't match the users 11 digits (R20) or licenseID (R21)?



  • Hi.

    @bentraje said in Implement A Rudimentary Licensing Solution?:

    RE: since you are going to hash it
    Correct me if I'm wrong, hashing means I'd have to generate a separate license/key file.

    Sorry, no, I just meant hashing in the sense of a secure hash function (e.g. MD5 or SHA), i.e. something that translates some data dump into a unique identifier of a fixed length. Here is an example for a simple server-client license model.

    import c4d
    import hashlib
    
    # This is a very simple server-client serial schema. Please note that this
    # wont stop any serious piracy attempts, so you might just move the serial
    # generation to the client side and scrap the server. But then there is the
    # question of why bothering with a serial at all, because it would be
    # equally trivial to crack.
    
    # Server sided serial generation
    # ---------------------------------------------------------------------------
    
    # Something that identifies your plugin, i.e. some kind of salt that
    # makes the serial hash unique to your plugin. This could be just the
    # plugin id or something more fancy.
    salt = "123456"
    # serial_info would be the serial data sent by your plugin.
    serial_info = c4d.GeGetSerialInfo()
    serial_info["salt"] = salt
    # Hash everything together with some hash function, the function itself
    # does not really matter, you can practically use any of them. This a 256
    # bit SHA-Hash, which is probably totally unnecessary, but does not cost us
    # anything either.
    serial = hashlib.sha256()
    for key in sorted(serial_info.keys()):
        serial.update(serial_info[key])
    
    # The hexadecimal representation of our user hash, this will always be a 64
    # character string, which is why we do not care about how Cinema identifies
    # a license. Send this string back to the user.
    hex_serial = serial.hexdigest()
    print "The unique plugin serial:", hex_serial
    
    
    # Client sided serial handling (after the initial request)
    # ---------------------------------------------------------------------------
    
    import time
    
    # The plugin id of our plugin (this is one of mine, so please do not use it)
    plugin_id = 1053529
    # The time span in second after which we require the plugin to validate a
    # serial with a license server again (at least every 50 days).
    validation_delta = 60 * 60 * 24 * 50
    
    # Writing the serial into Cinema's encrypted serial container, once you
    # retrieved a serial from the license server.
    
    # A time stamp for when this serial has been written. We will use it to
    # determine when to ask the server to validate a serial. This will have 
    # a character length of ten until the UNIX-epoch time roll-over in 2038, 
    # use another time format if this is not future proof enough for you.
    time_stamp = str(int(time.time()))
    # The byte sequence to store our plugin data in, we need 64 bytes for the
    # serial and 10 bytes for the date.
    data = c4d.storage.ByteSeq(None, 64 + 10)
    data[:64] = hex_serial
    data[64:] = time_stamp
    # Let Cinema encrypt that data and store it internally.
    c4d.plugins.WritePluginInfo(plugin_id, data)
    
    # Checking a serial when to decide if a plugin is registered or not:
    
    data = c4d.plugins.ReadPluginInfo(plugin_id, 64 + 10)
    serial = str(data[:64])
    time_stamp = int(data[64:])
    print "Red out serial:", serial
    print "Red out time stamp:", time_stamp
    
    if time.time() - time_stamp > validation_delta:
        # Let the server evaluate the serial, if it passes, overwrite the
        # serial container with a new time stamp. If not, do not register
        # or unlock your plugin.
        pass
    

    Cheers,
    zipit



  • @bentraje said in Implement A Rudimentary Licensing Solution?:

    And for R21+ users, I'll ask for licenseId?

    That licenseId value is a temporary value and has no use for anyone.

    If you want to know more about the R21+ license system, see Plugin Licensing Manual.



  • hi,

    we can't tell you how to manage your licenses to protect your plugins. all

    Hard coding the first digit of the serial number of Cinema 4D is really something you MUST NOT do.
    Those data are not yours. They are personal for each user. Knowing that python plugins are quiet easy to crack and retrieve the original code is pretty simple, you are kind of exposing personal data to the public.

    You can just generate one file that contain your licence and check that file. For you, there's no difference between generating a file and a new version of your plugin.
    You can hash different information, First name, last name, c4d serial.
    Those function can be done by a website without your doing anything.

    For the "new" system, you already have all the links needed.
    Let us know if you have some issue with it.

    Cheers,
    Manuel



  • Thanks for the response.

    @zipit
    Gotcha. I totally misinterpreted it.
    Thanks for the providing a script to illustrate it. Helps a lot

    @PluginStudent
    Thanks for the heads up. I guess I'll just use userID. It seems to be consistent (i.e. not temporary) for R21+ then for pre R21 their first 11 digits.

    @m_magalhaes

    RE: Hard coding the first digit of the serial number of Cinema 4D is really something you MUST NOT do.
    Thanks for the warning, as I was dead set on using the first 11 digits.
    Anyway, I will still hard code data but not their first 11 digits (or any personal info) but rather their hash data like what @zipit shown.

    I really don't like serials, even when I buy plugins.



  • hi,

    @bentraje said in Implement A Rudimentary Licensing Solution?:

    Anyway, I will still hard code data but not their first 11 digits (or any personal info) but rather their hash data like what @zipit shown.

    Storing the result and the code to reach that result in the same file doesn't sound like a good idea to me. But as I said, we can't say what's good or bad protection, you have to decide :)

    Cheers,
    Manuel



  • Thanks will close the thread for now.


Log in to reply