Алгоритм шифрования 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.
Взято из 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.