Componentes.Terceros.RemObj.../internal/5.0.24.615/1/RemObjects SDK for Delphi/Source/RODEC/uROCipher.pas

4127 lines
114 KiB
ObjectPascal

{Copyright: Hagen Reddmann mailto:HaReddmann@AOL.COM
Author: Hagen Reddmann
Remarks: freeware, but this Copyright must be included
known Problems: none
Version: 3.0, Part I from Delphi Encryption Compendium ( DEC Part I)
Delphi 2-4, designed and testet under D3 & D4
Description: Include a Selection of various RO_Cipher's (Encryption Algo)
impl. Algo:
Gost, Blowfish, IDEA, SAFER in 6 Types,
SAFER-K40 (konvetional), SAFER-SK40 (with Keyscheduling),
SAFER-K64, SAFER-SK64, SAFER-K128, SAFER-SK128,
TEA, TEAN (TEA extended), SCOP, Q128, 3Way,
Twofish, Shark, Square
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
unit uROCipher;
interface
{$I uROVer.inc}
uses SysUtils, Classes, uRODECUtil, uROHash;
const {ErrorCode's for EROCipherException}
errGeneric = 0; {generic Error}
errInvalidKey = 1; {Decode Key is not correct}
errInvalidKeySize = 2; {Size of the Key is too large}
errNotInitialized = 3; {Methods Init() or InitKey() were not called}
errInvalidMACMode = 4; {CalcMAC can't use cmECB, cmOFB}
errCantCalc = 5;
type
EROCipherException = class(Exception)
public
Errorcode: Integer;
end;
{all RO_Cipher Classes in this Unit, a good Selection}
TROCipher_Gost = class;
TROCipher_Blowfish = class;
TROCipher_IDEA = class;
TROCipher_SAFER = class;
TROCipher_SAFER_K40 = class;
TROCipher_SAFER_SK40 = class;
TROCipher_SAFER_K64 = class;
TROCipher_SAFER_SK64 = class;
TROCipher_SAFER_K128 = class;
TROCipher_SAFER_SK128 = class;
TROCipher_TEA = class;
TROCipher_TEAN = class;
TROCipher_SCOP = class; {Streamcipher}
TROCipher_Q128 = class;
TROCipher_3Way = class;
TROCipher_Twofish = class;
TROCipher_Shark = class;
TROCipher_Square = class;
TCipherMode = (cmCTS, cmCBC, cmCFB, cmOFB, cmECB, cmCTSMAC, cmCBCMAC, cmCFBMAC);
{ the RO_Cipher Modes:
cmCTS RO_Cipher Text Stealing, a Variant from cmCBC, but relaxes
the restriction that the DataSize must be a mulitply from BufSize,
this is the Defaultmode, fast and Bytewise
cmCBC RO_Cipher Block Chaining
cmCFB K-bit RO_Cipher Feedback, here is K = 8 -> 1 Byte
cmOFB K-bit Output Feedback, here is K = 8 -> 1 Byte
cmECB * Electronic Codebook, DataSize must be a multiply from BufSize
cmCTSMAC Build a Message Authentication Code in cmCTS Mode
cmCBCMAC Build a CBC-MAC
cmCFBMAC Build a CFB-MAC
}
TROCipherClass = class of TROCipher;
TROCipher = class(TROProtection)
private
FMode: TCipherMode;
FHash: TROHash;
FHashClass: TROHashClass;
FKeySize: Integer;
FBufSize: Integer;
FUserSize: Integer;
FBuffer: Pointer;
FVector: Pointer;
FFeedback: Pointer;
FUser: Pointer;
FFlags: Integer;
function GetHash: TROHash;
procedure SetHashClass(Value: TROHashClass);
procedure InternalCodeStream(Source, Dest: TStream; DataSize: Integer; Encode: Boolean);
procedure InternalCodeFile(const Source, Dest: string; Encode: Boolean);
protected
function GetFlag(Index: Integer): Boolean;
procedure SetFlag(Index: Integer; Value: Boolean); virtual;
{used in method Init()}
procedure InitBegin(var Size: Integer);
procedure InitEnd(IVector: Pointer); virtual;
{must override}
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); virtual;
class function TestVector: Pointer; virtual;
{override TROProtection Methods}
procedure CodeInit(Action: TPAction); override;
procedure CodeDone(Action: TPAction); override;
procedure CodeBuf(var Buffer; const BufferSize: Integer; Action: TPAction); override;
{the encode function, must override}
procedure Encode(Data: Pointer); virtual;
{the decode function, must override}
procedure Decode(Data: Pointer); virtual;
{the individual Userdata and Buffer}
property User: Pointer read FUser;
property Buffer: Pointer read FBuffer;
property UserSize: Integer read FUserSize;
public
constructor Create(const Password: string; AProtection: TROProtection);
destructor Destroy; override;
class function MaxKeySize: Integer;
{performs a Test of correct work}
class function SelfTest: Boolean;
{initialization form the RO_Cipher}
procedure Init(const Key; Size: Integer; IVector: Pointer); virtual;
procedure InitKey(const Key: string; IVector: Pointer);
{reset the Feedbackregister with the actual IVector}
procedure Done; virtual;
{protect the security Data's, Feedback, Buffer, Vector etc.}
procedure Protect; virtual;
procedure EncodeBuffer(const Source; var Dest; DataSize: Integer);
procedure DecodeBuffer(const Source; var Dest; DataSize: Integer);
function EncodeString(const Source: string): string;
function DecodeString(const Source: string): string;
procedure EncodeFile(const Source, Dest: string);
procedure DecodeFile(const Source, Dest: string);
procedure EncodeStream(const Source, Dest: TStream; DataSize: Integer);
procedure DecodeStream(const Source, Dest: TStream; DataSize: Integer);
{calculate a MAC, Message Authentication Code, can be use in
cmCBCMAC, cmCTSMAC, cmCFBMAC Modes -> Dest is not modified, or
cmCBC, cmCTS, cmCFB Modes -> normal En/Decoding of Dest.}
function CalcMAC(Format: Integer): string;
{the RO_Cipher Mode = cmXXX}
property Mode: TCipherMode read FMode write FMode;
{the Current RO_Hash-Object, to build a Digest from InitKey()}
property RO_Hash: TROHash read GetHash;
{the Class of the RO_Hash-Object}
property HashClass: TROHashClass read FHashClass write SetHashClass;
{the maximal KeySize and BufSize (Size of Feedback, Buffer and Vector}
property KeySize: Integer read FKeySize;
property BufSize: Integer read FBufSize;
{Init() was called}
property Initialized: Boolean index 1 read GetFlag write SetFlag;
{the actual IVector, BufSize Bytes long}
property Vector: Pointer read FVector;
{the Feedback register, BufSize Bytes long}
property Feedback: Pointer read FFeedback;
{the Key is set from InitKey() and the RO_Hash.DigestKey^ include the encrypted RO_Hash-Key}
property HasHashKey: Boolean index 0 read GetFlag;
end;
// now the RO_Cipher's
TROCipher_Gost = class(TROCipher) {russian RO_Cipher}
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_Blowfish = class(TROCipher)
private
{$IFDEF UseASM}
{$IFNDEF 486GE} // no Support for <= CPU 386
procedure Encode386(Data: Pointer);
procedure Decode386(Data: Pointer);
{$ENDIF}
{$ENDIF}
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_IDEA = class(TROCipher) {International Data Encryption Algorithm }
private
procedure RO_Cipher(Data, Key: PWordArray);
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TSAFERMode = (smDefault, smK40, smK64, smK128, smStrong, smSK40, smSK64, smSK128);
{smDefault Mode is build from KeyLength "Size"
if Size <= 5 then is smK40 used
if Size <= 8 then is smK64 used
if Size <= 16 then is smK128 used
smK40 SAFER K-40 Keysize is 40bit -> 5 Byte
smK64 SAFER K-64 Keysize is 64bit -> 8 Byte
smK128 SAFER K-128 KeySize is 128bit -> 16 Byte
smStrong Mode is build from KeyLength "Size" and stronger as smDefault,
if Size <= 5 then is smSK40 used
if Size <= 8 then is smSK64 used
if Size <= 16 then is smSK128 used
this is the Defaultmode for TROCipher_SAFER
smSK40 SAFER SK-40 stronger Version from K-40 with better Keyscheduling
smSK64 SAFER SK-64 stronger Version from K-64 with better Keyscheduling
smSK128 SAFER SK-128 stronger Version from K-128 with better Keyscheduling}
TROCipher_SAFER = class(TROCipher) {SAFER = Secure And Fast Encryption Routine}
private
FRounds: Integer;
FSAFERMode: TSAFERMode;
procedure SetRounds(Value: Integer);
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
procedure InitNew(const Key; Size: Integer; IVector: Pointer; SAFERMode: TSAFERMode);
property Rounds: Integer read FRounds write SetRounds;
end;
TROCipher_SAFER_K40 = class(TROCipher_SAFER)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_SAFER_SK40 = class(TROCipher_SAFER_K40)
protected
class function TestVector: Pointer; override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_SAFER_K64 = class(TROCipher_SAFER)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_SAFER_SK64 = class(TROCipher_SAFER_K64)
protected
class function TestVector: Pointer; override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_SAFER_K128 = class(TROCipher_SAFER)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_SAFER_SK128 = class(TROCipher_SAFER_K128)
protected
class function TestVector: Pointer; override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_TEA = class(TROCipher) {Tiny Encryption Algorithm}
private
FRounds: Integer; {16 - 32, default 16 is sufficient, 32 is ample}
procedure SetRounds(Value: Integer);
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
property Rounds: Integer read FRounds write SetRounds;
end;
TROCipher_TEAN = class(TROCipher_TEA) {Tiny Encryption Algorithm, extended Version}
protected
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
end;
TROCipher_SCOP = class(TROCipher) {Stream RO_Cipher in Blockmode}
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
procedure Done; override;
end;
TROCipher_Q128 = class(TROCipher)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_3Way = class(TROCipher)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_Twofish = class(TROCipher)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_Shark = class(TROCipher)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
TROCipher_Square = class(TROCipher)
protected
class procedure GetContext(var ABufSize, AKeySize, AUserSize: Integer); override;
class function TestVector: Pointer; override;
procedure Encode(Data: Pointer); override;
procedure Decode(Data: Pointer); override;
public
procedure Init(const Key; Size: Integer; IVector: Pointer); override;
end;
function DefaultCipherClass: TROCipherClass;
procedure SetDefaultCipherClass(CipherClass: TROCipherClass);
procedure RaiseCipherException(const Errorcode: Integer; const Msg: string);
function RegisterCipher(const ACipher: TROCipherClass; const aName, ADescription: string): Boolean;
function UnregisterCipher(const ACipher: TROCipherClass): Boolean;
function CipherList: TStrings;
procedure CipherNames(List: TStrings);
function GetCipherClass(const Name: string): TROCipherClass;
function GetCipherName(CipherClass: TROCipherClass): string;
const
CheckCipherKeySize: Boolean = False;
{set to True raises Exception when Size of the Key is too large, (Method Init())
otherwise will truncate the Key, default mode is False}
implementation
uses uRODECConst, Windows;
{$I *.inc}
{$I uROSquare.inc}
const
FDefaultCipherClass: TROCipherClass = TROCipher_Blowfish;
FCipherList : TStringList = nil;
function DefaultCipherClass: TROCipherClass;
begin
Result := FDefaultCipherClass;
end;
procedure SetDefaultCipherClass(CipherClass: TROCipherClass);
begin
if CipherClass = nil then
FDefaultCipherClass := TROCipher_Blowfish
else
FDefaultCipherClass := CipherClass;
end;
procedure RaiseCipherException(const Errorcode: Integer; const Msg: string);
var
e : EROCipherException;
begin
e := EROCipherException.Create(Msg);
e.Errorcode := Errorcode;
raise e;
end;
function RegisterCipher(const ACipher: TROCipherClass; const aName, ADescription: string): Boolean;
var
i : Integer;
S : string;
begin
Result := False;
if ACipher = nil then
Exit;
S := Trim(aName);
if S = '' then
begin
S := ACipher.ClassName;
if S[1] = 'T' then
Delete(S, 1, 1);
i := Pos('_', S);
if i > 0 then
Delete(S, 1, i);
end;
S := S + '=' + ADescription;
i := CipherList.IndexOfObject(Pointer(ACipher));
if i < 0 then
CipherList.AddObject(S, Pointer(ACipher))
else
CipherList[i] := S;
Result := True;
end;
function UnregisterCipher(const ACipher: TROCipherClass): Boolean;
var
i : Integer;
begin
Result := False;
repeat
i := CipherList.IndexOfObject(Pointer(ACipher));
if i < 0 then
Break;
Result := True;
CipherList.Delete(i);
until False;
end;
function CipherList: TStrings;
begin
if not IsObject(FCipherList, TStringList) then
FCipherList := TStringList.Create;
Result := FCipherList;
end;
procedure CipherNames(List: TStrings);
var
i : Integer;
begin
if not IsObject(List, TStrings) then
Exit;
for i := 0 to CipherList.Count - 1 do
List.AddObject(FCipherList.Names[i], FCipherList.Objects[i]);
end;
function GetCipherClass(const Name: string): TROCipherClass;
var
i : Integer;
N : string;
begin
Result := nil;
N := Name;
i := Pos('_', N);
if i > 0 then
Delete(N, 1, i);
for i := 0 to CipherList.Count - 1 do
if AnsiCompareText(N, GetShortClassName(TClass(FCipherList.Objects[i]))) = 0 then
begin
Result := TROCipherClass(FCipherList.Objects[i]);
Exit;
end;
i := FCipherList.IndexOfName(N);
if i >= 0 then
Result := TROCipherClass(FCipherList.Objects[i]);
end;
function GetCipherName(CipherClass: TROCipherClass): string;
var
i : Integer;
begin
i := CipherList.IndexOfObject(Pointer(CipherClass));
if i >= 0 then
Result := FCipherList.Names[i]
else
Result := GetShortClassName(CipherClass);
end;
function TROCipher.GetFlag(Index: Integer): Boolean;
begin
Result := FFlags and (1 shl Index) <> 0;
end;
procedure TROCipher.SetFlag(Index: Integer; Value: Boolean);
begin
Index := 1 shl Index;
if Value then
FFlags := FFlags or Index
else
FFlags := FFlags and not Index;
end;
procedure TROCipher.InitBegin(var Size: Integer);
begin
Initialized := False;
Protect;
if Size < 0 then
Size := 0;
if Size > KeySize then
if not CheckCipherKeySize then
Size := KeySize
else
RaiseCipherException(errInvalidKeySize, Format(sInvalidKeySize, [ClassName, 0, KeySize]));
end;
procedure TROCipher.InitEnd(IVector: Pointer);
begin
if IVector = nil then
Encode(Vector)
else
Move(IVector^, Vector^, BufSize);
Move(Vector^, Feedback^, BufSize);
Initialized := True;
end;
class procedure TROCipher.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 0;
AKeySize := 0;
AUserSize := 0;
end;
class function TROCipher.TestVector: Pointer;
begin
Result := GetTestVector;
end;
procedure TROCipher.Encode(Data: Pointer);
begin
end;
procedure TROCipher.Decode(Data: Pointer);
begin
end;
constructor TROCipher.Create(const Password: string; AProtection: TROProtection);
begin
inherited Create(AProtection);
FHashClass := DefaultHashClass;
GetContext(FBufSize, FKeySize, FUserSize);
GetMem(FVector, FBufSize);
GetMem(FFeedback, FBufSize);
GetMem(FBuffer, FBufSize);
GetMem(FUser, FUserSize);
Protect;
if Password <> '' then
InitKey(Password, nil);
end;
destructor TROCipher.Destroy;
begin
Protect;
ReallocMem(FVector, 0);
ReallocMem(FFeedback, 0);
ReallocMem(FBuffer, 0);
ReallocMem(FUser, 0);
FHash.release;
FHash := nil;
inherited Destroy;
end;
class function TROCipher.MaxKeySize: Integer;
var
Dummy : Integer;
begin
GetContext(Dummy, Result, Dummy);
end;
class function TROCipher.SelfTest: Boolean;
var
Data : array[0..63] of Char;
Key : string;
SaveKeyCheck : Boolean;
begin
Result := InitTestIsOk; {have anonyme modified the testvectors ?}
{we will use the ClassName as Key :-)}
Key := ClassName;
SaveKeyCheck := CheckCipherKeySize;
with Self.Create('', nil) do
try
CheckCipherKeySize := False;
Mode := cmCTS;
Init(PChar(Key)^, Length(Key), nil);
EncodeBuffer(GetTestVector^, Data, 32);
Result := Result and (MemCompare(TestVector, @Data, 32) = 0);
Done;
DecodeBuffer(Data, Data, 32);
Result := Result and (MemCompare(GetTestVector, @Data, 32) = 0);
finally
CheckCipherKeySize := SaveKeyCheck;
Free;
end;
FillChar(Data, SizeOf(Data), 0);
end;
procedure TROCipher.Init(const Key; Size: Integer; IVector: Pointer);
begin
end;
procedure TROCipher.InitKey(const Key: string; IVector: Pointer);
var
i : Integer;
begin
RO_Hash.Init;
RO_Hash.Calc(PChar(Key)^, Length(Key));
RO_Hash.Done;
i := RO_Hash.DigestKeySize;
if i > FKeySize then
i := FKeySize; {generaly will truncate to large Keys}
Init(RO_Hash.DigestKey^, i, IVector);
EncodeBuffer(RO_Hash.DigestKey^, RO_Hash.DigestKey^, RO_Hash.DigestKeySize);
Done;
SetFlag(0, True);
end;
procedure TROCipher.Done;
begin
if MemCompare(FVector, FFeedback, FBufSize) = 0 then
Exit;
Move(FFeedback^, FBuffer^, FBufSize);
Move(FVector^, FFeedback^, FBufSize);
end;
procedure TROCipher.Protect;
begin
SetFlag(0, False);
Initialized := False;
// a Crypto Fanatican say: this is better !!
FillChar(FVector^, FBufSize, $AA);
FillChar(FFeedback^, FBufSize, $AA);
FillChar(FBuffer^, FBufSize, $AA);
FillChar(FUser^, FUserSize, $AA);
FillChar(FVector^, FBufSize, $55);
FillChar(FFeedback^, FBufSize, $55);
FillChar(FBuffer^, FBufSize, $55);
FillChar(FUser^, FUserSize, $55);
FillChar(FVector^, FBufSize, $FF);
FillChar(FFeedback^, FBufSize, $FF);
FillChar(FBuffer^, FBufSize, 0);
FillChar(FUser^, FUserSize, 0);
end;
function TROCipher.GetHash: TROHash;
begin
if not IsObject(FHash, TROHash) then
begin
if FHashClass = nil then
FHashClass := DefaultHashClass;
FHash := FHashClass.Create(nil);
FHash.AddRef;
end;
Result := FHash;
end;
procedure TROCipher.SetHashClass(Value: TROHashClass);
begin
if Value <> FHashClass then
begin
FHash.release;
FHash := nil;
FHashClass := Value;
if FHashClass = nil then
FHashClass := DefaultHashClass;
end;
end;
procedure TROCipher.InternalCodeStream(Source, Dest: TStream; DataSize: Integer; Encode: Boolean);
const
maxBufSize = 1024 * 4;
var
Buf : PChar;
SPos : Integer;
dPos : Integer;
Len : Integer;
Proc : procedure(const Source; var Dest; DataSize: Integer) of object;
Size : Integer;
begin
if Source = nil then
Exit;
if Encode or (Mode in [cmCBCMAC, cmCTSMAC, cmCFBMAC]) then
Proc := EncodeBuffer
else
Proc := DecodeBuffer;
if Dest = nil then
Dest := Source;
if DataSize < 0 then
begin
DataSize := Source.Size;
Source.Position := 0;
end;
Buf := nil;
Size := DataSize;
DoProgress(Self, 0, Size);
try
Buf := AllocMem(maxBufSize);
dPos := Dest.Position;
SPos := Source.Position;
if Mode in [cmCTSMAC, cmCBCMAC, cmCFBMAC] then
begin
while DataSize > 0 do
begin
Len := DataSize;
if Len > maxBufSize then
Len := maxBufSize;
Len := Source.read(Buf^, Len);
if Len <= 0 then
Break;
Proc(Buf^, Buf^, Len);
Dec(DataSize, Len);
DoProgress(Self, Size - DataSize, Size);
end;
end
else
while DataSize > 0 do
begin
Source.Position := SPos;
Len := DataSize;
if Len > maxBufSize then
Len := maxBufSize;
Len := Source.read(Buf^, Len);
SPos := Source.Position;
if Len <= 0 then
Break;
Proc(Buf^, Buf^, Len);
Dest.Position := dPos;
Dest.Write(Buf^, Len);
dPos := Dest.Position;
Dec(DataSize, Len);
DoProgress(Self, Size - DataSize, Size);
end;
finally
DoProgress(Self, 0, 0);
ReallocMem(Buf, 0);
end;
end;
procedure TROCipher.InternalCodeFile(const Source, Dest: string; Encode: Boolean);
var
S, d : tfilestream;
begin
S := nil;
d := nil;
try
if Mode in [cmCBCMAC, cmCTSMAC, cmCFBMAC] then
begin
S := tfilestream.Create(Source, fmOpenRead or fmShareDenyNone);
d := S;
end
else
if (AnsiCompareText(Source, Dest) <> 0) and (Trim(Dest) <> '') then
begin
S := tfilestream.Create(Source, fmOpenRead or fmShareDenyNone);
d := tfilestream.Create(Dest, fmCreate);
end
else
begin
S := tfilestream.Create(Source, fmOpenReadWrite);
d := S;
end;
InternalCodeStream(S, d, -1, Encode);
finally
S.Free;
if S <> d then
begin
{$IFDEF VER_D3H}
d.Size := d.Position;
{$ENDIF}
d.Free;
end;
end;
end;
procedure TROCipher.EncodeStream(const Source, Dest: TStream; DataSize: Integer);
begin
InternalCodeStream(Source, Dest, DataSize, True);
end;
procedure TROCipher.DecodeStream(const Source, Dest: TStream; DataSize: Integer);
begin
InternalCodeStream(Source, Dest, DataSize, False);
end;
procedure TROCipher.EncodeFile(const Source, Dest: string);
begin
InternalCodeFile(Source, Dest, True);
end;
procedure TROCipher.DecodeFile(const Source, Dest: string);
begin
InternalCodeFile(Source, Dest, False);
end;
function TROCipher.EncodeString(const Source: string): string;
begin
SetLength(Result, Length(Source));
EncodeBuffer(PChar(Source)^, PChar(Result)^, Length(Source));
if Mode in [cmCBCMAC, cmCTSMAC, cmCFBMAC] then
Result := '';
end;
function TROCipher.DecodeString(const Source: string): string;
begin
SetLength(Result, Length(Source));
DecodeBuffer(PChar(Source)^, PChar(Result)^, Length(Source));
if Mode in [cmCBCMAC, cmCTSMAC, cmCFBMAC] then
Result := '';
end;
procedure TROCipher.EncodeBuffer(const Source; var Dest; DataSize: Integer);
var
S, d, f : PByte;
begin
if not Initialized then
RaiseCipherException(errNotInitialized, Format(sNotInitialized, [ClassName]));
S := @Source;
d := @Dest;
case FMode of
cmECB:
begin
if S <> d then
Move(S^, d^, DataSize);
while DataSize >= FBufSize do
begin
Encode(d);
Inc(d, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(d^, FBuffer^, DataSize);
Encode(FBuffer);
Move(FBuffer^, d^, DataSize);
end;
end;
cmCTS:
begin
while DataSize >= FBufSize do
begin
XORBuffers(S, FFeedback, FBufSize, d);
Encode(d);
XORBuffers(d, FFeedback, FBufSize, FFeedback);
Inc(S, FBufSize);
Inc(d, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(S, FBuffer, DataSize, d);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
cmCBC:
begin
f := FFeedback;
while DataSize >= FBufSize do
begin
XORBuffers(S, f, FBufSize, d);
Encode(d);
f := d;
Inc(S, FBufSize);
Inc(d, FBufSize);
Dec(DataSize, FBufSize);
end;
Move(f^, FFeedback^, FBufSize);
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(S, FBuffer, DataSize, d);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
cmCFB:
while DataSize > 0 do
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
d^ := S^ xor PByte(FBuffer)^;
Move(PByteArray(FFeedback)[1], FFeedback^, FBufSize - 1);
PByteArray(FFeedback)[FBufSize - 1] := d^;
Inc(d);
Inc(S);
Dec(DataSize);
end;
cmOFB:
while DataSize > 0 do
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
d^ := S^ xor PByte(FBuffer)^;
Move(PByteArray(FFeedback)[1], FFeedback^, FBufSize - 1);
PByteArray(FFeedback)[FBufSize - 1] := PByte(FBuffer)^;
Inc(d);
Inc(S);
Dec(DataSize);
end;
cmCTSMAC:
begin
while DataSize >= FBufSize do
begin
XORBuffers(S, FFeedback, FBufSize, FBuffer);
Encode(FBuffer);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
Inc(S, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
cmCBCMAC:
begin
while DataSize >= FBufSize do
begin
XORBuffers(S, FFeedback, FBufSize, FBuffer);
Encode(FBuffer);
Move(FBuffer^, FFeedback^, FBufSize);
Inc(S, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
cmCFBMAC:
while DataSize > 0 do
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
Move(PByteArray(FFeedback)[1], FFeedback^, FBufSize - 1);
PByteArray(FFeedback)[FBufSize - 1] := S^ xor PByte(FBuffer)^;
Inc(S);
Dec(DataSize);
end;
end;
end;
procedure TROCipher.DecodeBuffer(const Source; var Dest; DataSize: Integer);
var
S, d, f, b : PByte;
begin
if not Initialized then
RaiseCipherException(errNotInitialized, Format(sNotInitialized, [ClassName]));
S := @Source;
d := @Dest;
case FMode of
cmECB:
begin
if S <> d then
Move(S^, d^, DataSize);
while DataSize >= FBufSize do
begin
Decode(d);
Inc(d, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(d^, FBuffer^, DataSize);
Encode(FBuffer);
Move(FBuffer^, d^, DataSize);
end;
end;
cmCTS:
begin
if S <> d then
Move(S^, d^, DataSize);
f := FFeedback;
b := FBuffer;
while DataSize >= FBufSize do
begin
XORBuffers(d, f, FBufSize, b);
Decode(d);
XORBuffers(d, f, FBufSize, d);
S := b;
b := f;
f := S;
Inc(d, FBufSize);
Dec(DataSize, FBufSize);
end;
if f <> FFeedback then
Move(f^, FFeedback^, FBufSize);
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(FBuffer, d, DataSize, d);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
cmCBC:
begin
if S <> d then
Move(S^, d^, DataSize);
f := FFeedback;
b := FBuffer;
while DataSize >= FBufSize do
begin
Move(d^, b^, FBufSize);
Decode(d);
XORBuffers(f, d, FBufSize, d);
S := b;
b := f;
f := S;
Inc(d, FBufSize);
Dec(DataSize, FBufSize);
end;
if f <> FFeedback then
Move(f^, FFeedback^, FBufSize);
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(d, FBuffer, DataSize, d);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
cmCFB:
while DataSize > 0 do
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
Move(PByteArray(FFeedback)[1], FFeedback^, FBufSize - 1);
PByteArray(FFeedback)[FBufSize - 1] := S^;
d^ := S^ xor PByte(FBuffer)^;
Inc(d);
Inc(S);
Dec(DataSize);
end;
cmOFB:
while DataSize > 0 do
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
d^ := S^ xor PByte(FBuffer)^;
Move(PByteArray(FFeedback)[1], FFeedback^, FBufSize - 1);
PByteArray(FFeedback)[FBufSize - 1] := PByte(FBuffer)^;
Inc(d);
Inc(S);
Dec(DataSize);
end;
cmCTSMAC, cmCBCMAC, cmCFBMAC:
begin
EncodeBuffer(Source, Dest, DataSize);
Exit;
end;
end;
end;
procedure TROCipher.CodeInit(Action: TPAction);
begin
if not Initialized then
RaiseCipherException(errNotInitialized, Format(sNotInitialized, [ClassName]));
{ if (Mode in [cmCBCMAC, cmCTSMAC, cmCFBMAC]) <> (Action = paCalc) then
RaiseCipherException(errCantCalc, Format(sCantCalc, [ClassName]));}
if Action <> paCalc then
if Action <> paWipe then
Done
else
RndXORBuffer(RndTimeSeed, FFeedback^, FBufSize);
inherited CodeInit(Action);
end;
procedure TROCipher.CodeDone(Action: TPAction);
begin
inherited CodeDone(Action);
if Action <> paCalc then
if Action <> paWipe then
Done
else
RndXORBuffer(RndTimeSeed, FFeedback^, FBufSize);
end;
procedure TROCipher.CodeBuf(var Buffer; const BufferSize: Integer; Action: TPAction);
begin
if Action = paDecode then
begin
if Action in Actions then
DecodeBuffer(Buffer, Buffer, BufferSize);
inherited CodeBuf(Buffer, BufferSize, Action);
end
else
begin
inherited CodeBuf(Buffer, BufferSize, Action);
if Action in Actions then
EncodeBuffer(Buffer, Buffer, BufferSize);
end;
end;
function TROCipher.CalcMAC(Format: Integer): string;
var
b : PByteArray;
begin
if Mode in [cmECB, cmOFB] then
RaiseCipherException(errInvalidMACMode, sInvalidMACMode);
Done;
b := AllocMem(FBufSize);
try
Move(FBuffer^, b^, FBufSize);
EncodeBuffer(b^, b^, FBufSize);
SetLength(Result, FBufSize);
Move(FFeedback^, PChar(Result)^, FBufSize);
if Protection <> nil then
Result := Protection.CodeString(Result, paScramble, Format)
else
Result := StrToFormat(PChar(Result), Length(Result), Format);
finally
ReallocMem(b, 0);
Done;
end;
end;
class procedure TROCipher_Gost.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 8;
AKeySize := 32;
AUserSize := 32;
end;
class function TROCipher_Gost.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0B3h,003h,0A0h,03Fh,0B5h,07Bh,091h,04Dh
DB 097h,051h,024h,040h,0BDh,0CFh,025h,015h
DB 034h,005h,09Ch,0F8h,0ABh,010h,086h,09Fh
DB 0F2h,080h,047h,084h,047h,09Bh,01Ah,0D1h
end;
type
PCipherRec = ^TCipherRec;
TCipherRec = packed record
case Integer of
0: (x: array[0..7] of Byte);
1: (A, b: LongWord);
end;
procedure TROCipher_Gost.Encode(Data: Pointer);
var
i, A, b, t : LongWord;
k : pintarray;
begin
k := User;
A := PCipherRec(Data).A;
b := PCipherRec(Data).b;
for i := 0 to 11 do
begin
if i and 3 = 0 then
k := User;
t := A + k[0];
b := b xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
t := b + k[1];
A := A xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
Inc(PInteger(k), 2);
end;
k := @pintarray(User)[6];
for i := 0 to 3 do
begin
t := A + k[1];
b := b xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
t := b + k[0];
A := A xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
Dec(PInteger(k), 2);
end;
PCipherRec(Data).A := b;
PCipherRec(Data).b := A;
end;
procedure TROCipher_Gost.Decode(Data: Pointer);
var
i, A, b, t : LongWord;
k : pintarray;
begin
A := PCipherRec(Data).A;
b := PCipherRec(Data).b;
k := User;
for i := 0 to 3 do
begin
t := A + k[0];
b := b xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
t := b + k[1];
A := A xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
Inc(PInteger(k), 2);
end;
for i := 0 to 11 do
begin
if i and 3 = 0 then
k := @pintarray(User)[6];
t := A + k[1];
b := b xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
t := b + k[0];
A := A xor Gost_Data[0, t and $FF] xor
Gost_Data[1, t shr 8 and $FF] xor
Gost_Data[2, t shr 16 and $FF] xor
Gost_Data[3, t shr 24];
Dec(PInteger(k), 2);
end;
PCipherRec(Data).A := b;
PCipherRec(Data).b := A;
end;
procedure TROCipher_Gost.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitBegin(Size);
Move(Key, User^, Size);
InitEnd(IVector);
end;
class procedure TROCipher_Blowfish.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 8;
AKeySize := 56;
AUserSize := SizeOf(Blowfish_Data) + SizeOf(Blowfish_Key);
end;
class function TROCipher_Blowfish.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 019h,071h,0CAh,0CDh,02Bh,09Ch,085h,029h
DB 0DAh,081h,047h,0B7h,0EBh,0CEh,016h,0C6h
DB 091h,00Eh,01Dh,0C8h,040h,012h,03Eh,035h
DB 070h,0EDh,0BCh,096h,04Ch,013h,0D0h,0B8h
end;
type
PBlowfish = ^TBlowfish;
TBlowfish = array[0..3, 0..255] of LongWord;
{$IFDEF UseASM}
{$IFNDEF 486GE} // no Support for <= CPU 386
procedure TROCipher_Blowfish.Encode386(Data: Pointer);
asm // specaly for CPU < 486
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH EDX
MOV ESI,[EAX].TROCipher_Blowfish.FUser
MOV EBX,[EDX] // A
MOV EDX,[EDX + 4] // B
XCHG BL,BH // here BSWAP EBX,EDX
XCHG DL,DH
ROL EBX,16
ROL EDX,16
XCHG BL,BH
XCHG DL,DH
XOR EBX,[ESI + 4 * 256 * 4]
XOR EDI,EDI
@@1: MOV EAX,EBX
SHR EBX,16
MOVZX ECX,BH
MOV EBP,[ESI + ECX * 4 + 1024 * 0]
MOVZX ECX,BL
ADD EBP,[ESI + ECX * 4 + 1024 * 1]
MOVZX ECX,AH
XOR EBP,[ESI + ECX * 4 + 1024 * 2]
MOVZX ECX,AL
ADD EBP,[ESI + ECX * 4 + 1024 * 3]
XOR EDX,[ESI + 4 * 256 * 4 + 4 + EDI * 4]
XOR EBP,EDX
MOV EDX,EAX
MOV EBX,EBP
INC EDI
TEST EDI,010h
JZ @@1
POP EAX
XOR EDX,[ESI + 4 * 256 * 4 + 17 * 4]
XCHG BL,BH // here BSWAP EBX,EDX
XCHG DL,DH
ROL EBX,16
ROL EDX,16
XCHG BL,BH
XCHG DL,DH
MOV [EAX],EDX
MOV [EAX + 4],EBX
POP EBP
POP EBX
POP ESI
POP EDI
end;
procedure TROCipher_Blowfish.Decode386(Data: Pointer);
asm // specaly for CPU < 486
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH EDX
MOV ESI,[EAX].TROCipher_Blowfish.FUser
MOV EBX,[EDX] // A
MOV EDX,[EDX + 4] // B
XCHG BL,BH
XCHG DL,DH
ROL EBX,16
ROL EDX,16
XCHG BL,BH
XCHG DL,DH
XOR EBX,[ESI + 4 * 256 * 4 + 17 * 4]
MOV EDI,16
@@1: MOV EAX,EBX
SHR EBX,16
MOVZX ECX,BH
MOV EBP,[ESI + ECX * 4 + 1024 * 0]
MOVZX ECX,BL
ADD EBP,[ESI + ECX * 4 + 1024 * 1]
MOVZX ECX,AH
XOR EBP,[ESI + ECX * 4 + 1024 * 2]
MOVZX ECX,AL
ADD EBP,[ESI + ECX * 4 + 1024 * 3]
XOR EDX,[ESI + 4 * 256 * 4 + EDI * 4]
XOR EBP,EDX
MOV EDX,EAX
MOV EBX,EBP
DEC EDI
JNZ @@1
POP EAX
XOR EDX,[ESI + 4 * 256 * 4]
XCHG BL,BH // BSWAP
XCHG DL,DH
ROL EBX,16
ROL EDX,16
XCHG BL,BH
XCHG DL,DH
MOV [EAX],EDX
MOV [EAX + 4],EBX
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ENDIF} //486GE
{$ENDIF}
procedure TROCipher_Blowfish.Encode(Data: Pointer);
{$IFDEF UseASM} // specialy for CPU >= 486
asm
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH EDX
MOV ESI,[EAX].TROCipher_Blowfish.FUser
MOV EBX,[EDX] // A
MOV EBP,[EDX + 4] // B
BSWAP EBX // CPU >= 486
BSWAP EBP
XOR EDI,EDI
XOR EBX,[ESI + 4 * 256 * 4]
// XOR ECX,ECX
@@1:
MOV EAX,EBX
SHR EBX,16
MOVZX ECX,BH // it's faster with AMD Chips,
// MOV CL,BH // it's faster with PII's
MOV EDX,[ESI + ECX * 4 + 1024 * 0]
MOVZX ECX,BL
// MOV CL,BL
ADD EDX,[ESI + ECX * 4 + 1024 * 1]
MOVZX ECX,AH
// MOV CL,AH
XOR EDX,[ESI + ECX * 4 + 1024 * 2]
MOVZX ECX,AL
// MOV CL,AL
ADD EDX,[ESI + ECX * 4 + 1024 * 3]
XOR EBP,[ESI + 4 * 256 * 4 + 4 + EDI * 4]
INC EDI
XOR EDX,EBP
TEST EDI,010h
MOV EBP,EAX
MOV EBX,EDX
JZ @@1
POP EAX
XOR EBP,[ESI + 4 * 256 * 4 + 17 * 4]
BSWAP EBX
BSWAP EBP
MOV [EAX],EBP
MOV [EAX + 4],EBX
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ELSE}
var
i, A, b : LongWord;
p : pintarray;
d : PBlowfish;
begin
d := User;
p := Pointer(PChar(User) + SizeOf(Blowfish_Data));
A := SwapInteger(PCipherRec(Data).A) xor p[0];
Inc(PInteger(p));
b := SwapInteger(PCipherRec(Data).b);
for i := 0 to 7 do
begin
b := b xor p[0] xor (d[0, A shr 24] +
d[1, A shr 16 and $FF] xor
d[2, A shr 8 and $FF] +
d[3, A and $FF]);
A := A xor p[1] xor (d[0, b shr 24] +
d[1, b shr 16 and $FF] xor
d[2, b shr 8 and $FF] +
d[3, b and $FF]);
Inc(PInteger(p), 2);
end;
PCipherRec(Data).A := SwapInteger(b xor p[0]);
PCipherRec(Data).b := SwapInteger(A);
end;
{$ENDIF}
procedure TROCipher_Blowfish.Decode(Data: Pointer);
{$IFDEF UseASM}
asm
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH EDX
MOV ESI,[EAX].TROCipher_Blowfish.FUser
MOV EBX,[EDX] // A
MOV EBP,[EDX + 4] // B
BSWAP EBX
BSWAP EBP
XOR EBX,[ESI + 4 * 256 * 4 + 17 * 4]
MOV EDI,16
// XOR ECX,ECX
@@1: MOV EAX,EBX
SHR EBX,16
MOVZX ECX,BH
// MOV CL,BH
MOV EDX,[ESI + ECX * 4 + 1024 * 0]
MOVZX ECX,BL
// MOV CL,BL
ADD EDX,[ESI + ECX * 4 + 1024 * 1]
MOVZX ECX,AH
// MOV CL,AH
XOR EDX,[ESI + ECX * 4 + 1024 * 2]
MOVZX ECX,AL
// MOV CL,AL
ADD EDX,[ESI + ECX * 4 + 1024 * 3]
XOR EBP,[ESI + 4 * 256 * 4 + EDI * 4]
XOR EDX,EBP
DEC EDI
MOV EBP,EAX
MOV EBX,EDX
JNZ @@1
POP EAX
XOR EBP,[ESI + 4 * 256 * 4]
BSWAP EBX
BSWAP EBP
MOV [EAX],EBP
MOV [EAX + 4],EBX
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ELSE}
var
i, A, b : LongWord;
p : pintarray;
d : PBlowfish;
begin
d := User;
p := Pointer(PChar(User) + SizeOf(Blowfish_Data) + SizeOf(Blowfish_Key) - SizeOf(Integer));
A := SwapInteger(PCipherRec(Data).A) xor p[0];
b := SwapInteger(PCipherRec(Data).b);
for i := 0 to 7 do
begin
Dec(PInteger(p), 2);
b := b xor p[1] xor (d[0, A shr 24] +
d[1, A shr 16 and $FF] xor
d[2, A shr 8 and $FF] +
d[3, A and $FF]);
A := A xor p[0] xor (d[0, b shr 24] +
d[1, b shr 16 and $FF] xor
d[2, b shr 8 and $FF] +
d[3, b and $FF]);
end;
Dec(PInteger(p));
PCipherRec(Data).A := SwapInteger(b xor p[0]);
PCipherRec(Data).b := SwapInteger(A);
end;
{$ENDIF}
procedure TROCipher_Blowfish.Init(const Key; Size: Integer; IVector: Pointer);
var
i, j : Integer;
b : array[0..7] of Byte;
k : PByteArray;
p : pintarray;
S : PBlowfish;
begin
InitBegin(Size);
k := @Key;
S := User;
p := Pointer(PChar(User) + SizeOf(Blowfish_Data));
Move(Blowfish_Data, S^, SizeOf(Blowfish_Data));
Move(Blowfish_Key, p^, SizeOf(Blowfish_Key));
j := 0;
for i := 0 to 17 do
begin
p[i] := p[i] xor (k[(j + 0) mod Size] shl 24 +
k[(j + 1) mod Size] shl 16 +
k[(j + 2) mod Size] shl 8 +
k[(j + 3) mod Size]);
j := (j + 4) mod Size;
end;
FillChar(b, SizeOf(b), 0);
for i := 0 to 8 do
begin
Encode(@b);
p[i * 2] := SwapInteger(PCipherRec(@b).A);
p[i * 2 + 1] := SwapInteger(PCipherRec(@b).b);
end;
for i := 0 to 3 do
for j := 0 to 127 do
begin
Encode(@b);
S[i, j * 2] := SwapInteger(PCipherRec(@b).A);
S[i, j * 2 + 1] := SwapInteger(PCipherRec(@b).b);
end;
FillChar(b, SizeOf(b), 0);
InitEnd(IVector);
end;
class procedure TROCipher_IDEA.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 8;
AKeySize := 16;
AUserSize := 208;
end;
class function TROCipher_IDEA.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 08Ch,065h,0CAh,0D8h,043h,0E7h,099h,093h
DB 0EDh,041h,0EAh,048h,0FDh,066h,050h,094h
DB 0A2h,025h,06Dh,0D7h,0B1h,0D0h,09Ah,023h
DB 03Dh,0D2h,0E8h,0ECh,0C9h,045h,07Fh,07Eh
end;
function IDEAMul(x, y: LongWord): LongWord; assembler; register;
asm
AND EAX,0FFFFh
JZ @@1
AND EDX,0FFFFh
JZ @@1
MUL EDX
MOV ECX,EAX
MOV EDX,EAX
SHR EDX,16
SUB EAX,EDX
CMP AX,CX
JNA @@2
INC EAX
@@2: RET
@@1: MOV ECX,1
SUB ECX,EAX
SUB ECX,EDX
MOV EAX,ECX
end;
procedure TROCipher_IDEA.RO_Cipher(Data, Key: PWordArray);
var
i : LongWord;
x, y, A, b, c, d : LongWord;
begin
i := SwapInteger(pintarray(Data)[0]);
A := LongRec(i).Hi;
b := LongRec(i).Lo;
i := SwapInteger(pintarray(Data)[1]);
c := LongRec(i).Hi;
d := LongRec(i).Lo;
for i := 0 to 7 do
begin
A := IDEAMul(A, Key[0]);
Inc(b, Key[1]);
Inc(c, Key[2]);
d := IDEAMul(d, Key[3]);
y := c xor A;
y := IDEAMul(y, Key[4]);
x := b xor d + y;
x := IDEAMul(x, Key[5]);
Inc(y, x);
A := A xor x;
d := d xor y;
y := b xor y;
b := c xor x;
c := y;
Inc(PWord(Key), 6);
end;
LongRec(i).Hi := IDEAMul(A, Key[0]);
LongRec(i).Lo := c + Key[1];
pintarray(Data)[0] := SwapInteger(i);
LongRec(i).Hi := b + Key[2];
LongRec(i).Lo := IDEAMul(d, Key[3]);
pintarray(Data)[1] := SwapInteger(i);
end;
procedure TROCipher_IDEA.Encode(Data: Pointer);
begin
RO_Cipher(Data, User);
end;
procedure TROCipher_IDEA.Decode(Data: Pointer);
begin
RO_Cipher(Data, @pintarray(User)[26]);
end;
procedure TROCipher_IDEA.Init(const Key; Size: Integer; IVector: Pointer);
function IDEAInv(x: word): word;
var
A, b, c, d : word;
begin
if x <= 1 then
begin
Result := x;
Exit;
end;
A := 1;
b := $10001 div x;
c := $10001 mod x;
while c <> 1 do
begin
d := x div c;
x := x mod c;
Inc(A, b * d);
if x = 1 then
begin
Result := A;
Exit;
end;
d := c div x;
c := c mod x;
Inc(b, A * d);
end;
Result := 1 - b;
end;
var
i : Integer;
e : PWordArray;
A, b, c : word;
k, d : PWordArray;
begin
InitBegin(Size);
e := User;
Move(Key, e^, Size);
for i := 0 to 7 do
e[i] := swap(e[i]);
for i := 0 to 39 do
e[i + 8] := e[i and not 7 + (i + 1) and 7] shl 9 or
e[i and not 7 + (i + 2) and 7] shr 7;
for i := 41 to 44 do
e[i + 7] := e[i] shl 9 or e[i + 1] shr 7;
k := e;
d := @e[100];
A := IDEAInv(k[0]);
b := 0 - k[1];
c := 0 - k[2];
d[3] := IDEAInv(k[3]);
d[2] := c;
d[1] := b;
d[0] := A;
Inc(PWord(k), 4);
for i := 1 to 8 do
begin
Dec(PWord(d), 6);
A := k[0];
d[5] := k[1];
d[4] := A;
A := IDEAInv(k[2]);
b := 0 - k[3];
c := 0 - k[4];
d[3] := IDEAInv(k[5]);
d[2] := b;
d[1] := c;
d[0] := A;
Inc(PWord(k), 6);
end;
A := d[2];
d[2] := d[1];
d[1] := A;
InitEnd(IVector);
end;
type
PSAFERRec = ^TSAFERRec;
TSAFERRec = packed record
case Integer of
0: (A, b, c, d, e, f, G, H: Byte);
1: (x, y: Integer);
end;
procedure TROCipher_SAFER.SetRounds(Value: Integer);
begin
if (Value < 4) or (Value > 13) then
case FSAFERMode of {Default Rounds}
smK40, smSK40: Value := 5;
smK64, smSK64: Value := 6;
smK128, smSK128: Value := 10;
else
Value := 8;
end;
FRounds := Value;
end;
class procedure TROCipher_SAFER.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 8;
AKeySize := 16;
AUserSize := 768;
end;
class function TROCipher_SAFER.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 000h,03Dh,049h,020h,073h,063h,085h,0AAh
DB 0D9h,0C2h,00Ah,0DEh,07Eh,09Eh,0E9h,0ABh
DB 024h,0D0h,074h,034h,047h,07Eh,021h,01Dh
DB 055h,0F9h,035h,028h,098h,084h,0A8h,075h
end;
procedure TROCipher_SAFER.Encode(Data: Pointer);
var
EXP, Log, Key : PByteArray;
i : Integer;
t : Byte;
begin
EXP := User;
Log := Pointer(PChar(User) + 256);
Key := Pointer(PChar(User) + 512);
with PSAFERRec(Data)^ do
begin
for i := 1 to FRounds do
begin
A := A xor Key[0];
b := b + Key[1];
c := c + Key[2];
d := d xor Key[3];
e := e xor Key[4];
f := f + Key[5];
G := G + Key[6];
H := H xor Key[7];
A := EXP[A] + Key[8];
b := Log[b] xor Key[9];
c := Log[c] xor Key[10];
d := EXP[d] + Key[11];
e := EXP[e] + Key[12];
f := Log[f] xor Key[13];
G := Log[G] xor Key[14];
H := EXP[H] + Key[15];
Inc(b, A);
Inc(A, b);
Inc(d, c);
Inc(c, d);
Inc(f, e);
Inc(e, f);
Inc(H, G);
Inc(G, H);
Inc(c, A);
Inc(A, c);
Inc(G, e);
Inc(e, G);
Inc(d, b);
Inc(b, d);
Inc(H, f);
Inc(f, H);
Inc(e, A);
Inc(A, e);
Inc(f, b);
Inc(b, f);
Inc(G, c);
Inc(c, G);
Inc(H, d);
Inc(d, H);
t := b;
b := e;
e := c;
c := t;
t := d;
d := f;
f := G;
G := t;
Inc(PByte(Key), 16);
end;
A := A xor Key[0];
b := b + Key[1];
c := c + Key[2];
d := d xor Key[3];
e := e xor Key[4];
f := f + Key[5];
G := G + Key[6];
H := H xor Key[7];
end;
end;
procedure TROCipher_SAFER.Decode(Data: Pointer);
var
EXP, Log, Key : PByteArray;
i : Integer;
t : Byte;
begin
EXP := User;
Log := Pointer(PChar(User) + 256);
Key := Pointer(PChar(User) + 504 + 8 * (FRounds * 2 + 1));
with PSAFERRec(Data)^ do
begin
H := H xor Key[7];
G := G - Key[6];
f := f - Key[5];
e := e xor Key[4];
d := d xor Key[3];
c := c - Key[2];
b := b - Key[1];
A := A xor Key[0];
for i := 1 to FRounds do
begin
Dec(PByte(Key), 16);
t := e;
e := b;
b := c;
c := t;
t := f;
f := d;
d := G;
G := t;
Dec(A, e);
Dec(e, A);
Dec(b, f);
Dec(f, b);
Dec(c, G);
Dec(G, c);
Dec(d, H);
Dec(H, d);
Dec(A, c);
Dec(c, A);
Dec(e, G);
Dec(G, e);
Dec(b, d);
Dec(d, b);
Dec(f, H);
Dec(H, f);
Dec(A, b);
Dec(b, A);
Dec(c, d);
Dec(d, c);
Dec(e, f);
Dec(f, e);
Dec(G, H);
Dec(H, G);
H := H - Key[15];
G := G xor Key[14];
f := f xor Key[13];
e := e - Key[12];
d := d - Key[11];
c := c xor Key[10];
b := b xor Key[9];
A := A - Key[8];
H := Log[H] xor Key[7];
G := EXP[G] - Key[6];
f := EXP[f] - Key[5];
e := Log[e] xor Key[4];
d := Log[d] xor Key[3];
c := EXP[c] - Key[2];
b := EXP[b] - Key[1];
A := Log[A] xor Key[0];
end;
end;
end;
procedure TROCipher_SAFER.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smStrong);
end;
procedure TROCipher_SAFER.InitNew(const Key; Size: Integer; IVector: Pointer; SAFERMode: TSAFERMode);
procedure InitTab;
var
i, e : Integer;
EXP : PByte;
Log : PByteArray;
begin
EXP := User;
Log := Pointer(PChar(User) + 256);
e := 1;
for i := 0 to 255 do
begin
EXP^ := e and $FF;
Log[e and $FF] := i;
e := (e * 45) mod 257;
Inc(EXP);
end;
end;
procedure InitKey;
function ROR3(Value: Byte): Byte; assembler;
asm
ROR AL,3
end;
function ROL6(Value: Byte): Byte; assembler;
asm
ROL AL,6
end;
var
d : PByte;
EXP : PByteArray;
Strong : Boolean;
k : array[Boolean, 0..8] of Byte;
i, j : Integer;
begin
Strong := FSAFERMode in [smStrong, smSK40, smSK64, smSK128];
EXP := User;
d := User;
Inc(d, 512);
FillChar(k, SizeOf(k), 0);
{Setup Key A}
i := Size;
if i > 8 then
i := 8;
Move(Key, k[False], i);
{Setup the Key for K-40, SK-40}
if FSAFERMode in [smK40, smSK40] then
begin
k[False, 5] := k[False, 0] xor k[False, 2] xor 129;
k[False, 6] := k[False, 0] xor k[False, 3] xor k[False, 4] xor 66;
k[False, 7] := k[False, 1] xor k[False, 2] xor k[False, 4] xor 36;
k[False, 8] := k[False, 1] xor k[False, 3] xor 24;
Move(k[False], k[True], SizeOf(k[False]));
end
else
begin
if Size > 8 then
begin
i := Size - 8;
if i > 8 then
i := 8;
Move(TByteArray(Key)[8], k[True], i);
end
else
Move(k[False], k[True], 9);
for i := 0 to 7 do
begin
k[False, 8] := k[False, 8] xor k[False, i];
k[True, 8] := k[True, 8] xor k[True, i];
end;
end;
{Setup the KeyData}
Move(k[True], d^, 8);
Inc(d, 8);
for i := 0 to 8 do
k[False, i] := ROR3(k[False, i]);
for i := 1 to FRounds do
begin
for j := 0 to 8 do
begin
k[False, j] := ROL6(k[False, j]);
k[True, j] := ROL6(k[True, j]);
end;
for j := 0 to 7 do
begin
if Strong then
d^ := k[False, (j + i * 2 - 1) mod 9] + EXP[EXP[18 * i + j + 1]]
else
d^ := k[False, j] + EXP[EXP[18 * i + j + 1]];
Inc(d);
end;
for j := 0 to 7 do
begin
if Strong then
d^ := k[True, (j + i * 2) mod 9] + EXP[EXP[18 * i + j + 10]]
else
d^ := k[True, j] + EXP[EXP[18 * i + j + 10]];
Inc(d);
end;
end;
FillChar(k, SizeOf(k), 0);
end;
begin
InitBegin(Size);
FSAFERMode := SAFERMode;
if SAFERMode = smDefault then
if Size <= 5 then
FSAFERMode := smK40
else
if Size <= 8 then
FSAFERMode := smK64
else
FSAFERMode := smK128
else
if SAFERMode = smStrong then
if Size <= 5 then
FSAFERMode := smSK40
else
if Size <= 8 then
FSAFERMode := smSK64
else
FSAFERMode := smSK128;
SetRounds(FRounds);
InitTab;
InitKey;
InitEnd(IVector);
end;
class procedure TROCipher_SAFER_K40.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
inherited GetContext(ABufSize, AKeySize, AUserSize);
AKeySize := 5;
end;
class function TROCipher_SAFER_K40.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 005h,0B4h,019h,057h,026h,05Ch,013h,060h
DB 0A0h,082h,094h,045h,0D6h,0A5h,046h,0D8h
DB 073h,050h,096h,080h,04Fh,06Dh,0F7h,0E5h
DB 0C8h,01Ah,0EFh,044h,04Ch,0B4h,059h,013h
end;
procedure TROCipher_SAFER_K40.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smK40);
end;
class function TROCipher_SAFER_SK40.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0D9h,003h,003h,06Dh,018h,038h,0D1h,0C1h
DB 089h,0E8h,038h,012h,07Fh,028h,0FCh,0C7h
DB 0C5h,00Bh,0B7h,0C4h,0DBh,021h,0A4h,031h
DB 020h,008h,08Ah,077h,0F7h,0DFh,026h,0FFh
end;
procedure TROCipher_SAFER_SK40.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smSK40);
end;
class procedure TROCipher_SAFER_K64.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
inherited GetContext(ABufSize, AKeySize, AUserSize);
AKeySize := 8;
end;
class function TROCipher_SAFER_K64.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 08Ch,0B2h,032h,0F0h,00Eh,0C2h,0DAh,0CBh
DB 039h,008h,02Dh,05Ch,093h,0FFh,0CEh,0F3h
DB 08Fh,01Fh,0B7h,02Ch,0C5h,0C7h,0A7h,0E9h
DB 089h,0BEh,061h,08Bh,000h,0E6h,09Fh,00Eh
end;
procedure TROCipher_SAFER_K64.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smK64);
end;
class function TROCipher_SAFER_SK64.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0DDh,09Ch,01Ah,0D6h,029h,00Ch,0EEh,04Fh
DB 0E5h,04Bh,0C0h,055h,0BFh,022h,00Eh,0BCh
DB 019h,041h,078h,0CFh,094h,0DBh,02Fh,039h
DB 06Bh,01Eh,0A7h,0CAh,04Bh,05Fh,077h,0E0h
end;
procedure TROCipher_SAFER_SK64.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smSK64);
end;
class procedure TROCipher_SAFER_K128.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
inherited GetContext(ABufSize, AKeySize, AUserSize);
AKeySize := 16;
end;
class function TROCipher_SAFER_K128.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 00Ch,0A9h,070h,0B9h,0F3h,014h,087h,0D9h
DB 09Eh,05Eh,078h,031h,074h,0DFh,0A8h,0BBh
DB 03Dh,040h,0A5h,0D9h,08Ch,07Ch,004h,0B7h
DB 09Ch,001h,0DAh,063h,0ABh,026h,035h,0BCh
end;
procedure TROCipher_SAFER_K128.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smK128);
end;
class function TROCipher_SAFER_SK128.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0C8h,0A6h,070h,033h,029h,038h,038h,02Bh
DB 069h,0ACh,061h,072h,08Fh,0DCh,09Fh,0A4h
DB 09Eh,06Fh,0C4h,053h,0D8h,089h,0FFh,042h
DB 072h,009h,07Dh,0CDh,0D0h,0EAh,07Eh,028h
end;
procedure TROCipher_SAFER_SK128.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitNew(Key, Size, IVector, smSK128);
end;
type
PTEARec = ^TTEARec;
TTEARec = packed record
A, b, c, d: LongWord;
end;
const
TEA_Delta = $9E3779B9;
procedure TROCipher_TEA.SetRounds(Value: Integer);
begin
FRounds := Value;
if FRounds < 16 then
FRounds := 16
else
if FRounds > 32 then
FRounds := 32;
end;
class procedure TROCipher_TEA.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 8;
AKeySize := 16;
AUserSize := 32;
end;
class function TROCipher_TEA.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0B7h,0B8h,0AAh,0BBh,026h,04Bh,006h,0F9h
DB 070h,086h,0B0h,0E4h,056h,004h,029h,0CCh
DB 0BFh,055h,0EAh,04Eh,0EFh,059h,026h,018h
DB 019h,0B0h,003h,07Ch,029h,08Ch,0E2h,077h
end;
procedure TROCipher_TEA.Encode(Data: Pointer);
{$IFDEF UseASM}
asm
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH EDX
MOV EBX,[EDX] // X
MOV EDX,[EDX + 4] // Y
XOR EDI,EDI // Sum
MOV ESI,[EAX].TROCipher_TEA.FUser // User
MOV ECX,[EAX].TROCipher_TEA.FRounds // Rounds
@@1: ADD EDI,TEA_Delta
MOV EAX,EDX
MOV EBP,EDX
SHL EAX,4
SHR EBP,5
ADD EAX,[ESI]
ADD EBP,[ESI + 4]
XOR EAX,EDX
ADD EAX,EDI
XOR EAX,EBP
ADD EAX,EBX
MOV EBX,EAX
SHL EAX,4
MOV EBP,EBX
SHR EBP,5
ADD EAX,[ESI + 8]
XOR EAX,EBX
ADD EBP,[ESI + 12]
ADD EAX,EDI
XOR EAX,EBP
ADD EDX,EAX
DEC ECX
JNZ @@1
POP EAX
MOV [EAX],EBX
MOV [EAX + 4],EDX
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ELSE}
var
i, sum, x, y : LongWord;
begin
sum := 0;
x := PTEARec(Data).A;
y := PTEARec(Data).b;
with PTEARec(User)^ do
for i := 1 to FRounds do
begin
Inc(sum, TEA_Delta);
Inc(x, (y shl 4 + A) xor y + sum xor (y shr 5 + b));
Inc(y, (x shl 4 + c) xor x + sum xor (x shr 5 + d));
end;
PTEARec(Data).A := x;
PTEARec(Data).b := y;
end;
{$ENDIF}
procedure TROCipher_TEA.Decode(Data: Pointer);
{$IFDEF UseASM}
asm
PUSH EDI
PUSH ESI
PUSH EBX
PUSH EBP
PUSH EDX
MOV EBX,[EDX] // X
MOV EDX,[EDX + 4] // Y
MOV ESI,[EAX].TROCipher_TEA.FUser // User
MOV EDI,TEA_Delta
MOV ECX,[EAX].TROCipher_TEA.FRounds // Rounds
IMUL EDI,ECX
@@1: MOV EAX,EBX
MOV EBP,EBX
SHL EAX,4
SHR EBP,5
ADD EAX,[ESI + 8]
ADD EBP,[ESI + 12]
XOR EAX,EBX
ADD EAX,EDI
XOR EAX,EBP
SUB EDX,EAX
MOV EAX,EDX
SHL EAX,4
MOV EBP,EDX
SHR EBP,5
ADD EAX,[ESI]
XOR EAX,EDX
ADD EBP,[ESI + 4]
ADD EAX,EDI
XOR EAX,EBP
SUB EDI,TEA_Delta
SUB EBX,EAX
DEC ECX
JNZ @@1
POP EAX
MOV [EAX],EBX
MOV [EAX + 4],EDX
POP EBP
POP EBX
POP ESI
POP EDI
end;
{$ELSE}
var
i, sum, x, y : LongWord;
begin
sum := TEA_Delta * LongWord(FRounds);
x := PTEARec(Data).A;
y := PTEARec(Data).b;
with PTEARec(User)^ do
for i := 1 to FRounds do
begin
Dec(y, (x shl 4 + c) xor x + sum xor (x shr 5 + d));
Dec(x, (y shl 4 + A) xor y + sum xor (y shr 5 + b));
Dec(sum, TEA_Delta);
end;
PTEARec(Data).A := x;
PTEARec(Data).b := y;
end;
{$ENDIF}
procedure TROCipher_TEA.Init(const Key; Size: Integer; IVector: Pointer);
begin
InitBegin(Size);
Move(Key, User^, Size);
SetRounds(FRounds);
InitEnd(IVector);
end;
class function TROCipher_TEAN.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0CDh,07Eh,0BBh,0A2h,092h,01Ah,04Bh,03Bh
DB 0E2h,09Eh,062h,0CFh,0F7h,01Dh,0A5h,0DFh
DB 063h,033h,094h,029h,0E2h,036h,07Ch,066h
DB 03Fh,0F8h,01Ah,0F9h,002h,078h,0BFh,0A1h
end;
procedure TROCipher_TEAN.Encode(Data: Pointer);
var
i, sum, x, y : LongWord;
k : pintarray;
begin
sum := 0;
x := PTEARec(Data).A;
y := PTEARec(Data).b;
k := User;
for i := 1 to FRounds do
begin
Inc(x, (y shl 4 xor y shr 5) + (y xor sum) + k[sum and 3]);
Inc(sum, TEA_Delta);
Inc(y, (x shl 4 xor x shr 5) + (x xor sum) + k[sum shr 11 and 3]);
end;
PTEARec(Data).A := x;
PTEARec(Data).b := y;
end;
procedure TROCipher_TEAN.Decode(Data: Pointer);
var
i, sum, x, y : LongWord;
k : pintarray;
begin
sum := TEA_Delta * LongWord(FRounds);
x := PTEARec(Data).A;
y := PTEARec(Data).b;
k := User;
with PTEARec(User)^ do
for i := 1 to FRounds do
begin
Dec(y, (x shl 4 xor x shr 5) + (x xor sum) + k[sum shr 11 and 3]);
Dec(sum, TEA_Delta);
Dec(x, (y shl 4 xor y shr 5) + (y xor sum) + k[sum and 3]);
end;
PTEARec(Data).A := x;
PTEARec(Data).b := y;
end;
const
SCOP_SIZE = 32; {is the Maximum}
class procedure TROCipher_SCOP.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := SCOP_SIZE * SizeOf(Integer);
AKeySize := 48;
AUserSize := (384 * 4 + 4 * SizeOf(Integer)) * 2;
end;
class function TROCipher_SCOP.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 014h,0C0h,009h,0E8h,073h,0B6h,053h,092h
DB 08Bh,013h,069h,0A9h,0F2h,099h,0FEh,05Eh
DB 0EEh,03Bh,0FDh,0C1h,050h,059h,00Eh,094h
DB 062h,017h,008h,01Eh,0A4h,01Ah,04Dh,08Fh
end;
procedure TROCipher_SCOP.Encode(Data: Pointer);
var
i, j, w : Byte;
t, t1, T2, T3 : Integer;
p : pintarray;
b : PInteger;
begin
p := User;
i := p[0];
j := p[1];
T3 := p[3];
p := @p[4 + 128];
b := Data;
for w := 1 to SCOP_SIZE do
begin
t1 := p[j];
Inc(j, T3);
t := p[i - 128];
T2 := p[j];
Inc(i);
T3 := T2 + t;
p[j] := T3;
Inc(j, T2);
Inc(b^, t1 + T2);
Inc(b);
end;
end;
procedure TROCipher_SCOP.Decode(Data: Pointer);
var
i, j, w : Byte;
t, t1, T2, T3 : Integer;
p : pintarray;
b : PInteger;
begin
p := User;
i := p[0];
j := p[1];
T3 := p[3];
p := @p[4 + 128];
b := Data;
for w := 1 to SCOP_SIZE do
begin
t1 := p[j];
Inc(j, T3);
t := p[i - 128];
T2 := p[j];
Inc(i);
T3 := T2 + t;
p[j] := T3;
Inc(j, T2);
Dec(b^, t1 + T2);
Inc(b);
end;
end;
procedure TROCipher_SCOP.Init(const Key; Size: Integer; IVector: Pointer);
var
Init_State : packed record
Coef: array[0..7, 0..3] of Byte;
x: array[0..3] of LongWord;
end;
procedure ExpandKey;
var
p : PByteArray;
i, c : Integer;
begin
c := 1;
p := @Init_State;
Move(Key, p^, Size);
for i := Size to 47 do
p[i] := p[i - Size] + p[i - Size + 1];
for i := 0 to 31 do
if p[i] = 0 then
begin
p[i] := c;
Inc(c);
end;
end;
procedure GP8(Data: pintarray);
var
i, i2 : Integer;
NewX : array[0..3] of LongWord;
x1, x2, X3, X4 : LongWord;
y1, y2 : LongWord;
begin
i := 0;
while i < 8 do
begin
i2 := i shr 1;
x1 := Init_State.x[i2] shr 16;
x2 := x1 * x1;
X3 := x2 * x1;
X4 := X3 * x1;
y1 := Init_State.Coef[i][0] * X4 +
Init_State.Coef[i][1] * X3 +
Init_State.Coef[i][2] * x2 +
Init_State.Coef[i][3] * x1 + 1;
x1 := Init_State.x[i2] and $FFFF;
x2 := x1 * x1;
X3 := x2 * x1;
X4 := X3 * x1;
y2 := Init_State.Coef[i + 1][0] * X4 +
Init_State.Coef[i + 2][1] * X3 +
Init_State.Coef[i + 3][2] * x2 +
Init_State.Coef[i + 4][3] * x1 + 1;
Data[i2] := y1 shl 16 or y2 and $FFFF;
NewX[i2] := y1 and $FFFF0000 or y2 shr 16;
Inc(i, 2);
end;
Init_State.x[0] := NewX[0] shr 16 or NewX[3] shl 16;
Init_State.x[1] := NewX[0] shl 16 or NewX[1] shr 16;
Init_State.x[2] := NewX[1] shl 16 or NewX[2] shr 16;
Init_State.x[3] := NewX[2] shl 16 or NewX[3] shr 16;
end;
var
i, j : Integer;
t : array[0..3] of Integer;
p : pintarray;
begin
InitBegin(Size);
FillChar(Init_State, SizeOf(Init_State), 0);
FillChar(t, SizeOf(t), 0);
p := Pointer(PChar(User) + 12);
ExpandKey;
for i := 0 to 7 do
GP8(@t);
for i := 0 to 11 do
begin
for j := 0 to 7 do
GP8(@p[i * 32 + j * 4]);
GP8(@t);
end;
GP8(@t);
i := t[3] and $7F;
p[i] := p[i] or 1;
p := User;
p[0] := t[3] shr 24;
p[1] := t[3] shr 16;
p[2] := t[3] shr 8;
FillChar(Init_State, SizeOf(Init_State), 0);
InitEnd(IVector);
p := Pointer(PChar(User) + FUserSize shr 1);
Move(User^, p^, FUserSize shr 1);
end;
procedure TROCipher_SCOP.Done;
begin
inherited Done;
Move(PByteArray(User)[FUserSize shr 1], User^, FUserSize shr 1);
end;
class procedure TROCipher_Q128.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 16;
AKeySize := 16;
AUserSize := 256;
end;
class function TROCipher_Q128.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 099h,0AAh,0D0h,03Dh,0CAh,014h,04Eh,02Ah
DB 0F8h,01Eh,001h,0A0h,0EAh,0ABh,09Fh,048h
DB 023h,02Dh,059h,054h,054h,07Eh,02Bh,012h
DB 086h,080h,0E8h,033h,0EBh,0E1h,05Eh,0AEh
end;
procedure TROCipher_Q128.Encode(Data: Pointer);
{$IFDEF UseASM}
asm
PUSH ESI
PUSH EDI
PUSH EBX
PUSH EBP
PUSH EDX
MOV EDI,[EAX].TROCipher_Q128.FUser
MOV EAX,[EDX] // B0
MOV EBX,[EDX + 4] // B1
MOV ECX,[EDX + 8] // B2
MOV EDX,[EDX + 12] // B3
MOV EBP,16
@@1: MOV ESI,EAX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ROL ESI,10
ADD EAX,[EDI]
XOR EAX,EBX
MOV EBX,EAX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ROL EBX,10
ADD EAX,[EDI + 4]
XOR EAX,ECX
MOV ECX,EAX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ROL ECX,10
ADD EAX,[EDI + 8]
XOR EAX,EDX
MOV EDX,EAX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ROL EDX,10
ADD EAX,[EDI + 12]
XOR EAX,ESI
ADD EDI,16
DEC EBP
JNZ @@1
POP ESI
MOV [ESI],EAX // B0
MOV [ESI + 4],EBX // B1
MOV [ESI + 8],ECX // B2
MOV [ESI + 12],EDX // B3
POP EBP
POP EBX
POP EDI
POP ESI
end;
{$ELSE}
var
d : PInteger;
B0, B1, B2, B3, i : LongWord;
begin
d := User;
B0 := pintarray(Data)[0];
B1 := pintarray(Data)[1];
B2 := pintarray(Data)[2];
B3 := pintarray(Data)[3];
for i := 1 to 16 do
begin
B1 := B1 xor (Q128_Data[B0 and $03FF] + d^);
Inc(d);
B0 := B0 shl 10 or B0 shr 22;
B2 := B2 xor (Q128_Data[B1 and $03FF] + d^);
Inc(d);
B1 := B1 shl 10 or B1 shr 22;
B3 := B3 xor (Q128_Data[B2 and $03FF] + d^);
Inc(d);
B2 := B2 shl 10 or B2 shr 22;
B0 := B0 xor (Q128_Data[B3 and $03FF] + d^);
Inc(d);
B3 := B3 shl 10 or B3 shr 22;
end;
pintarray(Data)[0] := B0;
pintarray(Data)[1] := B1;
pintarray(Data)[2] := B2;
pintarray(Data)[3] := B3;
end;
{$ENDIF}
procedure TROCipher_Q128.Decode(Data: Pointer);
{$IFDEF UseASM}
asm
PUSH ESI
PUSH EDI
PUSH EBX
PUSH EBP
PUSH EDX
MOV EDI,[EAX].TROCipher_Q128.FUser
LEA EDI,[EDI + 64 * 4]
MOV ESI,[EDX] // B0
MOV EBX,[EDX + 4] // B1
MOV ECX,[EDX + 8] // B2
MOV EDX,[EDX + 12] // B3
MOV EBP,16
@@1: SUB EDI,16
ROR EDX,10
MOV EAX,EDX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 12]
XOR ESI,EAX
ROR ECX,10
MOV EAX,ECX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 8]
XOR EDX,EAX
ROR EBX,10
MOV EAX,EBX
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI + 4]
XOR ECX,EAX
ROR ESI,10
MOV EAX,ESI
AND EAX,03FFh
MOV EAX,[EAX * 4 + OFFSET Q128_DATA]
ADD EAX,[EDI]
XOR EBX,EAX
DEC EBP
JNZ @@1
POP EAX
MOV [EAX],ESI // B0
MOV [EAX + 4],EBX // B1
MOV [EAX + 8],ECX // B2
MOV [EAX + 12],EDX // B3
POP EBP
POP EBX
POP EDI
POP ESI
end;
{$ELSE}
var
d : PInteger;
B0, B1, B2, B3, i : LongWord;
begin
d := @pintarray(User)[63];
B0 := pintarray(Data)[0];
B1 := pintarray(Data)[1];
B2 := pintarray(Data)[2];
B3 := pintarray(Data)[3];
for i := 1 to 16 do
begin
B3 := B3 shr 10 or B3 shl 22;
B0 := B0 xor (Q128_Data[B3 and $03FF] + d^);
Dec(d);
B2 := B2 shr 10 or B2 shl 22;
B3 := B3 xor (Q128_Data[B2 and $03FF] + d^);
Dec(d);
B1 := B1 shr 10 or B1 shl 22;
B2 := B2 xor (Q128_Data[B1 and $03FF] + d^);
Dec(d);
B0 := B0 shr 10 or B0 shl 22;
B1 := B1 xor (Q128_Data[B0 and $03FF] + d^);
Dec(d);
end;
pintarray(Data)[0] := B0;
pintarray(Data)[1] := B1;
pintarray(Data)[2] := B2;
pintarray(Data)[3] := B3;
end;
{$ENDIF}
procedure TROCipher_Q128.Init(const Key; Size: Integer; IVector: Pointer);
var
k : array[0..3] of LongWord;
i : Integer;
d : PInteger;
begin
InitBegin(Size);
FillChar(k, SizeOf(k), 0);
Move(Key, k, Size);
d := User;
for i := 19 downto 1 do
begin
k[1] := k[1] xor Q128_Data[k[0] and $03FF];
k[0] := k[0] shr 10 or k[0] shl 22;
k[2] := k[2] xor Q128_Data[k[1] and $03FF];
k[1] := k[1] shr 10 or k[1] shl 22;
k[3] := k[3] xor Q128_Data[k[2] and $03FF];
k[2] := k[2] shr 10 or k[2] shl 22;
k[0] := k[0] xor Q128_Data[k[3] and $03FF];
k[3] := k[3] shr 10 or k[3] shl 22;
if i <= 16 then
begin
d^ := k[0];
Inc(d);
d^ := k[1];
Inc(d);
d^ := k[2];
Inc(d);
d^ := k[3];
Inc(d);
end;
end;
FillChar(k, SizeOf(k), 0);
InitEnd(IVector);
end;
type
P3Way_Key = ^T3Way_Key;
T3Way_Key = packed record
E_Key: array[0..2] of Integer;
E_Data: array[0..11] of Integer;
D_Key: array[0..2] of Integer;
D_Data: array[0..11] of Integer;
end;
class procedure TROCipher_3Way.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 12;
AKeySize := 12;
AUserSize := SizeOf(T3Way_Key);
end;
class function TROCipher_3Way.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 077h,0FCh,077h,094h,07Ch,08Fh,0DEh,021h
DB 0E9h,081h,0DFh,02Ah,0B1h,0BCh,07Eh,0F8h
DB 0A3h,0B6h,044h,04Bh,0B6h,0FCh,079h,0C4h
DB 09Bh,068h,04Fh,009h,0C7h,0BFh,00Eh,005h
end;
procedure TROCipher_3Way.Encode(Data: Pointer);
var
i : Integer;
A0, A1, A2 : LongWord;
B0, B1, B2 : LongWord;
K0, k1, K2 : LongWord;
e : PLongWord;
begin
with P3Way_Key(User)^ do
begin
K0 := E_Key[0];
k1 := E_Key[1];
K2 := E_Key[2];
e := @E_Data;
end;
A0 := pintarray(Data)[0];
A1 := pintarray(Data)[1];
A2 := pintarray(Data)[2];
for i := 0 to 10 do
begin
A0 := A0 xor K0 xor e^ shl 16;
A1 := A1 xor k1;
A2 := A2 xor K2 xor e^;
Inc(e);
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
asm
ROR B0,10
ROL B2,1
end;
A0 := B0 xor (B1 or not B2);
A1 := B1 xor (B2 or not B0);
A2 := B2 xor (B0 or not B1);
asm
ROL A0,1
ROR A2,10
end;
end;
A0 := A0 xor K0 xor e^ shl 16;
A1 := A1 xor k1;
A2 := A2 xor K2 xor e^;
pintarray(Data)[0] := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
pintarray(Data)[1] := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
pintarray(Data)[2] := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
end;
procedure TROCipher_3Way.Decode(Data: Pointer);
var
i : Integer;
A0, A1, A2 : LongWord;
B0, B1, B2 : LongWord;
K0, k1, K2 : LongWord;
e : PLongWord;
begin
with P3Way_Key(User)^ do
begin
K0 := D_Key[0];
k1 := D_Key[1];
K2 := D_Key[2];
e := @D_Data;
end;
A0 := SwapBits(pintarray(Data)[2]);
A1 := SwapBits(pintarray(Data)[1]);
A2 := SwapBits(pintarray(Data)[0]);
for i := 0 to 10 do
begin
A0 := A0 xor K0 xor e^ shl 16;
A1 := A1 xor k1;
A2 := A2 xor K2 xor e^;
Inc(e);
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
asm
ROR B0,10
ROL B2,1
end;
A0 := B0 xor (B1 or not B2);
A1 := B1 xor (B2 or not B0);
A2 := B2 xor (B0 or not B1);
asm
ROL A0,1
ROR A2,10
end;
end;
A0 := A0 xor K0 xor e^ shl 16;
A1 := A1 xor k1;
A2 := A2 xor K2 xor e^;
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
pintarray(Data)[2] := SwapBits(B0);
pintarray(Data)[1] := SwapBits(B1);
pintarray(Data)[0] := SwapBits(B2);
end;
procedure TROCipher_3Way.Init(const Key; Size: Integer; IVector: Pointer);
procedure RANDGenerate(start: Integer; var p: array of Integer);
var
i : Integer;
begin
for i := 0 to 11 do
begin
p[i] := start;
start := start shl 1;
if start and $10000 <> 0 then
start := start xor $11011;
end;
end;
var
A0, A1, A2 : Integer;
B0, B1, B2 : Integer;
begin
InitBegin(Size);
with P3Way_Key(User)^ do
begin
Move(Key, E_Key, Size);
Move(Key, D_Key, Size);
RANDGenerate($0B0B, E_Data);
RANDGenerate($B1B1, D_Data);
A0 := D_Key[0];
A1 := D_Key[1];
A2 := D_Key[2];
B0 := A0 xor A0 shr 16 xor A1 shl 16 xor A1 shr 16 xor A2 shl 16 xor
A1 shr 24 xor A2 shl 8 xor A2 shr 8 xor A0 shl 24 xor
A2 shr 16 xor A0 shl 16 xor A2 shr 24 xor A0 shl 8;
B1 := A1 xor A1 shr 16 xor A2 shl 16 xor A2 shr 16 xor A0 shl 16 xor
A2 shr 24 xor A0 shl 8 xor A0 shr 8 xor A1 shl 24 xor
A0 shr 16 xor A1 shl 16 xor A0 shr 24 xor A1 shl 8;
B2 := A2 xor A2 shr 16 xor A0 shl 16 xor A0 shr 16 xor A1 shl 16 xor
A0 shr 24 xor A1 shl 8 xor A1 shr 8 xor A2 shl 24 xor
A1 shr 16 xor A2 shl 16 xor A1 shr 24 xor A2 shl 8;
D_Key[2] := SwapBits(B0);
D_Key[1] := SwapBits(B1);
D_Key[0] := SwapBits(B2);
end;
InitEnd(IVector);
end;
class procedure TROCipher_Twofish.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 16;
AKeySize := 32;
AUserSize := 4256;
end;
class function TROCipher_Twofish.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0A5h,053h,057h,003h,0EFh,033h,048h,079h
DB 09Fh,022h,0B4h,054h,097h,005h,084h,019h
DB 087h,0BDh,083h,01Ch,04Dh,0AEh,012h,013h
DB 060h,07Ch,07Ch,0D1h,098h,045h,002h,019h
end;
type
PTwofishBox = ^TTwofishBox;
TTwofishBox = array[0..3, 0..255] of LongWord;
TLongRec = record
case Integer of
0: (L: LongWord);
1: (A, b, c, d: Byte);
end;
procedure TROCipher_Twofish.Encode(Data: Pointer);
var
S : pintarray;
Box : PTwofishBox;
i, x, y : LongWord;
A, b, c, d : TLongRec;
begin
S := User;
A.L := pintarray(Data)[0] xor S[0];
b.L := pintarray(Data)[1] xor S[1];
c.L := pintarray(Data)[2] xor S[2];
d.L := pintarray(Data)[3] xor S[3];
S := @pintarray(User)[8];
Box := @pintarray(User)[40];
for i := 0 to 7 do
begin
x := Box[0, A.A] xor Box[1, A.b] xor Box[2, A.c] xor Box[3, A.d];
y := Box[1, b.A] xor Box[2, b.b] xor Box[3, b.c] xor Box[0, b.d];
asm ROL D.L,1
end;
c.L := c.L xor (x + y + S[0]);
d.L := d.L xor (x + y shl 1 + S[1]);
asm ROR C.L,1
end;
x := Box[0, c.A] xor Box[1, c.b] xor Box[2, c.c] xor Box[3, c.d];
y := Box[1, d.A] xor Box[2, d.b] xor Box[3, d.c] xor Box[0, d.d];
asm ROL B.L,1
end;
A.L := A.L xor (x + y + S[2]);
b.L := b.L xor (x + y shl 1 + S[3]);
asm ROR A.L,1
end;
Inc(PInteger(S), 4);
end;
S := User;
pintarray(Data)[0] := c.L xor S[4];
pintarray(Data)[1] := d.L xor S[5];
pintarray(Data)[2] := A.L xor S[6];
pintarray(Data)[3] := b.L xor S[7];
end;
procedure TROCipher_Twofish.Decode(Data: Pointer);
var
S : pintarray;
Box : PTwofishBox;
i, x, y : LongWord;
A, b, c, d : TLongRec;
begin
S := User;
Box := @pintarray(User)[40];
c.L := pintarray(Data)[0] xor S[4];
d.L := pintarray(Data)[1] xor S[5];
A.L := pintarray(Data)[2] xor S[6];
b.L := pintarray(Data)[3] xor S[7];
S := @pintarray(User)[36];
for i := 0 to 7 do
begin
x := Box[0, c.A] xor Box[1, c.b] xor Box[2, c.c] xor Box[3, c.d];
y := Box[0, d.d] xor Box[1, d.A] xor Box[2, d.b] xor Box[3, d.c];
asm ROL A.L,1
end;
b.L := b.L xor (x + y shl 1 + S[3]);
A.L := A.L xor (x + y + S[2]);
asm ROR B.L,1
end;
x := Box[0, A.A] xor Box[1, A.b] xor Box[2, A.c] xor Box[3, A.d];
y := Box[0, b.d] xor Box[1, b.A] xor Box[2, b.b] xor Box[3, b.c];
asm ROL C.L,1
end;
d.L := d.L xor (x + y shl 1 + S[1]);
c.L := c.L xor (x + y + S[0]);
asm ROR D.L,1
end;
Dec(PByte(S), 16);
end;
S := User;
pintarray(Data)[0] := A.L xor S[0];
pintarray(Data)[1] := b.L xor S[1];
pintarray(Data)[2] := c.L xor S[2];
pintarray(Data)[3] := d.L xor S[3];
end;
procedure TROCipher_Twofish.Init(const Key; Size: Integer; IVector: Pointer);
var
BoxKey : array[0..3] of TLongRec;
SubKey : pintarray;
Box : PTwofishBox;
procedure SetupKey;
function Encode(K0, k1: Integer): Integer;
var
R, i, j, G2, G3: Integer;
b : Byte;
begin
R := 0;
for i := 0 to 1 do
begin
if i <> 0 then
R := R xor K0
else
R := R xor k1;
for j := 0 to 3 do
begin
b := R shr 24;
if b and $80 <> 0 then
G2 := (b shl 1 xor $014D) and $FF
else
G2 := b shl 1 and $FF;
if b and 1 <> 0 then
G3 := (b shr 1 and $7F) xor $014D shr 1 xor G2
else
G3 := (b shr 1 and $7F) xor G2;
R := R shl 8 xor G3 shl 24 xor G2 shl 16 xor G3 shl 8 xor b;
end;
end;
Result := R;
end;
function F32(x: Integer; k: array of Integer): Integer;
var
A, b, c, d : Integer;
begin
A := x and $FF;
b := x shr 8 and $FF;
c := x shr 16 and $FF;
d := x shr 24;
if Size = 32 then
begin
A := Twofish_8x8[1, A] xor k[3] and $FF;
b := Twofish_8x8[0, b] xor k[3] shr 8 and $FF;
c := Twofish_8x8[0, c] xor k[3] shr 16 and $FF;
d := Twofish_8x8[1, d] xor k[3] shr 24;
end;
if Size >= 24 then
begin
A := Twofish_8x8[1, A] xor k[2] and $FF;
b := Twofish_8x8[1, b] xor k[2] shr 8 and $FF;
c := Twofish_8x8[0, c] xor k[2] shr 16 and $FF;
d := Twofish_8x8[0, d] xor k[2] shr 24;
end;
A := Twofish_8x8[0, A] xor k[1] and $FF;
b := Twofish_8x8[1, b] xor k[1] shr 8 and $FF;
c := Twofish_8x8[0, c] xor k[1] shr 16 and $FF;
d := Twofish_8x8[1, d] xor k[1] shr 24;
A := Twofish_8x8[0, A] xor k[0] and $FF;
b := Twofish_8x8[0, b] xor k[0] shr 8 and $FF;
c := Twofish_8x8[1, c] xor k[0] shr 16 and $FF;
d := Twofish_8x8[1, d] xor k[0] shr 24;
Result := Twofish_Data[0, A] xor Twofish_Data[1, b] xor
Twofish_Data[2, c] xor Twofish_Data[3, d];
end;
var
i, j, A, b : Integer;
e, o : array[0..3] of Integer;
k : array[0..7] of Integer;
begin
FillChar(k, SizeOf(k), 0);
Move(Key, k, Size);
if Size <= 16 then
Size := 16
else
if Size <= 24 then
Size := 24
else
Size := 32;
j := Size shr 3 - 1;
for i := 0 to j do
begin
e[i] := k[i shl 1];
o[i] := k[i shl 1 + 1];
BoxKey[j].L := Encode(e[i], o[i]);
Dec(j);
end;
j := 0;
for i := 0 to 19 do
begin
A := F32(j, e);
b := ROL(F32(j + $01010101, o), 8);
SubKey[i shl 1] := A + b;
b := A + b shr 1;
SubKey[i shl 1 + 1] := ROL(b, 9);
Inc(j, $02020202);
end;
end;
procedure DoXOR(d, S: pintarray; Value: LongWord);
var
i : LongWord;
begin
Value := (Value and $FF) * $01010101;
for i := 0 to 63 do
d[i] := S[i] xor Value;
end;
procedure SetupBox128;
var
L : array[0..255] of Byte;
A, i : Integer;
begin
DoXOR(@L, @Twofish_8x8[0], BoxKey[1].L);
A := BoxKey[0].A;
for i := 0 to 255 do
Box[0, i] := Twofish_Data[0, Twofish_8x8[0, L[i]] xor A];
DoXOR(@L, @Twofish_8x8[1], BoxKey[1].L shr 8);
A := BoxKey[0].b;
for i := 0 to 255 do
Box[1, i] := Twofish_Data[1, Twofish_8x8[0, L[i]] xor A];
DoXOR(@L, @Twofish_8x8[0], BoxKey[1].L shr 16);
A := BoxKey[0].c;
for i := 0 to 255 do
Box[2, i] := Twofish_Data[2, Twofish_8x8[1, L[i]] xor A];
DoXOR(@L, @Twofish_8x8[1], BoxKey[1].L shr 24);
A := BoxKey[0].d;
for i := 0 to 255 do
Box[3, i] := Twofish_Data[3, Twofish_8x8[1, L[i]] xor A];
end;
procedure SetupBox192;
var
L : array[0..255] of Byte;
A, b, i : Integer;
begin
DoXOR(@L, @Twofish_8x8[1], BoxKey[2].L);
A := BoxKey[0].A;
b := BoxKey[1].A;
for i := 0 to 255 do
Box[0, i] := Twofish_Data[0, Twofish_8x8[0, Twofish_8x8[0, L[i]] xor b] xor A];
DoXOR(@L, @Twofish_8x8[1], BoxKey[2].L shr 8);
A := BoxKey[0].b;
b := BoxKey[1].b;
for i := 0 to 255 do
Box[1, i] := Twofish_Data[1, Twofish_8x8[0, Twofish_8x8[1, L[i]] xor b] xor A];
DoXOR(@L, @Twofish_8x8[0], BoxKey[2].L shr 16);
A := BoxKey[0].c;
b := BoxKey[1].c;
for i := 0 to 255 do
Box[2, i] := Twofish_Data[2, Twofish_8x8[1, Twofish_8x8[0, L[i]] xor b] xor A];
DoXOR(@L, @Twofish_8x8[0], BoxKey[2].L shr 24);
A := BoxKey[0].d;
b := BoxKey[1].d;
for i := 0 to 255 do
Box[3, i] := Twofish_Data[3, Twofish_8x8[1, Twofish_8x8[1, L[i]] xor b] xor A];
end;
procedure SetupBox256;
var
L : array[0..255] of Byte;
k : array[0..255] of Byte;
A, b, i : Integer;
begin
DoXOR(@k, @Twofish_8x8[1], BoxKey[3].L);
for i := 0 to 255 do
L[i] := Twofish_8x8[1, k[i]];
DoXOR(@L, @L, BoxKey[2].L);
A := BoxKey[0].A;
b := BoxKey[1].A;
for i := 0 to 255 do
Box[0, i] := Twofish_Data[0, Twofish_8x8[0, Twofish_8x8[0, L[i]] xor b] xor A];
DoXOR(@k, @Twofish_8x8[0], BoxKey[3].L shr 8);
for i := 0 to 255 do
L[i] := Twofish_8x8[1, k[i]];
DoXOR(@L, @L, BoxKey[2].L shr 8);
A := BoxKey[0].b;
b := BoxKey[1].b;
for i := 0 to 255 do
Box[1, i] := Twofish_Data[1, Twofish_8x8[0, Twofish_8x8[1, L[i]] xor b] xor A];
DoXOR(@k, @Twofish_8x8[0], BoxKey[3].L shr 16);
for i := 0 to 255 do
L[i] := Twofish_8x8[0, k[i]];
DoXOR(@L, @L, BoxKey[2].L shr 16);
A := BoxKey[0].c;
b := BoxKey[1].c;
for i := 0 to 255 do
Box[2, i] := Twofish_Data[2, Twofish_8x8[1, Twofish_8x8[0, L[i]] xor b] xor A];
DoXOR(@k, @Twofish_8x8[1], BoxKey[3].L shr 24);
for i := 0 to 255 do
L[i] := Twofish_8x8[0, k[i]];
DoXOR(@L, @L, BoxKey[2].L shr 24);
A := BoxKey[0].d;
b := BoxKey[1].d;
for i := 0 to 255 do
Box[3, i] := Twofish_Data[3, Twofish_8x8[1, Twofish_8x8[1, L[i]] xor b] xor A];
end;
begin
InitBegin(Size);
SubKey := User;
Box := @SubKey[40];
SetupKey;
if Size = 16 then
SetupBox128
else
if Size = 24 then
SetupBox192
else
SetupBox256;
InitEnd(IVector);
end;
class procedure TROCipher_Shark.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 8;
AKeySize := 16;
AUserSize := 112;
end;
class function TROCipher_Shark.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 0D9h,065h,021h,0AAh,0C0h,0C3h,084h,060h
DB 09Dh,0CEh,01Fh,08Bh,0FBh,0ABh,018h,03Fh
DB 0A1h,021h,0ACh,0F8h,053h,049h,0C0h,06Fh
DB 027h,03Ah,089h,015h,0D3h,07Ah,0E9h,00Bh
end;
{$IFDEF VER_D4H} // >= D4
{.$DEFINE Shark64}//use this with D4 64bit Operation, but the 32 bit Code is 174 % faster
{$ENDIF}
type
PInt64 = ^TInt64;
{$IFDEF Shark64}
TInt64 = Int64;
{$ELSE}
TInt64 = packed record
L, R: Integer;
end;
{$ENDIF}
PInt64Array = ^TInt64Array;
TInt64Array = array[0..1023] of TInt64;
{$IFDEF Shark64}
TShark_Data = array[0..7, 0..255] of Int64;
{$ENDIF}
procedure TROCipher_Shark.Encode(Data: Pointer);
var
i, t : Integer;
{$IFDEF Shark64}
d : TInt64;
k : PInt64;
{$ELSE}
L, R : LongWord;
k : pintarray;
{$ENDIF}
begin
k := User;
{$IFDEF Shark64}
d := PInt64(Data)^;
for i := 0 to 4 do
begin
d := d xor k^;
Inc(k);
d := TShark_Data(Shark_CE)[0, d shr 56 and $FF] xor
TShark_Data(Shark_CE)[1, d shr 48 and $FF] xor
TShark_Data(Shark_CE)[2, d shr 40 and $FF] xor
TShark_Data(Shark_CE)[3, d shr 32 and $FF] xor
TShark_Data(Shark_CE)[4, d shr 24 and $FF] xor
TShark_Data(Shark_CE)[5, d shr 16 and $FF] xor
TShark_Data(Shark_CE)[6, d shr 8 and $FF] xor
TShark_Data(Shark_CE)[7, d and $FF];
end;
d := d xor k^;
Inc(k);
d := (Int64(Shark_SE[d shr 56 and $FF]) shl 56) xor
(Int64(Shark_SE[d shr 48 and $FF]) shl 48) xor
(Int64(Shark_SE[d shr 40 and $FF]) shl 40) xor
(Int64(Shark_SE[d shr 32 and $FF]) shl 32) xor
(Int64(Shark_SE[d shr 24 and $FF]) shl 24) xor
(Int64(Shark_SE[d shr 16 and $FF]) shl 16) xor
(Int64(Shark_SE[d shr 8 and $FF]) shl 8) xor
(Int64(Shark_SE[d and $FF]));
PInt64(Data)^ := d xor k^;
{$ELSE}
L := PInt64(Data).L;
R := PInt64(Data).R;
for i := 0 to 4 do
begin
L := L xor k[0];
R := R xor k[1];
Inc(PInteger(k), 2);
t := Shark_CE[0, R shr 23 and $1FE] xor
Shark_CE[1, R shr 15 and $1FE] xor
Shark_CE[2, R shr 7 and $1FE] xor
Shark_CE[3, R shl 1 and $1FE] xor
Shark_CE[4, L shr 23 and $1FE] xor
Shark_CE[5, L shr 15 and $1FE] xor
Shark_CE[6, L shr 7 and $1FE] xor
Shark_CE[7, L shl 1 and $1FE];
R := Shark_CE[0, R shr 23 and $1FE or 1] xor
Shark_CE[1, R shr 15 and $1FE or 1] xor
Shark_CE[2, R shr 7 and $1FE or 1] xor
Shark_CE[3, R shl 1 and $1FE or 1] xor
Shark_CE[4, L shr 23 and $1FE or 1] xor
Shark_CE[5, L shr 15 and $1FE or 1] xor
Shark_CE[6, L shr 7 and $1FE or 1] xor
Shark_CE[7, L shl 1 and $1FE or 1];
L := t;
end;
L := L xor k[0];
R := R xor k[1];
Inc(PInteger(k), 2);
L := LongWord(Shark_SE[L shr 24]) shl 24 xor
LongWord(Shark_SE[L shr 16 and $FF]) shl 16 xor
LongWord(Shark_SE[L shr 8 and $FF]) shl 8 xor
LongWord(Shark_SE[L and $FF]);
R := LongWord(Shark_SE[R shr 24]) shl 24 xor
LongWord(Shark_SE[R shr 16 and $FF]) shl 16 xor
LongWord(Shark_SE[R shr 8 and $FF]) shl 8 xor
LongWord(Shark_SE[R and $FF]);
PInt64(Data).L := L xor k[0];
PInt64(Data).R := R xor k[1];
{$ENDIF}
end;
procedure TROCipher_Shark.Decode(Data: Pointer);
var
i, t : Integer;
{$IFDEF Shark64}
d : TInt64;
k : PInt64;
{$ELSE}
R, L : LongWord;
k : pintarray;
{$ENDIF}
begin
k := User;
{$IFDEF Shark64}
Inc(k, 7);
d := PInt64(Data)^;
for i := 0 to 4 do
begin
d := d xor k^;
Inc(k);
d := TShark_Data(Shark_CD)[0, d shr 56 and $FF] xor
TShark_Data(Shark_CD)[1, d shr 48 and $FF] xor
TShark_Data(Shark_CD)[2, d shr 40 and $FF] xor
TShark_Data(Shark_CD)[3, d shr 32 and $FF] xor
TShark_Data(Shark_CD)[4, d shr 24 and $FF] xor
TShark_Data(Shark_CD)[5, d shr 16 and $FF] xor
TShark_Data(Shark_CD)[6, d shr 8 and $FF] xor
TShark_Data(Shark_CD)[7, d and $FF];
end;
d := d xor k^;
Inc(k);
d := (Int64(Shark_SD[d shr 56 and $FF]) shl 56) xor
(Int64(Shark_SD[d shr 48 and $FF]) shl 48) xor
(Int64(Shark_SD[d shr 40 and $FF]) shl 40) xor
(Int64(Shark_SD[d shr 32 and $FF]) shl 32) xor
(Int64(Shark_SD[d shr 24 and $FF]) shl 24) xor
(Int64(Shark_SD[d shr 16 and $FF]) shl 16) xor
(Int64(Shark_SD[d shr 8 and $FF]) shl 8) xor
(Int64(Shark_SD[d and $FF]));
PInt64(Data)^ := d xor k^;
{$ELSE}
Inc(PInteger(k), 14);
L := PInt64(Data).L;
R := PInt64(Data).R;
for i := 0 to 4 do
begin
L := L xor k[0];
R := R xor k[1];
Inc(PInteger(k), 2);
t := Shark_CD[0, R shr 23 and $1FE] xor
Shark_CD[1, R shr 15 and $1FE] xor
Shark_CD[2, R shr 7 and $1FE] xor
Shark_CD[3, R shl 1 and $1FE] xor
Shark_CD[4, L shr 23 and $1FE] xor
Shark_CD[5, L shr 15 and $1FE] xor
Shark_CD[6, L shr 7 and $1FE] xor
Shark_CD[7, L shl 1 and $1FE];
R := Shark_CD[0, R shr 23 and $1FE or 1] xor
Shark_CD[1, R shr 15 and $1FE or 1] xor
Shark_CD[2, R shr 7 and $1FE or 1] xor
Shark_CD[3, R shl 1 and $1FE or 1] xor
Shark_CD[4, L shr 23 and $1FE or 1] xor
Shark_CD[5, L shr 15 and $1FE or 1] xor
Shark_CD[6, L shr 7 and $1FE or 1] xor
Shark_CD[7, L shl 1 and $1FE or 1];
L := t;
end;
L := L xor k[0];
R := R xor k[1];
Inc(PInteger(k), 2);
L := Integer(Shark_SD[L shr 24]) shl 24 xor
Integer(Shark_SD[L shr 16 and $FF]) shl 16 xor
Integer(Shark_SD[L shr 8 and $FF]) shl 8 xor
Integer(Shark_SD[L and $FF]);
R := Integer(Shark_SD[R shr 24]) shl 24 xor
Integer(Shark_SD[R shr 16 and $FF]) shl 16 xor
Integer(Shark_SD[R shr 8 and $FF]) shl 8 xor
Integer(Shark_SD[R and $FF]);
PInt64(Data).L := L xor k[0];
PInt64(Data).R := R xor k[1];
{$ENDIF}
end;
procedure TROCipher_Shark.Init(const Key; Size: Integer; IVector: Pointer);
var
Log, ALog : array[0..255] of Byte;
procedure InitLog;
var
i, j : word;
begin
ALog[0] := 1;
for i := 1 to 255 do
begin
j := ALog[i - 1] shl 1;
if j and $100 <> 0 then
j := j xor $01F5;
ALog[i] := j;
end;
for i := 1 to 254 do
Log[ALog[i]] := i;
end;
function Transform(A: TInt64): TInt64;
type
TInt64Rec = packed record
Lo, Hi: Integer;
end;
function Mul(A, b: Integer): Byte;
begin
Result := ALog[(Log[A] + Log[b]) mod 255];
end;
var
i, j : Byte;
k, t : array[0..7] of Byte;
begin
{$IFDEF Shark64}
Move(TInt64Rec(A).Hi, k[0], 4);
Move(TInt64Rec(A).Lo, k[4], 4);
SwapIntegerBuffer(@k, @k, 2);
{$ELSE}
Move(A.R, k[0], 4);
Move(A.L, k[4], 4);
SwapIntegerBuffer(@k, @k, 2);
{$ENDIF}
for i := 0 to 7 do
begin
t[i] := Mul(Shark_I[i, 0], k[0]);
for j := 1 to 7 do
t[i] := t[i] xor Mul(Shark_I[i, j], k[j]);
end;
{$IFDEF Shark64}
Result := t[0];
for i := 1 to 7 do
Result := Result shl 8 xor t[i];
{$ELSE}
Result.L := t[0];
Result.R := 0;
for i := 1 to 7 do
begin
Result.R := Result.R shl 8 or Result.L shr 24;
Result.L := Result.L shl 8 xor t[i];
end;
{$ENDIF}
end;
function Shark(d: TInt64; k: PInt64): TInt64;
var
R, t : Integer;
begin
{$IFDEF Shark64}
for R := 0 to 4 do
begin
d := d xor k^;
Inc(k);
d := TShark_Data(Shark_CE)[0, d shr 56 and $FF] xor
TShark_Data(Shark_CE)[1, d shr 48 and $FF] xor
TShark_Data(Shark_CE)[2, d shr 40 and $FF] xor
TShark_Data(Shark_CE)[3, d shr 32 and $FF] xor
TShark_Data(Shark_CE)[4, d shr 24 and $FF] xor
TShark_Data(Shark_CE)[5, d shr 16 and $FF] xor
TShark_Data(Shark_CE)[6, d shr 8 and $FF] xor
TShark_Data(Shark_CE)[7, d and $FF];
end;
d := d xor k^;
Inc(k);
d := (Int64(Shark_SE[d shr 56 and $FF]) shl 56) xor
(Int64(Shark_SE[d shr 48 and $FF]) shl 48) xor
(Int64(Shark_SE[d shr 40 and $FF]) shl 40) xor
(Int64(Shark_SE[d shr 32 and $FF]) shl 32) xor
(Int64(Shark_SE[d shr 24 and $FF]) shl 24) xor
(Int64(Shark_SE[d shr 16 and $FF]) shl 16) xor
(Int64(Shark_SE[d shr 8 and $FF]) shl 8) xor
(Int64(Shark_SE[d and $FF]));
Result := d xor k^;
{$ELSE}
for R := 0 to 4 do
begin
d.L := d.L xor k.L;
d.R := d.R xor k.R;
Inc(k);
t := Shark_CE[0, d.R shr 23 and $1FE] xor
Shark_CE[1, d.R shr 15 and $1FE] xor
Shark_CE[2, d.R shr 7 and $1FE] xor
Shark_CE[3, d.R shl 1 and $1FE] xor
Shark_CE[4, d.L shr 23 and $1FE] xor
Shark_CE[5, d.L shr 15 and $1FE] xor
Shark_CE[6, d.L shr 7 and $1FE] xor
Shark_CE[7, d.L shl 1 and $1FE];
d.R := Shark_CE[0, d.R shr 23 and $1FE or 1] xor
Shark_CE[1, d.R shr 15 and $1FE or 1] xor
Shark_CE[2, d.R shr 7 and $1FE or 1] xor
Shark_CE[3, d.R shl 1 and $1FE or 1] xor
Shark_CE[4, d.L shr 23 and $1FE or 1] xor
Shark_CE[5, d.L shr 15 and $1FE or 1] xor
Shark_CE[6, d.L shr 7 and $1FE or 1] xor
Shark_CE[7, d.L shl 1 and $1FE or 1];
d.L := t;
end;
d.L := d.L xor k.L;
d.R := d.R xor k.R;
Inc(k);
d.L := Integer(Shark_SE[d.L shr 24 and $FF]) shl 24 xor
Integer(Shark_SE[d.L shr 16 and $FF]) shl 16 xor
Integer(Shark_SE[d.L shr 8 and $FF]) shl 8 xor
Integer(Shark_SE[d.L and $FF]);
d.R := Integer(Shark_SE[d.R shr 24 and $FF]) shl 24 xor
Integer(Shark_SE[d.R shr 16 and $FF]) shl 16 xor
Integer(Shark_SE[d.R shr 8 and $FF]) shl 8 xor
Integer(Shark_SE[d.R and $FF]);
Result.L := d.L xor k.L;
Result.R := d.R xor k.R;
{$ENDIF}
end;
var
t : array[0..6] of TInt64;
A : array[0..6] of TInt64;
k : array[0..15] of Byte;
i, j, R : Byte;
e, d : PInt64Array;
L : TInt64;
begin
InitBegin(Size);
FillChar(k, SizeOf(k), 0);
Move(Key, k, Size);
InitLog;
e := User;
d := @e[7];
Move(Shark_CE[0], t, SizeOf(t));
t[6] := Transform(t[6]);
i := 0;
{$IFDEF Shark64}
for R := 0 to 6 do
begin
Inc(i);
A[R] := k[i and $F];
for j := 1 to 7 do
begin
Inc(i);
A[R] := A[R] shl 8 or k[i and $F];
end;
end;
e[0] := A[0] xor Shark(0, @t);
for R := 1 to 6 do
e[R] := A[R] xor Shark(e[R - 1], @t);
{$ELSE}
for R := 0 to 6 do
begin
Inc(i);
A[R].L := k[i and $F];
A[R].R := 0;
for j := 1 to 7 do
begin
Inc(i);
A[R].R := A[R].R shl 8 or A[R].L shr 24;
A[R].L := A[R].L shl 8 or k[i and $F];
end;
end;
L.L := 0;
L.R := 0;
L := Shark(L, @t);
e[0].L := A[0].L xor L.L;
e[0].R := A[0].R xor L.R;
for R := 1 to 6 do
begin
L := Shark(e[R - 1], @t);
e[R].L := A[R].L xor L.L;
e[R].R := A[R].R xor L.R;
end;
{$ENDIF}
e[6] := Transform(e[6]);
d[0] := e[6];
d[6] := e[0];
for R := 1 to 5 do
d[R] := Transform(e[6 - R]);
FillChar(Log, SizeOf(Log), 0);
FillChar(ALog, SizeOf(ALog), 0);
FillChar(t, SizeOf(t), 0);
FillChar(A, SizeOf(A), 0);
FillChar(k, SizeOf(k), 0);
InitEnd(IVector);
end;
class procedure TROCipher_Square.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 16;
AKeySize := 16;
AUserSize := 9 * 4 * 2 * SizeOf(LongWord);
end;
class function TROCipher_Square.TestVector: Pointer;
asm
MOV EAX,OFFSET @Vector
RET
@Vector: DB 043h,09Ch,0A6h,0C4h,067h,0E8h,02Eh,047h
DB 022h,095h,066h,085h,006h,039h,06Ah,0C9h
DB 018h,021h,020h,0F7h,044h,036h,0F1h,061h
DB 07Dh,014h,090h,0B1h,0A9h,068h,056h,0C7h
end;
procedure TROCipher_Square.Encode(Data: Pointer);
var
Key : pintarray;
A, b, c, d : LongWord;
AA, BB, CC : LongWord;
i : Integer;
begin
Key := User;
A := pintarray(Data)[0] xor Key[0];
b := pintarray(Data)[1] xor Key[1];
c := pintarray(Data)[2] xor Key[2];
d := pintarray(Data)[3] xor Key[3];
Inc(PInteger(Key), 4);
for i := 0 to 6 do
begin
AA := Square_TE[0, A and $FF] xor
Square_TE[1, b and $FF] xor
Square_TE[2, c and $FF] xor
Square_TE[3, d and $FF] xor Key[0];
BB := Square_TE[0, A shr 8 and $FF] xor
Square_TE[1, b shr 8 and $FF] xor
Square_TE[2, c shr 8 and $FF] xor
Square_TE[3, d shr 8 and $FF] xor Key[1];
CC := Square_TE[0, A shr 16 and $FF] xor
Square_TE[1, b shr 16 and $FF] xor
Square_TE[2, c shr 16 and $FF] xor
Square_TE[3, d shr 16 and $FF] xor Key[2];
d := Square_TE[0, A shr 24] xor
Square_TE[1, b shr 24] xor
Square_TE[2, c shr 24] xor
Square_TE[3, d shr 24] xor Key[3];
Inc(PInteger(Key), 4);
A := AA;
b := BB;
c := CC;
end;
pintarray(Data)[0] := LongWord(Square_SE[A and $FF]) xor
LongWord(Square_SE[b and $FF]) shl 8 xor
LongWord(Square_SE[c and $FF]) shl 16 xor
LongWord(Square_SE[d and $FF]) shl 24 xor Key[0];
pintarray(Data)[1] := LongWord(Square_SE[A shr 8 and $FF]) xor
LongWord(Square_SE[b shr 8 and $FF]) shl 8 xor
LongWord(Square_SE[c shr 8 and $FF]) shl 16 xor
LongWord(Square_SE[d shr 8 and $FF]) shl 24 xor Key[1];
pintarray(Data)[2] := LongWord(Square_SE[A shr 16 and $FF]) xor
LongWord(Square_SE[b shr 16 and $FF]) shl 8 xor
LongWord(Square_SE[c shr 16 and $FF]) shl 16 xor
LongWord(Square_SE[d shr 16 and $FF]) shl 24 xor Key[2];
pintarray(Data)[3] := LongWord(Square_SE[A shr 24]) xor
LongWord(Square_SE[b shr 24]) shl 8 xor
LongWord(Square_SE[c shr 24]) shl 16 xor
LongWord(Square_SE[d shr 24]) shl 24 xor Key[3];
end;
procedure TROCipher_Square.Decode(Data: Pointer);
var
Key : pintarray;
A, b, c, d : LongWord;
AA, BB, CC : LongWord;
i : Integer;
begin
Key := @pintarray(User)[9 * 4];
A := pintarray(Data)[0] xor Key[0];
b := pintarray(Data)[1] xor Key[1];
c := pintarray(Data)[2] xor Key[2];
d := pintarray(Data)[3] xor Key[3];
Inc(PInteger(Key), 4);
for i := 0 to 6 do
begin
AA := Square_TD[0, A and $FF] xor
Square_TD[1, b and $FF] xor
Square_TD[2, c and $FF] xor
Square_TD[3, d and $FF] xor Key[0];
BB := Square_TD[0, A shr 8 and $FF] xor
Square_TD[1, b shr 8 and $FF] xor
Square_TD[2, c shr 8 and $FF] xor
Square_TD[3, d shr 8 and $FF] xor Key[1];
CC := Square_TD[0, A shr 16 and $FF] xor
Square_TD[1, b shr 16 and $FF] xor
Square_TD[2, c shr 16 and $FF] xor
Square_TD[3, d shr 16 and $FF] xor Key[2];
d := Square_TD[0, A shr 24] xor
Square_TD[1, b shr 24] xor
Square_TD[2, c shr 24] xor
Square_TD[3, d shr 24] xor Key[3];
Inc(PInteger(Key), 4);
A := AA;
b := BB;
c := CC;
end;
pintarray(Data)[0] := LongWord(Square_SD[A and $FF]) xor
LongWord(Square_SD[b and $FF]) shl 8 xor
LongWord(Square_SD[c and $FF]) shl 16 xor
LongWord(Square_SD[d and $FF]) shl 24 xor Key[0];
pintarray(Data)[1] := LongWord(Square_SD[A shr 8 and $FF]) xor
LongWord(Square_SD[b shr 8 and $FF]) shl 8 xor
LongWord(Square_SD[c shr 8 and $FF]) shl 16 xor
LongWord(Square_SD[d shr 8 and $FF]) shl 24 xor Key[1];
pintarray(Data)[2] := LongWord(Square_SD[A shr 16 and $FF]) xor
LongWord(Square_SD[b shr 16 and $FF]) shl 8 xor
LongWord(Square_SD[c shr 16 and $FF]) shl 16 xor
LongWord(Square_SD[d shr 16 and $FF]) shl 24 xor Key[2];
pintarray(Data)[3] := LongWord(Square_SD[A shr 24]) xor
LongWord(Square_SD[b shr 24]) shl 8 xor
LongWord(Square_SD[c shr 24]) shl 16 xor
LongWord(Square_SD[d shr 24]) shl 24 xor Key[3];
end;
procedure TROCipher_Square.Init(const Key; Size: Integer; IVector: Pointer);
type
PSquare_Key = ^TSquare_Key;
TSquare_Key = array[0..8, 0..3] of LongWord;
var
e, d : PSquare_Key;
t, i : Integer;
begin
InitBegin(Size);
e := User;
d := User;
Inc(d);
Move(Key, e^, Size);
for t := 1 to 8 do
begin
e[t, 0] := e[t - 1, 0] xor ROR(e[t - 1, 3], 8) xor 1 shl (t - 1);
d[8 - t, 0] := e[t, 0];
e[t, 1] := e[t - 1, 1] xor e[t, 0];
d[8 - t, 1] := e[t, 1];
e[t, 2] := e[t - 1, 2] xor e[t, 1];
d[8 - t, 2] := e[t, 2];
e[t, 3] := e[t - 1, 3] xor e[t, 2];
d[8 - t, 3] := e[t, 3];
for i := 0 to 3 do
e[t - 1, i] := Square_PHI[e[t - 1, i] and $FF] xor
ROL(Square_PHI[e[t - 1, i] shr 8 and $FF], 8) xor
ROL(Square_PHI[e[t - 1, i] shr 16 and $FF], 16) xor
ROL(Square_PHI[e[t - 1, i] shr 24], 24);
end;
d[8] := e[0];
InitEnd(IVector);
end;
{$IFDEF UseASM}
{$IFNDEF 486GE} // no Support for <= CPU 386
{ Ok, follow a BAD BAD dirty Trick, BUT realy realistic and correct
The Problem:
I will use for CPU's >= 486 the BSWAP Mnemonic to speedup Blowfish more.
( BSWAP swaps the Byteorder from a 32bit Word A,B,C,D to D,C,B,A and back
and is the fastes Solution, but only for >= 486 CPU)
I must wrote two assembler optimated function, one for >= 486
and one for <= 386. -> En/Decode() and En/Decode386().
The normal Solution:
See in RO_Hash.pas the SwapInteger proc. We can define a private
procedural Field in TROCipher_Blowfish that contains a pointer to the CPU
depended code procedure.
i.E. an implementation:
TROCipher_Blowfish.Encode()
begin
FProc(Data);
end;
The Program must make a call to the virtual Method Encode() and
a second call to FProc(Data), and in the Init() or Constructor must
we initialize these FProc Field.
The Dirty Solution:
A virtual Method, and ONLY a virtual Method, is identicaly to a
private Field in the Object Class.
This Class Definition is stored in the Code Segment.
Now, we modifying, when CPU <= 386, these Field, from the Classdefinition
in the Code Segment !!!, and save a new Methodaddress, the Address from
TROCipher_Blowfish.Encode386 etc.
This changes have Effect to all TROCipher_Blowfish Instances,
but not descending Classes from TROCipher_Blowfish :-)
This Trick work's theoretical with BP5? upto D4.
Ok, You say many expense for a little speed more !?
YES, but have You this here known ? NO ?, but now.
}
procedure FindVirtualMethodAndChange(aClass: TClass; MethodAddr, NewAddress: Pointer);
// MethodAddr must explicit exists
type
PPointer = ^Pointer;
const
PageSize = SizeOf(Pointer);
var
Table : PPointer;
SaveFlag : DWord;
begin
Table := PPointer(aClass);
while Table^ <> MethodAddr do
Inc(Table);
if VirtualProtect(Table, PageSize, PAGE_EXECUTE_READWRITE, @SaveFlag) then
try
Table^ := NewAddress;
finally
VirtualProtect(Table, PageSize, SaveFlag, @SaveFlag);
end;
end;
{$ENDIF}
{$ENDIF}
{$IFDEF VER_D3H}
procedure ModuleUnload(Module: Longword);
var
i : Integer;
begin
if IsObject(FCipherList, TStringList) then
for i := FCipherList.Count - 1 downto 0 do
if FindClassHInstance(TClass(FCipherList.Objects[i])) = Module then
FCipherList.Delete(i);
end;
{$ENDIF}
initialization
{$IFDEF UseASM}
{$IFNDEF 486GE} // no Support for <= CPU 386
if CPUType <= 3 then // CPU <= 386
begin
FindVirtualMethodAndChange(TROCipher_Blowfish, @TROCipher_Blowfish.Encode,
@TROCipher_Blowfish.Encode386);
FindVirtualMethodAndChange(TROCipher_Blowfish, @TROCipher_Blowfish.Decode,
@TROCipher_Blowfish.Decode386);
end;
{$ENDIF}
{$ENDIF}
{$IFDEF VER_D3H}
AddModuleUnloadProc(ModuleUnload);
{$ENDIF}
{$IFNDEF ManualRegisterClasses}
RegisterCipher(TROCipher_3Way, '', '');
RegisterCipher(TROCipher_Blowfish, '', '');
RegisterCipher(TROCipher_Gost, '', '');
RegisterCipher(TROCipher_IDEA, '', 'free for non-commercial');
RegisterCipher(TROCipher_Q128, '', '');
RegisterCipher(TROCipher_SAFER_K40, 'SAFER-K40', '');
RegisterCipher(TROCipher_SAFER_SK40, 'SAFER-SK40', 'Keyscheduling');
RegisterCipher(TROCipher_SAFER_K64, 'SAFER-K64', '');
RegisterCipher(TROCipher_SAFER_SK64, 'SAFER-SK64', 'Keyscheduling');
RegisterCipher(TROCipher_SAFER_K128, 'SAFER-K128', '');
RegisterCipher(TROCipher_SAFER_SK128, 'SAFER-SK128', 'Keyscheduling');
RegisterCipher(TROCipher_SCOP, '', '');
RegisterCipher(TROCipher_Shark, '', '');
RegisterCipher(TROCipher_Square, '', '');
RegisterCipher(TROCipher_TEA, 'TEA', '');
RegisterCipher(TROCipher_TEAN, 'TEA extended', '');
RegisterCipher(TROCipher_Twofish, '', '');
{$ENDIF}
finalization
{$IFDEF VER_D3H}
RemoveModuleUnloadProc(ModuleUnload);
{$ENDIF}
FCipherList.Free;
FCipherList := nil;
end.