Add Original SDK
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
Cython Sample Code
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
NB - tested under Python 2.7 and Python 3.6 with Cython 0.29 with Visual Studio C compiler
|
||||
but it should work for all versions of Python, Cython and C compiler. (We also tested the
|
||||
32-bit code using MinGW).
|
||||
|
||||
If you are coding in Cython then you can link the Dinkey Pro/FD Runtime module directly to
|
||||
your code (rather than having to call an external Python extension). See the notes for
|
||||
Python sample code as to why this is preferable. Use:
|
||||
|
||||
dpwin32_coff.obj for 32-bit code
|
||||
dpwin64.obj for 64-bit code
|
||||
|
||||
The source files in the project are:
|
||||
|
||||
File name Description
|
||||
objtest.pyx main source code file for Cython containing protection functions
|
||||
objtest.pxd implements the DRIS structure and function definitions
|
||||
ddpro.h Used by the pxd file so we can call DDProtCheck (a hack because it is
|
||||
difficult to declare a stdcall function in a pxd file)
|
||||
setup.py python file to compile the Cython sample code
|
||||
|
||||
The sample code is just a guide. You should implement the protection in a stronger way
|
||||
using the techniques described in the "Increasing your Protection" chapter of the manual.
|
||||
|
||||
NB - our sample code assumes that you are using 64-bit Python 3. If not then you will have
|
||||
to make some small modifications to setup.py:
|
||||
|
||||
32-bit Python: modify extra_objects to list "dpwin32_coff.obj" instead of "dpwin64.obj"
|
||||
|
||||
Python 2: modify 'language_level' to be "2" (If you are using an old version of Python/Cython
|
||||
you may have to modify the objtest.pyx code. e.g. "DEMO" instead of b'DEMO' and use
|
||||
print instead of print()
|
||||
|
||||
To compile run the following command:
|
||||
|
||||
python setup.py build_ext --inplace --compiler=msvc
|
||||
|
||||
(for mingw32 use --compiler=mingw32)
|
||||
|
||||
So a makefile could look like this:
|
||||
|
||||
all:
|
||||
python setup.py build_ext -c mingw32 --inplace
|
||||
rm -rf ./build
|
||||
rm -f *.c
|
||||
|
||||
Code marked with !!!! are places where you should customise the sample code so
|
||||
that it will work properly:
|
||||
@@ -0,0 +1,2 @@
|
||||
int __stdcall DDProtCheck(void*, unsigned char*);
|
||||
int __stdcall DDGetNetUserList(char*, int*, void*, int, int*);
|
||||
@@ -0,0 +1,62 @@
|
||||
#DRIS struture
|
||||
cdef packed struct DRIS:
|
||||
# the first 4 fields are never encrypted
|
||||
char header[4] # should be set to DRIS
|
||||
# inputs
|
||||
int size # size of this structure
|
||||
int seed1 # seed for data/dris encryption
|
||||
int seed2 # as above
|
||||
# (maybe encrypted from now on)
|
||||
int function # specify only one function
|
||||
int flags # options for the function selected. To use more than one OR them together: OPTION1 | OPTION2...
|
||||
unsigned int execs_decrement # amount by which to dec execs if we use flag: DEC_MANY_EXECS
|
||||
int data_crypt_key_num # number of the key (1-3) that the dongle uses to encrypt or decrypt user data
|
||||
int rw_offset # offset in the dongle data area to read or write data
|
||||
int rw_length # length of data are to read/write/encrypt/decrypt
|
||||
char *rw_data_ptr # pointer to data to write / be read
|
||||
char alt_prog_name[256] # protection check for different program instead of this one, must be null-terminated
|
||||
int var_a # variable values for user algorithm
|
||||
int var_b
|
||||
int var_c
|
||||
int var_d
|
||||
int var_e
|
||||
int var_f
|
||||
int var_g
|
||||
int var_h
|
||||
int alg_number # the number of the user algorithm that you want to execute
|
||||
# outputs
|
||||
int ret_code # return code from the protection check
|
||||
int ext_err # extended error
|
||||
int type # type of dongle detected. 1 = Pro, 2 = FD
|
||||
int model # model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited
|
||||
int sdsn # Software Developer's Serial Number
|
||||
char prodcode[12] # Product Code (null-terminated)
|
||||
unsigned int dongle_number
|
||||
int update_number
|
||||
unsigned int data_area_size # size of the data area used in the dongle detected
|
||||
int max_alg_num # the maximum algorithm number in the dongle detected
|
||||
int execs # executions left: -1 indicates 'no limit'
|
||||
int exp_day # expiry day: -1 indicates 'no limit'
|
||||
int exp_month # expiry month: -1 indicates 'no limit'
|
||||
int exp_year # expiry year: -1 indicates 'no limit'
|
||||
unsigned int features # features value
|
||||
int net_users # maximum number of network users for the dongle detected: -1 indicates 'no limit'
|
||||
int alg_answer # answer to the user algorithm executed with the given variable values
|
||||
unsigned int fd_capacity # capacity of the data area in FD dongle.
|
||||
char fd_drive[128] # drive letter of FD dongle detected e.g. 'f:\' (or mount name under Linux)
|
||||
int swkey_type # 0 = no swkey detected, 1 = temporary software key, 2 = demo software key
|
||||
int swkey_exp_day # software key expiry date (if software key detected)
|
||||
int swkey_exp_month
|
||||
int swkey_exp_year
|
||||
|
||||
#NU_INFO struture
|
||||
cdef packed struct NU_INFO:
|
||||
char licenceName[256]
|
||||
char userName[50]
|
||||
char computerName[256]
|
||||
char ipAddress[16]
|
||||
|
||||
# declare DDProtCheck (we do it like this because it is stdcall - the default for Cython is cdecl)
|
||||
cdef extern from "ddpro.h":
|
||||
int __stdcall DDProtCheck(void*, unsigned char*)
|
||||
int __stdcall DDGetNetUserList(char*, int*, void*, int, int*)
|
||||
@@ -0,0 +1,647 @@
|
||||
from libc.string cimport memcpy
|
||||
from libc.string cimport strlen
|
||||
import random
|
||||
|
||||
# The sample code 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 should
|
||||
# implement the protection in a stronger way using the techniques described in
|
||||
# the "Increasing your Protection" chapter of the manual.
|
||||
#
|
||||
# If you are using Dinkey Lite then you can only use 4 functions:
|
||||
# ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc
|
||||
|
||||
# this file contains 10 protection-check functions.
|
||||
# ProtCheck a standard protection check
|
||||
# ProtCheckWithAlg a protection check & executing an Algorithm
|
||||
# WriteBytes a protection check & write data to the dongle
|
||||
# ReadBytes a protection check & read data from the dongle
|
||||
# EncryptUserData a protection check & encrypting data and then decrypting the data
|
||||
|
||||
# these functions are the same as the functions listed above but encrypting all parameters passed to our API
|
||||
# ProtCheckEnc a standard protection check
|
||||
# ProtCheckWithAlgEnc a protection check & executing an Algorithm
|
||||
# WriteBytesEnc a protection check & write data to the dongle
|
||||
# ReadBytesEnc a protection check & read data from the dongle
|
||||
# EncryptUserDataEnc a protection check & encrypting data and then decrypting the data
|
||||
|
||||
DEF MY_SDSN = 10101 # !!!! modify this value to your SDSN
|
||||
DEF MY_PRODCODE = b'DEMO' # !!!! change this value to match the Product Code in the dongle
|
||||
|
||||
# for some reason these constants have to be declared here rather than the pxd file
|
||||
# functions - must specify only one
|
||||
DEF PROTECTION_CHECK=1 # checks for dongle, check program params...
|
||||
DEF EXECUTE_ALGORITHM=2 # protection check + calculate answer for specified algorithm with specified inputs
|
||||
DEF WRITE_DATA_AREA=3 # protection check + writes dongle data area
|
||||
DEF READ_DATA_AREA=4 # protection check + reads dongle data area
|
||||
DEF ENCRYPT_USER_DATA=5 # protection check + the dongle will encrypt user data
|
||||
DEF DECRYPT_USER_DATA=6 # protection check + the dongle will decrypt user data
|
||||
DEF FAST_PRESENCE_CHECK=7 # checks for the presence of the correct dongle only with minimal security, no flags allowed.
|
||||
DEF STOP_NET_USER=8 # stops a network user (a protection check is NOT performed)
|
||||
|
||||
# flags - can specify as many as you like
|
||||
DEF DEC_ONE_EXEC=1 # decrement execs by 1
|
||||
DEF DEC_MANY_EXECS=2 # decrement execs by number specified in execs_decrement
|
||||
DEF START_NET_USER=4 # starts a network user
|
||||
DEF USE_FUNCTION_ARGUMENT=16 # use the extra argument in the function for pointers
|
||||
DEF CHECK_LOCAL_FIRST=32 # always look in local ports before looking in network ports
|
||||
DEF CHECK_NETWORK_FIRST=64 # always look on the network before looking in local ports
|
||||
DEF USE_ALT_PROG_NAME=128 # use name specified in prog_name instead of this program name
|
||||
DEF DONT_SET_MAXDAYS_EXPIRY=256 # if the max days expiry date has not been calculated then do not do it this time
|
||||
DEF MATCH_DONGLE_NUMBER=512 # restrict the search to match the dongle number specified in the DRIS
|
||||
DEF DONT_RETURN_FD_DRIVE=1024 # if an FD dongle has been detected then don't return the flash drive/mount name
|
||||
|
||||
# ************************* our 10 functions **********************************
|
||||
|
||||
# ************************** ProtCheck ***************************************
|
||||
cpdef int ProtCheck():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = PROTECTION_CHECK # standard protection check
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
if (dris.prodcode != MY_PRODCODE):
|
||||
print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
print("It worked!")
|
||||
return 0
|
||||
|
||||
|
||||
# ************************** ProtCheckWithAlg ******************************
|
||||
|
||||
# !!!! You should replace this function with the one generated by the
|
||||
# "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm)
|
||||
# or from DinkeyLook if you are using a Dinkey Lite dongle.
|
||||
# (If it does not generate source code for Python you have translate it from C)
|
||||
cdef int MyAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h):
|
||||
return a + b + c + d + e + f + g + h
|
||||
|
||||
# NB for this to work you must program at least "user algorithm" into the dongle
|
||||
# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the
|
||||
# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample
|
||||
# code from DinkeyLook
|
||||
cpdef int ProtCheckWithAlg():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = EXECUTE_ALGORITHM # standard protection check and execute algorithm
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.alg_number = 1 # execute algorithm 1 (you do not need to specify this field if you are only using Lite models)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
# if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code
|
||||
# !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd
|
||||
if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer):
|
||||
print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine")
|
||||
return -1
|
||||
|
||||
print("It worked!")
|
||||
return 0
|
||||
|
||||
|
||||
# ************************** WriteBytes ******************************
|
||||
# This writes the string "Hello, World!" to the dongle data area at offset 7
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
cpdef int WriteBytes():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
cdef char *datatowrite = "Hello, World!"
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = WRITE_DATA_AREA # standard protection check and write data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.rw_offset = 7
|
||||
dris.rw_length = <int>strlen(datatowrite)+1 # include the null
|
||||
dris.rw_data_ptr = datatowrite
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
print("It worked!")
|
||||
return 0
|
||||
|
||||
# ************************ ReadBytes ************************************
|
||||
# This reads 13 bytes of data from offset 7 in the dongle data area
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
# In order for the data to be displayed properly by this routine it will need to be text data
|
||||
cpdef ReadBytes():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
cdef char datatoread[14]
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = READ_DATA_AREA # standard protection check and read data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.rw_offset = 7
|
||||
dris.rw_length = sizeof(datatoread)
|
||||
dris.rw_data_ptr = datatoread
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
print("It worked! Dinkey Dongle Data area, offset 7 is: " + str(datatoread))
|
||||
return 0
|
||||
|
||||
# ************************** EncryptUserData ****************************
|
||||
# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1
|
||||
# It will then do another protection check & decrypt the data
|
||||
cpdef EncryptUserData():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
cdef char *mydata = "Hello, World!"
|
||||
cdef int data_length = <int>strlen(mydata)+1 # include the NULL
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = ENCRYPT_USER_DATA # standard protection check and encrypt data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.data_crypt_key_num = 1
|
||||
dris.rw_length = data_length
|
||||
dris.rw_data_ptr = mydata
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
# ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ...
|
||||
|
||||
# Now decrypt this (encrypted) data to get the original values
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = DECRYPT_USER_DATA # standard protection check and decrypt data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.data_crypt_key_num = 1
|
||||
dris.rw_length = data_length
|
||||
dris.rw_data_ptr = mydata
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
print("It worked! Data decrypted is " + str(mydata))
|
||||
return 0
|
||||
|
||||
# !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!!
|
||||
# In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API"
|
||||
# in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm
|
||||
# but the code can be modified easily to use the 3 encryption parameters.
|
||||
|
||||
# !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm
|
||||
# NB DinkeyAdd currently does not generate code for Python so you will have to translate it from C
|
||||
cdef int MyRWAlgorithm(int a, int b, int c, int d, int e, int f, int g, int h):
|
||||
return a ^ b ^ c ^ d ^ e ^ f
|
||||
|
||||
# !!!! modify parameters 1,2 and 3 to match those specified in DinkeyAdd
|
||||
cdef void CryptDRIS(DRIS *dris, unsigned int seed1, unsigned int seed2):
|
||||
cdef int i, j, k, t
|
||||
cdef unsigned char bigseed[256]
|
||||
cdef unsigned char S[256]
|
||||
cdef unsigned char temp
|
||||
|
||||
for i in range(0, 256, 8):
|
||||
memcpy(bigseed+i, &seed1, 4)
|
||||
memcpy(bigseed+i+4, &seed2, 4)
|
||||
for i in range(256):
|
||||
S[i] = i
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + S[i] + bigseed[i] + 123) % 256 # parameter 1
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
i = 0
|
||||
j = 0
|
||||
for k in range(16, <int>sizeof(DRIS)):
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i] + 212) % 256 # parameter 2
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
t = (S[i] + S[j] + 97) % 256 # parameter 3
|
||||
(<unsigned char *>dris)[k] ^= S[t]
|
||||
return
|
||||
|
||||
# !!!! modify parameters 1,2 and 3 to match those specified in DinkeyAdd (if you specified r/w algorithm then no need to modify anything)
|
||||
cdef void CryptApiData(unsigned char *mydata, int length, unsigned int seed1, unsigned int seed2, int alg_answer):
|
||||
cdef int i, j, k, t
|
||||
cdef unsigned char bigseed[256]
|
||||
cdef unsigned char S[256]
|
||||
cdef unsigned char temp
|
||||
|
||||
for i in range(0, 256, 8):
|
||||
memcpy(bigseed+i, &seed1, 4)
|
||||
memcpy(bigseed+i+4, &seed2, 4)
|
||||
for i in range(256):
|
||||
S[i] = i
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256 # parameter1
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
i = 0
|
||||
j = 0
|
||||
for k in range(length):
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256 # parameter 2
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
t = (S[i] + S[j] + ((alg_answer >> 16) & 0xff)) % 256 # parameter 3
|
||||
(<unsigned char *>mydata)[k] ^= S[t]
|
||||
return
|
||||
|
||||
# ************************** ProtCheckEnc ***************************************
|
||||
# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file with parameters specified in DinkeyAdd
|
||||
# NB if you are using the debug module then do not call CryptDRIS as DRIS encryption is not supported. See notes in C readme.txt
|
||||
cpdef int ProtCheckEnc():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = PROTECTION_CHECK # standard protection check
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
if (dris.prodcode != MY_PRODCODE):
|
||||
print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
print("It worked!")
|
||||
return 0
|
||||
|
||||
|
||||
# ************************** ProtCheckWithAlgEnc ******************************
|
||||
|
||||
# NB for this to work you must program at least "user algorithm" into the dongle
|
||||
# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the
|
||||
# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample
|
||||
# code from DinkeyLook
|
||||
# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file with parameters specified in DinkeyAdd
|
||||
cpdef int ProtCheckWithAlgEnc():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = EXECUTE_ALGORITHM # standard protection check and execute algorithm
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.alg_number = 1 # execute algorithm 1 (you do not need to specify this field if you are only using Lite models)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
# if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code
|
||||
# !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd
|
||||
if (MyAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h) != dris.alg_answer):
|
||||
print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine")
|
||||
return -1
|
||||
|
||||
print("It worked!")
|
||||
return 0
|
||||
|
||||
|
||||
# ************************** WriteBytesEnc ******************************
|
||||
# This writes the string "Hello, World!" to the dongle data area at offset 7
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file with parameters specified in DinkeyAdd.
|
||||
cpdef int WriteBytesEnc():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code, alg_answer
|
||||
cdef char *datatowrite = "Hello, World!"
|
||||
cdef string_length = <int>strlen(datatowrite)+1 # include the null
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = WRITE_DATA_AREA # standard protection check and write data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.rw_offset = 7
|
||||
dris.rw_length = string_length
|
||||
dris.rw_data_ptr = datatowrite
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd
|
||||
alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)
|
||||
|
||||
# encrypt data we want to write.
|
||||
CryptApiData(<unsigned char *>datatowrite, string_length, dris.seed1, dris.seed2, alg_answer)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
print("It worked!")
|
||||
return 0
|
||||
|
||||
# ************************ ReadBytesEnc ************************************
|
||||
# This reads 13 bytes of data from offset 7 in the dongle data area
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
# In order for the data to be displayed properly by this routine it will need to be text data
|
||||
# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file with parameters specified in DinkeyAdd.
|
||||
cpdef ReadBytesEnc():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code, alg_answer
|
||||
cdef char datatoread[14]
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = READ_DATA_AREA # standard protection check and read data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.rw_offset = 7
|
||||
dris.rw_length = sizeof(datatoread)
|
||||
dris.rw_data_ptr = datatoread
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd
|
||||
alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
if (dris.sdsn != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return -1
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return -1
|
||||
|
||||
# decrypt data that was read
|
||||
CryptApiData(<unsigned char *>datatoread, sizeof(datatoread), dris.seed1, dris.seed2, alg_answer)
|
||||
|
||||
print("It worked! Dinkey Dongle Data area, offset 7 is: " + str(datatoread))
|
||||
return 0
|
||||
|
||||
# ************************** EncryptUserDataEnc ****************************
|
||||
# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1
|
||||
# It will then do another protection check & decrypt the data
|
||||
# We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
|
||||
cpdef EncryptUserDataEnc():
|
||||
cdef DRIS dris
|
||||
cdef int ret_code, alg_answer
|
||||
cdef char *mydata = "Hello, World!"
|
||||
cdef int data_length = <int>strlen(mydata)+1 # include the NULL
|
||||
|
||||
# set the DRIS to have random values
|
||||
cdef unsigned char *drisbuf = <unsigned char*>&dris
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
# then set the values we want to use
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = ENCRYPT_USER_DATA # standard protection check and encrypt data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.data_crypt_key_num = 1
|
||||
dris.rw_length = data_length
|
||||
dris.rw_data_ptr = mydata
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd
|
||||
alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)
|
||||
|
||||
# encrypt data we want to write.
|
||||
CryptApiData(<unsigned char *>mydata, data_length, dris.seed1, dris.seed2, alg_answer)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
# ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ...
|
||||
|
||||
# Now decrypt this (encrypted) data to get the original values
|
||||
for i in range(sizeof(DRIS)):
|
||||
drisbuf[i]= <unsigned char>random.randint(0,255)
|
||||
memcpy(dris.header, b'DRIS', 4)
|
||||
dris.size = sizeof(DRIS)
|
||||
dris.function = DECRYPT_USER_DATA # standard protection check and decrypt data
|
||||
dris.flags = 0 # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.data_crypt_key_num = 1
|
||||
dris.rw_length = data_length
|
||||
dris.rw_data_ptr = mydata
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm specified in DinkeyAdd
|
||||
alg_answer = MyRWAlgorithm(dris.var_a, dris.var_b, dris.var_c, dris.var_d, dris.var_e, dris.var_f, dris.var_g, dris.var_h)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(&dris, NULL)
|
||||
|
||||
CryptDRIS(&dris, dris.seed1, dris.seed2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
DisplayError(ret_code, dris.ext_err)
|
||||
return ret_code
|
||||
|
||||
# decrypt data that was pass to us by the API
|
||||
CryptApiData(<unsigned char *>mydata, data_length, dris.seed1, dris.seed2, alg_answer)
|
||||
|
||||
print("It worked! Data decrypted is " + str(mydata))
|
||||
return 0
|
||||
|
||||
|
||||
#displays messages for the most common errors. You will want to change this for your code
|
||||
cdef void DisplayError(int ret_code, int extended_error):
|
||||
cdef char szBuffer[200]
|
||||
|
||||
if (ret_code == 401):
|
||||
print("Error! No dongles detected!")
|
||||
elif (ret_code == 403):
|
||||
print("Error! The dongle detected has a different type to the one specified in DinkeyAdd.")
|
||||
elif (ret_code == 404):
|
||||
print("Error! The dongle detected has a different model to those specified in DinkeyAdd.")
|
||||
elif (ret_code == 409):
|
||||
print("Error! The dongle detected has not been programmed by DinkeyAdd.")
|
||||
elif (ret_code == 410):
|
||||
print("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.")
|
||||
elif (ret_code == 411):
|
||||
print("Error! The dongle detected does not contain the licence associated with this program.")
|
||||
elif (ret_code == 413):
|
||||
print("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.")
|
||||
elif (ret_code == 417):
|
||||
print("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.")
|
||||
elif (ret_code == 423):
|
||||
print("Error! The number of network users has been exceeded.")
|
||||
elif (ret_code == 435):
|
||||
print("Error! DinkeyServer has not been detected on the network.")
|
||||
elif (ret_code == 922):
|
||||
print("Error! The Software Key has expired.")
|
||||
else:
|
||||
print("An error occurred checking the dongle.\nError: " + str(ret_code) + ", Extended Error: " + str(extended_error))
|
||||
return
|
||||
@@ -0,0 +1,16 @@
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
from Cython.Distutils import build_ext
|
||||
|
||||
my_modules = [
|
||||
Extension("objtest", ["objtest.pyx"], extra_objects=["dpwin64.obj", "advapi32.lib", "user32.lib"]),
|
||||
]
|
||||
|
||||
for e in my_modules:
|
||||
e.cython_directives = {'language_level': "3"} #all are Python-3
|
||||
|
||||
setup(
|
||||
name = 'objtest',
|
||||
cmdclass = {'build_ext': build_ext},
|
||||
ext_modules = my_modules
|
||||
)
|
||||
@@ -0,0 +1,155 @@
|
||||
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.
|
||||
@@ -0,0 +1,574 @@
|
||||
import dris # code that communicates with the Dinkey Pro/FD runtime extension
|
||||
import sys # so we can load the correct extension dependent on OS & bitness
|
||||
|
||||
# The sample code 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 should
|
||||
# implement the protection in a stronger way using the techniques described in
|
||||
# the "Increasing your Protection" chapter of the manual.
|
||||
#
|
||||
# If you are using Dinkey Lite then you can only use 4 functions:
|
||||
# ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc
|
||||
|
||||
|
||||
# this file contains 10 protection-check functions.
|
||||
# ProtCheck a standard protection check
|
||||
# ProtCheckWithAlg a protection check & executing an Algorithm
|
||||
# WriteBytes a protection check & write data to the dongle
|
||||
# ReadBytes a protection check & read data from the dongle
|
||||
# EncryptUserData a protection check & encrypting data and then decrypting the data
|
||||
|
||||
# these functions are the same as the functions listed above but encrypting all parameters passed to our API
|
||||
# ProtCheckEnc a standard protection check
|
||||
# ProtCheckWithAlgEnc a protection check & executing an Algorithm
|
||||
# WriteBytesEnc a protection check & write data to the dongle
|
||||
# ReadBytesEnc a protection check & read data from the dongle
|
||||
# EncryptUserDataEnc a protection check & encrypting data and then decrypting the data
|
||||
|
||||
MY_SDSN = 10101 # !!!! change this value to be the value of your SDSN (demo = 10101)
|
||||
MY_PRODCODE = "DEMO" # !!!! change this value to be the value of the Product Code in the dongle
|
||||
|
||||
# ************************* our 10 functions **********************************
|
||||
|
||||
# ************************** ProtCheck ***************************************
|
||||
def ProtCheck():
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.PROTECTION_CHECK) # standard protection check
|
||||
dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
|
||||
ret_code = DDProtCheck(mydris)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
if (dris.get_prodcode(mydris) != MY_PRODCODE):
|
||||
print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
print("It worked!")
|
||||
return ret_code
|
||||
|
||||
# ************************** ProtCheckWithAlg ******************************
|
||||
|
||||
# this function should be used instead of % for modulo as python calculates this differently to C for negative numbers
|
||||
def mod(x, y):
|
||||
return abs(x)%abs(y)*(1,-1)[x<0]
|
||||
|
||||
# this function should be used instead of // for integer division as python calculates this differently to C for negative numbers
|
||||
def div(x, y):
|
||||
if (x >= 0) != (y >= 0) and x % y:
|
||||
return x // y + 1
|
||||
else:
|
||||
return x // y
|
||||
|
||||
# !!!! You should replace this function with the one generated by the
|
||||
# "generate source code" button in Algorithm tab for DinkeyAdd (if you have specified an algorithm)
|
||||
# or from DinkeyLook if you are using a Dinkey Lite dongle.
|
||||
# (If it does not generate source code for Python you have translate it from C but use the mod function instead of % and div instead of //)
|
||||
def MyAlgorithm(a, b, c, d, e, f, g, h):
|
||||
value = a + b + c + d + e + f + g + h # place your algorithm here using mod instead of % and div instead of //
|
||||
return dris.make_signed32bit(value) # this line always needs to be here to convert the value to a signed 32bit integer
|
||||
|
||||
# NB for this to work you must program at least "user algorithm" into the dongle
|
||||
# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the
|
||||
# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample
|
||||
# code from DinkeyLook
|
||||
def ProtCheckWithAlg():
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.EXECUTE_ALGORITHM) # standard protection check & execute algorithm
|
||||
dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.set_alg_number(mydris, 1) # execute algorithm 1 (you do not need to specify this field if you are only using Lite models).
|
||||
# you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
|
||||
dris.set_var_a(mydris, 1) # sample values
|
||||
dris.set_var_b(mydris, 2)
|
||||
dris.set_var_c(mydris, 3)
|
||||
dris.set_var_d(mydris, 4)
|
||||
dris.set_var_e(mydris, 5)
|
||||
dris.set_var_f(mydris, 6)
|
||||
dris.set_var_g(mydris, 7)
|
||||
dris.set_var_h(mydris, 8)
|
||||
|
||||
ret_code = DDProtCheck(mydris)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
# if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code
|
||||
# !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd
|
||||
if MyAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), dris.get_var_e(mydris), \
|
||||
dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) != dris.get_alg_answer(mydris):
|
||||
print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine")
|
||||
return
|
||||
|
||||
print("It worked!")
|
||||
return ret_code
|
||||
|
||||
# ************************** WriteBytes ******************************
|
||||
# This writes the string "Hello, World!" to the dongle data area at offset 7
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
def WriteBytes():
|
||||
datatowrite = bytearray("Hello, World!", "ascii")
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.WRITE_DATA_AREA) # standard protection check and write data
|
||||
dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_rw_offset(mydris, 7)
|
||||
dris.set_rw_length(mydris, len(datatowrite))
|
||||
|
||||
ret_code = DDProtCheck(mydris, datatowrite)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
print("It worked!")
|
||||
return ret_code
|
||||
|
||||
# ************************ ReadBytes ************************************
|
||||
# This reads 13 bytes of data from offset 7 in the dongle data area
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
# In order for the data to be displayed properly by this routine it will need to be text data
|
||||
def ReadBytes():
|
||||
datatoread = bytearray(13)
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.READ_DATA_AREA) # standard protection check and read data
|
||||
dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_rw_offset(mydris, 7)
|
||||
dris.set_rw_length(mydris, len(datatoread))
|
||||
|
||||
ret_code = DDProtCheck(mydris, datatoread)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
print("It worked! Dinkey Dongle Data area, offset 7 is " + datatoread.decode("ascii"))
|
||||
return ret_code
|
||||
|
||||
# ************************** EncryptUserData ****************************
|
||||
# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1
|
||||
# It will then do another protection check & decrypt the data
|
||||
def EncryptUserData():
|
||||
data = bytearray("Hello, World!", "ascii")
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.ENCRYPT_USER_DATA) # standard protection check and encrypt data
|
||||
dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_data_crypt_key_num(mydris, 1)
|
||||
dris.set_rw_length(mydris, len(data))
|
||||
|
||||
ret_code = DDProtCheck(mydris, data)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ...
|
||||
|
||||
# Now decrypt this (encrypted) data to get the original values
|
||||
mydris2 = dris.create()
|
||||
dris.set_function(mydris2, dris.DECRYPT_USER_DATA) # standard protection check and decrypt data
|
||||
dris.set_flags(mydris2, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_data_crypt_key_num(mydris2, 1)
|
||||
dris.set_rw_length(mydris2, len(data))
|
||||
|
||||
ret_code = DDProtCheck(mydris2, data)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris2))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris2) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris2) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
print("It worked! Data decrypted is " + data.decode("ascii"))
|
||||
return ret_code
|
||||
|
||||
# !!!!!!!!!!! all the functions listed below encrypt all parameters to our API !!!!!!!!!!!!!!!!!!!!!
|
||||
# In order for them to work properly you need to choose "Encrypt DRIS" and "Encrypt Data passed to API"
|
||||
# in the Extra Security tab of DinkeyAdd. In this example, for Data Encryption I use the r/w algorithm
|
||||
# but the code can be modified easily to use the 3 encryption parameters.
|
||||
|
||||
# !!!! please overwrite this function with the one generated by DinkeyAdd for R/W Algorithm
|
||||
# NB DinkeyAdd currently does not generate code for Python so you will have to translate it from C
|
||||
def MyRWAlgorithm(a, b, c, d, e, f, g, h):
|
||||
value = a ^ b ^ c ^ d ^ e ^ f
|
||||
return dris.make_signed32bit(value)
|
||||
|
||||
# !!!! please overwrite this function with the one generated by DinkeyAdd
|
||||
# It is not generated by DinkeyAdd for Python currently so just modify parameters 1,2 and 3 accordingly
|
||||
def CryptDRIS(mydris):
|
||||
bigseed = bytearray(256)
|
||||
S = bytearray(256)
|
||||
|
||||
for i in range(0, 256, 8):
|
||||
bigseed[i:i+4] = mydris[8:12] # seed1
|
||||
bigseed[i+4:i+8] = mydris[12:16] # seed2
|
||||
|
||||
for i in range(256):
|
||||
S[i] = i
|
||||
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + S[i] + bigseed[i] + 123) % 256 # !!!! parameter 1
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
for k in range(16,dris.DRIS_SIZE):
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i] + 212) % 256 # !!!! parameter 2
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
t = (S[i] + S[j] + 97) % 256 # !!!! parameter 3
|
||||
mydris[k] = mydris[k] ^ S[t]
|
||||
return
|
||||
|
||||
# !!!! please overwrite this function with the one generated by DinkeyAdd
|
||||
# It is not generated by DinkeyAdd for Python currently. This is set-up for using r/w parameters
|
||||
def CryptApiData(data, mydris, length, alg_answer):
|
||||
bigseed = bytearray(256)
|
||||
S = bytearray(256)
|
||||
|
||||
for i in range(0, 256, 8):
|
||||
bigseed[i:i+4] = mydris[8:12] # seed1
|
||||
bigseed[i+4:i+8] = mydris[12:16] # seed2
|
||||
|
||||
for i in range(256):
|
||||
S[i] = i
|
||||
|
||||
j = 0
|
||||
for i in range(256):
|
||||
j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256 # parameter 1
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
for k in range(length):
|
||||
i = (i + 1) % 256
|
||||
j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256 # parameter 2
|
||||
temp = S[i]
|
||||
S[i] = S[j]
|
||||
S[j] = temp
|
||||
t = (S[i] + S[j] + ((alg_answer >> 16) & 0xff)) % 256 # parameter 3
|
||||
data[k] = data[k] ^ S[t]
|
||||
return
|
||||
|
||||
# ************************* ProtCheckEnc *******************************
|
||||
def ProtCheckEnc():
|
||||
# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.PROTECTION_CHECK) # standard protection check
|
||||
dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
|
||||
CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(mydris)
|
||||
|
||||
CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
if (dris.get_prodcode(mydris) != MY_PRODCODE):
|
||||
print("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
print("It worked!")
|
||||
return ret_code
|
||||
|
||||
# ************************ ProtCheckWithAlgEnc ***********************
|
||||
# NB for this to work you must program at least "user algorithm" into the dongle
|
||||
# NB We have used a very simple algorithm here (in the MyAlgorithm function). You must patch this with the
|
||||
# sample code generated by DinkeyAdd for the algorithm that you are using. For Lite models copy the sample
|
||||
# code from DinkeyLook
|
||||
# We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
|
||||
def ProtCheckWithAlgEnc():
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.EXECUTE_ALGORITHM) # standard protection check & execute algorithm
|
||||
dris.set_flags(mydris, 0) # no extra flags, but you may want to specify some if you want to start a network user or decrement execs,...
|
||||
dris.set_alg_number(mydris, 1) # execute algorithm 1 (you do not need to specify this field if you are only using Lite models).
|
||||
# you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
|
||||
dris.set_var_a(mydris, 1) # sample values
|
||||
dris.set_var_b(mydris, 2)
|
||||
dris.set_var_c(mydris, 3)
|
||||
dris.set_var_d(mydris, 4)
|
||||
dris.set_var_e(mydris, 5)
|
||||
dris.set_var_f(mydris, 6)
|
||||
dris.set_var_g(mydris, 7)
|
||||
dris.set_var_h(mydris, 8)
|
||||
|
||||
CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(mydris)
|
||||
|
||||
CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
# if you want you can check the algorithm answer - however if algorithm is from your code then best to just use the answer in your code
|
||||
# !!!! Make sure you have replaced the MyAlgorithm routine with the algorithm you have specified in DinkeyAdd
|
||||
if MyAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), dris.get_var_e(mydris), \
|
||||
dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris)) != dris.get_alg_answer(mydris):
|
||||
print("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine")
|
||||
return
|
||||
|
||||
print("It worked!")
|
||||
return ret_code
|
||||
|
||||
# ************************** WriteBytesEnc ******************************
|
||||
# This writes the string "Hello, World!" to the dongle data area at offset 7
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
# We encrypt the DRIS and Data passed to the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
|
||||
def WriteBytesEnc():
|
||||
datatowrite = bytearray("Hello, World!", "ascii")
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.WRITE_DATA_AREA) # standard protection check and write data
|
||||
dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_rw_offset(mydris, 7)
|
||||
dris.set_rw_length(mydris, len(datatowrite))
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \
|
||||
dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris))
|
||||
|
||||
# encrypt data we want to write.
|
||||
CryptApiData(datatowrite, mydris, len(datatowrite), alg_ans)
|
||||
|
||||
CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(mydris, datatowrite)
|
||||
|
||||
CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
print("It worked!")
|
||||
return ret_code
|
||||
|
||||
# ************************ ReadBytesEnc ************************************
|
||||
# This reads 13 bytes of data from offset 7 in the dongle data area
|
||||
# In order for this function to work you will need to have a data area in your dongle that is at least 21 bytes long.
|
||||
# In order for the data to be displayed properly by this routine it will need to be text data
|
||||
# We encrypt the DRIS and Data passed from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
|
||||
def ReadBytesEnc():
|
||||
datatoread = bytearray(13)
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.READ_DATA_AREA) # standard protection check and read data
|
||||
dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_rw_offset(mydris, 7)
|
||||
dris.set_rw_length(mydris, len(datatoread))
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \
|
||||
dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris))
|
||||
|
||||
CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(mydris, datatoread)
|
||||
|
||||
CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
# decrypt data that was read
|
||||
CryptApiData(datatoread, mydris, len(datatoread), alg_ans)
|
||||
print("It worked! Dinkey Dongle Data area, offset 7 is " + datatoread.decode("ascii"))
|
||||
return ret_code
|
||||
|
||||
# ************************** EncryptUserDataEnc ****************************
|
||||
# This function will do a protection check and ask the dongle to encrypt some data using encryption key 1
|
||||
# It will then do another protection check & decrypt the data
|
||||
# We encrypt the DRIS and Data passed to/from the API. Patch the CryptDRIS and CryptApiData functions in this file from source code generated by DinkeyAdd.
|
||||
def EncryptUserDataEnc():
|
||||
data = bytearray("Hello, World!", "ascii")
|
||||
# create the DRIS and allocate the values we want to use
|
||||
mydris = dris.create()
|
||||
dris.set_function(mydris, dris.ENCRYPT_USER_DATA) # standard protection check and encrypt data
|
||||
dris.set_flags(mydris, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_data_crypt_key_num(mydris, 1)
|
||||
dris.set_rw_length(mydris, len(data))
|
||||
|
||||
# calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = MyRWAlgorithm(dris.get_var_a(mydris), dris.get_var_b(mydris), dris.get_var_c(mydris), dris.get_var_d(mydris), \
|
||||
dris.get_var_e(mydris), dris.get_var_f(mydris), dris.get_var_g(mydris), dris.get_var_h(mydris))
|
||||
|
||||
# encrypt data we want to pass.
|
||||
CryptApiData(data, mydris, len(data), alg_ans)
|
||||
|
||||
CryptDRIS(mydris) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(mydris, data)
|
||||
|
||||
CryptDRIS(mydris) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris))
|
||||
return
|
||||
|
||||
# ... could add code to check other elements of the DRIS, e.g. ret_code, sdsn, ...
|
||||
|
||||
# Now decrypt this (encrypted) data to get the original values
|
||||
mydris2 = dris.create()
|
||||
dris.set_function(mydris2, dris.DECRYPT_USER_DATA) # standard protection check and decrypt data
|
||||
dris.set_flags(mydris2, dris.USE_FUNCTION_ARGUMENT) # we have to do it this way in Python
|
||||
dris.set_data_crypt_key_num(mydris2, 1)
|
||||
dris.set_rw_length(mydris2, len(data))
|
||||
|
||||
CryptDRIS(mydris2) # encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DDProtCheck(mydris2, data)
|
||||
|
||||
CryptDRIS(mydris2) # decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0):
|
||||
dris.DisplayError(ret_code, dris.get_ext_err(mydris2))
|
||||
return
|
||||
|
||||
# later in your code you can check other values in the DRIS...
|
||||
if (dris.get_sdsn(mydris2) != MY_SDSN):
|
||||
print("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.")
|
||||
return
|
||||
|
||||
# later on in your program you can check the return code again
|
||||
if (dris.get_ret_code(mydris2) != 0):
|
||||
print("Dinkey Dongle protection error")
|
||||
return
|
||||
|
||||
alg_ans = MyRWAlgorithm(dris.get_var_a(mydris2), dris.get_var_b(mydris2), dris.get_var_c(mydris2), dris.get_var_d(mydris2), \
|
||||
dris.get_var_e(mydris2), dris.get_var_f(mydris2), dris.get_var_g(mydris2), dris.get_var_h(mydris2))
|
||||
|
||||
# decrypt data passed to us by the API
|
||||
CryptApiData(data, mydris2, len(data), alg_ans)
|
||||
|
||||
print("It worked! Data decrypted is " + data.decode("ascii"))
|
||||
return ret_code
|
||||
|
||||
# entry point
|
||||
if __name__ == "__main__":
|
||||
# load the correct extension dependent on the OS and bitness of Python
|
||||
if sys.platform == 'win32':
|
||||
if sys.maxsize > 2**32:
|
||||
from dpwin64py import DDProtCheck
|
||||
else:
|
||||
from dpwin32py import DDProtCheck
|
||||
elif 'linux' in sys.platform:
|
||||
if sys.maxsize > 2**32:
|
||||
from dplin64py import DDProtCheck
|
||||
else:
|
||||
from dplin32py import DDProtCheck
|
||||
elif sys.platform == 'darwin':
|
||||
if sys.maxsize > 2**32:
|
||||
from dpmac64py import DDProtCheck
|
||||
else:
|
||||
from dpmac32py import DDProtCheck
|
||||
|
||||
# choose the protection check function of your choice here. We have chosen the basic protection check.
|
||||
ProtCheck()
|
||||
@@ -0,0 +1,254 @@
|
||||
import random
|
||||
import sys
|
||||
|
||||
#define constants
|
||||
|
||||
#these constants depend on the bitness of the OS - the DRIS is 4 bytes bigger for 64-bit code
|
||||
if sys.maxsize > 2**32:
|
||||
DRIS_SIZE = 564 # DRIS size is bigger for 64-bit (it has an 8-byte pointer)
|
||||
python64 = 4 # so we can adjust structure offsets for 64-bit python
|
||||
else:
|
||||
DRIS_SIZE = 560
|
||||
python64 = 0
|
||||
|
||||
#function values
|
||||
PROTECTION_CHECK = 1 # checks for dongle, check program params...
|
||||
EXECUTE_ALGORITHM = 2 # protection check + calculate answer for specified algorithm with specified inputs
|
||||
WRITE_DATA_AREA = 3 # protection check + writes dongle data area
|
||||
READ_DATA_AREA = 4 # protection check + reads dongle data area
|
||||
ENCRYPT_USER_DATA = 5 # protection check + the dongle will encrypt user data
|
||||
DECRYPT_USER_DATA = 6 # protection check + the dongle will decrypt user data
|
||||
FAST_PRESENCE_CHECK = 7 # checks for the presence of the correct dongle only with minimal security, no flags allowed.
|
||||
STOP_NET_USER = 8 # stops a network user (a protection check is NOT performed)
|
||||
|
||||
# flags - can specify as many as you like
|
||||
DEC_ONE_EXEC = 1 # decrement execs by 1
|
||||
DEC_MANY_EXECS = 2 # decrement execs by number specified in execs_decrement
|
||||
START_NET_USER = 4 # starts a network user
|
||||
USE_FUNCTION_ARGUMENT = 16 # use the extra argument in the function for pointers
|
||||
CHECK_LOCAL_FIRST = 32 # always look in local ports before looking in network ports
|
||||
CHECK_NETWORK_FIRST = 64 # always look on the network before looking in local ports
|
||||
USE_ALT_LICENCE_NAME = 128 # use name specified in alt_licence_name instead of the default one
|
||||
DONT_SET_MAXDAYS_EXPIRY = 256 # if the max days expiry date has not been calculated then do not do it this time
|
||||
MATCH_DONGLE_NUMBER = 512 # restrict the search to match the dongle number specified in the DRIS
|
||||
DONT_RETURN_FD_DRIVE = 1024 # if an FD dongle has been detected then don't return the flash drive/mount name
|
||||
|
||||
# set 4 bytes in our DRIS byte array from an integer
|
||||
def set4bytes(data, offset, value):
|
||||
data[offset] = value & 0xff
|
||||
data[offset+1] = (value >> 8) & 0xff
|
||||
data[offset+2] = (value >> 16) & 0xff
|
||||
data[offset+3] = (value >> 24) & 0xff
|
||||
return
|
||||
|
||||
# trunctates a value to 32-bit and converts to a signed integer
|
||||
def make_signed32bit(value):
|
||||
value = value & 0xffffffff
|
||||
if (value > (2**31)):
|
||||
value = value - (2**32)
|
||||
return value
|
||||
|
||||
# get 4 bytes in our DRIS byte array and convert to an unsigned integer
|
||||
# this returns an unsigned value, which is useful for dongle number, features, etc...
|
||||
def get4bytes(data, offset):
|
||||
return (data[offset] + data[offset+1]*0x100 + data[offset+2]*0x10000 + data[offset+3]*0x1000000)
|
||||
|
||||
# this returns a signed value, which is useful for alg_answer, expiry day...
|
||||
def get4bytes_signed(data, offset):
|
||||
value = data[offset] + data[offset+1]*0x100 + data[offset+2]*0x10000 + data[offset+3]*0x1000000
|
||||
if (value > (2**31)):
|
||||
value = value - (2**32)
|
||||
return value
|
||||
|
||||
# create the DRIS structure as a byte array, populate it with random values, initialise the header and size fields
|
||||
def create():
|
||||
dris = bytearray(DRIS_SIZE)
|
||||
random.seed()
|
||||
for n in range(DRIS_SIZE):
|
||||
dris[n] = random.randint(0, 255)
|
||||
dris[0] = ord('D')
|
||||
dris[1] = ord('R')
|
||||
dris[2] = ord('I')
|
||||
dris[3] = ord('S')
|
||||
set4bytes(dris, 4, DRIS_SIZE)
|
||||
return dris
|
||||
|
||||
# these functions set various values in the DRIS
|
||||
def set_function(dris, value):
|
||||
set4bytes(dris, 16, value)
|
||||
|
||||
def set_flags(dris, value):
|
||||
set4bytes(dris, 20, value)
|
||||
|
||||
def set_execs_decrement(dris, value):
|
||||
set4bytes(dris, 24, value)
|
||||
|
||||
def set_data_crypt_key_num(dris, value):
|
||||
set4bytes(dris, 28, value)
|
||||
|
||||
def set_rw_offset(dris, value):
|
||||
set4bytes(dris, 32, value)
|
||||
|
||||
def set_rw_length(dris, value):
|
||||
set4bytes(dris, 36, value)
|
||||
|
||||
def set_alt_licence_name(dris, licence_name):
|
||||
dris[44+python64:44+python64+len(licence_name)] = licence_name
|
||||
dris[44+python64+len(licence_name)] = 0 # null-terminate the string
|
||||
|
||||
def set_var_a(dris, value):
|
||||
set4bytes(dris, 300+python64, value)
|
||||
|
||||
def set_var_b(dris, value):
|
||||
set4bytes(dris, 304+python64, value)
|
||||
|
||||
def set_var_c(dris, value):
|
||||
set4bytes(dris, 308+python64, value)
|
||||
|
||||
def set_var_d(dris, value):
|
||||
set4bytes(dris, 312+python64, value)
|
||||
|
||||
def set_var_e(dris, value):
|
||||
set4bytes(dris, 316+python64, value)
|
||||
|
||||
def set_var_f(dris, value):
|
||||
set4bytes(dris, 320+python64, value)
|
||||
|
||||
def set_var_g(dris, value):
|
||||
set4bytes(dris, 324+python64, value)
|
||||
|
||||
def set_var_h(dris, value):
|
||||
set4bytes(dris, 328+python64, value)
|
||||
|
||||
def set_alg_number(dris, value):
|
||||
set4bytes(dris, 332+python64, value)
|
||||
|
||||
# these functions get values from the DRIS
|
||||
def get_ret_code(dris):
|
||||
return get4bytes(dris, 336+python64)
|
||||
|
||||
def get_ext_err(dris):
|
||||
return get4bytes(dris, 340+python64)
|
||||
|
||||
def get_type(dris):
|
||||
return get4bytes(dris, 344+python64)
|
||||
|
||||
def get_model(dris):
|
||||
return get4bytes(dris, 348+python64)
|
||||
|
||||
def get_sdsn(dris):
|
||||
return get4bytes(dris, 352+python64)
|
||||
|
||||
def get_prodcode(dris):
|
||||
for n in range(356+python64,368+python64):
|
||||
if dris[n] == 0:
|
||||
break
|
||||
return dris[356+python64:n].decode("utf-8")
|
||||
|
||||
def get_dongle_number(dris):
|
||||
return get4bytes(dris, 368+python64)
|
||||
|
||||
def get_update_number(dris):
|
||||
return get4bytes(dris, 372+python64)
|
||||
|
||||
def get_data_area_size(dris):
|
||||
return get4bytes(dris, 376+python64)
|
||||
|
||||
def get_max_alg_num(dris):
|
||||
return get4bytes(dris, 380+python64)
|
||||
|
||||
def get_execs(dris):
|
||||
return get4bytes(dris, 384+python64)
|
||||
|
||||
def get_exp_day(dris):
|
||||
return get4bytes_signed(dris, 388+python64)
|
||||
|
||||
def get_exp_month(dris):
|
||||
return get4bytes_signed(dris, 392+python64)
|
||||
|
||||
def get_exp_year(dris):
|
||||
return get4bytes_signed(dris, 396+python64)
|
||||
|
||||
def get_features(dris):
|
||||
return get4bytes(dris, 400+python64)
|
||||
|
||||
def get_net_users(dris):
|
||||
return get4bytes(dris, 404+python64)
|
||||
|
||||
def get_alg_answer(dris):
|
||||
return get4bytes_signed(dris, 408+python64)
|
||||
|
||||
def get_fd_capacity(dris):
|
||||
return get4bytes(dris, 412+python64)
|
||||
|
||||
def get_fd_drive(dris):
|
||||
for n in range(416+python64,544+python64):
|
||||
if dris[n] == 0:
|
||||
break
|
||||
return dris[416+python64:n].decode("utf-8")
|
||||
|
||||
def get_swkey_type(dris):
|
||||
return get4bytes(dris, 544+python64)
|
||||
|
||||
def get_swkey_exp_day(dris):
|
||||
return get4bytes(dris, 548+python64)
|
||||
|
||||
def get_swkey_exp_month(dris):
|
||||
return get4bytes(dris, 552+python64)
|
||||
|
||||
def get_swkey_exp_year(dris):
|
||||
return get4bytes(dris, 556+python64)
|
||||
|
||||
# you may also want to retrieve var_a values that you already entered into the dris!
|
||||
def get_var_a(dris):
|
||||
return get4bytes_signed(dris, 300+python64)
|
||||
|
||||
def get_var_b(dris):
|
||||
return get4bytes_signed(dris, 304+python64)
|
||||
|
||||
def get_var_c(dris):
|
||||
return get4bytes_signed(dris, 308+python64)
|
||||
|
||||
def get_var_d(dris):
|
||||
return get4bytes_signed(dris, 312+python64)
|
||||
|
||||
def get_var_e(dris):
|
||||
return get4bytes_signed(dris, 316+python64)
|
||||
|
||||
def get_var_f(dris):
|
||||
return get4bytes_signed(dris, 320+python64)
|
||||
|
||||
def get_var_g(dris):
|
||||
return get4bytes_signed(dris, 324+python64)
|
||||
|
||||
def get_var_h(dris):
|
||||
return get4bytes_signed(dris, 328+python64)
|
||||
|
||||
# function to display the most common error codes.
|
||||
# You will want to change this with your own error messages
|
||||
def DisplayError(ret_code, extended_error):
|
||||
if (ret_code == 401):
|
||||
print("Error! No dongles detected!")
|
||||
elif (ret_code == 403):
|
||||
print("Error! The dongle detected has a different type to the one specified in DinkeyAdd.")
|
||||
elif (ret_code == 404):
|
||||
print("Error! The dongle detected has a different model to those specified in DinkeyAdd.")
|
||||
elif (ret_code == 409):
|
||||
print("Error! The dongle detected has not been programmed by DinkeyAdd.")
|
||||
elif (ret_code == 410):
|
||||
print("Error! The dongle detected has a different Product Code to the one specified in DinkeyAdd.")
|
||||
elif (ret_code == 411):
|
||||
print("Error! The dongle detected does not contain the licence associated with this program.")
|
||||
elif (ret_code == 413):
|
||||
print("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.")
|
||||
elif (ret_code == 417):
|
||||
print("Error! One or more of the parameters set in the DRIS is incorrect. This could be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.")
|
||||
elif (ret_code == 423):
|
||||
print("Error! The number of network users has been exceeded.")
|
||||
elif (ret_code == 435):
|
||||
print("Error! DinkeyServer has not been detected on the network.")
|
||||
elif (ret_code == 922):
|
||||
print("Error! The Software Key has expired.")
|
||||
else:
|
||||
print("An error occurred checking the dongle.\nError: " + str(ret_code) + ", Extended Error: " + str(extended_error))
|
||||
return
|
||||
Reference in New Issue
Block a user