Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Алгоритм шифрования TEA

01.01.2007

Немного модифицированный вариант для шифрования не особо критичных данных

////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Unit Name : TEA
//  * Purpose   : Модуль шифрования по алгоритму TEA
//                (Tiny Encryption Algorithm)
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.04
//  * Home Page : http://rouse.drkb.ru
//  ****************************************************************************
//
 
// Схема действия
// В функцию передается массив данных
// Генерируется уникальный 128 битный ключ для кодирования на основе GUID
// Вычисляется размер данных, они должны быть кратны четному
// кол-ву 32 битных блоков, недостающий обьем заполняется мусором
// Первые три байта занимает заголовок ETA
// В четвертую позицию данных добавляется значение указывающее объем мусора
// Производится кодирование ранее сгенерированным ключем
// Сам ключ кодируется внутренним ключем, делится на четыре части
// 128 битный ключ разделяется на четыре 32 битных блока
// Ключ добавляется в данные со сдвигом в любое место
// в следующем порядке 4-ый, 3-ий, 1-ый, 2-ой блоки
// На 14 ую позицию данных вставляется со сдвигом указатель на начало ключа
// Итого в закодированном буффере находится помимо основной
// еще и 21 байт служебной информации
// Для раскодирования все действи производится в обратном порядке
 
unit TEA;
 
{$Q-} // Отключаем INTEGER OVERFLOW
 
interface
 
uses
  Windows,
  SysUtils,
  Classes;
 
const
  Delta = $9E3779B9;  // Смещение контрольной суммы ~ 32 бит
  Header = 'ETA'; // Enhanced TEA
 
var
  _k0: DWORD = 0;    // Главный 128 битный ключ (4 части по 32 бита)
  _k1: DWORD = 0;    // Его нужно изменить на свой аналог...
  _k2: DWORD = 0;
  _k3: DWORD = 0;
 
type
  PHash = ^THash;
  THash = array of Byte;
  Int256 = array [0..31] of Byte;
 
  procedure EnCript(var S: THash);
  procedure EnCryptStream(Stream: TStream);
  function DeCript(var S: THash): Boolean;
  function DeCriptStream(Stream: TStream): Boolean;
  procedure SetDefaultKey;
  procedure SetKey(Value: Int256);
 
implementation
 
//  Установка ключа по умолчанию (DEMO - ключ)
// =============================================================================
procedure SetDefaultKey;
begin                
  _k0 := $982C98C1;    // Главный 128 битный ключ (4 части по 32 бита)
  _k1 := $7F8F4D4B;    // Его нужно изменить на свой аналог...
  _k2 := $BCAE3151;
  _k3 := $971BC789;
end;
 
//  Установка рабочего ключа
// =============================================================================
procedure SetKey(Value: Int256);
var
  XorKey: DWORD;
begin
  // Ну например вот так :)
  Move(Value[0], _k0, 4);
  Move(Value[4], XorKey, 4);
  _k0 := _k0 xor XorKey;
  Move(Value[4], _k1, 4);
  Move(Value[12], XorKey, 4);
  _k1 := _k1 xor XorKey;
  Move(Value[24], _k2, 4);
  Move(Value[20], XorKey, 4);
  _k2 := _k2 xor XorKey;
  Move(Value[16], _k3, 4);
  Move(Value[28], XorKey, 4);
  _k3 := _k3 xor XorKey;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// ЧАСТЬ ПЕРВАЯ * * * КОДИРОВАНИЕ * * *
 
procedure EnCript(var S: THash);
var
  InBuf,
  OutBuf,
  ResultBuf: THash;   // Входной, выходной и результирующий буфера
  Y, Z, Sum: LongWord;        // Временные переменные для кодируемых блоков данных
  k0, k1, k2 , k3: LongWord;  // Текущий ключ для шифрования
  I, A, Len: Integer;         // Переменные для циклов
  C: Byte;                    // Счетчик кол-ва мусора
  Guid, Key: String;
  G: TGUID;
begin
  // Проверка заданного ключа
  if _k0 = 0 then SetDefaultKey;
 
  // Проверка размера данных
  if Length(S) = 0 then Exit;
 
  Randomize;
 
  CreateGUID(G); // Генерируем ключик на основе GUID - а :)
  Guid := GUIDToString(G);
  for I := 1 to Length(Guid) do
    if Guid[I] in ['0'..'9', 'A'..'F'] then
      Key := Key + Guid[I];      
 
  k0 := StrToInt64('$' + Copy(Key, 1, 8));
  k1 := StrToInt64('$' + Copy(Key, 9, 8));
  k2 := StrToInt64('$' + Copy(Key, 17, 8));
  k3 := StrToInt64('$' + Copy(Key, 25, 8));
 
  C := 0; // Инициализируем счетчик дозаполнений
  // Дозаполняем данные чтобы последний блок данных был равен 64 битам
  while (Length(S) div 8) * 8 <> Length(S) do // 64 бита = 8 байтам :)
  begin
    Len := Length(S);
    Inc(Len);
    SetLength(S, Len);
    S[Len - 1] := Random(255); // Заполняем случайными данными
    Inc(C);
  end;
 
  Len := Length(S); // Вычисляем размер кодируемого блока
  SetLength(InBuf, Len);  // Устанавливаем размер буферов
 
  // Размер выходного буфера увеличен на 21 байт из-за
  // 3 байта - заголовок ETA
  // 1 байт - счетчик кол-ва мусора в конце буфера
  // 16 байт - кодированный ключ - 4 Cardinal 
  // 1 байт - метка расположения кодированного ключа
  Inc(Len, 21);
  SetLength(OutBuf, Len);
  SetLength(ResultBuf, Len);
 
  Inc(C);// Увеличим кол-во мусора для удаления самого поля счетчика
  OutBuf[0] := Ord(Header[1]); // добавляем идентификатор
  OutBuf[1] := Ord(Header[2]);
  OutBuf[2] := Ord(Header[3]);
  OutBuf[3] := C; // Добавляем счетчик мусора
 
  Move(S[0], InBuf[0], Length(S));// Заполняем входной буфер данными
 
  I := 0;
  while I < Len - 21 do // Непосредственно кодировка
  begin
    Move(InBuf[I], Y, 4);     // Берем первые 32 бита
    Move(InBuf[I + 4], Z, 4); // Берем вторые 32 бита
    // Кодируем
    Sum := 0;
    for A := 0 to 31 do  // 64 битный кодируемый блок (2 части по 32 бита)
    begin
      Inc(Sum, Delta);
      Inc(Y, ((Z shl 4) + k0) xor (Z + Sum) xor ((Z shr 5) + k1));
      Inc(Z, ((Y shl 4) + k2) xor (Y + Sum) xor ((Y shr 5) + k3));
    end;
    Move (Y, OutBuf[I + 4], 4); // Помещаем кодированные блоки в выходном буфер
    Move (Z, OutBuf[I + 8], 4);
    Inc(I, 8); // Пропускаем обработанный блок, переходим к следующему
  end;
 
  Sum := 0;
  for A := 0 to 31 do  // Кодируем первые 2 части ключа внутренним ключем
  begin
    Inc(sum,Delta);
    Inc(k0, ((k1 shl 4) + _k0) xor (k1 + Sum) xor ((k1 shr 5) + _k1));
    Inc(k1, ((k0 shl 4) + _k2) xor (k0 + Sum) xor ((k0 shr 5) + _k3));
  end;
 
  Sum := 0;
  for A := 0 to 31 do  // Кодируем вторые 2 части ключа внутренним ключем
  begin
    Inc(Sum, Delta);
    Inc(k2, ((k3 shl 4) + _k0) xor (k3 + Sum) xor ((k3 shr 5) + _k1));
    Inc(k3, ((k2 shl 4) + _k2) xor (k2 + Sum) xor ((k2 shr 5) + _k3));
  end;
 
  // Определяем позицию размещения ключа в блоке данных
  Randomize;
  if Len < 255 then
    I := Len
  else
    I := 255;
  repeat
    I := Random(I);
    if I < 4 then I := 4;
  until I < Len - 16; // <- исправление глюка с шифрованием маленьких блоков данных
 
  // Смещаем данные освобождая место для четырех
  // частей ключа
  Move(OutBuf[0], ResultBuf[0], I);
  Move(OutBuf[I], ResultBuf[I + 16], Len - I - 17);
 
  // Разбиваем четвертую четверть ключа на 4 восьмибитных части
  ResultBuf[I]    := Byte(k3 shr 24);
  ResultBuf[I + 1]  := Byte(k3 shr 16);
  ResultBuf[I + 2]  := Byte(k3 shr 8);
  ResultBuf[I + 3]  := Byte(k3);
 
  // Разбиваем третью четверть ключа на 4 восьмибитных части
  ResultBuf[I + 4]  := Byte(k2 shr 24);
  ResultBuf[I + 5]  := Byte(k2 shr 16);
  ResultBuf[I + 6]  := Byte(k2 shr 8);
  ResultBuf[I + 7]  := Byte(k2);
 
  // Разбиваем первую четверть ключа на 4 восьмибитных части
  ResultBuf[I + 8]  := Byte(k0 shr 24);
  ResultBuf[I + 9]  := Byte(k0 shr 16);
  ResultBuf[I + 10] := Byte(k0 shr 8);
  ResultBuf[I + 11] := Byte(k0);
 
  // Разбиваем вторую четверть ключа на 4 восьмибитных части
  ResultBuf[I + 12] := Byte(k1 shr 24);
  ResultBuf[I + 13] := Byte(k1 shr 16);
  ResultBuf[I + 14] := Byte(k1 shr 8);
  ResultBuf[I + 15] := Byte(k1);
 
  // Сдвигаем данные с 14 позиции на одну вправо для метки
  // (буфер начинается с нуля)
  for A := Len - 1 downto 14 do
    ResultBuf[A] := ResultBuf[A - 1];
 
  // Помещаем метку начала ключа (14-й байт)
  ResultBuf[13] := I;
 
  S := ResultBuf;
end;
 
//  Функция кодирует стрим с текущей позиции и до конца.
//  Результат помещается в текущую позицию. Размеры стрима корректируются
// =============================================================================
procedure EnCryptStream(Stream: TStream);
var
  Template: THash;
  Position: Int64;
begin
  if Stream = nil then
    raise Exception.Create('Empty stream.');
  Position := Stream.Position;
  SetLength(Template, Stream.Size - Position);
  Stream.Read(Template[0], Length(Template));
  EnCript(Template);
  Stream.Size := Position + Length(Template);
  Stream.Position := Position;
  Stream.Write(Template[0], Length(Template));
end;
 
////////////////////////////////////////////////////////////////////////////////
//
// ЧАСТЬ ВТОРАЯ * * * ДЕКОДИРОВАНИЕ * * *
 
function DeCript (var S: THash): Boolean;
var
  InBuf,
  OutBuf,
  ResultBuf: THash; // Входной, выходной и результирующий буфера
  Y , Z, Sum: LongWord;     // Временные переменные для кодируемых блоков данных
  k0, k1, k2, k3: LongWord; // Текущий ключ для шифрования
  I, A, Len: Integer;       // Переменные для циклов
  AHeader: String;
begin
  Result := False;
 
  // Проверка заданного ключа
  if _k0 = 0 then SetDefaultKey;
 
  Len := Length(S); // Вычисляем размер декодируемого блока
 
  // Проверка размера
  if Len < 27 then Exit;
  if Len <> (((Len - 21) div 8) * 8) + 21 then Exit;
 
  // Проверка заголовка
  AHeader := Char(S[0]) + Char(S[1]) + Char(S[2]);
  if AHeader <> Header then Exit;
 
  // Проверка позиции ключа
  if not(S[13] in [4..255]) then Exit;
  if S[13] + 16 > Len then Exit;
 
  // Проверка счетчика мусора
  if S[3] > 8 then Exit;
 
  SetLength(InBuf, Len);  // Устанавливаем размер буферов
 
  Move(S[0], InBuf[0], Len);// Заполняем входной буфер данными
 
  I := InBuf[13]; // Узнаем начальную позицию ключа
 
  // Удаляем метку на начало ключа
  for A := 13 to Len - 2 do
  begin
    InBuf[A] := InBuf[A + 1];
    InBuf[A + 1] := 0;
  end;
  Dec(Len);
 
  // Извлекаем ключ
  k3 :=(InBuf[I + 3] or (InBuf[I + 2] shl 8) or (InBuf[I + 1] shl 16) or (InBuf[I] shl 24));
  k2 :=(InBuf[I + 7] or (InBuf[I + 6] shl 8) or (InBuf[I + 5] shl 16) or (InBuf[I + 4] shl 24));
  k0 :=(InBuf[I + 11] or (InBuf[I + 10] shl 8) or (InBuf[I + 9] shl 16) or (InBuf[I + 8] shl 24));
  k1 :=(InBuf[I + 15] or (InBuf[I + 14] shl 8) or (InBuf[I + 13] shl 16) or (InBuf[I + 12] shl 24));
 
  // Удаляем ключ из блока данных
  for A := I + 16 to Len do
  begin
    InBuf[A - 16] := InBuf[A];
    InBuf[A] := 0;
  end;
  SetLength(OutBuf, Len);
  ZeroMemory(OutBuf, Len);
  Dec(Len, 16); // Удаляем размер ключа
 
  // Декодируем первые две части ключа
  Sum := Delta shl 5;
  for A := 0 to 31 do
  begin
    Dec(k1, ((k0 shl 4) + _k2) xor (k0 + Sum) xor ((k0 shr 5) + _k3));
    Dec(k0, ((k1 shl 4) + _k0) xor (k1 + Sum) xor ((k1 shr 5) + _k1));
    Dec(Sum, Delta);
  end;
 
  // Декодируем вторые две части ключа
  Sum := Delta shl 5;
  for A := 0 to 31 do
  begin
    Dec(k3, ((k2 shl 4) + _k2) xor (k2 + Sum) xor ((k2 shr 5) + _k3));
    Dec(k2, ((k3 shl 4) + _k0) xor (k3 + Sum) xor ((k3 shr 5) + _k1));
    Dec(Sum, Delta);
  end;
 
  I := 0;
  Dec(Len); // Удяляем из размера место счетчика мусора
  Dec(Len, 3); // Удаляем из размера заголовок ETA
  while I < Len do // Непосредственно декодировка
  begin
    Move(InBuf[I + 4], Y, 4);  // Берем первые 32 бита
    Move(InBuf[I + 8], Z, 4);  // Берем вторые 32 бита
    // Декодируем
    Sum := Delta shl 5;
    for A := 0 to 31 do  // 64 битный кодируемый блок (2 части по 32 бита)
    begin
      Dec(Z, ((Y shl 4) + k2) xor (Y + Sum) xor ((Y shr 5) + k3));
      Dec(Y, ((Z shl 4) + k0) xor (Z + Sum) xor ((Z shr 5) + k1));
      Dec(Sum, Delta);
    end;
    Move(Y, OutBuf[I], 4);  // Запоминаем кодированные блоки в выходном буфере
    Move(Z, OutBuf[I + 4], 4);
    Inc(I, 8);              // Пропускаем обработанный блок, переходим к следующему
  end;
 
  // Отрезаем мусор (-1 потому что место для счетчика уже удалено из Len)
  Len := Len - (InBuf[3] - 1);
  SetLength(ResultBuf, Len);
  Move(OutBuf[0], ResultBuf[0], Len);
 
  // Выводим текст из выходного буфера
  S := ResultBuf;
  Result := True;
end;
 
//  Функция декодирует стрим с текущей позиции и до конца.
//  Результат помещается в текущую позицию. Размеры стрима корректируются
// =============================================================================
function DeCriptStream(Stream: TStream): Boolean;
var
  Template: THash;
  Position: Int64;
begin
  if Stream = nil then
    raise Exception.Create('Empty stream.');
  Position := Stream.Position;
  SetLength(Template, Stream.Size - Position);
  Stream.Read(Template[0], Length(Template));
  Result := DeCript(Template);
  Stream.Size := Position + Length(Template);
  Stream.Position := Position;
  Stream.Write(Template[0], Length(Template));
end;
 
end.
 

Автор: Александр (Rouse_) Багель

Взято из https://forum.sources.ru


{ **** UBPFD *********** by kladovka.net.ru ****
>> Алгоритм 128-битного шифрования (TEA)
 
Зависимости: system
Автор:       Valts Silaputnins, valts@velns.org
Copyright:   Valts Silaputnins
Дата:        19 августа 2002 г.
********************************************** }
 
unit ucrypt;
 
interface
type TEAKey = array [0..3] of cardinal;
 
//Use 64-bit aligned data size (8,16...) or else some data will be left unencrypted!
procedure TEA_Encode(Input,Output:pointer;size:integer;key:TEAKey);
procedure TEA_Decode(Input,Output:pointer;size:integer;key:TEAKey);
 
 
implementation
type
     TEAData = array[0..1] of cardinal;
     PTEAKey = ^TEAKey;
     PTEAData = ^TEAData;
 
Procedure TEA_Cipher(v:PTEAData;var w:PTEAData;k:PTEAKey);
var y,z,sum,delta,n:Cardinal;
begin
 y:=(v)[0]; z:=(v)[1];
 sum:=0; delta:=$9E3779B9;
 n:=32;
 
 while (n > 0) do begin
   inc(y, (z shl 4 xor z shr 5) + z xor sum + (k)[sum and 3]);
   inc(sum,delta);
   inc(z,(y shl 4 xor y shr 5) + y xor sum + (k)[sum shr 11 and 3]);
  dec(n);
 end;
 
 (w)[0]:=y; (w)[1]:=z;
end;
Procedure TEA_DeCipher(v:PTEAData;var w:PTEAData;k:PTEAKey);
var y,z,sum,delta,n:Cardinal;
begin
 
   y:=v[0];
   z:=v[1];
   sum:=$0C6EF3720;
   delta:=$9E3779B9;
   n:=32;
 
   while (n > 0) do begin
    dec(z,(y shl 4 xor y shr 5) + y xor sum + k[sum shr 11 and 3]);
    dec(sum,delta);
    dec(y,(z shl 4 xor z shr 5) + z xor sum + k[sum and 3]);
    dec(n);
   end;
 
   w[0]:=y; w[1]:=z;
 
 
end;
procedure TEA_EnDec(encode:boolean;Input,Output:pointer;size:integer;key:TEAKey);
var DataIn,DataOut:TEAData;
    DOut:PTEAData;
    i,sz:integer;
begin
    DOut:=@DataOut;
    sz:=(size shr 3) shl 3;
    i:=0;
    repeat
      DataIn[0]:=Cardinal((pointer(Cardinal(Input)+Cardinal(i)))^);
      DataIn[1]:=Cardinal((pointer(Cardinal(Input)+Cardinal(i+4)))^);
      if encode then TEA_Cipher(@DataIn,DOut,@key) else TEA_DECipher(@DataIn,DOut,@key);
      Cardinal(pointer(Cardinal(Output)+Cardinal(i))^):=DataOut[0];
      Cardinal(pointer(Cardinal(Output)+Cardinal(i+4))^):=DataOut[1];
      inc(i,8);
    until i>=sz;
 
end;
procedure TEA_Encode(Input,Output:pointer;size:integer;key:TEAKey);
begin
 TEA_EnDec(true,Input,Output,size,key);
end;
 
procedure TEA_Decode(Input,Output:pointer;size:integer;key:TEAKey);
begin
 TEA_EnDec(false,Input,Output,size,key);
end;
 
end.