Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Проблема при использовании DLL-враппера для Crypt32.dll / 8 сообщений из 8, страница 1 из 1
25.11.2019, 13:56
    #39893934
vdix
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
Приветствую, коллеги. Есть программа, функционал которой расширяется плагинами, одно из таких расширений должно поддерживать шифрование с помощью CryptProtectData/CryptUnprotectData из Data Protection API (Crypt32.dll). Сперва написали тестовый модуль и статически прописали загрузку Crypt32.dll - всё работает отлично, написали обёртку - и тут случился облом. Операционка возвращает "System Error. Code: 127. The specified procedure could not be found" после не успешного вызова CryptProtectData() - по идее CryptUnprotectData() делает то же самое, просто до него дело не доходит. Сделал динамическую загрузку Crypt32.dll - результат тот же, если функции Crypt32.dll вызываются непосредственно из EXE - всё замечательно работает, если вызываем через обёртку из DLL - опять проблема. Иногда вместо ошибки 127 возвращается "System Error. Code: 87. The parameter is incorrect", но эта ошибка зачастую лечится перезапуском Делфи и ребилдом проекта.

Если вдруг имеет какое значение, то проект собирался на Делфи 10.2. Буду рад любой подсказке, ибо сам весь в смущении и непонятности :)

Выглядит вся эта кухня вот так:

DPCrypt.pas
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
unit DPCrypt;

{$DEFINE STATIC_LINK} // comment for dynamic DLL loading

interface

uses
  EncdDecd, Winapi.Windows, System.SysUtils;

type
  TLargeByteArray = array [0..Pred(MaxInt)] of Byte;
  PLargeByteArray = ^TLargeByteArray;
  _CRYPTOAPI_BLOB = packed record
    cbData: DWORD;
    pbData: PByte;
  end;
  TCryptoApiBlob       = _CRYPTOAPI_BLOB;
  PCrypyoApiBlob       = ^TCryptoApiBlob;
  CRYPT_INTEGER_BLOB   = _CRYPTOAPI_BLOB;
  PCRYPT_INTEGER_BLOB  = ^CRYPT_INTEGER_BLOB;
  CRYPT_UINT_BLOB      = _CRYPTOAPI_BLOB;
  PCRYPT_UINT_BLOB     = ^CRYPT_INTEGER_BLOB;
  CRYPT_OBJID_BLOB     = _CRYPTOAPI_BLOB;
  PCRYPT_OBJID_BLOB    = ^CRYPT_INTEGER_BLOB;
  CERT_NAME_BLOB       = _CRYPTOAPI_BLOB;
  PCERT_NAME_BLOB      = ^CRYPT_INTEGER_BLOB;
  CERT_RDN_VALUE_BLOB  = _CRYPTOAPI_BLOB;
  PCERT_RDN_VALUE_BLOB = ^CRYPT_INTEGER_BLOB;
  CERT_BLOB            = _CRYPTOAPI_BLOB;
  PCERT_BLOB           = ^CRYPT_INTEGER_BLOB;
  CRL_BLOB             = _CRYPTOAPI_BLOB;
  PCRL_BLOB            = ^CRYPT_INTEGER_BLOB;
  DATA_BLOB            = _CRYPTOAPI_BLOB;
  PDATA_BLOB           = ^CRYPT_INTEGER_BLOB;
  CRYPT_DATA_BLOB      = _CRYPTOAPI_BLOB;
  PCRYPT_DATA_BLOB     = ^CRYPT_INTEGER_BLOB;
  CRYPT_HASH_BLOB      = _CRYPTOAPI_BLOB;
  PCRYPT_HASH_BLOB     = ^CRYPT_INTEGER_BLOB;
  CRYPT_DIGEST_BLOB    = _CRYPTOAPI_BLOB;
  PCRYPT_DIGEST_BLOB   = ^CRYPT_INTEGER_BLOB;
  CRYPT_DER_BLOB       = _CRYPTOAPI_BLOB;
  PCRYPT_DER_BLOB      = ^CRYPT_INTEGER_BLOB;
  CRYPT_ATTR_BLOB      = _CRYPTOAPI_BLOB;
  PCRYPT_ATTR_BLOB     = ^CRYPT_INTEGER_BLOB;

  _CRYPTPROTECT_PROMPTSTRUCT = packed record
    cbSize:        DWORD;
    dwPromptFlags: DWORD;
    hwndApp:       HWND;
    szPrompt:      LPCWSTR;
  end;
  TCryptProtectPromptStruct  = _CRYPTPROTECT_PROMPTSTRUCT;
  PCryptProtectPromptStruct  = ^TCryptProtectPromptStruct;
  CRYPTPROTECT_PROMPTSTRUCT  = _CRYPTPROTECT_PROMPTSTRUCT;
  PCRYPTPROTECT_PROMPTSTRUCT = ^_CRYPTPROTECT_PROMPTSTRUCT;

function CryptProtectString(S: PWideChar): PWideChar; //stdcall;
function CryptUnprotectString(S: PWideChar): PWideChar; //stdcall;

implementation

{$IFDEF STATIC_LINK}
function CryptProtectData(pDataIn: PDATA_BLOB; szDataDescr: LPCWSTR; pOptionalEntropy: PDATA_BLOB; pReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';
function CryptUnprotectData(pDataIn: PDATA_BLOB; var ppszDataDescr: LPWSTR; pOptionalEntropy: PDATA_BLOB; pReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';
{$ELSE}
type
  TCryptProtectData = function(pDataIn: PDATA_BLOB; szDataDescr: LPCWSTR; pOptionalEntropy: PDATA_BLOB; pReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;
  TCryptUnprotectData = function(pDataIn: PDATA_BLOB; var ppszDataDescr: LPWSTR; pOptionalEntropy: PDATA_BLOB; pReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall;
var
  CryptProtectData: TCryptProtectData;
  CryptUnprotectData: TCryptUnprotectData;
  Crypt32DLL: THandle;

function LoadCrypt32DLL: Boolean;
begin
  Crypt32DLL := LoadLibrary('Crypt32.dll');
  Result := Crypt32DLL <> 0;
  if Result then
  begin
    CryptProtectData := GetProcAddress(Crypt32DLL, 'CryptProtectData');
    Result := @CryptProtectData <> nil;
    if not Result then
       Exit;
    CryptUnprotectData := GetProcAddress(Crypt32DLL, 'CryptUnprotectData');
    Result := @CryptUnprotectData <> nil;
  end;
end;
{$ENDIF}

function dpApiProtectData(var fpDataIn: TBytes): tBytes;
var
  dataIn,               // Input buffer (clear-text/data)
  dataOut: DATA_BLOB;   // Output buffer (encrypted)
begin
  dataOut.cbData := 0;
  dataOut.pbData := nil;

  dataIn.cbData := Length(fpDataIn); // How much data (in bytes) we want to encrypt
  dataIn.pbData := @fpDataIn[0];     // Pointer to the data itself - the address of the first element of the input byte array

  if not CryptProtectData(@dataIn, nil, nil, nil, nil, 0, @dataOut) then
    RaiseLastOSError;

  SetLength(Result, dataOut.cbData);
  Move(dataOut.pbData^, Result[0], dataOut.cbData);
  LocalFree(HLOCAL(dataOut.pbData));                  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261(v=vs.85).aspx
end;

function dpApiUnprotectData(fpDataIn: TBytes): tBytes;
var
  dataIn,               // Input buffer (clear-text/data)
  dataOut: DATA_BLOB;   // Output buffer (encrypted)
  lpwszDesc: PWideChar;
begin
  dataOut.cbData := 0;
  dataOut.pbData := nil;

  dataIn.cbData := Length(fpDataIn);
  dataIn.pbData := @fpDataIn[0];

 if not CryptUnprotectData(@dataIn, lpwszDesc, nil, nil, nil, 0, @dataOut) then
    RaiseLastOSError;

  SetLength(Result, dataOut.cbData);
  Move(dataOut.pbData^, Result[0], dataOut.cbData);
  LocalFree(HLOCAL(dataOut.pbData));                  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa380882%28v=vs.85%29.aspx
end;


function CryptProtectString(S: PWideChar): PWideChar; //stdcall;
var
  strIn: String;
  bytesEncrypted: TBytes;
  strOut: AnsiString;
begin
  {$IFNDEF STATIC_LINK}if not LoadCrypt32DLL then Exit;{$ENDIF}
  Result := '';
  strIn := S;
  SetLength(bytesEncrypted, Length(strIn) * SizeOf(Char));
  Move(strIn[1], bytesEncrypted[0], Length(strIn) * SizeOf(Char));
  bytesEncrypted := dpApiProtectData(bytesEncrypted);  // Encrypt data
  SetString(strOut, PAnsiChar(bytesEncrypted), Length(bytesEncrypted));
  Result := StrNew(PWideChar(EncodeString(strOut)));
  {$IFNDEF STATIC_LINK}if Crypt32DLL <> 0 then FreeModule(Crypt32DLL);{$ENDIF}
end;

function CryptUnprotectString(S: PWideChar): PWideChar; //stdcall;
var
  strIn: AnsiString;
  bytesEncrypted: TBytes;
  strOut: String;
begin
  {$IFNDEF STATIC_LINK}if not LoadCrypt32DLL then Exit;{$ENDIF}
  Result := '';
  strIn := DecodeString(S);
  SetLength(bytesEncrypted, Length(strIn));
  Move(strIn[1], bytesEncrypted[0], Length(strIn));
  bytesEncrypted := dpApiUnprotectData(bytesEncrypted);  // Decrypt data
  SetLength(strOut, Length(bytesEncrypted) div SizeOf(Char));
  Move(bytesEncrypted[0], strOut[1], length(bytesEncrypted));
  Result := StrNew(PWideChar(strOut));
  {$IFNDEF STATIC_LINK}if Crypt32DLL <> 0 then FreeModule(Crypt32DLL);{$ENDIF}
end;

end.



TestApp.dpr
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
program TestApp;

{$APPTYPE CONSOLE}

{.$DEFINE USE_DLL} // remove the dot for DLL

uses
  {$IFNDEF USE_DLL} DPCrypt, {$ENDIF}
  Windows, Messages, SysUtils;

{$IFDEF USE_DLL}
type
  TPluginFn = function(S: PWideChar): PWideChar; stdcall;

var
  DPAPI: THandle;
  dpApiProtectString,
  dpApiUnprotectString: TPluginFn;

function LoadDPAPI_DLL: Boolean;
begin
  DPAPI := LoadLibrary('DPAPI.dll');
  Result := DPAPI <> 0;
  if Result then
  begin
    dpApiProtectString := GetProcAddress(DPAPI, 'dpApiProtectString');
    dpApiUnprotectString := GetProcAddress(DPAPI, 'dpApiUnprotectString');
  end
  else
    WriteLn(SysErrorMessage(GetLastError));
end;
{$ENDIF}


var
  S: String;
begin
  S := 'Hello world';
  WriteLn('original_string:  ' + S);

  {$IFDEF USE_DLL}

  if LoadDPAPI_DLL then
  try
    S := dpApiProtectString(PWideChar(S));
    WriteLn('protected_string:  ' + S);
    S := dpApiUnprotectString(PWideChar(S));
    WriteLn('unprotected_string:  ' + S);
  finally
    if DPAPI <> 0 then
      FreeLibrary(DPAPI);
  end;

  {$ELSE}

  S := CryptProtectString(PWideChar(S));
  WriteLn('protected_string:  ' + S);
  S := CryptUnprotectString(PWideChar(S));
  WriteLn('unprotected_string:  ' + S);

  {$ENDIF}

  ReadLn;
end.



DPAPI.dpr
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
library DPAPI;

uses
  DPCrypt;

{$R *.res}

function dpApiProtectString(S: PWideChar): PWideChar; stdcall;
begin
  Result := CryptProtectString(S);
end;

function dpApiUnprotectString(S: PWideChar): PWideChar; stdcall;
begin
  Result := CryptUnprotectString(S);
end;


exports
  dpApiProtectString,
  dpApiUnprotectString;

end.
...
Рейтинг: 0 / 0
25.11.2019, 14:14
    #39893946
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
vdixБуду рад любой подсказке

Наибольшая вероятность у неинициализированных переменных.
Второе на очереди - порча памяти.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.11.2019, 14:22
    #39893951
vdix
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
Да вроде как всё инициализируется, память выделяется и освобождается корректно и делается это под каждый запрос в отдельности, у самого враппера никаких переменных нет, только локальные переменные функций, которые тут же и освобождаются.
...
Рейтинг: 0 / 0
25.11.2019, 14:43
    #39893972
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
DrMemory я бы попробовал напустить.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
25.11.2019, 14:48
    #39893976
Barmaley57
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
vdix, не поленился - скомпилил (D2009). У меня всё работает. В любых вариант. Да и в глаз с ходу ничего стремного не бросается.
...
Рейтинг: 0 / 0
25.11.2019, 15:00
    #39893989
goldmi45
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
vdix"System Error. Code: 127. The specified procedure could not be found"
автор
Код: pascal
1.
Crypt32DLL := LoadLibrary('Crypt32.dll');


может, не та dll подгружается...
...
Рейтинг: 0 / 0
25.11.2019, 15:24
    #39894010
vdix
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
Dimitry Sibiryakov
DrMemory я бы попробовал напустить.

Dr. Memory крашится под моей Win10 x64 если передать параметр -ignore_kernel, а без него ругается, что неизвестное ядро и нужно бы с этим параметром запускать.

goldmi45
vdix"System Error. Code: 127. The specified procedure could not be found"

автор
Код: pascal
1.
Crypt32DLL := LoadLibrary('Crypt32.dll');


может, не та dll подгружается...
Да другой у меня в системе нет. И грузится она с одного пути. Просто в одном случае напрямую, во втором - из обёртки.

Barmaley57
vdix, не поленился - скомпилил (D2009). У меня всё работает. В любых вариант. Да и в глаз с ходу ничего стремного не бросается.

А вот это странно. Благодарю! Хотя D2009 уже юникодная, тут не подкопаешься. Больше того, я только что собрал этот же проект на ХЕ2 и он тоже работает! Видимо, проблема в самой Delphi 10.2. Не исключено, что она исправлена в последней версии, но у меня её пока что нет...

Что же, спасибо всем за участие! Не сказать, что проблема решена, но как минимум один выход из создавшейся ситуации есть.
...
Рейтинг: 0 / 0
25.11.2019, 15:35
    #39894023
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема при использовании DLL-враппера для Crypt32.dll
vdixDr. Memory крашится под моей Win10 x64 если передать параметр -ignore_kernel, а без него
ругается, что неизвестное ядро и нужно бы с этим параметром запускать.

А, да, есть у него дурная привычка крашиться на оконных приложениях. Консольные вроде бы
должны работать.

Ну, тогда всегда остаётся старая добрая отладка записью в лог всего, чего ни попадя.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Проблема при использовании DLL-враппера для Crypt32.dll / 8 сообщений из 8, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]