Add Original SDK
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,58 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
//
|
||||
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||
//
|
||||
// Use the attributes below to control which key is used for signing.
|
||||
//
|
||||
// Notes:
|
||||
// (*) If no key is specified, the assembly is not signed.
|
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||
// a key.
|
||||
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||
// following processing occurs:
|
||||
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||
// in the KeyFile is installed into the CSP and used.
|
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||
// When specifying the KeyFile, the location of the KeyFile should be
|
||||
// relative to the project output directory which is
|
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||
// located in the project directory, you would specify the AssemblyKeyFile
|
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||
// documentation for more information on this.
|
||||
//
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
||||
@@ -0,0 +1,120 @@
|
||||
<VisualStudioProject>
|
||||
<CSHARP
|
||||
ProjectType = "Local"
|
||||
ProductVersion = "7.0.9466"
|
||||
SchemaVersion = "1.0"
|
||||
ProjectGuid = "{8199C796-57A5-4EA6-B0E0-41022918FCC2}"
|
||||
>
|
||||
<Build>
|
||||
<Settings
|
||||
ApplicationIcon = "App.ico"
|
||||
AssemblyKeyContainerName = ""
|
||||
AssemblyName = "DllTest"
|
||||
AssemblyOriginatorKeyFile = ""
|
||||
DefaultClientScript = "JScript"
|
||||
DefaultHTMLPageLayout = "Grid"
|
||||
DefaultTargetSchema = "IE50"
|
||||
DelaySign = "false"
|
||||
OutputType = "WinExe"
|
||||
RootNamespace = "DllTest"
|
||||
StartupObject = ""
|
||||
>
|
||||
<Config
|
||||
Name = "Debug"
|
||||
AllowUnsafeBlocks = "false"
|
||||
BaseAddress = "285212672"
|
||||
CheckForOverflowUnderflow = "false"
|
||||
ConfigurationOverrideFile = ""
|
||||
DefineConstants = "DEBUG;TRACE"
|
||||
DocumentationFile = ""
|
||||
DebugSymbols = "true"
|
||||
FileAlignment = "4096"
|
||||
IncrementalBuild = "true"
|
||||
Optimize = "false"
|
||||
OutputPath = "bin\Debug\"
|
||||
RegisterForComInterop = "false"
|
||||
RemoveIntegerChecks = "false"
|
||||
TreatWarningsAsErrors = "false"
|
||||
WarningLevel = "4"
|
||||
/>
|
||||
<Config
|
||||
Name = "Release"
|
||||
AllowUnsafeBlocks = "false"
|
||||
BaseAddress = "285212672"
|
||||
CheckForOverflowUnderflow = "false"
|
||||
ConfigurationOverrideFile = ""
|
||||
DefineConstants = "TRACE"
|
||||
DocumentationFile = ""
|
||||
DebugSymbols = "false"
|
||||
FileAlignment = "4096"
|
||||
IncrementalBuild = "false"
|
||||
Optimize = "true"
|
||||
OutputPath = "bin\Release\"
|
||||
RegisterForComInterop = "false"
|
||||
RemoveIntegerChecks = "false"
|
||||
TreatWarningsAsErrors = "false"
|
||||
WarningLevel = "4"
|
||||
/>
|
||||
</Settings>
|
||||
<References>
|
||||
<Reference
|
||||
Name = "System"
|
||||
AssemblyName = "System"
|
||||
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.0.3705\System.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Data"
|
||||
AssemblyName = "System.Data"
|
||||
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Drawing"
|
||||
AssemblyName = "System.Drawing"
|
||||
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.Windows.Forms"
|
||||
AssemblyName = "System.Windows.Forms"
|
||||
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
|
||||
/>
|
||||
<Reference
|
||||
Name = "System.XML"
|
||||
AssemblyName = "System.Xml"
|
||||
HintPath = "C:\WINNT\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
|
||||
/>
|
||||
</References>
|
||||
</Build>
|
||||
<Files>
|
||||
<Include>
|
||||
<File
|
||||
RelPath = "App.ico"
|
||||
BuildAction = "Content"
|
||||
/>
|
||||
<File
|
||||
RelPath = "AssemblyInfo.cs"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "dris.cs"
|
||||
SubType = "Code"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "Form1.cs"
|
||||
SubType = "Form"
|
||||
BuildAction = "Compile"
|
||||
/>
|
||||
<File
|
||||
RelPath = "Form1.resx"
|
||||
DependentUpon = "Form1.cs"
|
||||
BuildAction = "EmbeddedResource"
|
||||
/>
|
||||
<File
|
||||
RelPath = "readme.txt"
|
||||
BuildAction = "Content"
|
||||
/>
|
||||
</Include>
|
||||
</Files>
|
||||
</CSHARP>
|
||||
</VisualStudioProject>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllTest", "DllTest.csproj", "{8199C796-57A5-4EA6-B0E0-41022918FCC2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
ConfigName.0 = Debug
|
||||
ConfigName.1 = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectDependencies) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{8199C796-57A5-4EA6-B0E0-41022918FCC2}.Debug.ActiveCfg = Debug|.NET
|
||||
{8199C796-57A5-4EA6-B0E0-41022918FCC2}.Debug.Build.0 = Debug|.NET
|
||||
{8199C796-57A5-4EA6-B0E0-41022918FCC2}.Release.ActiveCfg = Release|.NET
|
||||
{8199C796-57A5-4EA6-B0E0-41022918FCC2}.Release.Build.0 = Release|.NET
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,874 @@
|
||||
// !! We strongly recommend that you read the "readme.txt" file in the sample code folder.
|
||||
// !! It contains important instructions on how to use the sample code
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using System.Data;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DllTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for Form1.
|
||||
/// </summary>
|
||||
public class Form1 : System.Windows.Forms.Form
|
||||
{
|
||||
private System.Windows.Forms.Label label1;
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.Container components = null;
|
||||
|
||||
public Form1()
|
||||
{
|
||||
//
|
||||
// Required for Windows Form Designer support
|
||||
//
|
||||
InitializeComponent();
|
||||
|
||||
//
|
||||
// TODO: Add any constructor code after InitializeComponent call
|
||||
//
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
protected override void Dispose( bool disposing )
|
||||
{
|
||||
if( disposing )
|
||||
{
|
||||
if (components != null)
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
}
|
||||
base.Dispose( disposing );
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
|
||||
this.label1.Location = new System.Drawing.Point(72, 72);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(160, 40);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "It Worked!";
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
|
||||
this.ClientSize = new System.Drawing.Size(296, 205);
|
||||
this.Controls.AddRange(new System.Windows.Forms.Control[] {
|
||||
this.label1});
|
||||
this.Name = "Form1";
|
||||
this.Text = "Form1";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
public const int MY_SDSN = 10101; // !!!! change this value to be the value of your SDSN (demo = 10101)
|
||||
public const string MY_PRODCODE = "DEMO"; // !!!! change this value to match the Product Code in the dongle
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
/* The sample code contains 11 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.
|
||||
|
||||
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
|
||||
// this function displays the current network users
|
||||
DisplayNetUsers
|
||||
|
||||
If you are using Dinkey Lite then you can only use 4 functions:
|
||||
ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc
|
||||
*/
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
// call the function(s) of your choice here
|
||||
// in this example I have chosen a standard protection check
|
||||
if (ProtCheck() != 0)
|
||||
return; // check fails - exit program
|
||||
Application.Run(new Form1());
|
||||
}
|
||||
|
||||
// ************************* our 10 functions follow *************************
|
||||
|
||||
// **************************** ProtCheck *********************************
|
||||
// standard protection check
|
||||
public static int ProtCheck()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.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 = DinkeyPro.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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dris.prodcode != MY_PRODCODE)
|
||||
{
|
||||
MessageBox.Show("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if you are using a network dongle and you want to list the network users then use this function:
|
||||
// DisplayNetUsers(dris);
|
||||
|
||||
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.
|
||||
private static 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 Dinkey Lite copy the sample code from DinkeyLook
|
||||
public static int ProtCheckWithAlg()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & 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).
|
||||
// you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
|
||||
dris.var_a = 1; // sample values
|
||||
dris.var_b = 2;
|
||||
dris.var_c = 3;
|
||||
dris.var_d = 4;
|
||||
dris.var_e = 5;
|
||||
dris.var_f = 6;
|
||||
dris.var_g = 7;
|
||||
dris.var_h = 8;
|
||||
|
||||
ret_code = DinkeyPro.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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
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)
|
||||
{
|
||||
MessageBox.Show("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************** WriteBytes ******************************
|
||||
// This writes the Data 0,1,2,3,4,5,6,7,8,9 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 18 bytes long.
|
||||
// if you want to write a string then you need to convert it to a byte array first:
|
||||
// encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is of ASCIIEncoding type.
|
||||
public static int WriteBytes()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataToWrite = {0,1,2,3,4,5,6,7,8,9};
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataToWrite.GetLength(0);
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite);
|
||||
|
||||
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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************ ReadBytes ************************************
|
||||
// This reads 10 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 18 bytes long.
|
||||
// if you want to read a string then you need to convert it from a byte array (via an array of char)
|
||||
// CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding
|
||||
// your_string = new String(CharArray, 0, your_string_length);
|
||||
public static int ReadBytes()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataToRead = new byte[10];
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataToRead.GetLength(0);
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataToRead);
|
||||
|
||||
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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
DataToRead[0], DataToRead[1], DataToRead[2], DataToRead[3], DataToRead[4], DataToRead[5], DataToRead[6], DataToRead[7], DataToRead[8], DataToRead[9]);
|
||||
MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
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
|
||||
// if you want to encrypt of decrypt string then see comment for WriteBytes and ReadBytes
|
||||
public static int EncryptUserData()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] Data = {0,1,2,3,4,5,6,7,8,9};
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT;
|
||||
dris.rw_length = Data.GetLength(0);
|
||||
dris.data_crypt_key_num = 1;
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, Data);
|
||||
|
||||
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 the same data to get the original values
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_length = Data.GetLength(0);
|
||||
dris.data_crypt_key_num = 1;
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, Data);
|
||||
|
||||
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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]);
|
||||
MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
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
|
||||
private static 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;
|
||||
}
|
||||
|
||||
|
||||
// !!!! please overwrite this function with the one generated by DinkeyAdd
|
||||
private static void CryptDRIS(DRIS dris)
|
||||
{
|
||||
int i, j, k;
|
||||
byte[] bigseed = new byte[256];
|
||||
byte[] S = new byte[256];
|
||||
byte temp, t;
|
||||
byte[] dris_bytes = new byte[Marshal.SizeOf(dris)];
|
||||
|
||||
dris.DrisToByteArray(dris, dris_bytes); // convert DRIS to byte array so we can encrypt it
|
||||
|
||||
for (i=0; i<256; i+=8)
|
||||
{
|
||||
dris.Set4Bytes(bigseed, i, dris.seed1);
|
||||
dris.Set4Bytes(bigseed, i+4, dris.seed2);
|
||||
}
|
||||
for (i=0; i<256; i++)
|
||||
S[i] = (byte)i;
|
||||
for (i=0, j=0; i<256; i++)
|
||||
{
|
||||
j = (j + S[i] + bigseed[i] + 123) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
}
|
||||
for (i=0, j=0, k=16; k<Marshal.SizeOf(dris); k++)
|
||||
{
|
||||
i = (i + 1) % 256;
|
||||
j = (j + S[i] + 212) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
t = (byte)(S[i] + S[j] + 97);
|
||||
dris_bytes[k] ^= S[t];
|
||||
}
|
||||
dris.ByteArrayToDris(dris_bytes, dris); // convert it back again
|
||||
return;
|
||||
}
|
||||
|
||||
// !!!! please overwrite this function with the one generated by DinkeyAdd
|
||||
private static void CryptApiData(DRIS dris, byte[] data, int length, int alg_answer)
|
||||
{
|
||||
int i, j, k;
|
||||
byte[] bigseed = new byte[256];
|
||||
byte[] S = new byte[256];
|
||||
byte temp, t;
|
||||
|
||||
for (i=0; i<256; i+=8)
|
||||
{
|
||||
dris.Set4Bytes(bigseed, i, dris.seed1);
|
||||
dris.Set4Bytes(bigseed, i+4, dris.seed2);
|
||||
}
|
||||
for (i=0; i<256; i++)
|
||||
S[i] = (byte)i;
|
||||
for (i=0, j=0; i<256; i++)
|
||||
{
|
||||
j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
}
|
||||
for (i=0, j=0, k=0; k<length; k++)
|
||||
{
|
||||
i = (i + 1) % 256;
|
||||
j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
t = (byte)(S[i] + S[j] + ((alg_answer >> 16) & 0xff));
|
||||
data[k] ^= S[t];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// **************************** ProtCheckEnc ******************************
|
||||
// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
|
||||
public static int ProtCheckEnc()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.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); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, null);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dris.prodcode != MY_PRODCODE)
|
||||
{
|
||||
MessageBox.Show("Incorrect Product Code! Please modify your source code so that MY_PRODCODE is set to be the Product Code in the dongle.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
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 Dinkey Lite copy source from DinkeyLook.
|
||||
// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
|
||||
public static int ProtCheckWithAlgEnc()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & 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).
|
||||
// you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
|
||||
dris.var_a = 1; // sample values
|
||||
dris.var_b = 2;
|
||||
dris.var_c = 3;
|
||||
dris.var_d = 4;
|
||||
dris.var_e = 5;
|
||||
dris.var_f = 6;
|
||||
dris.var_g = 7;
|
||||
dris.var_h = 8;
|
||||
|
||||
CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, null);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
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)
|
||||
{
|
||||
MessageBox.Show("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************** WriteBytesEnc ***************************
|
||||
// This writes the Data 0,1,2,3,4,5,6,7,8,9 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 18 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.
|
||||
// if you want to write strings then see comment for WriteBytes
|
||||
public static int WriteBytesEnc()
|
||||
{
|
||||
int ret_code, alg_ans;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataToWrite = {0,1,2,3,4,5,6,7,8,9};
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataToWrite.GetLength(0);
|
||||
|
||||
// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = 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(dris, DataToWrite, DataToWrite.GetLength(0), alg_ans);
|
||||
|
||||
CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************ ReadBytesEnc *********************************
|
||||
// This reads 10 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 18 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.
|
||||
// if you want to read strings then see comment for ReadBytes
|
||||
public static int ReadBytesEnc()
|
||||
{
|
||||
int ret_code, alg_ans;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataRead = new byte[10];
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataRead.GetLength(0);
|
||||
|
||||
// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = 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); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataRead);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// decrypt data that was read.
|
||||
CryptApiData(dris, DataRead, DataRead.GetLength(0), alg_ans);
|
||||
|
||||
DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
DataRead[0], DataRead[1], DataRead[2], DataRead[3], DataRead[4], DataRead[5], DataRead[6], DataRead[7], DataRead[8], DataRead[9]);
|
||||
MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
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 & 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.
|
||||
// if you want to encrypt of decrypt strings then see comment for WriteBytes and ReadBytes
|
||||
public static int EncryptUserDataEnc()
|
||||
{
|
||||
int ret_code, alg_ans;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
DRIS dris2 = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] Data = {0,1,2,3,4,5,6,7,8,9};
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT;
|
||||
dris.rw_length = Data.GetLength(0);
|
||||
dris.data_crypt_key_num = 1;
|
||||
|
||||
// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = 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 pass to our API.
|
||||
CryptApiData(dris, Data, Data.GetLength(0), alg_ans);
|
||||
|
||||
CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, Data);
|
||||
|
||||
CryptDRIS(dris); // 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, ...
|
||||
|
||||
// NB use another dris so that we can ensure elements are initialised to different random numbers
|
||||
dris2.size = Marshal.SizeOf(dris2);
|
||||
dris2.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data
|
||||
dris2.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris2.rw_length = Data.GetLength(0);
|
||||
dris2.data_crypt_key_num = 1;
|
||||
|
||||
CryptDRIS(dris2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris2, Data);
|
||||
|
||||
CryptDRIS(dris2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0)
|
||||
{
|
||||
DisplayError(ret_code, dris2.ext_err);
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
// later in your code you can check other values in the DRIS...
|
||||
if (dris2.sdsn != MY_SDSN)
|
||||
{
|
||||
MessageBox.Show("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// later on in your program you can check the return code again
|
||||
if (dris2.ret_code != 0)
|
||||
{
|
||||
MessageBox.Show("Dinkey Dongle protection error", "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
alg_ans = MyRWAlgorithm(dris2.var_a, dris2.var_b, dris2.var_c, dris2.var_d, dris2.var_e, dris2.var_f, dris2.var_g, dris2.var_h);
|
||||
// decrypt data that was passed to us by the API.
|
||||
CryptApiData(dris2, Data, Data.GetLength(0), alg_ans);
|
||||
|
||||
DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]);
|
||||
MessageBox.Show(DisplayString, "DllSample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *********************** DisplayNetUsers *******************************
|
||||
// This function displays the current network users (for DinkeyNet only).
|
||||
// The DDProtCheck function must be called before this function is called.
|
||||
// (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want)
|
||||
public static int DisplayNetUsers(DRIS dris)
|
||||
{
|
||||
string DisplayString;
|
||||
int num_net_users, extended_error, ret_code, i, max_net_users;
|
||||
NU_INFO[] nu_info;
|
||||
|
||||
if (dris.net_users == -1)
|
||||
max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example)
|
||||
else
|
||||
max_net_users = dris.net_users;
|
||||
|
||||
if (max_net_users == 0) // no network users are allowed, so nothing to do!
|
||||
return 0;
|
||||
|
||||
if (dris.model < 3) {
|
||||
MessageBox.Show("A network dongle has not been detected. Therefore you cannot display the network users.", "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret_code = DinkeyPro.DDGetNetUserList(null, out num_net_users, out nu_info, max_net_users, out extended_error);
|
||||
|
||||
if (ret_code != 0)
|
||||
{
|
||||
MessageBox.Show(String.Format("Error {0}/{1} finding network user information.", ret_code, extended_error), "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayString = String.Format("number of net users: {0}", num_net_users) + Environment.NewLine;
|
||||
for (i=0; i<num_net_users; i++)
|
||||
{
|
||||
DisplayString += String.Format("{0}. licence: {1}, user: {2}, computer: {3}, ip address: {4}", i+1,
|
||||
nu_info[i].licenceName, nu_info[i].userName, nu_info[i].computerName, nu_info[i].ipAddress);
|
||||
DisplayString += Environment.NewLine;
|
||||
}
|
||||
MessageBox.Show(DisplayString, "Net Users", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
// to display common errors that occur - !!!! you will want to change these messages
|
||||
public static void DisplayError(int ret_code, int ext_err)
|
||||
{
|
||||
string DisplayString;
|
||||
|
||||
switch(ret_code)
|
||||
{
|
||||
case 401:
|
||||
MessageBox.Show("Error! No dongles detected!", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 403:
|
||||
MessageBox.Show("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 404:
|
||||
MessageBox.Show("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 409:
|
||||
MessageBox.Show("Error! The dongle detected has not been programmed by DinkeyAdd.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 410:
|
||||
MessageBox.Show("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 411:
|
||||
MessageBox.Show("Error! The dongle detected does not contain the licence associated with this program.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 413:
|
||||
MessageBox.Show("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 417:
|
||||
MessageBox.Show("Error! One or more of the parameters set in the DRIS is incorrect.\nIt could also be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 423:
|
||||
MessageBox.Show("Error! The number of network users has been exceeded.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 435:
|
||||
MessageBox.Show("Error! DinkeyServer has not been detected on the network.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
case 922:
|
||||
MessageBox.Show("Error! The Software Key has expired.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
// internal error - cannot load DLL
|
||||
case -1:
|
||||
MessageBox.Show("Error! Cannot call protection check because DLL is not loaded.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
|
||||
default:
|
||||
DisplayString = "An error occurred checking the dongle. Error: " + String.Format("{0:D}", ret_code) + "\nExtended Error: " + String.Format("{0:D}", ext_err);
|
||||
MessageBox.Show(DisplayString, "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 1.3
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">1.3</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1">this is my long string</data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
[base64 mime encoded serialized .NET Framework object]
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
[base64 mime encoded string representing a byte array form of the .NET Framework object]
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="$this.Name">
|
||||
<value>Form1</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,287 @@
|
||||
// !! this file should not be modified
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory
|
||||
using System.Text; // so we can extract / set strings in the DRIS
|
||||
using System.Windows.Forms; // for MessageBox
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public class DRIS
|
||||
{
|
||||
// the first 4 fields are never encrypted
|
||||
public byte header1; // should be set to "DRIS"
|
||||
public byte header2;
|
||||
public byte header3;
|
||||
public byte header4;
|
||||
// inputs
|
||||
public int size; // size of this structure
|
||||
public int seed1; // seed for data/dris encryption
|
||||
public int seed2; // as above
|
||||
// (maybe encrypted from now on)
|
||||
public int function; // specify only one function
|
||||
public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2...
|
||||
public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS
|
||||
public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data
|
||||
public int rw_offset; // offset in the dongle data area to read or write data
|
||||
public int rw_length; // length of data are to read/write/encrypt/decrypt
|
||||
public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below)
|
||||
private byte[] _alt_licence_name = null; // protection check for different licence instead of this one
|
||||
public int var_a; // variable values for user algorithm
|
||||
public int var_b;
|
||||
public int var_c;
|
||||
public int var_d;
|
||||
public int var_e;
|
||||
public int var_f;
|
||||
public int var_g;
|
||||
public int var_h;
|
||||
public int alg_number; // the number of the user algorithm that you want to execute
|
||||
|
||||
// outputs
|
||||
public int ret_code; // return code from the protection check
|
||||
public int ext_err; // extended error
|
||||
public int type; // type of dongle detected. 1 = Pro, 2 = FD
|
||||
public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited
|
||||
public int sdsn; // Software Developer's Serial Number
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] // NB access this field by using prodcode (see below)
|
||||
private byte[] _prodcode = null; // product code (null-terminated)
|
||||
public uint dongle_number;
|
||||
public int update_number;
|
||||
public uint data_area_size; // size of the data area in the dongle detected
|
||||
public int max_alg_num; // number of algorithms in the dongle detected
|
||||
public int execs; // executions left: -1 indicates 'no limit'
|
||||
public int exp_day; // expiry day: -1 indicates 'no limit'
|
||||
public int exp_month; // expiry month: -1 indicates 'no limit'
|
||||
public int exp_year; // expiry year: -1 indicates 'no limit'
|
||||
public uint features; // features value
|
||||
public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit'
|
||||
public int alg_answer; // answer to the user algorithm executed with the given variable values
|
||||
public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future.
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below)
|
||||
private byte[] _fd_drive = null; // fd drive letter (null-terminated)
|
||||
public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key
|
||||
public int swkey_exp_day; // software key expiry date (if software key detected)
|
||||
public int swkey_exp_month;
|
||||
public int swkey_exp_year;
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string prodcode
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(12);
|
||||
foreach (byte b in _prodcode)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string fd_drive
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
foreach (byte b in _fd_drive)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string alt_licence_name
|
||||
{
|
||||
set
|
||||
{
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder(value, 256);
|
||||
for (i=0; i<sb.Length; i++)
|
||||
{
|
||||
_alt_licence_name[i] = (byte)sb[i];
|
||||
}
|
||||
_alt_licence_name[i] = 0; // null terminate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sets 4 bytes from an integer at the specified offset in a data array
|
||||
public void Set4Bytes(byte[] data, int offset, int value)
|
||||
{
|
||||
data[offset] = (byte)(value & 0xff);
|
||||
data[offset+1] = (byte)((value >> 8) & 0xff);
|
||||
data[offset+2] = (byte)((value >> 16) & 0xff);
|
||||
data[offset+3] = (byte)((value >> 24) & 0xff);
|
||||
return;
|
||||
}
|
||||
|
||||
// converts to DRIS structure to a byte array (so we can do encryption)
|
||||
public void DrisToByteArray(DRIS dris, byte[] data)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// converts a byte array to the DRIS structure (so we can do encryption)
|
||||
public void ByteArrayToDris(byte[] data, DRIS dris)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// to make a new instance of this class, initialise every element to a random value and then set the header
|
||||
public DRIS()
|
||||
{
|
||||
Random rnd = new Random();
|
||||
Byte[] temp = new Byte[Marshal.SizeOf(this)];
|
||||
rnd.NextBytes(temp);
|
||||
ByteArrayToDris(temp, this);
|
||||
this.header1 = (byte)'D';
|
||||
this.header2 = (byte)'R';
|
||||
this.header3 = (byte)'I';
|
||||
this.header4 = (byte)'S';
|
||||
}
|
||||
|
||||
// functions - must specify only one
|
||||
public const int PROTECTION_CHECK = 1; // checks for dongle, check program params...
|
||||
public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs
|
||||
public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area
|
||||
public const int READ_DATA_AREA = 4; // protection check + reads dongle data area
|
||||
public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data
|
||||
public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data
|
||||
public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed.
|
||||
public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed)
|
||||
|
||||
// flags - can specify as many as you like
|
||||
public const int DEC_ONE_EXEC = 1; // decrement execs by 1
|
||||
public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement
|
||||
public const int START_NET_USER = 4; // starts a network user
|
||||
public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers
|
||||
public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports
|
||||
public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports
|
||||
public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one
|
||||
public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time
|
||||
public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS
|
||||
public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public struct NU_INFO
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string licenceName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
|
||||
public string userName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string computerName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
|
||||
public string ipAddress;
|
||||
}
|
||||
|
||||
// 32-bit protection check (loads 32-bit DLL)
|
||||
class DDProtCheck32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// 64-bit protection check (loads 64-bit DLL)
|
||||
class DDProtCheck64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// 32-bit get network user info (loads 32-bit DLL)
|
||||
class DDGetNetUserList32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// 64-bit get network user info (loads 64-bit DLL)
|
||||
class DDGetNetUserList64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// call our API - we only want to load the correct DLL for the bit-ness of the computer. The other DLL may not exist.
|
||||
class DinkeyPro
|
||||
{
|
||||
// calls the DDProtCheck function in the appropriate DLL
|
||||
public static int DDProtCheck(DRIS dris, byte[] data)
|
||||
{
|
||||
int ret_code = -1;
|
||||
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheck32.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheck64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error)
|
||||
{
|
||||
int ret_code = -1;
|
||||
int i;
|
||||
extended_error = num_net_users = 0;
|
||||
byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))];
|
||||
byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))];
|
||||
GCHandle MyGC;
|
||||
nu_info = null;
|
||||
|
||||
// call the function and get info as a byte array
|
||||
if (IntPtr.Size == 4)
|
||||
ret_code = DDGetNetUserList32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
else
|
||||
ret_code = DDGetNetUserList64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
|
||||
if (ret_code != 0)
|
||||
return ret_code;
|
||||
|
||||
// convert byte array to an array of structs
|
||||
nu_info = new NU_INFO[num_net_users];
|
||||
for (i=0; i<num_net_users; i++)
|
||||
{
|
||||
Array.Copy(nu_info_bytes, i*Marshal.SizeOf(typeof(NU_INFO)), nu_info_one_struct, 0, Marshal.SizeOf(typeof(NU_INFO)));
|
||||
MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned);
|
||||
nu_info[i] = (NU_INFO)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(NU_INFO));
|
||||
MyGC.Free();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
// !! this file should not be modified
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory
|
||||
using System.Text; // so we can extract / set strings in the DRIS
|
||||
using System.Windows.Forms; // for MessageBox
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public class DRIS
|
||||
{
|
||||
// the first 4 fields are never encrypted
|
||||
public byte header1; // should be set to "DRIS"
|
||||
public byte header2;
|
||||
public byte header3;
|
||||
public byte header4;
|
||||
// inputs
|
||||
public int size; // size of this structure
|
||||
public int seed1; // seed for data/dris encryption
|
||||
public int seed2; // as above
|
||||
// (maybe encrypted from now on)
|
||||
public int function; // specify only one function
|
||||
public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2...
|
||||
public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS
|
||||
public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data
|
||||
public int rw_offset; // offset in the dongle data area to read or write data
|
||||
public int rw_length; // length of data are to read/write/encrypt/decrypt
|
||||
public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below)
|
||||
private byte[] _alt_licence_name = null; // protection check for different licence instead of this one
|
||||
public int var_a; // variable values for user algorithm
|
||||
public int var_b;
|
||||
public int var_c;
|
||||
public int var_d;
|
||||
public int var_e;
|
||||
public int var_f;
|
||||
public int var_g;
|
||||
public int var_h;
|
||||
public int alg_number; // the number of the user algorithm that you want to execute
|
||||
|
||||
// outputs
|
||||
public int ret_code; // return code from the protection check
|
||||
public int ext_err; // extended error
|
||||
public int type; // type of dongle detected. 1 = Pro, 2 = FD
|
||||
public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited
|
||||
public int sdsn; // Software Developer's Serial Number
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] // NB access this field by using prodcode (see below)
|
||||
private byte[] _prodcode = null; // product code (null-terminated)
|
||||
public uint dongle_number;
|
||||
public int update_number;
|
||||
public uint data_area_size; // size of the data area in the dongle detected
|
||||
public int max_alg_num; // number of algorithms in the dongle detected
|
||||
public int execs; // executions left: -1 indicates 'no limit'
|
||||
public int exp_day; // expiry day: -1 indicates 'no limit'
|
||||
public int exp_month; // expiry month: -1 indicates 'no limit'
|
||||
public int exp_year; // expiry year: -1 indicates 'no limit'
|
||||
public uint features; // features value
|
||||
public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit'
|
||||
public int alg_answer; // answer to the user algorithm executed with the given variable values
|
||||
public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future.
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below)
|
||||
private byte[] _fd_drive = null; // fd drive letter (null-terminated)
|
||||
public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key
|
||||
public int swkey_exp_day; // software key expiry date (if software key detected)
|
||||
public int swkey_exp_month;
|
||||
public int swkey_exp_year;
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string prodcode
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(12);
|
||||
foreach (byte b in _prodcode)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string fd_drive
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
foreach (byte b in _fd_drive)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string alt_licence_name
|
||||
{
|
||||
set
|
||||
{
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder(value, 256);
|
||||
for (i=0; i<sb.Length; i++)
|
||||
{
|
||||
_alt_licence_name[i] = (byte)sb[i];
|
||||
}
|
||||
_alt_licence_name[i] = 0; // null terminate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sets 4 bytes from an integer at the specified offset in a data array
|
||||
public void Set4Bytes(byte[] data, int offset, int value)
|
||||
{
|
||||
data[offset] = (byte)(value & 0xff);
|
||||
data[offset+1] = (byte)((value >> 8) & 0xff);
|
||||
data[offset+2] = (byte)((value >> 16) & 0xff);
|
||||
data[offset+3] = (byte)((value >> 24) & 0xff);
|
||||
return;
|
||||
}
|
||||
|
||||
// converts to DRIS structure to a byte array (so we can do encryption)
|
||||
public void DrisToByteArray(DRIS dris, byte[] data)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// converts a byte array to the DRIS structure (so we can do encryption)
|
||||
public void ByteArrayToDris(byte[] data, DRIS dris)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// to make a new instance of this class, initialise every element to a random value and then set the header
|
||||
public DRIS()
|
||||
{
|
||||
Random rnd = new Random();
|
||||
Byte[] temp = new Byte[Marshal.SizeOf(this)];
|
||||
rnd.NextBytes(temp);
|
||||
ByteArrayToDris(temp, this);
|
||||
this.header1 = (byte)'D';
|
||||
this.header2 = (byte)'R';
|
||||
this.header3 = (byte)'I';
|
||||
this.header4 = (byte)'S';
|
||||
}
|
||||
|
||||
// functions - must specify only one
|
||||
public const int PROTECTION_CHECK = 1; // checks for dongle, check program params...
|
||||
public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs
|
||||
public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area
|
||||
public const int READ_DATA_AREA = 4; // protection check + reads dongle data area
|
||||
public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data
|
||||
public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data
|
||||
public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed.
|
||||
public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed)
|
||||
|
||||
// flags - can specify as many as you like
|
||||
public const int DEC_ONE_EXEC = 1; // decrement execs by 1
|
||||
public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement
|
||||
public const int START_NET_USER = 4; // starts a network user
|
||||
public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers
|
||||
public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports
|
||||
public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports
|
||||
public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one
|
||||
public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time
|
||||
public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS
|
||||
public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public struct NU_INFO
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string licenceName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
|
||||
public string userName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string computerName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
|
||||
public string ipAddress;
|
||||
}
|
||||
|
||||
// DDProtCheck
|
||||
|
||||
// Windows 32-bit protection check (loads 32-bit DLL)
|
||||
class DDProtCheckWin32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Windows 64-bit protection check (loads 64-bit DLL)
|
||||
class DDProtCheckWin64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Linux 64-bit protection check (loads 64-bit so) (NB only 64-bit Linux is supported by .NET Core)
|
||||
class DDProtCheckLin64
|
||||
{
|
||||
[DllImport("dplin64.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Mac 64-bit protection check (loads 64-bit dylib) (NB only 64-bit Mac code is supported by .NET Core) (NB we found that the release module dpmac64.dylib crashed)
|
||||
class DDProtCheckMac64
|
||||
{
|
||||
[DllImport("dpmac64debug.dylib", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// DDGetNetUserList
|
||||
|
||||
// Windows 32-bit get network user info (loads 32-bit DLL)
|
||||
class DDGetNetUserListWin32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Windows 64-bit get network user info (loads 64-bit DLL)
|
||||
class DDGetNetUserListWin64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Linux 64-bit get network user info (loads 64-bit DLL)
|
||||
class DDGetNetUserListLin64
|
||||
{
|
||||
[DllImport("dplin64.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist.
|
||||
class DinkeyPro
|
||||
{
|
||||
// calls the DDProtCheck function in the appropriate DLL
|
||||
public static int DDProtCheck(DRIS dris, byte[] data)
|
||||
{
|
||||
int ret_code = -1;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7
|
||||
{
|
||||
if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckWin64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckWin32.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckLin64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dplin64.so. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckMac64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpmac64debug.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Error! Dinkey Pro/FD not supported on this OS.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error)
|
||||
{
|
||||
int ret_code = -1;
|
||||
int i;
|
||||
extended_error = num_net_users = 0;
|
||||
byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))];
|
||||
byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))];
|
||||
GCHandle MyGC;
|
||||
nu_info = null;
|
||||
|
||||
// call the function and get info as a byte array
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
else
|
||||
ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
MessageBox.Show("Error! This function is not supported in the Mac debug module.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
|
||||
if (ret_code != 0)
|
||||
return ret_code;
|
||||
|
||||
// convert byte array to an array of structs
|
||||
nu_info = new NU_INFO[num_net_users];
|
||||
for (i=0; i<num_net_users; i++)
|
||||
{
|
||||
Array.Copy(nu_info_bytes, i*Marshal.SizeOf(typeof(NU_INFO)), nu_info_one_struct, 0, Marshal.SizeOf(typeof(NU_INFO)));
|
||||
MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned);
|
||||
nu_info[i] = (NU_INFO)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(NU_INFO));
|
||||
MyGC.Free();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
// !! this file should not be modified
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory
|
||||
using System.Text; // so we can extract / set strings in the DRIS
|
||||
using System.Windows.Forms; // for MessageBox
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public class DRIS
|
||||
{
|
||||
// the first 4 fields are never encrypted
|
||||
public byte header1; // should be set to "DRIS"
|
||||
public byte header2;
|
||||
public byte header3;
|
||||
public byte header4;
|
||||
// inputs
|
||||
public int size; // size of this structure
|
||||
public int seed1; // seed for data/dris encryption
|
||||
public int seed2; // as above
|
||||
// (maybe encrypted from now on)
|
||||
public int function; // specify only one function
|
||||
public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2...
|
||||
public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS
|
||||
public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data
|
||||
public int rw_offset; // offset in the dongle data area to read or write data
|
||||
public int rw_length; // length of data are to read/write/encrypt/decrypt
|
||||
public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below)
|
||||
private byte[] _alt_licence_name = null; // protection check for different licence instead of this one
|
||||
public int var_a; // variable values for user algorithm
|
||||
public int var_b;
|
||||
public int var_c;
|
||||
public int var_d;
|
||||
public int var_e;
|
||||
public int var_f;
|
||||
public int var_g;
|
||||
public int var_h;
|
||||
public int alg_number; // the number of the user algorithm that you want to execute
|
||||
|
||||
// outputs
|
||||
public int ret_code; // return code from the protection check
|
||||
public int ext_err; // extended error
|
||||
public int type; // type of dongle detected. 1 = Pro, 2 = FD
|
||||
public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited
|
||||
public int sdsn; // Software Developer's Serial Number
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=12)] // NB access this field by using prodcode (see below)
|
||||
private byte[] _prodcode = null; // product code (null-terminated)
|
||||
public uint dongle_number;
|
||||
public int update_number;
|
||||
public uint data_area_size; // size of the data area in the dongle detected
|
||||
public int max_alg_num; // number of algorithms in the dongle detected
|
||||
public int execs; // executions left: -1 indicates 'no limit'
|
||||
public int exp_day; // expiry day: -1 indicates 'no limit'
|
||||
public int exp_month; // expiry month: -1 indicates 'no limit'
|
||||
public int exp_year; // expiry year: -1 indicates 'no limit'
|
||||
public uint features; // features value
|
||||
public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit'
|
||||
public int alg_answer; // answer to the user algorithm executed with the given variable values
|
||||
public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future.
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below)
|
||||
private byte[] _fd_drive = null; // fd drive letter (null-terminated)
|
||||
public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key
|
||||
public int swkey_exp_day; // software key expiry date (if software key detected)
|
||||
public int swkey_exp_month;
|
||||
public int swkey_exp_year;
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string prodcode
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(12);
|
||||
foreach (byte b in _prodcode)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string fd_drive
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
foreach (byte b in _fd_drive)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string alt_licence_name
|
||||
{
|
||||
set
|
||||
{
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder(value, 256);
|
||||
for (i=0; i<sb.Length; i++)
|
||||
{
|
||||
_alt_licence_name[i] = (byte)sb[i];
|
||||
}
|
||||
_alt_licence_name[i] = 0; // null terminate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sets 4 bytes from an integer at the specified offset in a data array
|
||||
public void Set4Bytes(byte[] data, int offset, int value)
|
||||
{
|
||||
data[offset] = (byte)(value & 0xff);
|
||||
data[offset+1] = (byte)((value >> 8) & 0xff);
|
||||
data[offset+2] = (byte)((value >> 16) & 0xff);
|
||||
data[offset+3] = (byte)((value >> 24) & 0xff);
|
||||
return;
|
||||
}
|
||||
|
||||
// converts to DRIS structure to a byte array (so we can do encryption)
|
||||
public void DrisToByteArray(DRIS dris, byte[] data)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// converts a byte array to the DRIS structure (so we can do encryption)
|
||||
public void ByteArrayToDris(byte[] data, DRIS dris)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// to make a new instance of this class, initialise every element to a random value and then set the header
|
||||
public DRIS()
|
||||
{
|
||||
Random rnd = new Random();
|
||||
Byte[] temp = new Byte[Marshal.SizeOf(this)];
|
||||
rnd.NextBytes(temp);
|
||||
ByteArrayToDris(temp, this);
|
||||
this.header1 = (byte)'D';
|
||||
this.header2 = (byte)'R';
|
||||
this.header3 = (byte)'I';
|
||||
this.header4 = (byte)'S';
|
||||
}
|
||||
|
||||
// functions - must specify only one
|
||||
public const int PROTECTION_CHECK = 1; // checks for dongle, check program params...
|
||||
public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs
|
||||
public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area
|
||||
public const int READ_DATA_AREA = 4; // protection check + reads dongle data area
|
||||
public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data
|
||||
public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data
|
||||
public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed.
|
||||
public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed)
|
||||
|
||||
// flags - can specify as many as you like
|
||||
public const int DEC_ONE_EXEC = 1; // decrement execs by 1
|
||||
public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement
|
||||
public const int START_NET_USER = 4; // starts a network user
|
||||
public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers
|
||||
public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports
|
||||
public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports
|
||||
public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one
|
||||
public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time
|
||||
public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS
|
||||
public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public struct NU_INFO
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string licenceName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
|
||||
public string userName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string computerName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
|
||||
public string ipAddress;
|
||||
}
|
||||
|
||||
// DDProtCheck
|
||||
|
||||
// Windows 32-bit protection check (loads 32-bit DLL)
|
||||
class DDProtCheckWin32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Windows 64-bit protection check (loads 64-bit DLL)
|
||||
class DDProtCheckWin64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Linux 32-bit protection check (loads 32-bit so)
|
||||
class DDProtCheckLin32
|
||||
{
|
||||
[DllImport("dplin32.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Linux 64-bit protection check (loads 64-bit so)
|
||||
class DDProtCheckLin64
|
||||
{
|
||||
[DllImport("dplin64.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Mac 32-bit protection check (loads 32-bit dylib)
|
||||
class DDProtCheckMac32
|
||||
{
|
||||
[DllImport("dpmac32.dylib", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// Mac 64-bit protection check (loads 64-bit dylib)
|
||||
class DDProtCheckMac64
|
||||
{
|
||||
[DllImport("dpmac64.dylib", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
}
|
||||
|
||||
// DDGetNetUserList
|
||||
|
||||
// Windows 32-bit get network user info (loads 32-bit DLL)
|
||||
class DDGetNetUserListWin32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Windows 64-bit get network user info (loads 64-bit DLL)
|
||||
class DDGetNetUserListWin64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Linux 32-bit get network user info (loads 32-bit so)
|
||||
class DDGetNetUserListLin32
|
||||
{
|
||||
[DllImport("dplin32.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Linux 64-bit get network user info (loads 64-bit so)
|
||||
class DDGetNetUserListLin64
|
||||
{
|
||||
[DllImport("dplin64.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Mac 32-bit get network user info (loads 32-bit dylib)
|
||||
class DDGetNetUserListMac32
|
||||
{
|
||||
[DllImport("dpmac32.dylib", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Mac 64-bit get network user info (loads 64-bit dylib)
|
||||
class DDGetNetUserListMac64
|
||||
{
|
||||
[DllImport("dpmac64.dylib", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist.
|
||||
class DinkeyPro
|
||||
{
|
||||
// calls the DDProtCheck function in the appropriate DLL
|
||||
public static int DDProtCheck(DRIS dris, byte[] data)
|
||||
{
|
||||
int ret_code = -1;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7
|
||||
{
|
||||
if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckWin64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckWin32.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckLin64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dplin64.do. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckLin32.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dplin32.so. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckMac64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpmac64.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckMac32.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
MessageBox.Show("Error! Cannot find dpmac32.dylib. This should be in the same folder as DllTest.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Error! Dinkey Pro/FD not supported on this OS.", "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
public static int DDGetNetUserList(string licence_name, out int num_net_users, out NU_INFO[] nu_info, int num_info_structs, out int extended_error)
|
||||
{
|
||||
int ret_code = -1;
|
||||
int i;
|
||||
extended_error = num_net_users = 0;
|
||||
byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))];
|
||||
byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))];
|
||||
GCHandle MyGC;
|
||||
nu_info = null;
|
||||
|
||||
// call the function and get info as a byte array
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
else
|
||||
ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
else
|
||||
ret_code = DDGetNetUserListLin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
ret_code = DDGetNetUserListMac64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
else
|
||||
ret_code = DDGetNetUserListMac32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
|
||||
if (ret_code != 0)
|
||||
return ret_code;
|
||||
|
||||
// convert byte array to an array of structs
|
||||
nu_info = new NU_INFO[num_net_users];
|
||||
for (i=0; i<num_net_users; i++)
|
||||
{
|
||||
Array.Copy(nu_info_bytes, i*Marshal.SizeOf(typeof(NU_INFO)), nu_info_one_struct, 0, Marshal.SizeOf(typeof(NU_INFO)));
|
||||
MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned);
|
||||
nu_info[i] = (NU_INFO)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(NU_INFO));
|
||||
MyGC.Free();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
DllTest - sample code to call Runtime module in C# using VS 2002 and higher
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This project is written in Visual Studio 2002 but will work in more recent versions of Visual Studio
|
||||
(they will upgrade the Project to the latest version. If prompted you should also upgrade the .NET
|
||||
framework the project requires). If you are using .NET Core then please read the notes at the bottom
|
||||
of this file. If you are using VS 2022 (or higher) then you will receive warnings when compiling this
|
||||
code - use the VS 2022 project instead.
|
||||
|
||||
The main source files in the project are:
|
||||
|
||||
File name Description
|
||||
Form1.cs main source code file for C#
|
||||
dris.cs contains the DRIS structure and low-level functions to manipulate it.
|
||||
|
||||
The best approach is to compile the sample code and see how it works and then to take the appropriate code
|
||||
and apply it to your own project. You should include the dris.cs file in your project and use/modify which
|
||||
ever functions from form1.cs you feel are appropriate. The dris.cs file should not be modified.
|
||||
|
||||
The sample code contains 11 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.
|
||||
|
||||
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 will also probably want to replace our error messages 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: microcosm.com/kb).
|
||||
|
||||
For users of Visual Studio 2005 or higher, the default setting for projects is to compile for the Target
|
||||
Platform "Any". This means that on 32-bit Windows, your code will run as 32-bit code (and needs to call
|
||||
dpwin32.dll) and under 64-bit Windows your code will run as 64-bit code (and needs to call dpwin64.dll).
|
||||
The sample code works this out automatically. If you select the target platform as "x86" then it will
|
||||
always be 32-bit and so you only need to use dpwin32.dll. If you select "x64" then your code will be
|
||||
64-bit and you only need to use dpwin64.dll.
|
||||
|
||||
Note - as you are using the API method in this sample you should protect dpwin32.dll and/or dpwin64.dll
|
||||
and not your program. Because your program is linked to the DLL it is protected. You can also protect
|
||||
your program with the Shell Method should you wish.
|
||||
|
||||
Note - if you are compiling for the Platform target "Any" (and therefore need to protect both dpwin32.dll
|
||||
and dpwin64.dll) then you will probably want to protect these modules to the same licence so that they share
|
||||
a common set of protection parameters.
|
||||
|
||||
Make sure you remember to do the following:
|
||||
|
||||
1) Insert the following namespaces in your code file:
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
2) Insert the dris.cs file in your project.
|
||||
|
||||
2) You need to output the protected dpwin32.dll (dpwin64.dll) to the folder that contains your assemblies.
|
||||
Otherwise the System.DllNotFoundException error will appear when you run DllTest.
|
||||
|
||||
If you wish you can rename dpwin32.dll (dpwin64.dll) to a name of your choice. In this case you will need to
|
||||
modify the dll name in the dris.cs file.
|
||||
|
||||
Note - CSharp is an interpreted language and so it is easier to decompile than other languages. You can
|
||||
improve security if you use an obfuscator to obfuscate your code. Or - even better - you could use the
|
||||
Shell Method to protect your assemblies. This encrypts your code (making it impossible to decompile).
|
||||
|
||||
Notes on Debugging 64-bit Code
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
When you use the 64-bit runtime module (dpwin64.dll) to protect your software the anti-debug code is so
|
||||
strong that if you are debugging your code, after the call DDProtCheck then it will crash with an SEH
|
||||
exception. If you want to be able to debug your code then you can setup your project so that your code calls
|
||||
the debug module (dpwin64debug.dll) in your "debug" build and the standard module (dpwin64.dll) in your
|
||||
release build. You can do this by modifying the declaration of DDProtCheck64 in dris.cs like this:
|
||||
|
||||
class DDProtCheck64
|
||||
{
|
||||
#if DEBUG ' debug module
|
||||
[DllImport("dpwin64debug.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
#else ' standard module
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[] data);
|
||||
#endif
|
||||
}
|
||||
|
||||
Note - the debug module has the following restrictions:
|
||||
|
||||
1) It will not correctly start a network user (network dongles only). However, other than that the protection
|
||||
check will function correctly and return success.
|
||||
2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you
|
||||
should make sure that CryptDRIS does not get called in your debug build).
|
||||
3) The protection check will take slightly longer than normal.
|
||||
4) The DDGetNetUserList function will return error 428 (not implemented).
|
||||
5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs.
|
||||
|
||||
This behaviour does not occur in 32-bit code, so if you are using dpwin32.dll then you can debug your code.
|
||||
|
||||
Important Note for UWP app Developers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Universal Windows Platform (UWP) application (previously called Windows Store Apps or Metro Apps) are not
|
||||
compatible with Lite or Plus dongles because the restrictions imposed by these applications. However, you
|
||||
can protect these Apps with network dongles (because the restrictive access is performed by the non-UWP
|
||||
DinkeyServer process). If you do this you will need to enable the "Private Networks (Client and Server)"
|
||||
Capability in your package manifest.
|
||||
|
||||
.NET Core / .NET 5+
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The sample code provided also works with .NET Core. However, .NET Core also supports Linux and macOS as well
|
||||
as other platforms. If you want to support these OS then please replace dris.cs with dris_dotnetcore.cs.
|
||||
The files are very similar but dris_dotnetcore.cs will load the relevant native runtime module (dpwin32.dll
|
||||
under 32-bit Windows; dpwin64.dll under 64-bit Windows; dplin64.so under Linux OS; dpmac64debug.dylib under
|
||||
macOS - unfortunately the release module is not compatible with the .NET Core framework so you have to use
|
||||
the debug one. This also means that our solution is not compatible with ARM-based macOS - because the debug
|
||||
modules do not exist).
|
||||
|
||||
If you are using .NET Core version earlier than 3.0 then Windows.Forms are not supported and you will have to
|
||||
replace the MessageBox.Show lines with Console.WriteLine.
|
||||
|
||||
The Shell Method is compatible with .NET Core Console, Windows.Forms and WPF applications. It is supported
|
||||
under Windows and Linux but not macOS. It is only supported for .NET Core version 3.0 or higher. If you are
|
||||
using the Shell Method then you should protect your compiled dll and not the "appHost" (this is a native
|
||||
executable which is just a stub program that loads the assemblies in your dll). Also do not use "dotnet run"
|
||||
to launch your application - it will run the unprotected version. Either launch the executable or run using
|
||||
"dotnet <program.dll>".
|
||||
|
||||
If you publish a "single-file executable" file then although this file can be protected we do not recommend
|
||||
it because it is not secure. (The single-file executable just comprises a stub loader with your compiled
|
||||
assemblies and configuration files appended to the end of the executable. These files are just considered as
|
||||
data appended to the executable file in a custom format and therefore are not protected. When you shell
|
||||
protect your executable you are just protecting the loader but not your assemblies). Instead you need to
|
||||
build your code and then add protection before publishing. You should protect your assemblies in the obj
|
||||
directory (and in the platform type you specified) e.g. obj/Release/net5.0/win-x64, because the publish
|
||||
process takes your assemblies from this location when it builds the single-file executable. You will also
|
||||
need to distribute all the extra files that DinkeyAdd generates. e.g. <file>.dp64.dll.
|
||||
|
||||
If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET
|
||||
assemblies and native code and the .NET Shell Method does not support that.
|
||||
|
||||
Mono
|
||||
~~~~
|
||||
|
||||
The sample code provided also works with Mono. However, Mono also supports Linux and macOS, and so if you want
|
||||
to support those OS then please replace dris.cs with dris_mono.cs. Note, dris_mono.cs is very similar to
|
||||
dris_dotnetcore.cs (see above) but with Mono, 32-bit Linux and 32-bit Mac are also supported and you don't
|
||||
need to use the debug modules (for release) under macOS.
|
||||
|
||||
Visual Studio Installer Projects Extension
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can use this extension to create a project in your solution that will create an installation program / msi
|
||||
file. Please note that after your application has been built you need to protect it with DinkeyAdd before you
|
||||
can invoke the installer project. You can do this manually by building your application project (not the entire
|
||||
solution); then adding protection to your application using DinkeyAdd; then building your installer project.
|
||||
Or you can automate this by executing DinkeyAddCmd as a post-build step. For example:
|
||||
"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2
|
||||
|
||||
Note - if you specify "primary output" in your installer project then it will take the files from
|
||||
obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files
|
||||
in this folder.
|
||||
|
||||
Note - if you use the API Method you will also need to include the protected runtime modules that you use
|
||||
(e.g. dpwin64.dll). If you use the Shell Method you will also need to include in your installer project all
|
||||
of the output files mentioned by DinkeyAdd. e.g. <application_name>.dp64.dll
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DllTest", "DllTest.csproj", "{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EDCD7B70-034F-417C-B7C0-E86583C2FC5C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {02BA6556-AD6D-40BD-A7EE-65BEE2095E5C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,808 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace DllTest
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public const int MY_SDSN = 10101; // !!!! change this value to be the value of your SDSN (demo = 10101)
|
||||
public const string MY_PRODCODE = "DEMO"; // !!!! change this value to match the Product Code in the dongle
|
||||
|
||||
/* The sample code contains 11 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.
|
||||
|
||||
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
|
||||
// this function displays the current network users
|
||||
DisplayNetUsers
|
||||
|
||||
If you are using Dinkey Lite then you can only use 4 functions:
|
||||
ProtCheck, ProtCheckWithAlg, ProtCheckEnc, ProtCheckWithAlgEnc
|
||||
*/
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// call the function(s) of your choice here
|
||||
// in this example I have chosen a standard protection check
|
||||
if (ProtCheck() == 0)
|
||||
{
|
||||
DisplayMessage("It worked!"); // NB on failure a message will have already been displayed
|
||||
}
|
||||
}
|
||||
|
||||
// **************************** ProtCheck *********************************
|
||||
// standard protection check
|
||||
public static int ProtCheck()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.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 = DinkeyPro.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)
|
||||
{
|
||||
DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dris.prodcode != MY_PRODCODE)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if you are using a network dongle and you want to list the network users then use this function:
|
||||
//DisplayNetUsers(dris);
|
||||
|
||||
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.
|
||||
private static 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 Dinkey Lite copy the sample code from DinkeyLook
|
||||
public static int ProtCheckWithAlg()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & 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).
|
||||
// you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
|
||||
dris.var_a = 1; // sample values
|
||||
dris.var_b = 2;
|
||||
dris.var_c = 3;
|
||||
dris.var_d = 4;
|
||||
dris.var_e = 5;
|
||||
dris.var_f = 6;
|
||||
dris.var_g = 7;
|
||||
dris.var_h = 8;
|
||||
|
||||
ret_code = DinkeyPro.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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************** WriteBytes ******************************
|
||||
// This writes the Data 0,1,2,3,4,5,6,7,8,9 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 18 bytes long.
|
||||
// if you want to write a string then you need to convert it to a byte array first:
|
||||
// encoding.GetBytes(your_string, 0, your_string.Length, data, 0) where encoding is of ASCIIEncoding type.
|
||||
public static int WriteBytes()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataToWrite = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataToWrite.GetLength(0);
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite);
|
||||
|
||||
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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************ ReadBytes ************************************
|
||||
// This reads 10 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 18 bytes long.
|
||||
// if you want to read a string then you need to convert it from a byte array (via an array of char)
|
||||
// CharArray = encoding.GetChars(data); where CharArray is of type char[] and encoding is of type ASCIIEncoding
|
||||
// your_string = new String(CharArray, 0, your_string_length);
|
||||
public static int ReadBytes()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataToRead = new byte[10];
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataToRead.GetLength(0);
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataToRead);
|
||||
|
||||
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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
DataToRead[0], DataToRead[1], DataToRead[2], DataToRead[3], DataToRead[4], DataToRead[5], DataToRead[6], DataToRead[7], DataToRead[8], DataToRead[9]);
|
||||
DisplayMessage(DisplayString);
|
||||
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
|
||||
// if you want to encrypt of decrypt string then see comment for WriteBytes and ReadBytes
|
||||
public static int EncryptUserData()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] Data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT;
|
||||
dris.rw_length = Data.GetLength(0);
|
||||
dris.data_crypt_key_num = 1;
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, Data);
|
||||
|
||||
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 the same data to get the original values
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_length = Data.GetLength(0);
|
||||
dris.data_crypt_key_num = 1;
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, Data);
|
||||
|
||||
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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]);
|
||||
DisplayMessage(DisplayString);
|
||||
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
|
||||
private static 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;
|
||||
}
|
||||
|
||||
|
||||
// !!!! please overwrite this function with the one generated by DinkeyAdd
|
||||
private static void CryptDRIS(DRIS dris)
|
||||
{
|
||||
int i, j, k;
|
||||
byte[] bigseed = new byte[256];
|
||||
byte[] S = new byte[256];
|
||||
byte temp, t;
|
||||
byte[] dris_bytes = new byte[Marshal.SizeOf(dris)];
|
||||
|
||||
dris.DrisToByteArray(dris, dris_bytes); // convert DRIS to byte array so we can encrypt it
|
||||
|
||||
for (i = 0; i < 256; i += 8)
|
||||
{
|
||||
dris.Set4Bytes(bigseed, i, dris.seed1);
|
||||
dris.Set4Bytes(bigseed, i + 4, dris.seed2);
|
||||
}
|
||||
for (i = 0; i < 256; i++)
|
||||
S[i] = (byte)i;
|
||||
for (i = 0, j = 0; i < 256; i++)
|
||||
{
|
||||
j = (j + S[i] + bigseed[i] + 123) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
}
|
||||
for (i = 0, j = 0, k = 16; k < Marshal.SizeOf(dris); k++)
|
||||
{
|
||||
i = (i + 1) % 256;
|
||||
j = (j + S[i] + 212) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
t = (byte)(S[i] + S[j] + 97);
|
||||
dris_bytes[k] ^= S[t];
|
||||
}
|
||||
dris.ByteArrayToDris(dris_bytes, dris); // convert it back again
|
||||
return;
|
||||
}
|
||||
|
||||
// !!!! please overwrite this function with the one generated by DinkeyAdd
|
||||
private static void CryptApiData(DRIS dris, byte[] data, int length, int alg_answer)
|
||||
{
|
||||
int i, j, k;
|
||||
byte[] bigseed = new byte[256];
|
||||
byte[] S = new byte[256];
|
||||
byte temp, t;
|
||||
|
||||
for (i = 0; i < 256; i += 8)
|
||||
{
|
||||
dris.Set4Bytes(bigseed, i, dris.seed1);
|
||||
dris.Set4Bytes(bigseed, i + 4, dris.seed2);
|
||||
}
|
||||
for (i = 0; i < 256; i++)
|
||||
S[i] = (byte)i;
|
||||
for (i = 0, j = 0; i < 256; i++)
|
||||
{
|
||||
j = (j + S[i] + bigseed[i] + (alg_answer & 0xff)) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
}
|
||||
for (i = 0, j = 0, k = 0; k < length; k++)
|
||||
{
|
||||
i = (i + 1) % 256;
|
||||
j = (j + S[i] + ((alg_answer >> 8) & 0xff)) % 256;
|
||||
temp = S[i];
|
||||
S[i] = S[j];
|
||||
S[j] = temp;
|
||||
t = (byte)(S[i] + S[j] + ((alg_answer >> 16) & 0xff));
|
||||
data[k] ^= S[t];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// **************************** ProtCheckEnc ******************************
|
||||
// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
|
||||
public static int ProtCheckEnc()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.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); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, null);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
DisplayMessage("Incorrect SDSN! Please modify your source code so that MY_SDSN is set to be your SDSN.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dris.prodcode != MY_PRODCODE)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
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 Dinkey Lite copy source from DinkeyLook.
|
||||
// We encrypt the DRIS passed to the API. Patch the CryptDRIS function in this file from source code generated by DinkeyAdd.
|
||||
public static int ProtCheckWithAlgEnc()
|
||||
{
|
||||
int ret_code;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.EXECUTE_ALGORITHM; // standard protection check & 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).
|
||||
// you should remove these entries if you are using Dinkey Lite so that algorithm arguments are random
|
||||
dris.var_a = 1; // sample values
|
||||
dris.var_b = 2;
|
||||
dris.var_c = 3;
|
||||
dris.var_d = 4;
|
||||
dris.var_e = 5;
|
||||
dris.var_f = 6;
|
||||
dris.var_g = 7;
|
||||
dris.var_h = 8;
|
||||
|
||||
CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, null);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey protection error!\nYou have not patched your algorithm in the MyAlgorithm routine");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************** WriteBytesEnc ***************************
|
||||
// This writes the Data 0,1,2,3,4,5,6,7,8,9 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 18 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.
|
||||
// if you want to write strings then see comment for WriteBytes
|
||||
public static int WriteBytesEnc()
|
||||
{
|
||||
int ret_code, alg_ans;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataToWrite = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.WRITE_DATA_AREA; // standard protection check & write data to dongle
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataToWrite.GetLength(0);
|
||||
|
||||
// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = 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(dris, DataToWrite, DataToWrite.GetLength(0), alg_ans);
|
||||
|
||||
CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataToWrite);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ************************ ReadBytesEnc *********************************
|
||||
// This reads 10 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 18 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.
|
||||
// if you want to read strings then see comment for ReadBytes
|
||||
public static int ReadBytesEnc()
|
||||
{
|
||||
int ret_code, alg_ans;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] DataRead = new byte[10];
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.READ_DATA_AREA; // standard protection check & read data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris.rw_offset = 7;
|
||||
dris.rw_length = DataRead.GetLength(0);
|
||||
|
||||
// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = 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); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, DataRead);
|
||||
|
||||
CryptDRIS(dris); // 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)
|
||||
{
|
||||
DisplayMessage("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)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// decrypt data that was read.
|
||||
CryptApiData(dris, DataRead, DataRead.GetLength(0), alg_ans);
|
||||
|
||||
DisplayString = "Dinkey Dongle data area, offset 7: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
DataRead[0], DataRead[1], DataRead[2], DataRead[3], DataRead[4], DataRead[5], DataRead[6], DataRead[7], DataRead[8], DataRead[9]);
|
||||
DisplayMessage(DisplayString);
|
||||
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 & 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.
|
||||
// if you want to encrypt of decrypt strings then see comment for WriteBytes and ReadBytes
|
||||
public static int EncryptUserDataEnc()
|
||||
{
|
||||
int ret_code, alg_ans;
|
||||
DRIS dris = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
DRIS dris2 = new DRIS(); // initialise the DRIS with random values & set the header
|
||||
byte[] Data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
string DisplayString;
|
||||
|
||||
dris.size = Marshal.SizeOf(dris);
|
||||
dris.function = DRIS.ENCRYPT_USER_DATA; // standard protection check & encrypt data
|
||||
dris.flags = DRIS.USE_FUNCTION_ARGUMENT;
|
||||
dris.rw_length = Data.GetLength(0);
|
||||
dris.data_crypt_key_num = 1;
|
||||
|
||||
// calculate r/w algorithm answer - NB need to replace MyRWAlgorithm code with code for r/w algorithm
|
||||
alg_ans = 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 pass to our API.
|
||||
CryptApiData(dris, Data, Data.GetLength(0), alg_ans);
|
||||
|
||||
CryptDRIS(dris); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris, Data);
|
||||
|
||||
CryptDRIS(dris); // 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, ...
|
||||
|
||||
// NB use another dris so that we can ensure elements are initialised to different random numbers
|
||||
dris2.size = Marshal.SizeOf(dris2);
|
||||
dris2.function = DRIS.DECRYPT_USER_DATA; // standard protection check & read data
|
||||
dris2.flags = DRIS.USE_FUNCTION_ARGUMENT; // you have to do it like this in C#
|
||||
dris2.rw_length = Data.GetLength(0);
|
||||
dris2.data_crypt_key_num = 1;
|
||||
|
||||
CryptDRIS(dris2); // encrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
ret_code = DinkeyPro.DDProtCheck(dris2, Data);
|
||||
|
||||
CryptDRIS(dris2); // decrypt DRIS (!!!!you should separate from DDProtCheck for greater security)
|
||||
|
||||
if (ret_code != 0)
|
||||
{
|
||||
DisplayError(ret_code, dris2.ext_err);
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
// later in your code you can check other values in the DRIS...
|
||||
if (dris2.sdsn != MY_SDSN)
|
||||
{
|
||||
DisplayMessage("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 (dris2.ret_code != 0)
|
||||
{
|
||||
DisplayMessage("Dinkey Dongle protection error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
alg_ans = MyRWAlgorithm(dris2.var_a, dris2.var_b, dris2.var_c, dris2.var_d, dris2.var_e, dris2.var_f, dris2.var_g, dris2.var_h);
|
||||
// decrypt data that was passed to us by the API.
|
||||
CryptApiData(dris2, Data, Data.GetLength(0), alg_ans);
|
||||
|
||||
DisplayString = "decrypted data is: " + String.Format("{0:D2} {1:D2} {2:D2} {3:D2} {4:D2} {5:D2} {6:D2} {7:D2} {8:D2} {9:D2}",
|
||||
Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9]);
|
||||
DisplayMessage(DisplayString);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *********************** DisplayNetUsers *******************************
|
||||
// This function displays the current network users (for DinkeyNet only).
|
||||
// The DDProtCheck function must be called before this function is called.
|
||||
// (Normally you would use DinkeyServer to view the network users but this enables you to do it from the client if you want)
|
||||
public static int DisplayNetUsers(DRIS dris)
|
||||
{
|
||||
string DisplayString;
|
||||
int num_net_users, extended_error, ret_code, i, max_net_users;
|
||||
NU_INFO[]? nu_info;
|
||||
|
||||
if (dris.net_users == -1)
|
||||
max_net_users = 100; // if unlimited network users are allowed then display up to 100 users (for example)
|
||||
else
|
||||
max_net_users = dris.net_users;
|
||||
|
||||
if (max_net_users == 0) // no network users are allowed, so nothing to do!
|
||||
return 0;
|
||||
|
||||
if (dris.model < 3)
|
||||
{
|
||||
DisplayMessage("A network dongle has not been detected. Therefore you cannot display the network users.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret_code = DinkeyPro.DDGetNetUserList(null, out num_net_users, out nu_info, max_net_users, out extended_error);
|
||||
|
||||
if (ret_code != 0)
|
||||
{
|
||||
DisplayMessage(String.Format("Error {0}/{1} finding network user information.", ret_code, extended_error));
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayString = String.Format("number of net users: {0}", num_net_users) + Environment.NewLine;
|
||||
if (nu_info != null)
|
||||
{
|
||||
for (i = 0; i < num_net_users; i++)
|
||||
{
|
||||
DisplayString += String.Format("{0}. licence: {1}, user: {2}, computer: {3}, ip address: {4}", i + 1,
|
||||
nu_info[i].licenceName, nu_info[i].userName, nu_info[i].computerName, nu_info[i].ipAddress);
|
||||
DisplayString += Environment.NewLine;
|
||||
}
|
||||
}
|
||||
DisplayMessage(DisplayString);
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
// to display common errors that occur - !!!! you will want to change these messages
|
||||
private static void DisplayError(int ret_code, int ext_err)
|
||||
{
|
||||
string DisplayString;
|
||||
|
||||
switch (ret_code)
|
||||
{
|
||||
case 401:
|
||||
DisplayMessage("Error! No dongles detected!");
|
||||
break;
|
||||
|
||||
case 403:
|
||||
DisplayMessage("Error! A dongle was detected but it was a different type to the one specified in DinkeyAdd.");
|
||||
break;
|
||||
|
||||
case 404:
|
||||
DisplayMessage("Error! A dongle was detected but it was a different model to those specified in DinkeyAdd.");
|
||||
break;
|
||||
|
||||
case 409:
|
||||
DisplayMessage("Error! The dongle detected has not been programmed by DinkeyAdd.");
|
||||
break;
|
||||
|
||||
case 410:
|
||||
DisplayMessage("Error! A dongle was detected but it has a different Product Code to the one specified in DinkeyAdd.");
|
||||
break;
|
||||
|
||||
case 411:
|
||||
DisplayMessage("Error! The dongle detected does not contain the licence associated with this program.");
|
||||
break;
|
||||
|
||||
case 413:
|
||||
DisplayMessage("Error! This program has not been protected by DinkeyAdd. For guidance please read the DinkeyAdd chapter of the Dinkey manual.");
|
||||
break;
|
||||
|
||||
case 417:
|
||||
DisplayMessage("Error! One or more of the parameters set in the DRIS is incorrect.\nIt could also be caused if you are encrypting the DRIS in your code but did not specify DRIS encryption in DinkeyAdd - or vice versa.");
|
||||
break;
|
||||
|
||||
case 423:
|
||||
DisplayMessage("Error! The number of network users has been exceeded.");
|
||||
break;
|
||||
|
||||
case 435:
|
||||
DisplayMessage("Error! DinkeyServer has not been detected on the network.");
|
||||
break;
|
||||
|
||||
case 922:
|
||||
DisplayMessage("Error! The Software Key has expired.");
|
||||
break;
|
||||
|
||||
// internal error - cannot load DLL
|
||||
case -1:
|
||||
DisplayMessage("Error! Cannot call protection check because DLL is not loaded.");
|
||||
break;
|
||||
|
||||
default:
|
||||
DisplayString = "An error occurred checking the dongle. Error: " + String.Format("{0:D}", ret_code) + "\nExtended Error: " + String.Format("{0:D}", ext_err);
|
||||
DisplayMessage(DisplayString);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
private static void DisplayMessage(string my_message)
|
||||
{
|
||||
// !!!! for Console programs use this line
|
||||
Console.WriteLine(my_message);
|
||||
// !!!! for Windows programs use this line
|
||||
// MessageBox.Show(my_message, "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
// !! this file should not be modified
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices; // so we can marshal the DRIS as a block of memory
|
||||
using System.Text; // so we can extract / set strings in the DRIS
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public class DRIS
|
||||
{
|
||||
// the first 4 fields are never encrypted
|
||||
public byte header1; // should be set to "DRIS"
|
||||
public byte header2;
|
||||
public byte header3;
|
||||
public byte header4;
|
||||
// inputs
|
||||
public int size; // size of this structure
|
||||
public int seed1; // seed for data/dris encryption
|
||||
public int seed2; // as above
|
||||
// (maybe encrypted from now on)
|
||||
public int function; // specify only one function
|
||||
public int flags; // options for the function selected. To use more than one OR them together: OPTION1 | OPTION2...
|
||||
public uint execs_decrement; // amount by which to dec execs if we use flag: DEC_MANY_EXECS
|
||||
public int data_crypt_key_num; // number of the key (1-3) that the dongle uses to encrypt or decrypt user data
|
||||
public int rw_offset; // offset in the dongle data area to read or write data
|
||||
public int rw_length; // length of data are to read/write/encrypt/decrypt
|
||||
public IntPtr DoNotUse; // do not use the rw_data_ptr element use the "Data" argument of the DDProtCheck function
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=256)] // NB access this field by using alg_licence_name (see below)
|
||||
private byte[] _alt_licence_name = { 0 }; // protection check for different licence instead of this one
|
||||
public int var_a; // variable values for user algorithm
|
||||
public int var_b;
|
||||
public int var_c;
|
||||
public int var_d;
|
||||
public int var_e;
|
||||
public int var_f;
|
||||
public int var_g;
|
||||
public int var_h;
|
||||
public int alg_number; // the number of the user algorithm that you want to execute
|
||||
|
||||
// outputs
|
||||
public int ret_code; // return code from the protection check
|
||||
public int ext_err; // extended error
|
||||
public int type; // type of dongle detected. 1 = Pro, 2 = FD
|
||||
public int model; // model of dongle detected. 1 = Lite, 2 = Plus, 4 = Net 5, 7 = Net Unlimited
|
||||
public int sdsn; // Software Developer's Serial Number
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] // NB access this field by using prodcode (see below)
|
||||
private byte[] _prodcode = { 0 }; // product code (null-terminated)
|
||||
public uint dongle_number;
|
||||
public int update_number;
|
||||
public uint data_area_size; // size of the data area in the dongle detected
|
||||
public int max_alg_num; // number of algorithms in the dongle detected
|
||||
public int execs; // executions left: -1 indicates 'no limit'
|
||||
public int exp_day; // expiry day: -1 indicates 'no limit'
|
||||
public int exp_month; // expiry month: -1 indicates 'no limit'
|
||||
public int exp_year; // expiry year: -1 indicates 'no limit'
|
||||
public uint features; // features value
|
||||
public int net_users; // maximum number of network users for the dongle detected: -1 indicates 'mo limit'
|
||||
public int alg_answer; // answer to the user algorithm executed with the given variable values
|
||||
public uint fd_capacity; // capacity of the data area in FD dongle. Currently fixed at ~10MB but may change in the future.
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] // NB access this field by using fd_drive (see below)
|
||||
private byte[] _fd_drive = { 0 }; // fd drive letter (null-terminated)
|
||||
public int swkey_type; // 0 = no swkey detected, 1 = temporary software key, 2 = demo software key
|
||||
public int swkey_exp_day; // software key expiry date (if software key detected)
|
||||
public int swkey_exp_month;
|
||||
public int swkey_exp_year;
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string prodcode
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(12);
|
||||
foreach (byte b in _prodcode)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string fd_drive
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
foreach (byte b in _fd_drive)
|
||||
{
|
||||
if (b == 0)
|
||||
return sb.ToString();
|
||||
else
|
||||
sb.Append((char)b);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// NB we have to do it this way because we cannot encrypt strings correctly unless they are byte arrays
|
||||
public string alt_licence_name
|
||||
{
|
||||
set
|
||||
{
|
||||
int i;
|
||||
StringBuilder sb = new StringBuilder(value, 256);
|
||||
for (i=0; i<sb.Length; i++)
|
||||
{
|
||||
_alt_licence_name[i] = (byte)sb[i];
|
||||
}
|
||||
_alt_licence_name[i] = 0; // null terminate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sets 4 bytes from an integer at the specified offset in a data array
|
||||
public void Set4Bytes(byte[] data, int offset, int value)
|
||||
{
|
||||
data[offset] = (byte)(value & 0xff);
|
||||
data[offset+1] = (byte)((value >> 8) & 0xff);
|
||||
data[offset+2] = (byte)((value >> 16) & 0xff);
|
||||
data[offset+3] = (byte)((value >> 24) & 0xff);
|
||||
return;
|
||||
}
|
||||
|
||||
// converts to DRIS structure to a byte array (so we can do encryption)
|
||||
public void DrisToByteArray(DRIS dris, byte[] data)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.StructureToPtr(dris, MyGC.AddrOfPinnedObject(), false);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// converts a byte array to the DRIS structure (so we can do encryption)
|
||||
public void ByteArrayToDris(byte[] data, DRIS dris)
|
||||
{
|
||||
GCHandle MyGC = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), dris);
|
||||
MyGC.Free();
|
||||
return;
|
||||
}
|
||||
|
||||
// to make a new instance of this class, initialise every element to a random value and then set the header
|
||||
public DRIS()
|
||||
{
|
||||
Random rnd = new Random();
|
||||
Byte[] temp = new Byte[Marshal.SizeOf(this)];
|
||||
rnd.NextBytes(temp);
|
||||
ByteArrayToDris(temp, this);
|
||||
this.header1 = (byte)'D';
|
||||
this.header2 = (byte)'R';
|
||||
this.header3 = (byte)'I';
|
||||
this.header4 = (byte)'S';
|
||||
}
|
||||
|
||||
// functions - must specify only one
|
||||
public const int PROTECTION_CHECK = 1; // checks for dongle, check program params...
|
||||
public const int EXECUTE_ALGORITHM = 2; // protection check + calculate answer for specified algorithm with specified inputs
|
||||
public const int WRITE_DATA_AREA = 3; // protection check + writes dongle data area
|
||||
public const int READ_DATA_AREA = 4; // protection check + reads dongle data area
|
||||
public const int ENCRYPT_USER_DATA = 5; // protection check + the dongle will encrypt user data
|
||||
public const int DECRYPT_USER_DATA = 6; // protection check + the dongle will decrypt user data
|
||||
public const int FAST_PRESENCE_CHECK = 7; // checks for the presence of the correct dongle only with minimal security, no flags allowed.
|
||||
public const int STOP_NET_USER = 8; // stops a network user (a protection check is NOT performed)
|
||||
|
||||
// flags - can specify as many as you like
|
||||
public const int DEC_ONE_EXEC = 1; // decrement execs by 1
|
||||
public const int DEC_MANY_EXECS = 2; // decrement execs by number specified in execs_decrement
|
||||
public const int START_NET_USER = 4; // starts a network user
|
||||
public const int USE_FUNCTION_ARGUMENT = 16; // use the extra argument in the function for pointers
|
||||
public const int CHECK_LOCAL_FIRST = 32; // always look in local ports before looking in network ports
|
||||
public const int CHECK_NETWORK_FIRST = 64; // always look on the network before looking in local ports
|
||||
public const int USE_ALT_LICENCE_NAME = 128; // use name specified in alt_licence_name instead of the default one
|
||||
public const int DONT_SET_MAXDAYS_EXPIRY = 256; // if the max days expiry date has not been calculated then do not do it this time
|
||||
public const int MATCH_DONGLE_NUMBER = 512; // restrict the search to match the dongle number specified in the DRIS
|
||||
public const int DONT_RETURN_FD_DRIVE = 1024; // if an FD dongle has been detected then don't return the flash drive/mount name in the DRIS
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=1)]
|
||||
public struct NU_INFO
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string licenceName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
|
||||
public string userName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
|
||||
public string computerName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
|
||||
public string ipAddress;
|
||||
}
|
||||
|
||||
// DDProtCheck
|
||||
|
||||
// Windows 32-bit protection check (loads 32-bit DLL)
|
||||
class DDProtCheckWin32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data);
|
||||
}
|
||||
|
||||
// Windows 64-bit protection check (loads 64-bit DLL)
|
||||
class DDProtCheckWin64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data);
|
||||
}
|
||||
|
||||
// Linux 64-bit protection check (loads 64-bit so) (NB only 64-bit Linux is supported by .NET Core)
|
||||
class DDProtCheckLin64
|
||||
{
|
||||
[DllImport("dplin64.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data);
|
||||
}
|
||||
|
||||
// Mac 64-bit protection check (loads 64-bit dylib) (NB only x64 Mac code is supported by .NET Core) (NB we found that the release module dpmac64.dylib crashed)
|
||||
class DDProtCheckMac64
|
||||
{
|
||||
[DllImport("dpmac64debug.dylib", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data);
|
||||
}
|
||||
|
||||
// DDGetNetUserList
|
||||
|
||||
// Windows 32-bit get network user info (loads 32-bit DLL)
|
||||
class DDGetNetUserListWin32
|
||||
{
|
||||
[DllImport("dpwin32.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Windows 64-bit get network user info (loads 64-bit DLL)
|
||||
class DDGetNetUserListWin64
|
||||
{
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// Linux 64-bit get network user info (loads 64-bit DLL)
|
||||
class DDGetNetUserListLin64
|
||||
{
|
||||
[DllImport("dplin64.so", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDGetNetUserList(string? licence_name, out int num_net_users, byte[] nu_info_bytes, int num_info_structs, out int extended_error);
|
||||
}
|
||||
|
||||
// call our API - we only want to load the correct DLL for the OS and bit-ness of the computer. The other DLLs may not exist.
|
||||
class DinkeyPro
|
||||
{
|
||||
// calls the DDProtCheck function in the appropriate DLL
|
||||
public static int DDProtCheck(DRIS dris, byte[]? data)
|
||||
{
|
||||
int ret_code = -1;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // method valid from .NET Core 1.0 and .NET framework 4.7
|
||||
{
|
||||
if (Environment.Is64BitProcess) // method valid from .NET Core 2.0 and .NET framework 4.0
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckWin64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
DisplayMessage("Error! Cannot find dpwin64.dll. This should be in the same folder as DllTest.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckWin32.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
DisplayMessage("Error! Cannot find dpwin32.dll. This should be in the same folder as DllTest.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckLin64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
DisplayMessage("Error! Cannot find dplin64.so. This should be in the same folder as DllTest.");
|
||||
}
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
try
|
||||
{
|
||||
ret_code = DDProtCheckMac64.DDProtCheck(dris, data);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
DisplayMessage("Error! Cannot find dpmac64debug.dylib. This should be in the same folder as DllTest.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessage("Error! Dinkey Pro/FD not supported on this OS.");
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
public static int DDGetNetUserList(string? licence_name, out int num_net_users, out NU_INFO[]? nu_info, int num_info_structs, out int extended_error)
|
||||
{
|
||||
int ret_code = -1;
|
||||
int i;
|
||||
extended_error = num_net_users = 0;
|
||||
byte[] nu_info_bytes = new byte[num_info_structs * Marshal.SizeOf(typeof(NU_INFO))];
|
||||
byte[] nu_info_one_struct = new byte[Marshal.SizeOf(typeof(NU_INFO))];
|
||||
GCHandle MyGC;
|
||||
nu_info = null;
|
||||
|
||||
// call the function and get info as a byte array
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (Environment.Is64BitProcess)
|
||||
ret_code = DDGetNetUserListWin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
else
|
||||
ret_code = DDGetNetUserListWin32.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
ret_code = DDGetNetUserListLin64.DDGetNetUserList(licence_name, out num_net_users, nu_info_bytes, num_info_structs, out extended_error);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
DisplayMessage("Error! This function is not supported in the Mac debug module.");
|
||||
}
|
||||
|
||||
if (ret_code != 0)
|
||||
return ret_code;
|
||||
|
||||
// convert byte array to an array of structs
|
||||
nu_info = new NU_INFO[num_net_users];
|
||||
for (i=0; i<num_net_users; i++)
|
||||
{
|
||||
Array.Copy(nu_info_bytes, i*Marshal.SizeOf(typeof(NU_INFO)), nu_info_one_struct, 0, Marshal.SizeOf(typeof(NU_INFO)));
|
||||
MyGC = GCHandle.Alloc(nu_info_one_struct, GCHandleType.Pinned);
|
||||
NU_INFO? an_nu_info = (NU_INFO?)Marshal.PtrToStructure(MyGC.AddrOfPinnedObject(), typeof(NU_INFO));
|
||||
if (an_nu_info != null)
|
||||
nu_info[i] = (NU_INFO)an_nu_info;
|
||||
MyGC.Free();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void DisplayMessage(string my_message)
|
||||
{
|
||||
// !!!! for Console programs use this line
|
||||
Console.WriteLine(my_message);
|
||||
// !!!! for Windows programs use this line
|
||||
// MessageBox.Show(my_message, "Sample", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
DllTest - sample code to call Runtime module in C# 8 using VS 2022 and higher
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This project is written in Visual Studio 2022 but will work in more recent versions of Visual Studio
|
||||
(they will upgrade the Project to the latest version. If prompted you should also upgrade the .NET
|
||||
framework the project requires). If you are using an older version of Visual Studio please use the
|
||||
Visual Studio 2002 sample. The code in this project is written in C# version 10. If you are using an
|
||||
older version of C# then please use the Visual Studio 2002 project.
|
||||
|
||||
This sample is a Console application but the code can be easily adapted to be used for other types
|
||||
applications.
|
||||
|
||||
This sample is very similar to the Visual Studio 2002 sample - however the C# code has been updated
|
||||
to prevent possible Null reference exceptions - introduced in C# version 8.
|
||||
|
||||
The main source files in the project are:
|
||||
|
||||
File name Description
|
||||
program.cs main source code file for C#
|
||||
dris.cs contains the DRIS structure and low-level functions to manipulate it.
|
||||
|
||||
The best approach is to compile the sample code and see how it works and then to take the appropriate code
|
||||
and apply it to your own project. You should include the dris.cs file in your project and use/modify which
|
||||
ever functions from program.cs you feel are appropriate. The dris.cs file should not be modified.
|
||||
|
||||
The sample code contains 11 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.
|
||||
|
||||
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 will also probably want to replace our error messages 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: microcosm.com/kb).
|
||||
|
||||
Note - as you are using the API method in this sample you should protect the correct Dinkey Pro runtime
|
||||
(e.g. dpwin64.dll) and not your program directly. Because your program is linked to the DLL it is protected.
|
||||
You can also protect your program with the Shell Method should you wish.
|
||||
|
||||
You need to protect the appropriate runtime module for the Platforms you support.
|
||||
Windows x64 - dpwin64.dll
|
||||
Windows x86 - dpwin32.dll
|
||||
Linux x64 - dplin64.so
|
||||
macOS x64 - dpmac64debug.dylib
|
||||
If you are using "Any CPU" then include all of the modules. The protected runtime module should be in the
|
||||
same directory as your compiled assemblies. e.g. bin\release\net6.0.
|
||||
|
||||
Note - if you need to protect multiple runtime modules then you will probably want to protect these modules
|
||||
to the same licence so that they share a common set of protection parameters.
|
||||
|
||||
Make sure you remember to do the following:
|
||||
|
||||
1) Insert the following namespaces in your code file:
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
2) Insert the dris.cs file in your project.
|
||||
|
||||
2) You need to output the protected runtime modules(s) (e.g. dpwin64.dll etc) to the folder that contains your
|
||||
assemblies. Otherwise the System.DllNotFoundException error will appear when you run DllTest.
|
||||
|
||||
If you wish you can rename the runtime module(s) to a name of your choice. In this case you will need to
|
||||
modify the dll name in the dris.cs file.
|
||||
|
||||
Note - CSharp is an interpreted language and so it is easier to decompile than other languages. You can
|
||||
improve security if you use an obfuscator to obfuscate your code. Or - even better - you could use the
|
||||
Shell Method to protect your assemblies. This encrypts your code (making it impossible to decompile).
|
||||
|
||||
Notes on Debugging 64-bit Code
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
When you use the 64-bit runtime module (dpwin64.dll) to protect your software the anti-debug code is so
|
||||
strong that if you are debugging your code, after the call DDProtCheck then it will crash with an SEH
|
||||
exception. If you want to be able to debug your code then you can setup your project so that your code calls
|
||||
the debug module (dpwin64debug.dll) in your "debug" build and the standard module (dpwin64.dll) in your
|
||||
release build. You can do this by modifying the declaration of DDProtCheck64 in dris.cs like this:
|
||||
|
||||
class DDProtCheck64
|
||||
{
|
||||
#if DEBUG ' debug module
|
||||
[DllImport("dpwin64debug.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data);
|
||||
#else ' standard module
|
||||
[DllImport("dpwin64.dll", CharSet = CharSet.Ansi)]
|
||||
public static extern int DDProtCheck([In, Out, MarshalAs(UnmanagedType.LPStruct)]DRIS dris, byte[]? data);
|
||||
#endif
|
||||
}
|
||||
|
||||
Note - the debug module has the following restrictions:
|
||||
|
||||
1) It will not correctly start a network user (network dongles only). However, other than that the protection
|
||||
check will function correctly and return success.
|
||||
2) You will not be able to encrypt the DRIS. (If you do encrypt the DRIS in your release build then you
|
||||
should make sure that CryptDRIS does not get called in your debug build).
|
||||
3) The protection check will take slightly longer than normal.
|
||||
4) The DDGetNetUserList function will return error 428 (not implemented).
|
||||
5) A temporary subprocess is created which may be (falsely) detected as malicious by anti-virus programs.
|
||||
|
||||
This behaviour does not occur in 32-bit code, so if you are using dpwin32.dll then you can debug your code.
|
||||
|
||||
Important Note for Windows Store App Developers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Universal Windows Platform (UWP) application (previously called Windows Store Apps or Metro Apps) are not
|
||||
compatible with Lite or Plus dongles because the restrictions imposed by these applications. However, you
|
||||
can protect these Apps with network dongles (because the restrictive access is performed by the non-UWP
|
||||
DinkeyServer process). If you do this you will need to enable the "Private Networks (Client and Server)"
|
||||
Capability in your package manifest.
|
||||
|
||||
Other Notes
|
||||
~~~~~~~~~~~
|
||||
|
||||
The Shell Method is compatible with .NET Core Console, Windows.Forms and WPF applications. It is supported
|
||||
under Windows and Linux but not MacOS. It is only supported for .NET Core version 3.0 or higher. If you are
|
||||
using the Shell Method then you should protect your compiled dll and not the "appHost" (this is a native
|
||||
executable which is just a stub program that loads the assemblies in your dll). Also do not use "dotnet run"
|
||||
to launch your application - it will run the unprotected version. Either launch the executable or run using
|
||||
"dotnet <program.dll>".
|
||||
|
||||
If you publish a "single-file executable" file then although this file can be protected we do not recommend
|
||||
it because it is not secure. (The single-file executable just comprises a stub loader with your compiled
|
||||
assemblies and configuration files appended to the end of the executable. These files are just considered as
|
||||
data appended to the executable file in a custom format and therefore are not protected. When you shell
|
||||
protect your executable you are just protecting the loader but not your assemblies). Instead you need to
|
||||
build your code and then add protection before publishing. You should protect your assemblies in the obj
|
||||
directory (and in the platform type you specified) e.g. obj/Release/net6.0/win-x64, because the publish
|
||||
process takes your assemblies from this location when it builds the single-file executable. You will also
|
||||
need to distribute all the extra files that DinkeyAdd generates. e.g. <file>.dp64.dll.
|
||||
|
||||
If you publish using the ReadytoRun compilation this will not work because it includes mixtures of .NET
|
||||
assemblies and native code and the .NET Shell Method does not support that.
|
||||
|
||||
|
||||
Visual Studio Installer Projects Extension
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can use this extension to create a project in your solution that will create an installation program / msi
|
||||
file. Please note that after your application has been built you need to protect it with DinkeyAdd before you
|
||||
can invoke the installer project. You can do this manually by building your application project (not the entire
|
||||
solution); then adding protection to your application using DinkeyAdd; then building your installer project.
|
||||
Or you can automate this by executing DinkeyAddCmd as a post-build step. For example:
|
||||
"c:\program files (x86)\Dinkey Pro 7.6.0\DinkeyAdd\DinkeyAddCmd.exe" c:\adir\mydapf.dapfj /a2
|
||||
|
||||
Note - if you specify "primary output" in your installer project then it will take the files from
|
||||
obj\Release\net5.0 (for example), rather than bin\Release\net5.0. So, you need to add protection to your files
|
||||
in this folder.
|
||||
|
||||
Note - you will also need to include in your installer project all of the output files mentioned by DinkeyAdd.
|
||||
e.g. <application_name>.dp64.dll
|
||||
@@ -0,0 +1,23 @@
|
||||
Which Project should I use?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Visual Studio 2002 project will work for any version of Visual Studio from
|
||||
Visual Studio 2002 to Visual Studio 2019. This project is a Windows Form
|
||||
application targeting the .NET 4 Framework. However, it can be easily adapted to
|
||||
target .NET Core or .NET 5 (and higher). The C# code is written in C# version 1.
|
||||
|
||||
The Visual Studio 2022 project will work with Visual Studio 2022 (and higher).
|
||||
It is a Console application targeting .NET 6 and using C# version 10. If you want
|
||||
to target earlier versions of .NET or C# then use the Visual Studio 2002 project.
|
||||
|
||||
The C# code is very similar in both projects. However, C# v8 required changes to
|
||||
account for possible Null reference exceptions.
|
||||
|
||||
Visual Studio 2019 was the first version of VS to support C# v8. However, null
|
||||
reference warnings are turned off by default, so you will get warnings if you
|
||||
compile the VS2022 C# code.
|
||||
|
||||
On the other hand in Visual Studio 2022 null reference warnings are turned on by
|
||||
default so you will get warnings if you compile the VS2002 C# code.
|
||||
|
||||
Whichever project you use always read the "readme" file for important instructions.
|
||||
Reference in New Issue
Block a user