Какой аналог криптографической функции Java PBEKeySpec в Windows Microsoft cryptographic CNG API?
Какой аналог криптографической функции Java PBEKeySpec в Windows Microsoft cryptographic CNG API?
Я пытаюсь портировать код изначально из Java для генерации ключа AES с паролем и солью в Windows используя только (CNG). Вот исходный код на Java поторый я пытаюсь портировать:
byte[] ret = null;
ret = SecretKeyFactory.getInstance(PBKDF2_ALGORIGHTM).generateSecret(new PBEKeySpec(password, salt, 1000, 256)).getEncoded();
Пытаюсь сделать (на Delphi) так:
[...]
type
BCRYPT_ALG_HANDLE = Pointer;
[...]
const
BCRYPT_AES_ALGORITHM: WideString = 'AES';
BCRYPT_SHA1_ALGORITHM: WideString = 'SHA1';
[...]
BCRYPT_ALG_HANDLE_HMAC_FLAG = 8;
[...]
function CreateKey(
const APassword, ASalt: AnsiString;
var AKey: AnsiString): NTSTATUS;
var
hAlg: BCRYPT_ALG_HANDLE;
derivedKeyLength: DWORD;
resultLength: DWORD;
pbPassword: Cardinal;
cbPassword: Cardinal;
pbSalt: Cardinal;
cbSalt: Cardinal;
cIterations: Cardinal;
pbDerivedKey: Cardinal;
cbDerivedKey: Cardinal;
dwFlags: Cardinal;
begin
AKey := '';
Result := BCryptOpenAlgorithmProvider(
hAlg,
@BCRYPT_SHA1_ALGORITHM[1],
nil,
BCRYPT_ALG_HANDLE_HMAC_FLAG);
if Result >= 0 then begin
Result := BCryptGetProperty(
hAlg,
@BCRYPT_OBJECT_LENGTH[1],
@derivedKeyLength,
sizeof(DWORD),
@resultLength,
0);
if Result >= 0 then begin
SetLength(AKey, derivedKeyLength);
pbPassword := Cardinal(@APassword[1]);
cbPassword := Length(APassword);
pbSalt := Cardinal(@ASalt[1]);
cbSalt := Length(ASalt);
cIterations := 1000;
pbDerivedKey := Cardinal(@AKey[1]);
cbDerivedKey := derivedKeyLength ;
dwFlags := 0;
asm
push [dwFlags]
push [cbDerivedKey]
push [pbDerivedKey]
push [cIterations]
push 0
push [cbSalt]
push [pbSalt]
push [cbPassword]
push [pbPassword]
push [hAlg]
call BCryptDeriveKeyPBKDF2
mov [Result],eax
end;
if Result >= 0 then
Exit;
[...]
end;
BCryptCloseAlgorithmProvider(hAlg, 0);
end;
end;
Пришлось применить inline ассемблер потому что функция BCryptDeriveKeyPBKDF2 из CNG должна получать один параметр ULONGLONG (количество итераций), но в Delphi 2007 нет типа данных 64 бит как сишный ULONGLONG, максимальный размер типа в Delphi 2007 только 32 бит (кардинал). Поэтому и пришлось сделать ассемблерную вставку для вызова этой функции чтобы положить в стек корректное значение количества итераций: сначала младшее слово, а затем старшее (всегда 0)
Но почему-то функция BCryptDeriveKeyPBKDF2 мне всегда возвращает INVALID_PARAMETER если я указываю провайдера как BCRYPT_SHA1_ALGORITHM, и INVALID_HANDLE, если я указываю в BCryptOpenAlgorithmProvider криптографического провайдера BCRYPT_AES_ALGORITHM.
Что я делаю не так? Не тот криптографический провайдер указываю? Какой вообще аналог функции PBEKeySpec из Java на Windows? Как я могу получить ключ AES из пароля и соли с помощью криптографического API Windows Microsoft CNG?