RC6

Материал из DRKB



Как я уже говорил, RC6 Очень похож на RC5, во всяком случае расчет субключа производится тем же способом, что и в RC5. RC6 участвовал в конкурсе на звание AES и, по некоторым данным, не выиграл только из-за медленной работы аппаратных реализаций. Программные же реализации RC6, пожалуй, являются самыми быстрыми среди алгоритмов шифрования, при обеспечении достаточной стойкости шифра.

Нижепредставленный модуль построен по тому же принципу, что и предыдущие - имена функций совпадают и если вы хотите заменить в своей программе шифрование с IDEA или RC5 на RC6 - просто добавьте модуль RC6, а IDEA или RC5 - удалите из списка uses.

Шифр RC6, в отличии от RC5, оперирует блоками по 16 байт, а модуль построен так, что если при шифрации методами: EncryptCopy, DecryptCopy, EncryptStream, DecryptStream размер данных не будет кратен 16 - последний блок длинной 1..15 байт не шифруется и в "чистом" виде добавляется к зашифрованным. Также и при дешифровании - если последний блок размером 1..15 байт он не дешифруется а добавляется к расшифрованным данным. Такой подход обеспечивает в полной мере "симметричное" шифрование так как размеры входных и выходных данных полностью совпадают. Однако такой подход приводит к некоторым сложностям, если последний блок также нуждается в шифровании. На мой взгляд лучший выход - добавить при шифровании к исходным данным строку определенной длинны и после дешифрования отсечь с конца строку той же длинны.

Также в заключении цикла статей, посвященных шифрованию я подготовил примеры по всем представленным алгоритмам (IDEA, RC5, RC6).


А вот последний модуль:

{ *********************************************************************** }
{                                                                         }
{ Delphi Еncryption Library                                               }
{ Еncryption / Decryption stream - RC6                                    }
{                                                                         }
{ Copyright (c) 2004 by Matveev Igor Vladimirovich                        }
{ With offers and wishes write: teap_leap@mail.ru                         }
{                                                                         }
{ *********************************************************************** }

unit RC6;

interface

uses
  SysUtils, Classes;

const
  Rounds    = 20;
  KeyLength = 2 * (Rounds + 2);

  BlockSize = 16;
  KeySize   = 16 * 4;

  P32       = $b7e15163;
  Q32       = $9e3779b9;
  lgw       = 5;

type
  TRC6Block = array[1..4] of LongWord;

var
  S      : array[0..KeyLength-1] of LongWord;
  Key    : string;
  KeyPtr : PChar;

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

procedure Initialize(AKey: string);          // Инициализация
procedure CalculateSubKeys;                  // Подготовка субключей
function EncipherBlock(var Block): Boolean;  // Шифрация блока (16 байт)
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;

function ROR(a, s: LongWord): LongWord;
asm
  mov    ecx, s
  ror    eax, cl
end;

procedure InvolveKey;
var
  TempKey: string;
  i, j: Integer;
  K1, K2: LongWord;
begin
  // Разворачивание ключа до длинны KeySize = 64
  TempKey := Key;
  i := 1;
  while ((Length(TempKey) mod KeySize) <> 0) do
  begin
    TempKey := TempKey + TempKey[i];
    Inc(i);
  end;

  i := 1;
  j := 0;
  while (i < Length(TempKey)) do
  begin
    Move((KeyPtr+j)^, K1, 4);
    Move(TempKey[i], K2, 4);
    K1 := ROL(K1, K2) xor K2;
    Move(K1, (KeyPtr+j)^, 4);
    j := (j + 4) mod KeySize;
    Inc(i, 4);
  end;
end;

procedure CalculateSubKeys;
var
  i, j, k: Integer;
  L: array[0..15] of LongWord;
  A, B: LongWord;
begin
  // Копирование ключа в L
  Move(KeyPtr^, L, KeySize);

  // Инициализация субключа S
  S[0] := P32;
  for i := 1 to KeyLength-1 do
    S[i] := S[i-1] + Q32;

  // Смешивание S с ключом
  i := 0;
  j := 0;
  A := 0;
  B := 0;
  for k := 1 to 3*KeyLength do
  begin
    A := ROL((S[i] + A + B), 3);
    S[i] := A;
    B := ROL((L[j] + A + B), (A + B));
    L[j] := B;
    i := (i + 1) mod KeyLength;
    j := (j + 1) mod 16;
  end;
end;

procedure Initialize(AKey: string);
begin
  GetMem(KeyPtr, KeySize);
  FillChar(KeyPtr^, KeySize, #0);
  Key := AKey;

  InvolveKey;
end;

function EncipherBlock(var Block): Boolean;
var
  RC6Block: TRC6Block absolute Block;
  i: Integer;
  t, u: LongWord;
  Temp: LongWord;
begin
  // Инициализация блока
  Inc(RC6Block[2], S[0]);
  Inc(RC6Block[4], S[1]);

  for i := 1 to Rounds do
  begin
    t := ROL((RC6Block[2] * (2*RC6Block[2] + 1)), lgw);
    u := ROL((RC6Block[4] * (2*RC6Block[4] + 1)), lgw);
    RC6Block[1] := ROL((RC6Block[1] xor t), u) + S[2*i];
    RC6Block[3] := ROL((RC6Block[3] xor u), t) + S[2*i+1];

    Temp := RC6Block[1];
    RC6Block[1] := RC6Block[2];
    RC6Block[2] := RC6Block[3];
    RC6Block[3] := RC6Block[4];
    RC6Block[4] := Temp;
  end;

  RC6Block[1] := RC6Block[1] + S[2*Rounds+2];
  RC6Block[3] := RC6Block[3] + S[2*Rounds+3];

  Result := True;
end;

function DecipherBlock(var Block): Boolean;
var
  RC6Block: TRC6Block absolute Block;
  i: Integer;
  t, u: LongWord;
  Temp: LongWord;
begin
  // Инициализация блока
  RC6Block[3] := RC6Block[3] - S[2*Rounds+3];
  RC6Block[1] := RC6Block[1] - S[2*Rounds+2];

  for i := Rounds downto 1 do
  begin
    Temp := RC6Block[4];
    RC6Block[4] := RC6Block[3];
    RC6Block[3] := RC6Block[2];
    RC6Block[2] := RC6Block[1];
    RC6Block[1] := Temp;

    u := ROL((RC6Block[4] * (2*RC6Block[4] + 1)),lgw);
    t := ROL((RC6Block[2] * (2*RC6Block[2] + 1)),lgw);
    RC6Block[3] := ROR((RC6Block[3]-S[2*i+1]), t) xor u;
    RC6Block[1] := ROR((RC6Block[1]-S[2*i]), u) xor t;
  end;

  Dec(RC6Block[4], S[1]);
  Dec(RC6Block[2], S[0]);

  Result := True;
end;

////////////////////////////////////////////////////////////////////////////////
// Реализация главных функций

function EncryptCopy(DestStream, SourseStream: TStream; Count: Int64;
  Key: string): Boolean;
var
  Buffer: TRC6Block;
  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 >= BlockSize do
    begin
      SourseStream.Read(Buffer, BlockSize);
      EncipherBlock(Buffer);
      DestStream.Write(Buffer, BlockSize);
      Inc(PrCount, BlockSize);
    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: TRC6Block;
  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 >= BlockSize do
    begin
      SourseStream.Read(Buffer, BlockSize);
      DecipherBlock(Buffer);
      DestStream.Write(Buffer, BlockSize);
      Inc(PrCount, BlockSize);
    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: TRC6Block;
  PrCount: Int64;
begin
  Result := True;
  try
    if Key = '' then
    begin
      DataStream.Seek(Count, soFromCurrent);
      Exit;
    end;
    Initialize(Key);
    CalculateSubKeys;
    PrCount := 0;
    while Count - PrCount >= BlockSize do
    begin
      DataStream.Read(Buffer, BlockSize);
      EncipherBlock(Buffer);
      DataStream.Seek(-BlockSize, soFromCurrent);
      DataStream.Write(Buffer, BlockSize);
      Inc(PrCount, BlockSize);
    end;
  except
    Result := False;
  end;
end;

function DecryptStream(DataStream: TStream; Count: Int64; Key: string): Boolean;
var
  Buffer   : TRC6Block;
  PrCount  : Int64;
begin
  Result := True;
  try
    if Key = '' then
    begin
      DataStream.Seek(Count, soFromCurrent);
      Exit;
    end;
    Initialize(Key);
    CalculateSubKeys;
    PrCount := 0;
    while Count - PrCount >= BlockSize do
    begin
      DataStream.Read(Buffer, BlockSize);
      DecipherBlock(Buffer);
      DataStream.Seek(-BlockSize, soFromCurrent);
      DataStream.Write(Buffer, BlockSize);
      Inc(PrCount, BlockSize);
    end;
  except
    Result := False;
  end;
end;

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

end.


Author: Матвеев Игорь
Source: http://delphiworld.narod.ru/
ID: 03988