📄 idea.pas
字号:
{
***************************************************
* A binary compatible IDEA implementation *
* written by Dave Barton (davebarton@bigfoot.com) *
***************************************************
* 64bit block encryption *
* 128bit key size *
***************************************************
}
unit IDEA;
interface
uses
Sysutils, Tools;
type
PWord = ^word;
TIDEAData = record
InitBlock: array[0..7] of byte; { initial IV }
LastBlock: array[0..7] of byte; { current IV }
EK: array[0..51] of word;
DK: array[0..51] of word;
end;
function IDEASelfTest: boolean;
{ performs a self test on this implementation }
procedure IDEAInit(var Data: TIDEAData; Key: pointer; Len: integer; IV:
pointer); stdcall; export;
{ initializes the TIDEAData structure with the key information and IV if applicable }
procedure IDEABurn(var Data: TIDEAData); stdcall; export;
{ erases all information about the key }
procedure IDEAEncryptECB(var Data: TIDEAData; InData, OutData: pointer);
stdcall; export;
{ encrypts the data in a 64bit block using the ECB mode }
procedure IDEAEncryptCBC(var Data: TIDEAData; InData, OutData: pointer);
stdcall; export;
{ encrypts the data in a 64bit block using the CBC chaining mode }
procedure IDEAEncryptOFB(var Data: TIDEAData; InData, OutData: pointer);
stdcall; export;
{ encrypts the data in a 64bit block using the OFB chaining mode }
procedure IDEAEncryptCFB(var Data: TIDEAData; InData, OutData: pointer; Len:
integer); stdcall; export;
{ encrypts Len bytes of data using the CFB chaining mode }
procedure IDEAEncryptOFBC(var Data: TIDEAData; InData, OutData: pointer; Len:
integer); stdcall; export;
{ encrypts Len bytes of data using the OFB counter chaining mode }
procedure IDEADecryptECB(var Data: TIDEAData; InData, OutData: pointer);
stdcall; export;
{ decrypts the data in a 64bit block using the ECB mode }
procedure IDEADecryptCBC(var Data: TIDEAData; InData, OutData: pointer);
stdcall; export;
{ decrypts the data in a 64bit block using the CBC chaining mode }
procedure IDEADecryptOFB(var Data: TIDEAData; InData, OutData: pointer);
stdcall; export;
{ decrypts the data in a 64bit block using the OFB chaining mode }
procedure IDEADecryptCFB(var Data: TIDEAData; InData, OutData: pointer; Len:
integer); stdcall; export;
{ decrypts Len bytes of data using the CFB chaining mode }
procedure IDEADecryptOFBC(var Data: TIDEAData; InData, OutData: pointer; Len:
integer); stdcall; export;
{ decrypts Len bytes of data using the OFB counter chaining mode }
procedure IDEAReset(var Data: TIDEAData); stdcall; export;
{ resets the chaining mode information }
{******************************************************************************}
implementation
function IDEASelfTest: boolean;
const
Key: array[0..15] of byte =
($00, $01, $00, $02, $00, $03, $00, $04, $00, $05, $00, $06, $00, $07, $00,
$08);
InBlock: array[0..7] of byte =
($00, $00, $00, $01, $00, $02, $00, $03);
OutBlock: array[0..7] of byte =
($11, $FB, $ED, $2B, $01, $98, $6D, $E5);
var
Block: array[0..7] of byte;
Data: TIDEAData;
begin
IDEAInit(Data, @Key, Sizeof(Key), nil);
IDEAEncryptECB(Data, @InBlock, @Block);
Result := CompareMem(@Block, @OutBlock, Sizeof(Block));
IDEADecryptECB(Data, @Block, @Block);
Result := Result and CompareMem(@Block, @InBlock, Sizeof(Block));
IDEABurn(Data);
end;
procedure Mul(var x: word; y: word);
var
p: DWord;
t16: word;
begin
p := DWord(x) * y;
if p = 0 then
x := 1 - x - y
else
begin
x := p shr 16;
t16 := p and $FFFF;
x := t16 - x;
if (t16 < x) then
Inc(x);
end;
end;
function MulInv(x: word): word;
var
t0, t1, q, y: word;
begin
if x <= 1 then
begin
Result := x;
Exit;
end;
t1 := DWord($10001) div x;
y := DWord($10001) mod x;
if y = 1 then
begin
Result := (1 - t1) and $FFFF;
Exit;
end;
t0 := 1;
repeat
q := x div y;
x := x mod y;
t0 := t0 + (q * t1);
if x = 1 then
begin
Result := t0;
Exit;
end;
q := y div x;
y := y mod x;
t1 := t1 + (q * t0);
until y = 1;
Result := (1 - t1) and $FFFF;
end;
procedure IDEAInvertKey(EK, DK: PWord);
var
i: integer;
t1, t2, t3: word;
temp: array[0..51] of word;
p: PWord;
begin
p := pointer(integer(@temp) + Sizeof(Temp));
Dec(p);
t1 := MulInv(EK^);
Inc(EK);
t2 := -EK^;
Inc(EK);
t3 := -EK^;
Inc(EK);
p^ := MulInv(EK^);
Inc(EK);
Dec(p);
p^ := t3;
Dec(p);
p^ := t2;
Dec(p);
p^ := t1;
Dec(p);
for i := 0 to 6 do
begin
t1 := EK^;
Inc(EK);
p^ := EK^;
Inc(EK);
Dec(p);
p^ := t1;
Dec(p);
t1 := MulInv(EK^);
Inc(EK);
t2 := -EK^;
Inc(EK);
t3 := -EK^;
Inc(EK);
p^ := MulInv(EK^);
Inc(EK);
Dec(p);
p^ := t2;
Dec(p);
p^ := t3;
Dec(p);
p^ := t1;
Dec(p);
end;
t1 := EK^;
Inc(EK);
p^ := EK^;
Dec(p);
Inc(EK);
p^ := t1;
Dec(p);
t1 := MulInv(EK^);
Inc(EK);
t2 := -EK^;
Inc(EK);
t3 := -EK^;
Inc(EK);
p^ := MulInv(EK^);
Dec(p);
p^ := t3;
Dec(p);
p^ := t2;
Dec(p);
p^ := t1;
Move(Temp, DK^, Sizeof(Temp));
FillChar(Temp, Sizeof(Temp), 0);
end;
procedure IDEAInit; stdcall; export;
var
UserKey: PByteArray;
PEK: PWordArray;
j: integer;
begin
if Len <> 16 then
raise Exception.Create('IDEA: Invalid key length');
with Data do
begin
if IV = nil then
begin
FillChar(InitBlock, 8, 0);
FillChar(LastBlock, 8, 0);
end
else
begin
Move(IV^, InitBlock, 8);
Move(IV^, LastBlock, 8);
end;
UserKey := Key;
PEK := @EK;
for j := 0 to 7 do
begin
PEK[j] := (UserKey[0] shl 8) + UserKey[1];
UserKey := pointer(integer(UserKey) + 2);
end;
for j := 1 to 6 do
begin
PEK[8] := (PEK[1] shl 9) or (PEK[2] shr 7);
PEK[9] := (PEK[2] shl 9) or (PEK[3] shr 7);
PEK[10] := (PEK[3] shl 9) or (PEK[4] shr 7);
PEK[11] := (PEK[4] shl 9) or (PEK[5] shr 7);
PEK[12] := (PEK[5] shl 9) or (PEK[6] shr 7);
PEK[13] := (PEK[6] shl 9) or (PEK[7] shr 7);
PEK[14] := (PEK[7] shl 9) or (PEK[0] shr 7);
PEK[15] := (PEK[0] shl 9) or (PEK[1] shr 7);
PEK := pointer(integer(PEK) + 16);
end;
IDEAInvertKey(@EK, @DK);
end;
end;
procedure IDEABurn; stdcall; export;
begin
FillChar(Data, Sizeof(Data), 0);
end;
procedure IDEACipher(Key: PWord; Input, Output: PWordArray);
var
x1, x2, x3, x4, s2, s3: word;
i: integer;
begin
x1 := (Input[0] shr 8) or (Input[0] shl 8);
x2 := (Input[1] shr 8) or (Input[1] shl 8);
x3 := (Input[2] shr 8) or (Input[2] shl 8);
x4 := (Input[3] shr 8) or (Input[3] shl 8);
i := 8;
repeat
Mul(x1, Key^);
Inc(Key);
x2 := x2 + Key^;
Inc(Key);
x3 := x3 + Key^;
Inc(Key);
Mul(x4, Key^);
Inc(Key);
s3 := x3;
x3 := x3 xor x1;
Mul(x3, Key^);
Inc(Key);
s2 := x2;
x2 := x2 xor x4;
x2 := x2 + x3;
Mul(x2, Key^);
Inc(Key);
x3 := x3 + x2;
x1 := x1 xor x2;
x4 := x4 xor x3;
x2 := x2 xor s3;
x3 := x3 xor s2;
Dec(i);
until (i = 0);
Mul(x1, Key^);
Inc(Key);
x3 := x3 + Key^;
Inc(Key);
x2 := x2 + Key^;
Inc(Key);
Mul(x4, Key^);
Output[0] := (x1 shr 8) or (x1 shl 8);
Output[1] := (x3 shr 8) or (x3 shl 8);
Output[2] := (x2 shr 8) or (x2 shl 8);
Output[3] := (x4 shr 8) or (x4 shl 8);
end;
procedure IDEAEncryptECB; stdcall; export;
begin
IDEACipher(@Data.EK, InData, OutData);
end;
procedure IDEADecryptECB; stdcall; export;
begin
IDEACipher(@Data.DK, InData, OutData);
end;
procedure IDEAEncryptCBC; stdcall; export;
begin
XorBlock(InData, @Data.LastBlock, OutData, 8);
IDEAEncryptECB(Data, OutData, OutData);
Move(OutData^, Data.LastBlock, 8);
end;
procedure IDEADecryptCBC; stdcall; export;
var
TempBlock: array[0..7] of byte;
begin
Move(InData^, TempBlock, 8);
IDEADecryptECB(Data, InData, OutData);
XorBlock(OutData, @Data.LastBlock, OutData, 8);
Move(TempBlock, Data.LastBlock, 8);
end;
procedure IDEAEncryptCFB; stdcall; export;
var
i: integer;
TempBlock: array[0..7] of byte;
begin
for i := 0 to Len - 1 do
begin
IDEAEncryptECB(Data, @Data.LastBlock, @TempBlock);
PByteArray(OutData)[i] := PByteArray(InData)[i] xor TempBlock[0];
Move(Data.LastBlock[1], Data.LastBlock[0], 7);
Data.LastBlock[7] := PByteArray(OutData)[i];
end;
end;
procedure IDEADecryptCFB; stdcall; export;
var
i: integer;
TempBlock: array[0..7] of byte;
b: byte;
begin
for i := 0 to Len - 1 do
begin
b := PByteArray(InData)[i];
IDEAEncryptECB(Data, @Data.LastBlock, @TempBlock);
PByteArray(OutData)[i] := PByteArray(InData)[i] xor TempBlock[0];
Move(Data.LastBlock[1], Data.LastBlock[0], 7);
Data.LastBlock[7] := b;
end;
end;
procedure IDEAEncryptOFB; stdcall; export;
begin
IDEAEncryptECB(Data, @Data.LastBlock, @Data.LastBlock);
XorBlock(@Data.LastBlock, InData, OutData, 8);
end;
procedure IDEADecryptOFB; stdcall; export;
begin
IDEAEncryptECB(Data, @Data.LastBlock, @Data.LastBlock);
XorBlock(@Data.LastBlock, InData, OutData, 8);
end;
procedure IDEAEncryptOFBC; stdcall; export;
var
i: integer;
TempBlock: array[0..7] of byte;
begin
for i := 0 to Len - 1 do
begin
IDEAEncryptECB(Data, @Data.LastBlock, @TempBlock);
PByteArray(OutData)[i] := PByteArray(InData)[i] xor TempBlock[0];
IncBlock(@Data.LastBlock, 8);
end;
end;
procedure IDEADecryptOFBC; stdcall; export;
var
i: integer;
TempBlock: array[0..7] of byte;
begin
for i := 0 to Len - 1 do
begin
IDEAEncryptECB(Data, @Data.LastBlock, @TempBlock);
PByteArray(OutData)[i] := PByteArray(InData)[i] xor TempBlock[0];
IncBlock(@Data.LastBlock, 8);
end;
end;
procedure IDEAReset; stdcall; export;
begin
Move(Data.InitBlock, Data.LastBlock, 8);
end;
exports
IDEAInit, IDEABurn, IDEAReset,
IDEAEncryptECB, IDEAEncryptCBC, IDEAEncryptOFB, IDEAEncryptCFB,
IDEAEncryptOFBC,
IDEADecryptECB, IDEADecryptCBC, IDEADecryptOFB, IDEADecryptCFB,
IDEADecryptOFBC;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -