IPB
ЛогинПароль:

 
 Ответить  Открыть новую тему 
> Реализация MD5Crypt на Delphi, crypt_md5.c, md5_crypt(), /etc/shadow, PHP crypt()
сообщение
Сообщение #1


Большевик–концептуал
***

Группа: Пользователи
Сообщений: 194
Пол: Мужской
Реальное имя: Иван Левашев
Jabber: bu_gen@octagram.name
Skype: i.levashew
QQ: 3152538431
WeChat
Ада: Сторонник
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик
Turbo Pascal: Установлен

Репутация: -  1  +


По работе потребовалось заводить пользователей в ISPConfig, а там пароли выглядят в базе так:
Код
$1$D955A9D4$wqySvFGhG5V9KsWxo0BvN0

Производятся такие зашифрованные пароли, например, используя PHP так:
php -r 'echo crypt("d8fgysdihgik34uj", '\''$1$D955A9D4$'\'')."\n";'


Впервые этот алгоритм появился в FreeBSD для защиты от брутфорса паролей в /etc/shadow на замену методу, основанному на DES. Затем его многократно скопипастили, в том числе, он попал в GNU libc и стал практически системным вызовом, его использовали самые разные программы. Вот и в PHP он доступен через фунцию crypt(), в отличие от php-mcrypt, которую ещё нужно установить, а на shared хостинге этого может просто и не быть. Таким образом, несмотря на возражения автора, встретить это шифрование можно нередко.

Нашёл для разных языков реализации, но для Delphi только на одном форуме некто похвастался, что у него такое есть, и не опубликовал.


В текущей реализации для MD5 используется Indy. Также у меня применяется подход, который принуждает к использованию Юникода даже неюникодные Delphi. Для этого в старых Delphi объявляется UnicodeString = WideString, и предоставляются некоторые недостающие функции из более новых Delphi для конвертации из UnicodeString в UTF8String и обратно. Вам потребуется, например, этот модуль, только я его переименовываю каждый раз для очередного проекта.

Если требуется не только генерить, но и проверять пароль, то надо Salt вычленять между $1$ и $, принимать в качестве ещё одного параметра, как в PHP и GNU libc, а не генерить случайную строку, как сейчас.


uses
  SysUtils, ComObj, ActiveX, IdGlobal, IdHash, IdHashMessageDigest, IdCoderMIME;

const
  L = UnicodeString('');
  // to make strings Unicode
  // in C++: L"abcd"
  // in Delphi: L+'abcd'
  // otherwise 'nonunicode literal' + UnicodeFunction(Arg1, Arg2) becomes
  // converted to screwed ANSI

function RandomString: UnicodeString;
var
  GUID: TGUID;
begin
  OleCheck(CreateGUID(GUID));
  Result := Copy(GUIDToString(GUID), 2, 36);
end;

const
  MD5CryptAlphabet : UnicodeString =
    UnicodeString('./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');

function MyMD5(const InputString: UTF8String): UTF8String;
var
  Input, Output: TIdBytes;
  X_Hash_Alg: TIdHash;
begin
  SetLength(Input, Length(InputString));
  Move(InputString[1], Input[0], Length(InputString));
  X_Hash_Alg := nil;
  try
    X_Hash_Alg := TIdHashMessageDigest5.Create;
    Output := X_Hash_Alg.HashBytes(Input);
    SetString(Result, PAnsiChar(@Output[0]), Length(Output));
  finally
    FreeAndNil(X_Hash_Alg);
  end;
end;

function MD5Crypt(const Password: UnicodeString): UnicodeString;
var
  Salt: UTF8String;
  PasswordUTF8: UTF8String;
  Len: Integer;
  I: Integer;
  FinalString: UTF8String;
  Final: TIdBytes;
  CTXString: UTF8String;
  CTX1String: UTF8String;
  procedure To64(Value, Len: Integer);
  var
    J: Integer;
  begin
    for J := 1 to Len do
    begin
      Result := Result + MD5CryptAlphabet[Value and $3f + 1];
      Value := Value shr 6;
    end;
  end;
begin
  Salt := Copy(UTF8Encode(RandomString), 1, 8);
  // Salt := 'D955A9D4';
  PasswordUTF8 := UTF8Encode(Password);

  CTXString := PasswordUTF8 + UTF8String('$1$') + Salt;

  FinalString := MyMD5(PasswordUTF8 + Salt + PasswordUTF8);

  // Add as many characters of Final to CTX
  Len := Length(PasswordUTF8);
  while Len > 0 do
  begin
    if Len >= Length(FinalString) then
    begin
      CTXString := CTXString + FinalString;
      Dec(Len, Length(FinalString));
    end
    else
    begin
      CTXString := CTXString + Copy(FinalString, 1, Len);
      Len := 0;
    end;
  end;

  // Then something really weird...
  I := Length(PasswordUTF8);
  while I > 0 do
  begin
    if I and 1 = 1 then
    begin
      CTXString := CTXString + UTF8String(#0);
    end
    else
    begin
      CTXString := CTXString + PasswordUTF8[1];
    end;
    I := I shr 1;
  end;

  FinalString := MyMD5(CTXString);

  // Do additional mutations
  for I := 0 to 999 do
  begin
    CTX1String := '';
    if I and 1 > 0 then
    begin
      CTX1String := CTX1String + PasswordUTF8;
    end
    else
    begin
      CTX1String := CTX1String + FinalString;
    end;

    if I mod 3 > 0 then
    begin
      CTX1String := CTX1String + Salt;
    end;

    if I mod 7 > 0 then
    begin
      CTX1String := CTX1String + PasswordUTF8;
    end;

    if I and 1 > 0 then
    begin
      CTX1String := CTX1String + FinalString;
    end
    else
    begin
      CTX1String := CTX1String + PasswordUTF8;
    end;

    FinalString := MyMD5(CTX1String);
  end;

  Result := L+'$1$' + UTF8ToUnicodeString(Salt) + '$';

  SetLength(Final, Length(FinalString));
  Move(FinalString[1], Final[0], Length(FinalString));
  To64(((Integer(Final[ 0]) and $FF) shl 16) or ((Integer(Final[ 6]) and $FF) shl 8) or (Integer(Final[12]) and $FF), 4);
  To64(((Integer(Final[ 1]) and $FF) shl 16) or ((Integer(Final[ 7]) and $FF) shl 8) or (Integer(Final[13]) and $FF), 4);
  To64(((Integer(Final[ 2]) and $FF) shl 16) or ((Integer(Final[ 8]) and $FF) shl 8) or (Integer(Final[14]) and $FF), 4);
  To64(((Integer(Final[ 3]) and $FF) shl 16) or ((Integer(Final[ 9]) and $FF) shl 8) or (Integer(Final[15]) and $FF), 4);
  To64(((Integer(Final[ 4]) and $FF) shl 16) or ((Integer(Final[10]) and $FF) shl 8) or (Integer(Final[ 5]) and $FF), 4);
  To64(                                           Integer(Final[11]) and $FF                                        , 2);
end;



Сообщение отредактировано: OCTAGRAM -


--------------------
If you want to get to the top, you have to start at the bottom
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 3.04.2025 0:45
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name