function dpsample %DPSAMPLE Example use of the Dinkey Pro/FD API in MATLAB. % Copyright 2015 Microcosm Ltd. % Load the correct library for this platform % !!!! If you rename the libraries as recommended in the user manual, % !!!! you need to modify the lines below to use the new names. switch computer() case 'PCWIN64' % 64-bit Windows loadlibrary('dpwin64.dll', @dinkeypro64proto, 'alias', 'dinkeypro'); case 'PCWIN' % 32-bit Windows loadlibrary('dpwin32.dll', @dinkeyprowin32proto, 'alias', 'dinkeypro'); case 'GLNXA64' % 64-bit Linux loadlibrary('dplin64.so', @dinkeypro64proto, 'alias', 'dinkeypro'); case 'GLNX86' % 32-bit Linux loadlibrary('dplin32.so', @dinkeypro32proto, 'alias', 'dinkeypro'); case 'MACI64' % 64-bit Mac OS X loadlibrary('dpmac64.dylib', @dinkeypro64proto, 'alias', 'dinkeypro'); case 'MAC' % 32-bit Mac OS X loadlibrary('dpmac32.dylib', @dinkeypro32proto, 'alias', 'dinkeypro'); otherwise disp('Error! Platform not supported!'); return end % Each of the functions below demonstrates different API functionality. % Uncomment the appropriate functions to execute the examples. % See the comments in each function for more details about the features % that they demonstrate. protcheck('dinkeypro'); %protcheckwithalg('dinkeypro'); %writedataarea('dinkeypro'); %readdataarea('dinkeypro'); %encryptuserdata('dinkeypro'); %protcheckenc('dinkeypro'); %writedataareaenc('dinkeypro'); %readdataareaenc('dinkeypro'); % Unload the library unloadlibrary('dinkeypro'); end function protcheck(libName) % An example of a basic protection check PROTECTION_CHECK = 1; DEC_ONE_EXEC = 1; START_NET_USER = 4; % Initialise the DRIS dris.function = PROTECTION_CHECK; dris.flags = bitor(DEC_ONE_EXEC, START_NET_USER); % Call the API [retCode, dris] = ddprotcheck(libName, dris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end % ... % You can check other values from the DRIS in other parts of your % program to improve security. For example: % Check the SDSN % !!!! "10101" is the SDSN used by the demo SDK and demo dongles % !!!! If not using a demo, replace "10101" with your own SDSN here if (dris.sdsn ~= 10101) disp('Incorrect SDSN! Have you replaced "10101" with your SDSN in the sample code?'); return end % Check the product code % !!!! Replace "DEMO" with the product code you specify when adding % protection with DinkeyAdd if (~strcmp(dris.prodcode, 'DEMO')) disp('Incorrect product code! Have you replaced "DEMO" with your product code in the sample code?'); return end disp('Protection check successful'); end function protcheckwithalg(libName) % An example of a protection check that also executes an algorithm stored % in the dongle. % The best way to use this feature is to identify lines of code in your % program that can be represented by algorithms stored in the dongle, and % replace these lines with calls to the API. Lite dongle users cannot % change the algorithm stored in the dongles, so should calculate the % algorithm in their own code and compare the result with the one returned % by the API, as in this example. EXECUTE_ALGORITHM = 2; % Initialise the DRIS dris.function = EXECUTE_ALGORITHM; dris.alg_vars = [1 2 3 4 5 6 7 8]; % The input variables to use in the algorithm dris.alg_number = 1; % The algorithm to execute. Lite dongles ignore this field, as they contain only 1 algorithm % Call the API [retCode, dris] = ddprotcheck(libName, dris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end % Check the algorithm result in another part of your program to improve % security. !!!! Ensure the myalgorithm() function matches the % algorithm that was executed by the protection check! if (dris.alg_answer ~= myalgorithm(dris.alg_vars)) disp('Error! The algorithm result was not as expected.'); return end disp('Protection check with algorithm successful'); end function writedataarea(libName) % An example of a protection check that also writes data to the dongle's % secure data area. % This feature is not supported by Lite dongles. % Make sure you specify a large enough data area size when adding % protection with DinkeyAdd! WRITE_DATA_AREA = 3; % Initialise the DRIS dris.function = WRITE_DATA_AREA; dris.rw_data = 'Hello, World!'; % Data to write dris.rw_offset = 0; % Index to start writing at. Note indices start at zero! % Call the API [retCode, dris] = ddprotcheck(libName, dris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end disp('Writing data successful'); end function readdataarea(libName) % An example of a protection check that also reads data from the dongle's % secure data area. % This feature is not supported by Lite dongles. % Make sure you specify a large enough data area size when adding % protection with DinkeyAdd! READ_DATA_AREA = 4; % Initialise the DRIS dris.function = READ_DATA_AREA; dris.rw_offset = 0; % Index to start reading at. Note indices start at zero! dris.rw_length = 13; % How many bytes to read % Call the API [retCode, dris] = ddprotcheck(libName, dris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end disp(['Reading data successful: ' char(dris.rw_data)]); end function encryptuserdata(libName) % An example of protection checks that encrypt/decrypt your data. % This feature is not supported by Lite dongles. ENCRYPT_USER_DATA = 5; DECRYPT_USER_DATA = 6; originalData = uint8(255 * rand(1, 10)); % Initialise the DRIS dris.function = ENCRYPT_USER_DATA; dris.rw_data = originalData; dris.data_crypt_key_num = 1; % Call the API [retCode, dris] = ddprotcheck(libName, dris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end encryptedData = dris.rw_data; % Initialise the DRIS dris.function = DECRYPT_USER_DATA; % Call the API [retCode, dris] = ddprotcheck(libName, dris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end decryptedData = dris.rw_data; disp('Data encryption successful'); disp('Original data:'); disp(originalData); disp('Encrypted data:'); disp(encryptedData); disp('Decrypted data:'); disp(decryptedData); end function protcheckenc(libName) % An example of a protection check that uses DRIS encryption for extra % security. PROTECTION_CHECK = 1; % Initialise the DRIS dris.function = PROTECTION_CHECK; dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes % Call the API [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end % You can check other values from the DRIS in other parts of your % program to improve security. For example: % Check the SDSN % !!!! "10101" is the SDSN used by the demo SDK and demo dongles % !!!! If not using a demo, replace "10101" with your own SDSN here if (dris.sdsn ~= 10101) disp('Incorrect SDSN! Have you replaced "10101" with your SDSN in the sample code?'); return end % Check the product code % !!!! Replace "DEMO" with the product code you specify when adding % protection with DinkeyAdd if (~strcmp(dris.prodcode, 'DEMO')) disp('Incorrect product code! Have you replaced "DEMO" with your product code in the sample code?'); return end disp('Protection check successful'); end function writedataareaenc(libName) % An example of a protection check that also writes data to the dongle's % secure data area. % This feature is not supported by Lite dongles. % Make sure you specify a large enough data area size when adding % protection with DinkeyAdd! This function also uses DRIS encryption and % encrypts the rw_data field for extra security. You must select these % options in DinkeyAdd for this function to work correctly! WRITE_DATA_AREA = 3; % Initialise the DRIS dris.function = WRITE_DATA_AREA; dris.rw_offset = 0; dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes dris.alg_vars = randint(1 , 8, double([intmin intmax])); % 8 random signed 32-bit integers rwAlgAnswer = myrwalgorithm(dris.alg_vars); % Encrypt the data to be written to the dongle dataToWrite = uint8('ABCDEFGHIJKLMNOPQRSTUVWXYZ'); dris.rw_data = cryptapidata(dataToWrite, dris.seed1, dris.seed2, rwAlgAnswer); % Call the API [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end disp('Writing data successful'); end function readdataareaenc(libName) % An example of a protection check that also reads data from the dongle's % secure data area. % This feature is not supported by Lite dongles. % Make sure you specify a large enough data area size when adding % protection with DinkeyAdd! This function also uses DRIS encryption and % encrypts the rw_data field for extra security. You must select these % options in DinkeyAdd for this function to work correctly! READ_DATA_AREA = 4; % Initialise the DRIS dris.function = READ_DATA_AREA; dris.rw_offset = 0; dris.rw_length = 10; dris.seed1 = uint8(255 * rand(1, 4)); % 4 random bytes dris.seed2 = uint8(255 * rand(1, 4)); % 4 random bytes dris.alg_vars = randint(1 , 8, double([intmin intmax])); % 8 random signed 32-bit integers % Call the API [retCode, dris] = ddprotcheck(libName, dris, @cryptdris); % Check the return value if (retCode ~= 0) displayerror(retCode, dris.ext_err); return end % Decrypt the data read from the dongle rwAlgAnswer = myrwalgorithm(dris.alg_vars); dataRead = cryptapidata(dris.rw_data, dris.seed1, dris.seed2, rwAlgAnswer); disp(['Reading data successful: ' char(dataRead)]); end function ret = myalgorithm(algVars) % !!!! This function must match one stored in the dongle for % protcheckwithalg() to work correctly. % For Lite dongles, use DinkeyLook to see the algorithm pre-programmed % into the dongle. For Plus and Net dongles, ensure this algorithm matches % one you specified in DinkeyAdd when adding protection. ret = algVars(1) - algVars(2) - algVars(3) - algVars(4) - algVars(5) - algVars(6) - algVars(7); end function ret = myrwalgorithm(algVars) % !!!! This function must match the R/W algorithm stored in the dongle for % writedataareaenc() and readdataareaenc() to work correctly. ret = algVars(1) - algVars(2) - algVars(3) - algVars(4) - algVars(5) - algVars(6); end function dris = cryptdris(dris) % This function can be used to encrypt/decrypt the DRIS. If using DRIS % encryption in your own program, copy this function exactly. Modify only % the parts indicated by !!!! % !!!! Overwrite the encryption parameters with those chosen in % DinkeyAdd. This example uses 123, 212, 97. DRIS_ENCRYPTION_PARAMETERS = [123 212 97]; S = 0:255; bigseed = zeros(256, 1); for i = 1:8:256 for j = 0:3 bigseed(i+j) = dris(9+j); bigseed(i+j+4) = dris(13+j); end end j = 0; for i = 0:255 j = bitand((j + S(i+1) + bigseed(i+1) + DRIS_ENCRYPTION_PARAMETERS(1)), 255); temp = S(i+1); S(i+1) = S(j+1); S(j+1) = temp; end i = 0; j = 0; for k = 17:length(dris) i = bitand((i + 1), 255); j = bitand((j + S(i+1) + DRIS_ENCRYPTION_PARAMETERS(2)), 255); temp = S(i+1); S(i+1) = S(j+1); S(j+1) = temp; t = bitand((S(i+1) + S(j+1) + DRIS_ENCRYPTION_PARAMETERS(3)), 255); dris(k) = bitxor(dris(k), S(t+1)); end end function data = cryptapidata(data, seed1, seed2, algAnswer) % This function is used to encrypt/decrypt data passed in the rw_data DRIS % field (applies to Plus and Net dongles only). If using this feature in % your own program, copy this function exactly. Modify only the parts % indicated by !!!! % !!!! If you are using constant encryption parameters, define them % like this: % DATA_ENCRYPTION_PARAMETERS = [X Y Z]; % !!!! If you are using the R/W algorithm, derive the encryption % parameters from the algorithm result like this: % 1. Convert algAnswer to uint32 without changing underlying data if (algAnswer < 0) algAnswer = uint32(double(algAnswer) + hex2dec('FFFFFFFF') + 1); else algAnswer = uint32(algAnswer); end % 2. Now algAnswer is a uint32 we can use bitwise operations to derive % the encryption parameters DATA_ENCRYPTION_PARAMETERS = [bitand(algAnswer, 255), bitand(bitshift(algAnswer,-8), 255), bitand(bitshift(algAnswer,-16), 255)]; % The rest of the function should not be modified! S = 0:255; bigseed = zeros(256, 1); for i = 1:8:256 for j = 0:3 bigseed(i+j) = seed1(j+1); bigseed(i+j+4) = seed2(j+1); end end j = 0; for i = 0:255 j = bitand((j + S(i+1) + bigseed(i+1) + DATA_ENCRYPTION_PARAMETERS(1)), 255); temp = S(i+1); S(i+1) = S(j+1); S(j+1) = temp; end i = 0; j = 0; for k = 1:length(data) i = bitand((i + 1), 255); j = bitand((j + S(i+1) + DATA_ENCRYPTION_PARAMETERS(2)), 255); temp = S(i+1); S(i+1) = S(j+1); S(j+1) = temp; t = bitand((S(i+1) + S(j+1) + DATA_ENCRYPTION_PARAMETERS(3)), 255); data(k) = bitxor(data(k), S(t+1)); end end % An example of error reporting % Displays descriptions for some common error codes % IMPORTANT - THE MESSAGES DISPLAYED ARE TO HELP DEVELOPERS IMPLEMENT THE % DINKEY PRO/FD API. THEY ARE NOT SUITABLE FOR DISPLAYING TO USERS! function displayerror(retCode, extErr) switch retCode case 401 disp('Error! No dongles detected!'); case 403 disp('Error! The dongle is a different type to the one specified in DinkeyAdd.'); case 404 disp('Error! The dongle is a different model to those specified in DinkeyAdd.'); case 409 disp('Error! The dongle has not been programmed by DinkeyAdd.'); case 410 disp('Error! The dongle has a different product code to the one specified in DinkeyAdd.'); case 411 disp('Error! This program''s licence was not found in the dongle.'); case 413 disp('Error! This program has not been locked by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the user manual.'); case 417 disp('Error! One or more of the parameters set in the DRIS is incorrect.'); disp('Check that you have defined the necessary input fields in the DRIS struct.'); disp('Also check if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.'); case 423 disp('Error! The number of network users has been exceeded.'); case 435 disp('Error! DinkeyServer has not been detected on the network.'); case 922 disp('Error! The Software Key has expired.'); otherwise str = sprintf('An error occurred checking the dongle. Error: %d, Extended Error: %d', retCode, extErr); disp(str); end end