IDEA шифрование

IDEA шифрование Автор: Матвеев Игорь

Часто в свои проекты необходимо включать шифрование данных. Самый простой способ - xor шифрование, но он подходит только когда необходимо обеспечить малый уровень защиты. Но иногда необходимы более серьезные алгоритмы.
Работая над архиватором файлов (вроде WinRar), у меня встал вопрос о шифровании, в таких программах как архиватор это просто необходимо.
Итак, существует ряд алгоритмов симметричного шифрования - когда один и тот же ключ используется для шифрования и дешифрования. Эти алгоритмы, как правило, очень хорошо изучены и их стойкость к различного рода атакам подтверждена результатами математических исследований.
Кроме того, 2 октября 2000 года NIST (Национальный институт стандартов и технологий, правопреемник прежнего НБС), утвердил алгоритм Rijndael Джоана Димена и Винсента Риджмена как AES (Усовершенствованный алгоритм шифрования, который должен стать заменой прежнего стандарта - DES). Алгоритм Rijndael свободен как для коммерческого, так и для некоммерческого использования и, по видимому, является наилучшим выбором если необходима достаточная стойкость шифра наряду с высокой скоростью работы и относительной простотой реализации.
Но я выбрал для своего архиватора алгоритм IDEA (International Data Encryption Algorithm). Этот алгоритм был разработан для простого воплощения как программно, так и аппаратно. Стойкость IDEA основывается на использовании трех несовместимых типов арифметических операций над 16-битными словами. IDEA очень распространен в Европе и используется в популярной программе шифрования электронных писем PGP (Pretty Good Privacy).
Нижепредставленный модуль полностью реализует в себе метода IDEA шифрования. Главными функциями являются:

function EncryptCopy(DestStream, SourseStream : TStream; Count: Int64;

 Key : string): Boolean; // Зашифровать данные из одного потока в другой

function DecryptCopy(DestStream, SourseStream : TStream; Count: Int64;

 Key : string): Boolean; // Расшифровать данные из одного потока в другой

function EncryptStream(DataStream: TStream; Count: Int64;

 Key : string): Boolean; // Зашифровать содержимое потока

function DecryptStream(DataStream: TStream; Count: Int64;

 Key : string): Boolean; // Расшифровать содержимое потока

А теперь сам модуль:

{ *********************************************************************** }

{ }

{ Delphi Еncryption Library }

{ Еncryption / Decryption stream - IDEA }

{ }

{ Copyright (c) 2004 by Matveev Igor Vladimirovich }

{ With offers and wishes write: <a href="mailto:teap_leap@mail.ru">teap_leap@mail.ru</a> }

{ }

{ *********************************************************************** }

unit IDEA;

interface

uses

 SysUtils, Classes, Math;

const

 Rounds = 8;

 KeyLength = (Rounds * 6) + 4;

 Maxim = 65537;

type

 TIDEAKey = array[0..KeyLength-1] of Word;

 TIDEABlock = array[1..4] of Word;

var

 Z : TIDEAKey;

 K : TIDEAKey;

 FBlockSize : Integer;

 FKey : string;

 FBufferSize : Integer;

 FKeySize : Integer;

 FKeyPtr : PChar;

////////////////////////////////////////////////////////////////////////////////

// Дополнительные функции

procedure Initialize(AKey: string); // Инициализация

procedure CalculateSubKeys; // Подготовка подключей

function EncipherBlock(var Block): Boolean; // Шифрация блока (8 байт)

function DecipherBlock(var Block): Boolean; // Дешифрация блока

////////////////////////////////////////////////////////////////////////////////

// Основные функции

function EncryptCopy(DestStream, SourseStream : TStream; Count: Int64;

 Key : string): Boolean; // Зашифровать данные из одного потока в другой

function DecryptCopy(DestStream, SourseStream : TStream; Count: Int64;

 Key : string): Boolean; // Расшифровать данные из одного потока в другой

function EncryptStream(DataStream: TStream; Count: Int64;

 Key: string): Boolean; // Зашифровать содержимое потока

function DecryptStream(DataStream: TStream; Count: Int64;

 Key: string): Boolean; // Расшифровать содержимое потока

implementation

////////////////////////////////////////////////////////////////////////////////

function ROL(a, s: LongWord): LongWord;

asm

 mov ecx, s

 rol eax, cl

end;

////////////////////////////////////////////////////////////////////////////////

procedure InvolveKey;

var

 TempKey : string;

 i, j : Integer;

 K1, K2 : LongWord;

begin

 // Разворачивание ключа до длинны 51 символ

 TempKey := FKey;

 i := 1;

 while ((Length(TempKey) mod FKeySize) <> 0) do

  begin

  TempKey := TempKey + TempKey[i];

  Inc(i);

  end;

 // Now shorten the key down to one KeySize block by combining the bytes

 i := 1;

 j := 0;

 while (i < Length(TempKey)) do

  begin

  Move((FKeyPtr+j)^, K1, 4);

  Move(TempKey[i], K2, 4);

  K1 := ROL(K1, K2) xor K2;

  Move(K1, (FKeyPtr+j)^, 4);

  j := (j + 4) mod FKeySize;

  Inc(i, 4);

  end;

end;

////////////////////////////////////////////////////////////////////////////////

{$R-,Q-}

procedure ExpandKeys;

var

 i : Integer;

begin

 // Копирование ключа в Z

 Move(FKeyPtr^, Z, FKeySize);

 // Генерация подключа зашифрование

 for i := 8 to KeyLength-1 do

  begin

  if (((i+2) mod 8) = 0) then Z[i] := (Z[i- 7] shl 9) xor (Z[i-14] shr 7)

  else if (((i+1) mod 8) = 0) then Z[i] := (Z[i-15] shl 9) xor (Z[i-14] shr 7)

     else Z[i] := (Z[i- 7] shl 9) xor (Z[i- 6] shr 7);

  end;

end;

////////////////////////////////////////////////////////////////////////////////

procedure InvertKeys;

type

 PWord    = ^Word;

var

 j : Integer;

 pz, pp : PWord;

 t1, t2, t3 : Word;

////////////////////////////////////////

 function Inv(I: Integer): Integer;

 var

  n1, n2, q, r, b1, b2, t : Integer;

 begin

  if (I = 0) then

  Result := 0 else

  begin

  n1 := Maxim;

  n2 := I;

  b2 := 1;

  b1 := 0;

  repeat

  r := (n1 mod n2);

  q := (n1-r) div n2;

  if (r = 0) then

  begin

  if (b2 < 0) then b2 := Maxim + b2;

  end else

  begin

  n1 := n2;

  n2 := r;

  t := b2;

  b2 := b1 - q * b2;

  b1 := t;

  end;

  until (r = 0);

  Result := b2;

  end;

 Result := (Result and $ffff);

 end;

////////////////////////////////////////

begin

  pz := @Z;

  pp := @K;

  Inc(pp, KeyLength);

// t1 = inv(*Z++);

  t1 := Inv(pz^);

  Inc(pz);

// t2 = -*Z++;

  t2 := -pz^;

  Inc(pz);

// t3 = -*Z++;

  t3 := -pz^;

  Inc(pz);

// *--p = inv(*Z++);

  Dec(pp);

  pp^ := Inv(pz^);

  Inc(pz);

// *--p = t3;

  Dec(pp);

  pp^ := t3;

// *--p = t2;

  Dec(pp);

  pp^ := t2;

// *--p = t1;

  Dec(pp);

  pp^ := t1;

  for j := 1 to Rounds-1 do

  begin

// t1 = *Z++;

  t1 := pz^;

  Inc(pz);

// *--p = *Z++;

  Dec(pp);

  pp^ := pz^;

  Inc(pz);

// *--p = t1;

  Dec(pp);

  pp^ := t1;

// t1 = inv(*Z++);

  t1 := Inv(pz^);

  Inc(pz);

// t2 = -*Z++;

  t2 := -pz^;

  Inc(pz);

// t3 = -*Z++;

  t3 := -pz^;

  Inc(pz);

// *--p = inv(*Z++);

  Dec(pp);

  pp^ := Inv(pz^);

  Inc(pz);

// *--p = t2;

  Dec(pp);

  pp^ := t2;

// *--p = t3;

  Dec(pp);

  pp^ := t3;

// *--p = t1;

  Dec(pp);

  pp^ := t1;

  end;

// t1 = *Z++;

  t1 := pz^;

  Inc(pz);

// *--p = *Z++;

  Dec(pp);

  pp^ := pz^;

  Inc(pz);

// *--p = t1;

  Dec(pp);

  pp^ := t1;

// t1 = inv(*Z++);

  t1 := Inv(pz^);

  Inc(pz);

// t2 = -*Z++;

  t2 := -pz^;

  Inc(pz);

// t3 = -*Z++;

  t3 := -pz^;

  Inc(pz);

// *--p = inv(*Z++);

  Dec(pp);

  pp^ := Inv(pz^);

// *--p = t3;

  Dec(pp);

  pp^ := t3;

// *--p = t2;

  Dec(pp);

  pp^ := t2;

// *--p = t1;

  Dec(pp);

  pp^ := t1;

end;

{$R+,Q+}

////////////////////////////////////////////////////////////////////////////////

procedure CalculateSubKeys;

begin

 ExpandKeys;

 InvertKeys;

end;

////////////////////////////////////////////////////////////////////////////////

procedure Initialize(AKey: string);

begin

 FBlockSize := 8;

 FBufferSize := 2048;

 FKey := AKey;

 FKeySize := 32;

 FillChar(Z, SizeOf(Z), 0);

 FillChar(K, SizeOf(K), 0);

 GetMem(FKeyPtr, FKeySize);

 FillChar(FKeyPtr^, FKeySize, #0);

 InvolveKey;

end;

////////////////////////////////////////////////////////////////////////////////

{$R-,Q-}

procedure Cipher(var Block: TIDEABlock; const Keys: TIDEAKey);

var

 x1, x2, x3, x4 : Word;

 t1, t2 : Word;

 pz : ^Word;

 r      : Integer;

////////////////////////////////////////

 function Mul(a,b: Word): Word;

 var

  p : LongWord;

 begin

  if (a > 0) then

  begin

  if (b > 0) then

  begin

  p := LongWord(a)*b;

  b := p and $ffff;

  a := p shr 16;

  Result := ((b - a) + Ord(b < a));

  end else Result := 1 - a;

  end else Result := 1 - b;

 end;

////////////////////////////////////////

begin

// x1 = *in++; x2 = *in++;

  x1 := Block[1];

  x2 := Block[2];

// x3 = *in++; x4 = *in;

  x3 := Block[3];

  x4 := Block[4];

  pz := @Keys;

  for r := 1 to Rounds do

  begin

// MUL(x1,*Z++);

  x1 := Mul(x1, pz^);

  Inc(pz);

// x2 += *Z++;

  x2 := x2 + pz^;

  Inc(pz);

// x3 += *Z++;

  x3 := x3 + pz^;

  Inc(pz);

// MUL(x4, *Z++);

  x4 := Mul(x4, pz^);

  Inc(pz);

// t2 = x1^x3;

  t2 := x1 xor x3;

// MUL(t2, *Z++);

  t2 := Mul(t2, pz^);

  Inc(pz);

// t1 = t2 + (x2^x4);

  t1 := t2 + (x2 xor x4);

// MUL(t1, *Z++);

  t1 := Mul(t1, pz^);

  Inc(pz);

// t2 = t1+t2;

  t2 := (t1 + t2);

// x1 ^= t1;

  x1 := x1 xor t1;

// x4 ^= t2;

  x4 := x4 xor t2;

// t2 ^= x2;

  t2 := t2 xor x2;

// x2 = x3^t1;

  x2 := x3 xor t1;

// x3 = t2;

  x3 := t2;

  end;

// MUL(x1, *Z++);

  x1 := Mul(x1, pz^);

  Inc(pz);

// *out++ = x1;

  Block[1] := x1;

// *out++ = x3 + *Z++;

  Block[2] := x3 + pz^;

  Inc(pz);

// *out++ = x2 + *Z++;

  Block[3] := x2 + pz^;

  Inc(pz);

// MUL(x4, *Z);

  x4 := Mul(x4, pz^);

// *out = x4;

  Block[4] := x4;

end;

{$R+,Q+}

////////////////////////////////////////////////////////////////////////////////

function EncipherBlock(var Block): Boolean;

begin

 Cipher(TIDEABlock(Block), Z);

 Result := TRUE;

end;

////////////////////////////////////////////////////////////////////////////////

function DecipherBlock(var Block): Boolean;

begin

 Cipher(TIDEABlock(Block), K);

 Result := TRUE;

end;

////////////////////////////////////////////////////////////////////////////////

// Главные функции ...

function EncryptCopy(DestStream, SourseStream : TStream; Count: Int64;

 Key : string): Boolean;

var

 Buffer : TIDEABlock;

 PrCount : Int64;

 AddCount : Byte;

begin

 Result := True;

 try

  if Key = '' then

  begin

  DestStream.CopyFrom(SourseStream, Count);

  Exit;

  end;

  Initialize(Key);

  CalculateSubKeys;

  PrCount := 0;

  while Count - PrCount >= 8 do

  begin

  SourseStream.Read(Buffer, SizeOf(TIDEABlock));

  EncipherBlock(Buffer);

  DestStream.Write(Buffer, SizeOf(TIDEABlock));

  Inc(PrCount, 8);

  end;

  AddCount := Count - PrCount;

  if Count - PrCount <> 0 then

  begin

  SourseStream.Read(Buffer, AddCount);

  DestStream.Write(Buffer, AddCount);

  end;

 except

  Result := False;

 end;

end;

////////////////////////////////////////////////////////////////////////////////

function DecryptCopy(DestStream, SourseStream : TStream; Count: Int64;

 Key : string): Boolean;

var

 Buffer : TIDEABlock;

 PrCount : Int64;

 AddCount : Byte;

begin

 Result := True;

 try

  if Key = '' then

  begin

  DestStream.CopyFrom(SourseStream, Count);

  Exit;

  end;

  Initialize(Key);

  CalculateSubKeys;

  PrCount := 0;

  while Count - PrCount >= 8 do

  begin

  SourseStream.Read(Buffer, SizeOf(TIDEABlock));

  DecipherBlock(Buffer);

  DestStream.Write(Buffer, SizeOf(TIDEABlock));

  Inc(PrCount, 8);

  end;

  AddCount := Count - PrCount;

  if Count - PrCount <> 0 then

  begin

  SourseStream.Read(Buffer, AddCount);

  DestStream.Write(Buffer, AddCount);

  end;

 except

  Result := False;

 end;

end;

////////////////////////////////////////////////////////////////////////////////

function EncryptStream(DataStream: TStream; Count: Int64; Key: string): Boolean;

var

 Buffer : TIDEABlock;

 PrCount : Int64;

 AddCount : Byte;

begin

 Result := True;

 try

  if Key = '' then

  begin

  DataStream.Seek(Count, soFromCurrent);

  Exit;

  end;

  Initialize(Key);

  CalculateSubKeys;

  PrCount := 0;

  while Count - PrCount >= 8 do

  begin

  DataStream.Read(Buffer, SizeOf(TIDEABlock));

  EncipherBlock(Buffer);

  DataStream.Seek(-SizeOf(TIDEABlock), soFromCurrent);

  DataStream.Write(Buffer, SizeOf(TIDEABlock));

  Inc(PrCount, 8);

  end;

 except

  Result := False;

 end;

end;

////////////////////////////////////////////////////////////////////////////////

function DecryptStream(DataStream: TStream; Count: Int64; Key: string): Boolean;

var

 Buffer : TIDEABlock;

 PrCount : Int64;

begin

 Result := True;

 try

  if Key = '' then

  begin

  DataStream.Seek(Count, soFromCurrent);

  Exit;

  end;

  Initialize(Key);

  CalculateSubKeys;

  PrCount := 0;

  while Count - PrCount >= 8 do

  begin

  DataStream.Read(Buffer, SizeOf(TIDEABlock));

  DecipherBlock(Buffer);

  DataStream.Seek(-SizeOf(TIDEABlock), soFromCurrent);

  DataStream.Write(Buffer, SizeOf(TIDEABlock));

  Inc(PrCount, 8);

  end;

 except

  Result := False;

 end;

end;

// Завершение главных функций ...

////////////////////////////////////////////////////////////////////////////////

end.

А пользоваться этим модулем можно так. Нижеприведенный пример демонстрирует шифрование / дешифрование файла с использованием функций EncryptStream / DecryptStream:

procedure TForm1.Button1Click(Sender: TObject);

var

 SourseStream : TFileStream;

begin

 SourseStream := TFileStream.Create(Edit1.Text, fmOpenReadWrite    );

 EncryptStream(SourseStream, SourseStream.Size, Edit2.Text);

 SourseStream.Free;

end;

procedure TForm1.Button2Click(Sender: TObject);

var

 SourseStream : TFileStream;

begin

 SourseStream := TFileStream.Create(Edit1.Text, fmOpenReadWrite    );

 DecryptStream(SourseStream, SourseStream.Size, Edit2.Text);

 SourseStream.Free;

end;

ПРИМЕЧАНИЕ: Так как алгоритм шифрует данные блоками по 8 байт, а размер шифруемых данных не всегда кратен 8, поэтому в данном модуле последний блок, если он размером больше нодя и меньше восьми, не шифруется. Поэтому, если функцию шифрования обозначить e(x), а Srt1 и Str2 - шифруемые данные, то e(Str1) + e(Str2) не всегда равно e(Str1 + Str2).
Матвеев Игорь Владимирович

DelphiWorld 6.0

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...