Question

I have exhausted my googling options...

We are using System Centre Orchestrator to automate user creation in multiple systems. We have a third party point of sale application that stores user passwords in the DB in an encrypted format that their application can read. For our automated inserts into the user DB we need to be able to insert an encrypted password for the application to recognise.

They wouldn't provide us with the encryption methodology they followed, but have created a DLL for us to consume written in Delphi. It takes a string passed in an XML wrapper, then returns an XML response with the encrypted password string.

From a System Centre Orchestrator point of view, what would be the best way to consume this DLL, bearing in mind myself or or Systems Engineer who is implementing this have never done something like this before.

Any suggestions are much appreciated.


EDIT

A string will be passed to the executable containing XML in the following format

<passwordEncryptionRequest>
<passwordIn>?</passwordIn>
<connectionDetails>
<serverName>?</serverName>
<serverInstance>?</serverInstance>
<userName>?</userName>
<connectionPassword>?</connectionPassword>
</connectionDetails>
</passwordEncryptionRequest>

A string will be returned from the executable containing XML in the following format

<passwordEncryptionResponse> 
<passwordOut>?</passwordOut>
<passwordEncryptionErrorResponse>
<errorDescription>?</errorDescription>
</passwordEncryptionErrorResponse>
</passwordEncryptionResponse>

The vendor came back to me and with some example code.

The function declaration is (Delphi):

function EncryptPassword(inputString: PWideChar; var outputString: PWideChar): wordbool; export; stdCall;

Example to use (c#):

[DllImport("PasswordEncrypt.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(string inputString, ref string outputString);

public FormTestEncryption()
{
    InitializeComponent();
}

private void buttonTest_Click(object sender, EventArgs e)
{

    string outputString = string.Empty;
    string inputString = string.Format(
         "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
         "<passwordEncryptionRequest>" +
             "<passwordIn>{0}</passwordIn>" +
             "<connectionDetails>" +
                 "<serverName>{1}</serverName>" +
                 "<serverInstance>{2}</serverInstance>" +
                 "<userName>{3}</userName>" +
                 "<connectionPassword>{4}</connectionPassword>" +
             "</connectionDetails>" +
         "</passwordEncryptionRequest>", 
    textPassword.Text, textServer.Text, textInstance.Text, textDBUser.Text, textDBPassword.Text);

    textOutput.Clear();

    bool result = EncryptPassword(inputString, ref outputString);

    textOutput.Text = outputString;
}

EDIT 2: After implementing the suggested definition and call i do in fact get a return string, however only when i enabled native code debugging and continued through the two break points. Stack trace was;

ntdll.dll!_RtlReportCriticalFailure@8() Unknown
ntdll.dll!_RtlpReportHeapFailure@4()    Unknown
ntdll.dll!_RtlpLogHeapFailure@24()  Unknown
ntdll.dll!_RtlFreeHeap@12() Unknown
ole32.dll!76f96e6a()    Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for ole32.dll] 
[External Code] 
WindowsFormsApplication2.exe!WindowsFormsApplication2.Form1.button1_Click(object sender, System.EventArgs e) Line 52    C#
[External Code] 
WindowsFormsApplication2.exe!WindowsFormsApplication2.Program.Main() Line 20    C#
[External Code] 

Seeing as it IS now actually implementing the 3rd party dll correctly (i checked the returned string and was fine), i have marked this as answered. I will try muscle my way through these other issues now :)

Thank you all for your input, i appreciate the help.

Regards, Dan

Was it helpful?

Solution

The function that these developers have supplied cannot be called reliably. And it certainly cannot be called from C# using the code you have been supplied. The function you have been supplied has been declared like this:

function EncryptPassword(inputString: PWideChar; 
  var outputString: PWideChar): WordBool; stdcall;

The return value really should be LongBool, but that won't actually matter.

The main problem is the second parameter. This requires the Delphi code to allocate a string, and return the pointer to that string in outputString. The calling code has no way to deallocate that string. C# code that could call the function looks like this:

[DllImport("PasswordEncrypt.dll", CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(string inputString, 
    out IntPtr outputString);

You would call it like this:

IntPtr outputStringPtr;
if (!EncryptPassword(inputString, out outputStringPtr))
    // handle error
string outputString = Marshal.PtrToStringUni(outputStringPtr);

And this leaves the memory that outputStringPtr still allocated with no way for you to deallocate it.

Of course, even this assumes that the Delphi developer allocated the memory in such a way that it would outlast the call to EncryptPassword. Quite possibly they implemented EncryptPassword like this:

function EncryptPassword(inputString: PWideChar; 
  var outputString: PWideChar): WordBool; stdcall;
var
  output: UnicodeString;
begin
  output := InternalEncryptPassword(string(intputString));
  outputString := PWideChar(output);
  Result := True;
end;

This function deallocates the memory that outputString points to as soon as it returns.

So, the bottom line is that the code you have been supplied with is no good. Here is what it should look like:

function EncryptPassword(inputString: WideString; 
  out outputString: WideString): LongBool; stdcall;

That function might be implemented something like this:

function EncryptPassword(inputString: WideString; 
  out outputString: WideString): LongBool; stdcall;
begin
  outputString := InternalEncryptPassword(intputString);
  Result := True;
end;

On the C# side it looks like this:

[DllImport("PasswordEncrypt.dll", CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(
    [MarshalAs(UnmanagedType.BStr)]
    string inputString, 
    [MarshalAs(UnmanagedType.BStr)]
    out string outputString
);

And call it like this:

string outputString;
if (!EncryptPassword(inputString, out outputString))
    // handle error

OTHER TIPS

declare function like

    function EncryptPassword(inputString: PWideChar; var outputString: PWideChar)
: wordbool; stdcall; external 'PasswordEncrypt.dll';

build a

inputstring := '<passwordEncryptionRequest>
<passwordIn>?</passwordIn>
<connectionDetails>
<serverName>?</serverName>
<serverInstance>?</serverInstance>
<userName>?</userName>
<connectionPassword>?</connectionPassword>
</connectionDetails>
</passwordEncryptionRequest>'

with passwordIn,serverName,userName datas

call the function

EncryptPassword(inputString,outputString); 

if the function return true you will get a xml string in outputString parse it and find your password in tag

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top