Главная arrow Windows, WinAPI arrow Шифрование с закрытым ключём  
06.09.2010
Главное меню
Главная
Лаборатория
Книги по дельфи
Инструменты
Статьи
Видео
Юмор
Поиск
Новости
Лента новостей
Новости Delphi
Новости проекта
Новости инструментов
Разные новости
База знаний Delphi
Общие вопросы
Windows, WinAPI
Графика, Звук
IDE Delphi
Консоль
Каталог@Mail.ru - каталог ресурсов интернет
комментарии
Шифрование с закрытым ключём Версия для печати
Рейтинг: / 11
ХудшаяЛучшая 
Написал Snowy   
20.06.2008
Рассмотрим пример классического шифрования с закрытым ключём.
Данное шифрование считается ненадёжным, если пароль заложен в программу. Если пароль вводится пользователем, то стойкость зависит от сложности пароля.
Данный пример создан для удобства хранения шифрованных данных в реестре или текстовых и ini файлах. То есть, шифрованные бинарные данные возвращаются в текстовом HEX виде.
В представленом ниже коде всего две функции:
 
function EncString(s: string; pass: string = def; alg: Cardinal = CALG_RC4): string;
function DecString(s: string; pass: string = def; alg: Cardinal = CALG_RC4): string;
Первая шифрует, вторая, соответственно, дешифрует.
Первый параметр обязательный - это сами данные.
Второй параметр необязательный - это пароль. Если не указан, используется внутренний фиксированный пароль (константа def).
Третий параметр совсем необязательный - алгоритм шифрования. Всего два варианта - RC2 и RC4. Для шифрования паролей лучше использовать RC2, т.к. в RC4 видно, сколько байт зашифровано. Для всего остального можно использовать RC4 (по умолчанию), чтоб не добавлять лишнего мусора.
Пример использования:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit2.Text := EncString(Edit1.Text);
  Edit1.Text := '';
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  Edit1.Text := DecString(Edit2.Text);
end;
Далее сам код модуля.
Код не использует других модулей (даже Windows). Построен на CryptoAPI функциях системы, поэтому практически не добавляет веса программе и может использоваться, как в VCL проектах, так и в проектах на чистом API.
Шифрованные данные "подсаливаются" так, что одни и те же данные, зашифрованные дважды, дают разный результат, что практически исключает возможность подобрать ключ анализом, а не тупым брутфорсом.
unit MiniCry;
 
interface
 
const
  CALG_RC4         = ((3 shl 13) or (4 shl 9) or 1);
  CALG_RC2         = ((3 shl 13) or (3 shl 9) or 2);
  def = 'WrSxnCNBpJ7Ko4[e",7Ty)a0ykP)62Ce[.bAA;SuOf4*{nagx4s,;5!eHU!v=p3z';
 
function EncString(s: string; pass: string = def; alg: Cardinal = CALG_RC4): string;
{* зашифровать строку }
function DecString(s: string; pass: string = def; alg: Cardinal = CALG_RC4): string;
{* расшифровать строку }
 
implementation
 
const
  ADVAPI32    = 'advapi32.dll';
  PROV_RSA_FULL    = 1;
  CRYPT_VERIFYCONTEXT = $F0000000;
  CALG_SHA         = ((4 shl 13) or 0 or 4);
 
type
  HCRYPTPROV  = Cardinal;
  HCRYPTKEY   = Cardinal;
  ALG_ID = Cardinal;
  PHCRYPTPROV = ^HCRYPTPROV;
  PHCRYPTKEY  = ^HCRYPTKEY;
  LPAWSTR = PWideChar;
  HCRYPTHASH  = Cardinal;
  PHCRYPTHASH = ^HCRYPTHASH;
 
function CryptReleaseContext(hProv:HCRYPTPROV;dwFlags:LongWord):LongBool;stdcall;external ADVAPI32 name 'CryptReleaseContext';
function CryptAcquireContext(Prov:PHCRYPTPROV;Container:LPAWSTR;Provider:LPAWSTR;ProvType:LongWord;Flags:LongWord):LongBool;stdcall;external ADVAPI32 name 'CryptAcquireContextW';
function CryptEncrypt(Key:HCRYPTKEY;Hash:HCRYPTHASH;Final:LongBool;Flags:LongWord;Data:PBYTE;Len:PLongWord;BufLen:LongWord):LongBool;stdcall;external ADVAPI32 name 'CryptEncrypt';
function CryptDecrypt(Key:HCRYPTKEY;Hash:HCRYPTHASH;Final:LongBool;Flags:LongWord;Data:PBYTE;Len:PLongWord):LongBool;stdcall;external ADVAPI32 name 'CryptDecrypt';
function CryptCreateHash(Prov:HCRYPTPROV;Algid:ALG_ID;Key:HCRYPTKEY;Flags:LongInt;Hash:PHCRYPTHASH):LongBool;stdcall;external ADVAPI32 name 'CryptCreateHash';
function CryptHashData(Hash:HCRYPTHASH;Data:PBYTE;DataLen :LongInt;Flags:LongInt):LongBool;stdcall;external ADVAPI32 name 'CryptHashData';
function CryptDeriveKey(Prov:HCRYPTPROV;Algid:ALG_ID;BaseData:HCRYPTHASH;Flags:LongInt;Key:PHCRYPTKEY) :LongBool;stdcall;external ADVAPI32 name 'CryptDeriveKey';
function CryptDestroyHash(hHash :HCRYPTHASH) :LongBool;stdcall;external ADVAPI32 name 'CryptDestroyHash';
 
function ByteToHex(b: byte): string;
  function GetChar(b: byte): char;
  begin
    if b < 10 then Result := chr(Ord('0') + b)
    else Result := chr(Ord('A') - 10 + b);
  end;
begin
  Result := GetChar(b div 16) + GetChar(b mod 16);
end;
 
function StringToHex(const s: string): string;
var
  i: integer;
begin
  result := '';
  for i := 1 to Length(s) do
    result := result + ByteToHex(ord(s[i]));
end;
 
function StrToIntDef(s: string; def: integer): integer;
var
  i, c: integer;
begin
  Val(s, i, c);
  if c = 0 then Result := i else Result := def;
end;
 
function HexToString(const s: string): string;
var
  i: integer;
begin
  result := '';
  for i := 1 to Length(s) div 2 do
    try result := result + chr(StrToIntDef('$' + copy(s, i*2-1, 2), 32));
    except result := result + '?'; end;
end;
 
procedure InitPass(pass: string; alg: LongWord; var hProv: HCRYPTPROV; var hSKey: HCRYPTKEY);
var
  hash:  HCRYPTHASH;
begin
  CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  CryptCreateHash(hProv, CALG_SHA, 0, 0, @hash);
  CryptHashData(hash, @pass[1], length(pass), 0);
  CryptDeriveKey(hProv, alg, hash, 0, @hSKey);
  CryptDestroyHash(hash);
end;
 
function EncString(s: string; pass: string = def; alg: Cardinal = CALG_RC4): string;
var
  p:  PByte;
  sz: LongWord;
  hProv: HCRYPTPROV;
  hSKey: HCRYPTKEY;
begin
  InitPass(pass, alg, hProv, hSKey);
  Insert(chr(Random(256)), s, 1);
  sz := Length(s);
  GetMem(p, sz + 8); move(s[1], p^, sz);
  if CryptEncrypt(hSKey, 0, true, 0, p, @sz, sz + 8) then
  begin
    SetLength(result, sz);
    move(p^, result[1], sz);
    result := StringToHex(result);
  end else result := s;
  FreeMem(p);
  CryptReleaseContext(hProv, 0);
end;
 
function DecString(s: string; pass: string = def; alg: Cardinal = CALG_RC4): string;
var
  p:  PByte;
  sz: LongWord;
  hProv: HCRYPTPROV;
  hSKey: HCRYPTKEY;
begin
  InitPass(pass, alg, hProv, hSKey);
  s := HexToString(s);
  sz := Length(s);
  GetMem(p, sz); move(s[1], p^, sz);
  if CryptDecrypt(hSKey, 0, true, 0, p, @sz) then
  begin
    SetLength(result, sz);
    move(p^, result[1], sz);
    delete(result, 1, 1);
  end else result := s;
  FreeMem(p);
  CryptReleaseContext(hProv, 0);
end;
 
initialization
  Randomize;
 
end.
опубликовано
Добавить новыйПоиск
Андрей - ШИФРОВАНИЕ С ЗАКРЫТЫМ КЛЮЧЁМ   2010-08-02 10:17:36
Ребята. Спасибо Вам огромное!!
Кирилл   2010-08-05 08:55:54
У меня при расшифровке выдает иероглифы :unsure:
Snowy   2010-08-05 13:24:35
Код писался до выхода Delphi 2009. В 2009 и выше работать не будет, ибо здесь классический случай, использования строки, как байт-буфера. Что в юникод версиях дельфи не работает. Возможно поможет замена string на AnsiString. Но не гарантирую. Если дойдут руки, переделаю код на универсальный, чтобы поддерживал 2009+
Добавить комментарий
Имя:
Веб-сайт:
Заголовок:
UBB-Код:
[b] [i] [u] [url] [quote] [code] [img] 
 
 
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch:
:(:shock::X:side::):P:unsure::woohoo::huh::whistle:;):s
:!::?::idea::arrow:
 
Security Image
Пожалуйста, введите проверочный код, который Вы видите на картинке.
 
След. >