DllTest - sample code for Python ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This sample code will work with versions of Python 2.6 and higher. Note - for Cython Sample code please look in the Cython sub-folder. The source files in the project are: File name Description dlltest.py main source code file for Python containing protection functions dris.py contains useful constants and functions that implement the DRIS structure. The sample code works by calling a Python extension that communicates with the dongle. The Python extension is located in the Modules/Python directory of the SDK. You need to use the extension that matches the version of Python you are using. For each version of Python we have extensions for each supported Operating System: dpwin32py.pyd - Windows 32-bit dpwin64py.pyd - Windows 64-bit dplin32py.so - Linux 32-bit dplin64py.so - Linux 64-bit dpmac64py.so - MacOS 64-bit Please contact Microcosm if you require a Python module for a different version to those we provide and we will generate it for you. The sample code (dris.py) will automatically work out the OS and bitness and load the appropriate extension for you. The sample code contains 10 functions which demonstrate some of the functionality offered by the Dinkey Pro/FD system. Code marked with !!!! are places where you should customise the sample code so that it will work properly: * Change the MY_SDSN value to the value of your SDSN * Change the MY_PRODCODE value to the Product Code in the dongle * Change the MyAlgorithm code (if you call a user algorithm) * Change the CryptDRIS code (if you encrypt the DRIS) * Change the CryptApiData (if you encrypt Data you send to our API) * Change the MyRWAlgorithm code (if encrypt Data you send to our API using the R/W algorithm) You should use DinkeyAdd to protect the Python extension(s) (e.g. dpmac64py.pyd etc...) and not your Python code directly. Because your program is linked to the protected extension then it is protected. How To Protect The Python Sample Code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use DinkeyAdd (using the API Method of protection) to protect the Dinkey Pro/FD Python extensions we provide for the version of Python you want to support. (If you know which Operating Systems you will support then you can just protect these extensions. If you are not sure then just protect them all). For example, if you were just distributing on Windows with 64-bit python 3.x then you should specify the extension: Modules/Python/x86-amd64/3.x/dpwin64py.pyd as the input pathname and the location of your python code as the output pathname. Do this for each extension you want to protect. In our example you will have the following in your sample code folder: dlltest.py dris.py dpwin64py.pyd [output from DinkeyAdd] To test everything is working run the sample code with and without the dongle attached. Note - the version of the extension you provide must match the version of Python that is being run. If not you will get an error. In our experience this is different for each OS: Windows: gives a sensible error message saying that the version of the extension is different. Linux: We actually found that any 2.x extension could run on any 2.y Python (similar for 3.x). Otherwise you get an error about PyInit_dpxxxx or init_dpxxx not being found in the extension. Mac: you get the very unhelpful error "PyThreadState_Get: no current thread" How To Add Protection to your Python Code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1) Modify your python code to check the dongle - you can base your protection check function on those from dlltest.py in the sample code. The sample code in dlltest.py contains 10 functions. You will not need to use all these functions in your code. Just use which ever functions are most appropriate and customise in your own way. The sample code is just a guide. You can implement the protection in a stronger way using the techniques described in the "Increasing your Protection" chapter of the manual. 2) You should import dris.py into your python code. 3) You will probably want to modify some of the error messages in dris.py with your own. However, you should still display or log any error codes returned by the protection check otherwise you will not be able to identify the cause of the error. You can look up error codes in our knowledge base: www.microcosm.com/kb. 4) Protect the relevant Python extensions just like in the step above for the sample code. 5) The protected Python extensions (for your version of Python) should be in the same directory as the dris module. 6) Compile your Python code (py files) to pyc files for distribution (see instructions below). Algorithms in Python ~~~~~~~~~~~~~~~~~~~~ Python implements modulo and integer division differently to other programming languages like C, when it is applied to negative integers. Also, when you perform arithmetic in Python it can expand the size of the variable to accommodate the size of the result. When the algorithms are executed in the dongle they assume the output and all the inputs are signed integers. To ensure that the algorithms are implemented in Python so that they match the output of the dongle you need to be aware of the following: * use the mod function defined in dlltest.py instead of the operator % * use the div function defined in dlltest.py instead of the integer operator // * apply the function dris.make_signed32bit to the value of the algorithm to ensure the output is a 32-bit signed value Level of Security ~~~~~~~~~~~~~~~~~ You should not distribute your py code as this editable and therefore not secure (an end user could edit the file and remove all the protection checks). You should distribute the compiled pyc or pyo files and the protected extensions. These files contain byte-code. You can do this by compiling your python code like this: python -m compile_all -b ./ [.\ for windows] This will generate the pyc files in the same directory as the py files (rather than the __pycache__ directory) and ensure that they will work in a pyc-only distribution. However, although byte-code is not readable like source code, it is still possible to use tools to decompile it back to source code. This will not be as easy to read as your source code but a hacker might be able to work out what your code is doing, remove the protection checks and re-compile. Also - it is possible to use tools that modify the byte-code directly. One way around this is to write your code (or the most sensitive parts of your code) in Cython (see Cython sample code) or in pure C (see C/C++ sample code). This is recommended if you have the skills to do it. Another technique is to use a Python obfuscator so that the bytecode is much more difficult to understand. Another tool you could look at is Nuitka (nuitka.net) which converts Python code to C and then compiles it. Another possible hack is to use the Python interpreter to replace the protection check function with a function that the hacker has written himself. You can combat this hack by using a user algorithm or (not quite so good) reading data from the dongle data area. This works because it means that the hacker would have to work out the algorithm (data) to defeat the protection. Another solution is write some of your code in pure C and call it from Python. Note - you may be tempted to not modify your source code and instead use py2exe and the Shell Method to protect the resulting executable. However, this is not secure as the "compiled" executable file is just a loader. Your compiled Python code is also included in the library.zip file, so someone could just extract these files and use them. Therefore you should not use this method but to use the API method with the source code instead. You can then use py2exe (without the Shell method) if you prefer to distribute your software this way. This is also the case for any other Python-to-executable software unless it specifically says that your compiled Python code is encrypted. We have not seen this feature in any Python-to-exe converter.