DLL-библиотека Delphi стороннего производителя
Я исчерпал свои возможности поиска в Google...
Мы используем System Center Orchestrator для автоматизации создания пользователей в нескольких системах. У нас есть стороннее приложение для точек продаж, которое хранит пароли пользователей в БД в зашифрованном формате, который их приложение может прочитать. Для наших автоматических вставок в пользовательскую БД мы должны иметь возможность вставить зашифрованный пароль для распознавания приложения.
Они не предоставили бы нам методологию шифрования, которой они следовали, но создали библиотеку DLL для использования в Delphi. Он принимает строку, переданную в оболочке XML, а затем возвращает ответ XML с зашифрованной строкой пароля.
С точки зрения System Center Orchestrator, что было бы лучшим способом использовать эту DLL, имея в виду меня или системного инженера, который это реализует, никогда раньше не делал ничего подобного.
Любые предложения очень ценятся.
РЕДАКТИРОВАТЬ
Строка будет передана в исполняемый файл, содержащий XML в следующем формате
<passwordEncryptionRequest>
<passwordIn>?</passwordIn>
<connectionDetails>
<serverName>?</serverName>
<serverInstance>?</serverInstance>
<userName>?</userName>
<connectionPassword>?</connectionPassword>
</connectionDetails>
</passwordEncryptionRequest>
Будет возвращена строка из исполняемого файла, содержащего XML, в следующем формате
<passwordEncryptionResponse>
<passwordOut>?</passwordOut>
<passwordEncryptionErrorResponse>
<errorDescription>?</errorDescription>
</passwordEncryptionErrorResponse>
</passwordEncryptionResponse>
Продавец вернулся ко мне и с некоторым примером кода.
Объявление функции (Delphi):
function EncryptPassword(inputString: PWideChar; var outputString: PWideChar): wordbool; export; stdCall;
Пример использования (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;
}
РЕДАКТИРОВАТЬ 2: После реализации предложенного определения и вызова я действительно получаю возвращаемую строку, однако только тогда, когда я включил отладку собственного кода и продолжил через две точки останова. След стека был;
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]
Видя, что теперь он действительно реализует стороннюю DLL правильно (я проверил возвращенную строку и все было в порядке), я отметил это как ответ. Я постараюсь обойти все эти проблемы сейчас:)
Спасибо всем за ваш вклад, я ценю помощь.
С уважением, Дэн
2 ответа
Функция, предоставленная этими разработчиками, не может быть надежно вызвана. И, конечно, он не может быть вызван из C# с использованием предоставленного вами кода. Предоставленная вами функция была объявлена так:
function EncryptPassword(inputString: PWideChar;
var outputString: PWideChar): WordBool; stdcall;
Возвращаемое значение действительно должно быть LongBool
, но это на самом деле не имеет значения.
Основная проблема - второй параметр. Это требует кода Delphi для выделения строки и возврата указателя на эту строку в outputString
, Вызывающий код не имеет возможности освободить эту строку. Код C#, который может вызвать функцию, выглядит следующим образом:
[DllImport("PasswordEncrypt.dll", CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(string inputString,
out IntPtr outputString);
Вы бы назвали это так:
IntPtr outputStringPtr;
if (!EncryptPassword(inputString, out outputStringPtr))
// handle error
string outputString = Marshal.PtrToStringUni(outputStringPtr);
И это оставляет память о том, что outputStringPtr
по-прежнему выделены без возможности для вас, чтобы освободить его.
Конечно, даже это предполагает, что разработчик Delphi выделил память таким образом, что это выдержит вызов EncryptPassword
, Вполне возможно они реализовали EncryptPassword
как это:
function EncryptPassword(inputString: PWideChar;
var outputString: PWideChar): WordBool; stdcall;
var
output: UnicodeString;
begin
output := InternalEncryptPassword(string(intputString));
outputString := PWideChar(output);
Result := True;
end;
Эта функция освобождает память, outputString
указывает на то, как только он возвращается.
Итак, суть в том, что предоставленный вами код не годится. Вот как это должно выглядеть:
function EncryptPassword(inputString: WideString;
out outputString: WideString): LongBool; stdcall;
Эта функция может быть реализована примерно так:
function EncryptPassword(inputString: WideString;
out outputString: WideString): LongBool; stdcall;
begin
outputString := InternalEncryptPassword(intputString);
Result := True;
end;
На стороне C# это выглядит так:
[DllImport("PasswordEncrypt.dll", CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(
[MarshalAs(UnmanagedType.BStr)]
string inputString,
[MarshalAs(UnmanagedType.BStr)]
out string outputString
);
И назовите это так:
string outputString;
if (!EncryptPassword(inputString, out outputString))
// handle error
Объявить функцию как
function EncryptPassword(inputString: PWideChar; var outputString: PWideChar)
: wordbool; stdcall; external 'PasswordEncrypt.dll';
построить
inputstring := '<passwordEncryptionRequest>
<passwordIn>?</passwordIn>
<connectionDetails>
<serverName>?</serverName>
<serverInstance>?</serverInstance>
<userName>?</userName>
<connectionPassword>?</connectionPassword>
</connectionDetails>
</passwordEncryptionRequest>'
с паролем в, имя_сервера, имя_пользователя
вызвать функцию
EncryptPassword(inputString,outputString);
если функция вернет true, вы получите XML-строку в outputString, проанализируете ее и найдете свой пароль в теге.