{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.