Страницы

Поиск по вопросам

Показаны сообщения с ярлыком cryptoapi. Показать все сообщения
Показаны сообщения с ярлыком cryptoapi. Показать все сообщения

четверг, 9 апреля 2020 г.

Какая максимальная длина пароля для password_hash(),sha512 и blowfish

#php #cryptoapi

                    
Какая максимальная длина пароля для password_hash(PASSWORD_DEFAULT), sha512 и blowfish
- crypt()?
    


Ответы

Ответ 1



Если заглянуть в определение хэш-функции в википедии: A hash function is any function that can be used to map data of arbitrary size to data of fixed size. Вывод хэш-функции (в php!) всегда представляет собой строку фиксированной длины, поэтому можете просто оценить длину любого из представленных алгоритмов на практике. Если вопрос касается максимальной длины входных данных, то она может быть произвольной и ограничена сверху только оперативной памятью (в случае итерационного использования, недоступного, насколько понимаю, в PHP из коробки - длина может быть условно-бесконечной).

среда, 4 марта 2020 г.

Авторизация в Steam на Delphi

#delphi #rsa #steam #cryptoapi


Добрый день, есть желание из своей программы, написанной на Delphi, авторизоваться
в Steam.
Посмотрев исходники программы Steam Desktop Authenticator, пришел к выводу, что нам
нужно сделать 2 POST-запроса к серверу Steam, первый вернет нам модуль и экспоненту
открытого ключа RSA, которым мы должны зашифровать свой пароль и отправить его во втором
запросе. Решил попробовать реализовать это с помощью функций Microsoft CryptoAPI: Next
Generation.
Набросал функцию, которая на входе получает 3 строки: пароль от Стима, открытые модуль
и экспоненту в виде строк, состоящих из шестнадцатеричных символов (их нам присылает
сервер). На выходе должны получить пароль, зашифрованный открытым ключом по алгоритму
RSA и закодированный в BASE64.




    unit uRSA;

    interface
    uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;

    //БЛОБ открытого ключа RSA, описание структуры есть на MSDN
    type TPublicKeyBLOB = packed record
    Magic: ULONG;
    BitLength: ULONG;
    cbPublicExp: ULONG;
    cbModulus: ULONG;
    cbPrime1: ULONG;
    cbPrime2: ULONG;
    exponent: array[0..2] of byte;
    modulus: array[0..255] of byte;
    end;
    pPublicKeyBLOB = ^TPublicKeyBLOB;

    //прототипы функций из библиотеки BCRYPT.DLL
    TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR;
    pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall;
    //--
    TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType:
LPCWSTR;
    phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG;
stdcall;
    //--
    TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo:
POINTER;
    pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG;
dwFlags: ULONG): ULONG; stdcall;
    //--
    TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG):
ULONG; stdcall;

    //сама функция шифрования
    type TRSA = class
    public
    function RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr:   string):
string;
    end;

    const
    BCRYPT_RSAPUBLIC_MAGIC = $31415352;  // RSA1
    BCRYPT_PAD_PKCS1 = $00000002;

    implementation

    function HexToByte(Str: string): Byte;
    begin
    result :=  Byte(StrToInt('$' + (Str)));
    end;

    function TRsa.RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string):
string;
    var
    PublicKeyBLOB: TPublicKeyBlob;
    i: word;
    status: ULONG;
    hLib: THandle;
    hAlg: THandle;
    hKey: tHandle;
    Password: TBytes;
    EncryptedPassword: TBytes;
    EncryptedSize: ULONG;
    BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider;
    BCryptImportKeyPair: TBCryptImportKeyPair;
    BCryptEncrypt: TBCryptEncrypt;
    BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider;
    begin
    //преобразовываем входные данные в массив байтов;
    Password := TEncoding.ASCII.GetBytes(DataStr);
    hLib := LoadLibrary('BCRYPT.DLL');
    //загрузка функций из библиотеки
    //функция инициализации провайдера
    @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider');
    //функция импорта ключа
    @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair');
    //функция шифрования
    @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt');
    //функция освобождения провайдера
    @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider');
    //собираем ключ
    with PublicKeyBLOB do
    begin
    Magic := BCRYPT_RSAPUBLIC_MAGIC;  // RSA1;
    BitLength := SizeOf(Modulus)*8;//размер модуля в битах
    cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах
    cbModulus := SizeOf(Modulus);//размер модуля в байтах
    //(необязательно) проверим, что в переданных параметрах - четное количество символов
    if (length(exponentstr) mod 2)  0 then
    exponentstr := '0' + exponentstr;
    if (length(modulusstr) mod 2)  0 then
    modulusstr := '0' + modulusstr;
    for i := Low(exponent) to High(exponent) do
    exponent[i] := HexToByte(copy(exponentstr,i*2+1,2));
    for i := Low(modulus) to High(modulus) do
    modulus[i] := HexToByte(copy(modulusstr,i*2+1,2));
    end;
    //инициализация провайдера
    status := BCryptOpenAlgorithmProvider(@halg,'RSA',nil,0);
    //импорт ключа
    status := BCryptImportKeyPair(hAlg,0,'RSAPUBLICBLOB', @hKey, @PublicKeyBLOB,
    SizeOf(PublicKeyBLOB),0);
    //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй
- шифруем текст
    status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil,
0, @EncryptedSize, BCRYPT_PAD_PKCS1);
    SetLength(EncryptedPassword,EncryptedSize);
    status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0],
Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1);
    //кодируем зашифрованное сообщение в Base64
    Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword);
    //освобождаем память
    status := BCryptCloseAlgorithmProvider(hAlg,0);
    FreeLibrary(hLib);
    end;

    end.




Вроде бы все успешно отрабатывает, но, когда делаю POST-запрос с зашифрованным паролем
к серверу STEAM - получаю в ответ:
    {"success":false,"requires_twofactor":false,
   "message":"The account name or password that you have entered is incorrect.",
   "clear_password_field":true,"captcha_needed":false,"captcha_gid":-1}

На вход функции подаются строки в виде

   "publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d",
   "publickey_exp":"010001"


Буду очень признателен, если кто-нибудь укажет на ошибку или даст совет: как в Delphi
можно зашифровать сообщение, имея экспоненту и модуль открытого ключа RSA.
    


Ответы

Ответ 1



Проблема была в некорректной работе //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); Эта функция не убирает переносы строки, так что придется получившийся результат обработать дополнительно: //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); Либо же можно использовать аналогичную функцию из пакета Indy, которая работает верно: uses IdCoderMIME, idcoder, idglobal; ... function MyFunc(): string; var Temp: TIdBytes; begin ... Result := TIdEncoderMIME.EncodeBytes(Temp); end; Рабочий код : unit uRSA; interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding; //БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB; //прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall; //сама функция шифрования type TRSA = class public function Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end; const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002; BCRYPT_RSA_ALGORITHM = 'RSA'; BCRYPT_RSAPUBLIC_BLOB = 'RSAPUBLICBLOB'; implementation function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end; function TRsa.Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); if hLib < 32 then begin ShowMessage('Error while loading BCRYPT.DLL!'); exit; end; //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) <> 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) <> 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,BCRYPT_RSA_ALGORITHM,nil,0); if status <> 0 then begin ShowMessage('BCryptOpenAlgorithmProvider error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //импорт ключа status := BCryptImportKeyPair(hAlg,0,BCRYPT_RSAPUBLIC_BLOB, @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); if status <> 0 then begin ShowMessage('BCryptImportKeyPair error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 1, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 2, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //освобождаем занятые ресурсы status := BCryptCloseAlgorithmProvider(hAlg,0); if status <> 0 then begin ShowMessage('BCryptCloseAlgorithmProvider error, status: ' + IntToStr(status) + SysErrorMessage(GetLastError())); exit; end; //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); //выгружаем библиотеку FreeLibrary(hLib); end; end. На вход функции подаются строки в виде: "publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"

суббота, 22 июня 2019 г.

Какая максимальная длина пароля для password_hash(),sha512 и blowfish

Какая максимальная длина пароля для password_hash(PASSWORD_DEFAULT), sha512 и blowfish - crypt()?


Ответ

Если заглянуть в определение хэш-функции в википедии:
A hash function is any function that can be used to map data of arbitrary size to data of fixed size
Вывод хэш-функции (в php!) всегда представляет собой строку фиксированной длины, поэтому можете просто оценить длину любого из представленных алгоритмов на практике.
Если вопрос касается максимальной длины входных данных, то она может быть произвольной и ограничена сверху только оперативной памятью (в случае итерационного использования, недоступного, насколько понимаю, в PHP из коробки - длина может быть условно-бесконечной).

понедельник, 20 мая 2019 г.

Авторизация в Steam на Delphi

Добрый день, есть желание из своей программы, написанной на Delphi, авторизоваться в Steam. Посмотрев исходники программы Steam Desktop Authenticator, пришел к выводу, что нам нужно сделать 2 POST-запроса к серверу Steam, первый вернет нам модуль и экспоненту открытого ключа RSA, которым мы должны зашифровать свой пароль и отправить его во втором запросе. Решил попробовать реализовать это с помощью функций Microsoft CryptoAPI: Next Generation. Набросал функцию, которая на входе получает 3 строки: пароль от Стима, открытые модуль и экспоненту в виде строк, состоящих из шестнадцатеричных символов (их нам присылает сервер). На выходе должны получить пароль, зашифрованный открытым ключом по алгоритму RSA и закодированный в BASE64.

unit uRSA;
interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;
//БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB;
//прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall;
//сама функция шифрования type TRSA = class public function RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end;
const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002;
implementation
function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end;
function TRsa.RSA_Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,'RSA',nil,0); //импорт ключа status := BCryptImportKeyPair(hAlg,0,'RSAPUBLICBLOB', @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //освобождаем память status := BCryptCloseAlgorithmProvider(hAlg,0); FreeLibrary(hLib); end;
end.

Вроде бы все успешно отрабатывает, но, когда делаю POST-запрос с зашифрованным паролем к серверу STEAM - получаю в ответ: {"success":false,"requires_twofactor":false, "message":"The account name or password that you have entered is incorrect.", "clear_password_field":true,"captcha_needed":false,"captcha_gid":-1} На вход функции подаются строки в виде
"publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"
Буду очень признателен, если кто-нибудь укажет на ошибку или даст совет: как в Delphi можно зашифровать сообщение, имея экспоненту и модуль открытого ключа RSA.


Ответ

Проблема была в некорректной работе
//кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword);
Эта функция не убирает переносы строки, так что придется получившийся результат обработать дополнительно:
//кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]);
Либо же можно использовать аналогичную функцию из пакета Indy, которая работает верно:
uses IdCoderMIME, idcoder, idglobal; ... function MyFunc(): string; var Temp: TIdBytes; begin ... Result := TIdEncoderMIME.EncodeBytes(Temp); end;

Рабочий код :
unit uRSA;
interface uses WinAPI.Windows, System.SysUtils, VCL.Dialogs, System.NetEncoding;
//БЛОБ открытого ключа RSA, описание структуры есть на MSDN type TPublicKeyBLOB = packed record Magic: ULONG; BitLength: ULONG; cbPublicExp: ULONG; cbModulus: ULONG; cbPrime1: ULONG; cbPrime2: ULONG; exponent: array[0..2] of byte; modulus: array[0..255] of byte; end; pPublicKeyBLOB = ^TPublicKeyBLOB;
//прототипы функций из библиотеки BCRYPT.DLL TBCryptOpenAlgorithmProvider = function (phAlgorithm: pHandle; pszAlgId: LPCWSTR; pszImplementation: LPCWSTR; dwFlags: DWORD): ULONG; stdcall; //-- TBCryptImportKeyPair = function (hAlgorithm: THandle; hImportKey: THandle; pszBlobType: LPCWSTR; phKey: pHandle; pbInput: pPublicKeyBLOB; cbInput: ULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptEncrypt = function (hKey: THandle; pbInput: PUCHAR; cbInput: ULONG; pPaddingInfo: POINTER; pbIV: PUCHAR; cbIV: ULONG; pbOutput: PUCHAR; cbOutput: ULONG; pcbResult: PULONG; dwFlags: ULONG): ULONG; stdcall; //-- TBCryptCloseAlgorithmProvider = function (hAlgorithm: THandle; dwFlags: ULONG): ULONG; stdcall;
//сама функция шифрования type TRSA = class public function Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; end;
const BCRYPT_RSAPUBLIC_MAGIC = $31415352; // RSA1 BCRYPT_PAD_PKCS1 = $00000002; BCRYPT_RSA_ALGORITHM = 'RSA'; BCRYPT_RSAPUBLIC_BLOB = 'RSAPUBLICBLOB';
implementation
function HexToByte(Str: string): Byte; begin result := Byte(StrToInt('$' + (Str))); end;
function TRsa.Encrypt(DataStr: string; modulusStr: string; exponentStr: string): string; var PublicKeyBLOB: TPublicKeyBlob; i: word; status: ULONG; hLib: THandle; hAlg: THandle; hKey: tHandle; Password: TBytes; EncryptedPassword: TBytes; EncryptedSize: ULONG; BCryptOpenAlgorithmProvider: TBCryptOpenAlgorithmProvider; BCryptImportKeyPair: TBCryptImportKeyPair; BCryptEncrypt: TBCryptEncrypt; BCryptCloseAlgorithmProvider: TBCryptCloseAlgorithmProvider; begin //преобразовываем входные данные в массив байтов; Password := TEncoding.ASCII.GetBytes(DataStr); hLib := LoadLibrary('BCRYPT.DLL'); if hLib < 32 then begin ShowMessage('Error while loading BCRYPT.DLL!'); exit; end; //загрузка функций из библиотеки //функция инициализации провайдера @BCryptOpenAlgorithmProvider := GetProcAddress(hLib, 'BCryptOpenAlgorithmProvider'); //функция импорта ключа @BCryptImportKeyPair := GetProcAddress(hLib, 'BCryptImportKeyPair'); //функция шифрования @BCryptEncrypt := GetProcAddress(hLib, 'BCryptEncrypt'); //функция освобождения провайдера @BCryptCloseAlgorithmProvider := GetProcAddress(hLib, 'BCryptCloseAlgorithmProvider'); //собираем ключ with PublicKeyBLOB do begin Magic := BCRYPT_RSAPUBLIC_MAGIC; // RSA1; BitLength := SizeOf(Modulus)*8;//размер модуля в битах cbPublicExp := SizeOf(Exponent);//размер экспоненты в байтах cbModulus := SizeOf(Modulus);//размер модуля в байтах //(необязательно) проверим, что в переданных параметрах - четное количество символов if (length(exponentstr) mod 2) <> 0 then exponentstr := '0' + exponentstr; if (length(modulusstr) mod 2) <> 0 then modulusstr := '0' + modulusstr; for i := Low(exponent) to High(exponent) do exponent[i] := HexToByte(copy(exponentstr,i*2+1,2)); for i := Low(modulus) to High(modulus) do modulus[i] := HexToByte(copy(modulusstr,i*2+1,2)); end; //инициализация провайдера status := BCryptOpenAlgorithmProvider(@halg,BCRYPT_RSA_ALGORITHM,nil,0); if status <> 0 then begin ShowMessage('BCryptOpenAlgorithmProvider error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //импорт ключа status := BCryptImportKeyPair(hAlg,0,BCRYPT_RSAPUBLIC_BLOB, @hKey, @PublicKeyBLOB, SizeOf(PublicKeyBLOB),0); if status <> 0 then begin ShowMessage('BCryptImportKeyPair error, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //шифрование сообщения. Первый проход - получаем размер выходного буфера, второй - шифруем текст status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, nil, 0, @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 1, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; SetLength(EncryptedPassword,EncryptedSize); status := BCryptEncrypt(hKey, @Password[0], Length(Password), nil, nil, 0, @EncryptedPassword[0], Length(EncryptedPassword), @EncryptedSize, BCRYPT_PAD_PKCS1); if status <> 0 then begin ShowMessage('BCryptEncrypt error 2, status: ' + IntToStr(status) + ', ' + SysErrorMessage(GetLastError())); exit; end; //освобождаем занятые ресурсы status := BCryptCloseAlgorithmProvider(hAlg,0); if status <> 0 then begin ShowMessage('BCryptCloseAlgorithmProvider error, status: ' + IntToStr(status) + SysErrorMessage(GetLastError())); exit; end; //кодируем зашифрованное сообщение в Base64 Result := TNetEncoding.Base64.EncodeBytesToString(EncryptedPassword); //удалим переносы строки Result := StringReplace(Result, #13#10, '',[rfReplaceAll]); //выгружаем библиотеку FreeLibrary(hLib); end;
end.
На вход функции подаются строки в виде:
"publickey_mod":"c152954756c74aee68ca1e6ac77bc71af6a93660bd56f1517e8141436b8fda4e32cc123ced02c0421a6a8d505dd25d07c4df9a25cf682799ea87ceb0eeaef7c7e71a8a30ec6c60d4dcfa8006a193f0b99958655894147b13d4f15285f9d7dc75baaa61b1b12265a303324c6b5e648bb272d87e0003295ca124e6e7a8a5ec45b9d2f1399e3ffbd0d9aec012afe1fbe65bfc9bd4c2087e7b7a73d2f9286e311e77341113f4cbde9a2a94141252e395e36bc2bf135ef38be90458090d6cd2c419e293a5dcf93bff3df2ca641edfb38ff85f6c9f8864f2905015cf34bd35d74e324f4a6a156c2462cfdd1c1fafb15567047a59b188c9f2a4f78157f2ec120ce09b5d", "publickey_exp":"010001"