📄 msgcipher.pas
字号:
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 TCipher_Square.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 16;
AKeySize := 16;
AUserSize := 9 * 4 * 2 * SizeOf(LongWord);
end;
class function TCipher_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 TCipher_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 TCipher_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 TCipher_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}
{$IFDEF MSWINDOWS}
{$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 Hash.pas the SwapInteger proc. We can define a private
procedural Field in TCipher_Blowfish that contains a pointer to the CPU
depended code procedure.
i.E. an implementation:
TCipher_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
TCipher_Blowfish.Encode386 etc.
This changes have Effect to all TCipher_Blowfish Instances,
but not descending Classes from TCipher_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}
{$ENDIF}
{$IFDEF VER_D3H}
procedure ModuleUnload(Module: Integer);
var
I: Integer;
begin
if IsObject(FCipherList, TStringList) then
for I := FCipherList.Count-1 downto 0 do
if Integer(FindClassHInstance(TClass(FCipherList.Objects[I]))) = Module then
FCipherList.Delete(I);
end;
{$ENDIF}
initialization
{$IFDEF DEBUG_LOG_INIT}
aaWriteToLog('MsgCipher> initialization started');
{$ENDIF}
{$IFDEF UseASM}
{$IFDEF MSWINDOWS}
{$IFNDEF 486GE} // no Support for <= CPU 386
if CPUType <= 3 then // CPU <= 386
begin
FindVirtualMethodAndChange(TCipher_Blowfish, @TCipher_Blowfish.Encode,
@TCipher_Blowfish.Encode386);
FindVirtualMethodAndChange(TCipher_Blowfish, @TCipher_Blowfish.Decode,
@TCipher_Blowfish.Decode386);
end;
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF VER_D3H}
AddModuleUnloadProc(ModuleUnload);
{$ENDIF}
{$IFNDEF ManualRegisterClasses}
RegisterCipher(TCipher_Blowfish, '', '');
RegisterCipher(TCipher_Square, '', '');
RegisterCipher(TCipher_Twofish, '', '');
{$ENDIF}
{$IFDEF DEBUG_LOG_INIT}
aaWriteToLog('MsgCipher> initialization finished');
{$ENDIF}
finalization
{$IFDEF VER_D3H}
RemoveModuleUnloadProc(ModuleUnload);
{$ENDIF}
FCipherList.Free;
FCipherList := nil;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -