Der Lightweight Encryption Algorithm (auch bekannt als LEA ) ist ein 128-Bit- Blockchiffre , der 2013 in Südkorea entwickelt wurde, um Vertraulichkeit in Hochgeschwindigkeitsumgebungen wie Big Data und Cloud Computing sowie in leichtgewichtigen Umgebungen wie IoT-Geräten und mobilen Geräten zu gewährleisten . LEA hat drei verschiedene Schlüssellängen: 128, 192 und 256 Bit. LEA verschlüsselt Daten etwa 1,5 bis 2 Mal schneller als AES , der in verschiedenen Softwareumgebungen am weitesten verbreitete Blockchiffre.
Es wird benötigt : 2xEditBox, 2xRadioButton, 4xButton und 1x Progressbar
Unit LEA_Hash.pas :unit LEA_Hash;
interface
{Unit LEA_Hash.pas}
uses Windows, SysUtils, Dialogs;
const
HashTable: array [$0..$3] of Longword = ($CF306227, $4FCE8AC8, $ACE059ED, $4E3079A6);
type
THash = record
A, B, C, D: Longword;
end;
TLEACallback = procedure (BlockIndex: Longword; BlockCount: Longword); stdcall;
function Hash (const Buffer; const Size: Longword; Callback: TLEACallback = nil): THash;
function HashStr (const Str : AnsiString ): THash;
function HashInt (const Int : Integer ): THash;
function HashFile (const FilePath: String; Callback: TLEACallback = nil): THash;
function HashToString (const Hash : THash ): AnsiString;
function StringToHash (const Str : AnsiString ): THash;
function SameHash (const A, B : THash ): Boolean;
function Same (A, B: Pointer; SzA, SzB: Longword): Boolean;
function HashCrypt (const Hash : AnsiString; Key: Longword): AnsiString;
function HashUncrypt (const Hash : AnsiString; Key: Longword): AnsiString;
function IsHash (const Hash : AnsiString ): Boolean;
implementation
const Power2: array [$1..$20] of Longword =($00000001, $00000002, $00000004, $00000008,
$00000010, $00000020, $00000040, $00000080,
$00000100, $00000200, $00000400, $00000800,
$00001000, $00002000, $00004000, $00008000,
$00010000, $00020000, $00040000, $00080000,
$00100000, $00200000, $00400000, $00800000,
$01000000, $02000000, $04000000, $08000000,
$10000000, $20000000, $40000000, $80000000);
function RShl(A, B: Longword): Longword;
begin
Result := (A shl B) or (B shl $20);
end;
type
PLEABuf = ^TLEABuf;
TLEABuf = array [$0..$F] of Longword;
procedure LEAInternal(var A, B, C, D: Longword; Buf: TLEABuf);
Var
I: Integer;
begin
for I := $1 to $F do { Pour chaque double mot du buffer }
begin
Inc(A, Buf[I] + (B or (C xor (not D))));
A := ((A shl $6) xor (A shr $D)) + Buf[Pred(I)];
Inc(B, Buf[I] + (C or (D xor (not A))));
B := ((B shl $A) xor (B shr $5)) + Buf[Pred(I)];
Inc(C, Buf[I] + (D or (A xor (not B))));
C := ((C shl $3) xor (C shr $C)) + Buf[Pred(I)];
Inc(D, Buf[I] + (A or (B xor (not C))));
D := ((D shl $E) xor (D shr $9)) + Buf[Pred(I)];
end;
end;
function Hash(const Buffer; const Size: Longword; Callback: TLEACallback = nil): THash;
Var
V: PLEABuf;
Sz, Cnt: Longword;
Buf: TLEABuf;
E: Pointer;
BlockCount: Longword;
begin
Move(HashTable, Result, $10);
if Size = $0 then Exit;
Cnt := $0;
Sz := Size;
repeat Inc(Sz) until Sz mod $40 = $0;
BlockCount := Sz div $40;
V := @Buffer;
E := Ptr(Longword(@Buffer) + Sz);
with Result do
repeat
begin
ZeroMemory(@Buf, $40);
if Size - Cnt > $3F then Move(V^, Buf, $40) else
begin
Move(V^, Buf, Size - Cnt);
FillMemory(Ptr(Longword(@Buf) + Succ(Size - Cnt)), 1, $80);
end;
LEAInternal(A, B, C, D, Buf);
if Assigned(Callback) then Callback(Cnt div $40, BlockCount);
Inc(V);
Inc(Cnt, $40);
end
until V = E;
end;
function HashStr(const Str: AnsiString): THash;
begin
Result := Hash(PAnsiChar(Str)^, Length(Str));
end;
function HashInt(const Int: Integer): THash;
begin
Result := Hash(Int, SizeOf(Integer));
end;
function HashFile(const FilePath: String; Callback: TLEACallback = nil): THash;
Var
H, M: Longword;
P: Pointer;
begin
ZeroMemory(@Result, 16);
H := CreateFile(PChar(FilePath), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
if H = INVALID_HANDLE_VALUE then Exit;
if GetFileSize(H, nil) = 0 then
begin
Result := Hash('', 0);
CloseHandle(H);
Exit;
end;
try
M := CreateFileMapping(H, nil, PAGE_READONLY, 0, 0, nil);
try
if M = 0 then Exit;
P := MapViewOfFile(M, FILE_MAP_READ, 0, 0, 0);
try
if P = nil then Exit;
Result := Hash(P^, GetFileSize(H, nil), Callback);
finally
UnmapViewOfFile(P);
end;
finally
CloseHandle(M);
end;
finally
CloseHandle(H);
end;
end;
function HashToString(const Hash: THash): AnsiString;
begin
Result := AnsiString(Format('%.8x%.8x%.8x%.8x', [Hash.A, Hash.B, Hash.C, Hash.D]));
end;
function StringToHash(const Str: AnsiString): THash;
begin
if IsHash(Str) then
with Result do
begin
A := StrToInt(Format('$%s', [Copy(Str, 1, 8)]));
B := StrToInt(Format('$%s', [Copy(Str, 9, 8)]));
C := StrToInt(Format('$%s', [Copy(Str, 17, 8)]));
D := StrToInt(Format('$%s', [Copy(Str, 25, 8)]));
end
else ZeroMemory(@Result, 16);
end;
function SameHash(const A, B: THash): Boolean;
begin
Result := CompareMem(@A, @B, 16);
end;
function Same(A, B: Pointer; SzA, SzB: Longword): Boolean;
begin
Result := SameHash(Hash(A, SzA), Hash(B, SzB));
end;
const
Z = #0;
function hxinc(X: AnsiChar): AnsiChar;
const
XInc: array [48..70] of AnsiChar = ('1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
Z, Z, Z, Z, Z, Z, Z, 'B', 'C', 'D', 'E', 'F', '0');
begin
if ord(X) in [48..57, 65..70] then Result := XInc[ord(X)] else Result := Z;
end;
function hxdec(X: AnsiChar): AnsiChar;
const
XDec: array [48..70] of AnsiChar = ('F', '0', '1', '2', '3', '4', '5', '6', '7', '8',
Z, Z, Z, Z, Z, Z, Z, '9', 'A', 'B', 'C', 'D', 'E');
begin
if ord(X) in [48..57, 65..70] then Result := XDec[ord(X)] else Result := Z;
end;
function HashCrypt(const Hash: AnsiString; Key: Longword): AnsiString;
Var
I: Integer;
begin
Result := Hash;
if not IsHash(Hash) then Exit;
for I := 32 downto 1 do
if Key and Power2[I] <> 0 then Result[I] := hxinc(Result[I]) else Result[I] := hxdec(Result[I]);
end;
function HashUncrypt(const Hash: AnsiString; Key: Longword): AnsiString;
Var
I: Integer;
begin
Result := Hash;
if not IsHash(Hash) then Exit;
for I := 32 downto 1 do
if Key and Power2[I] <> 0 then Result[I] := hxdec(Result[I]) else Result[I] := hxinc(Result[I]);
end;
function IsHash(const Hash: AnsiString): Boolean;
Var
I: Integer;
begin
Result := False;
if Length(Hash) <> 32 then Exit;
{$ifndef unicode}
for I := 1 to 32 do if not (Hash[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then Exit;
{$else}
for I := 1 to 32 do if not CharInSet(Hash[I], ['0'..'9', 'A'..'F', 'a'..'f']) then Exit;
{$endif}
Result := True;
end;
end.
Unit SEA.pas :
unit SEA;
interface
{Unit SEA.pas}
uses Windows, LEA_Hash;
type
TSEACallback = procedure (Position, Count: Longword);
TSEAKey = THash;
const
OPERATION_ENCRYPT = $1;
OPERATION_DECRYPT = $2;
OPERATION_FAST = $4;
OPERATION_SECURE = $8;
function ObtainKey(Str: String): TSEAKey;
function Encrypt(var Buffer; const Size: Longword; Key: TSEAKey; const Operation: Longword; Callback: TSEACallback = nil): Boolean;
function EncryptFile(const FilePath: String; const Key: TSEAKey; const Operation: Longword; Callback: TSEACallback = nil): Boolean;
implementation
function RShlLong(A, B: Longword): Longword;
begin
Result := (A shl B) or (A shr ($08 - B));
end;
function RShl(A, B: Byte): Byte;
begin
Result := (A shl B) or (A shr ($08 - B));
end;
function RShr(A, B: Byte): Byte;
begin
Result := (A shr B) or (A shl ($08 - B));
end;
function ObtainKey(Str: String): TSEAKey;
begin
Result := HashStr(Str);
end;
function Encrypt(var Buffer; const Size: Longword; Key: TSEAKey; const Operation: Longword; Callback: TSEACallback = nil): Boolean;
Var
P, E: PByte;
I: Longword;
H: THash;
begin
Result := False;
if (OPERATION_ENCRYPT and Operation <> 0) and (OPERATION_DECRYPT and Operation <> 0) then Exit;
if (OPERATION_ENCRYPT and Operation = 0) and (OPERATION_DECRYPT and Operation = 0) then Exit;
if (OPERATION_FAST and Operation <> 0) and (OPERATION_SECURE and Operation <> 0) then Exit;
if (OPERATION_FAST and Operation = 0) and (OPERATION_SECURE and Operation = 0) then Exit;
if Size = 0 then Exit;
P := @Buffer;
E := Ptr(Longword(@Buffer) + Size);
I := 0;
H := Hash(I, 4, nil);
repeat
if (OPERATION_DECRYPT and Operation <> 0) then P^ := RShr(P^, (Key.B mod $08) xor (I mod $08));
if (Operation and OPERATION_SECURE <> 0) then H := Hash(I, 4, nil);
if (Operation and OPERATION_FAST <> 0) then if Succ(I) mod $FF = 0 then H := Hash(I, 4, nil);
with H do
begin
P^ := (Key.B mod $FF) xor (P^ xor (C mod $FF));
P^ := (Key.A mod $FF) xor (P^ xor (B mod $FF));
P^ := (Key.D mod $FF) xor (P^ xor (A mod $FF));
P^ := (Key.C mod $FF) xor (P^ xor (D mod $FF));
end;
if (OPERATION_ENCRYPT and Operation <> 0) then P^ := RShl(P^, (Key.B mod $08) xor (I mod $08));
if Assigned(Callback) then Callback(Succ(I), Size);
Inc(P);
Inc(I);
until P = E;
Result := True;
end;
function EncryptFile(const FilePath: String; const Key: TSEAKey; const Operation: Longword; Callback: TSEACallback = nil): Boolean;
Var
H, M: Longword;
P: Pointer;
begin
Result := False;
H := CreateFile(PChar(FilePath), GENERIC_READ or GENERIC_WRITE, 0,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
if H = INVALID_HANDLE_VALUE then Exit;
if GetFileSize(H, nil) = 0 then
begin
CloseHandle(H);
Exit;
end;
try
M := CreateFileMapping(H, nil, PAGE_READWRITE, 0, 0, nil);
try
if M = 0 then Exit;
P := MapViewOfFile(M, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, 0);
try
if P = nil then Exit;
Result := Encrypt(P^, GetFileSize(H, nil), Key, Operation, Callback);
finally
UnmapViewOfFile(P);
end;
finally
CloseHandle(M);
end;
finally
CloseHandle(H);
end;
end;
end.
Unit1 :
uses SEA
var
Running: Boolean;
//
procedure Callback(Position, Count: Longword);
begin
if (Position mod 32768 <> 0) and (Position <> Count) then Exit;
Form1.Bar.Max := Count;
Form1.Bar.Position := Position;
Application.ProcessMessages;
end;
procedure TForm1.FileEditEnter(Sender: TObject);
begin
if OpenDlg.Execute then
begin
FileEdit.Text := ExtractFileName(OpenDlg.FileName);
EncryptBtn.Enabled := FileExists(OpenDlg.FileName);
DecryptBtn.Enabled := FileExists(OpenDlg.FileName);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
randomize;
end;
procedure TForm1.RandomBtnClick(Sender: TObject);
begin
KeyEdit.Text := Format('%x%x%x%x%x', [random(256),
random(256),
random(256),
random(256),
random(256)]);
end;
procedure TForm1.EncryptBtnClick(Sender: TObject);
const
CryptType: array [Boolean] of Longword = (OPERATION_FAST, OPERATION_SECURE);
begin
if Sender is TButton then with TButton(Sender) do
try
EncryptBtn.Enabled := False;
DecryptBtn.Enabled := False;
Running := True;
if not EncryptFile(OpenDlg.FileName, ObtainKey(KeyEdit.Text), Tag or CryptType[SecureOption.Checked], Callback) then
raise Exception.Create('Error Encrypting/Decrypting the file.');
finally
Bar.Position := 0;
EncryptBtn.Enabled := True;
DecryptBtn.Enabled := True;
Running := False;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if Running then
begin
Action := caNone;
MessageDlg('Impossible to stop during encryption/decryption, the file would then be half encrypted and half decrypted, which would make its reconstruction almost impossible.', mtWarning, [mbOK], 0);
end;
end;
Keine Kommentare:
Kommentar veröffentlichen