📄 msgcipher.pas
字号:
{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 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.
}
{ Modified: AidAim Software, 2003}
unit MsgCipher;
interface
{$I MsgVer.inc}
{$I Ver.inc}
uses
{$IFDEF LINUX}
Types,
{$ENDIF}
SysUtils, Classes,
{$IFDEF DEBUG_LOG}
MsgDebug,
{$ENDIF}
MsgDECUtil, MsgHash;
const {ErrorCode's for ECipherException}
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
PCipherRec = ^TCipherRec;
TCipherRec = packed record
case Integer of
0: (X: array[0..7] of Byte);
1: (A, B: LongWord);
end;
type
ECipherException = class(Exception)
public
ErrorCode: Integer;
end;
{all Cipher Classes in this Unit, a good Selection}
TCipher_Blowfish = class;
TCipher_Twofish = class;
TCipher_Square = class;
TCipherMode = (cmCTS, cmCBC, cmCFB, cmOFB, cmECB, cmCTSMAC, cmCBCMAC, cmCFBMAC);
{ the Cipher Modes:
cmCTS 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 Cipher Block Chaining
cmCFB K-bit 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
}
TCipherClass = class of TCipher;
TCipher = class(TProtection)
private
FMode: TCipherMode;
FHash: THash;
FHashClass: THashClass;
FKeySize: Integer;
FBufSize: Integer;
FUserSize: Integer;
FBuffer: Pointer;
FVector: Pointer;
FFeedback: Pointer;
FUser: Pointer;
FFlags: Integer;
function GetHash: THash;
procedure SetHashClass(Value: THashClass);
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 TProtection 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: TProtection);
destructor Destroy; override;
class function MaxKeySize: Integer;
{performs a Test of correct work}
class function SelfTest: Boolean;
{initialization form the 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 Cipher Mode = cmXXX}
property Mode: TCipherMode read FMode write FMode;
{the Current Hash-Object, to build a Digest from InitKey()}
property Hash: THash read GetHash;
{the Class of the Hash-Object}
property HashClass: THashClass 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 Hash.DigestKey^ include the encrypted Hash-Key}
property HasHashKey: Boolean index 0 read GetFlag;
end;
// now the Cipher's
TCipher_Blowfish = class(TCipher)
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;
TCipher_Twofish = class(TCipher)
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;
TCipher_Square = class(TCipher)
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: TCipherClass;
procedure SetDefaultCipherClass(CipherClass: TCipherClass);
procedure RaiseCipherException(const ErrorCode: Integer; const Msg: String);
function RegisterCipher(const ACipher: TCipherClass; const AName, ADescription: String): Boolean;
function UnregisterCipher(const ACipher: TCipherClass): Boolean;
function CipherList: TStrings;
procedure CipherNames(List: TStrings);
function GetCipherClass(const Name: String): TCipherClass;
function GetCipherName(CipherClass: TCipherClass): 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
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF}
MsgDecConst;
{$I cipher.inc}
{$I square.inc}
const
FDefaultCipherClass : TCipherClass = TCipher_Blowfish;
FCipherList : TStringList = nil;
function DefaultCipherClass: TCipherClass;
begin
Result := FDefaultCipherClass;
end;
procedure SetDefaultCipherClass(CipherClass: TCipherClass);
begin
if CipherClass = nil then FDefaultCipherClass := TCipher_Blowfish
else FDefaultCipherClass := CipherClass;
end;
procedure RaiseCipherException(const ErrorCode: Integer; const Msg: String);
var
E: ECipherException;
begin
E := ECipherException.Create(Msg);
E.ErrorCode := ErrorCode;
raise E;
end;
function RegisterCipher(const ACipher: TCipherClass; 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: TCipherClass): 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): TCipherClass;
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 := TCipherClass(FCipherList.Objects[I]);
Exit;
end;
I := FCipherList.IndexOfName(N);
if I >= 0 then Result := TCipherClass(FCipherList.Objects[I]);
end;
function GetCipherName(CipherClass: TCipherClass): String;
var
I: Integer;
begin
I := CipherList.IndexOfObject(Pointer(CipherClass));
if I >= 0 then Result := FCipherList.Names[I]
else Result := GetShortClassName(CipherClass);
end;
function TCipher.GetFlag(Index: Integer): Boolean;
begin
Result := FFlags and (1 shl Index) <> 0;
end;
procedure TCipher.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 TCipher.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 TCipher.InitEnd(IVector: Pointer);
begin
if IVector = nil then Encode(Vector)
else Move(IVector^, Vector^, BufSize);
Move(Vector^, Feedback^, BufSize);
Initialized := True;
end;
class procedure TCipher.GetContext(var ABufSize, AKeySize, AUserSize: Integer);
begin
ABufSize := 0;
AKeySize := 0;
AUserSize := 0;
end;
class function TCipher.TestVector: Pointer;
begin
Result := GetTestVector;
end;
procedure TCipher.Encode(Data: Pointer);
begin
end;
procedure TCipher.Decode(Data: Pointer);
begin
end;
constructor TCipher.Create(const Password: String; AProtection: TProtection);
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 TCipher.Destroy;
begin
Protect;
ReallocMem(FVector, 0);
ReallocMem(FFeedback, 0);
ReallocMem(FBuffer, 0);
ReallocMem(FUser, 0);
FHash.Release;
FHash := nil;
inherited Destroy;
end;
class function TCipher.MaxKeySize: Integer;
var
Dummy: Integer;
begin
GetContext(Dummy, Result, Dummy);
end;
class function TCipher.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 TCipher.Init(const Key; Size: Integer; IVector: Pointer);
begin
end;
procedure TCipher.InitKey(const Key: String; IVector: Pointer);
var
I: Integer;
begin
Hash.Init;
Hash.Calc(PChar(Key)^, Length(Key));
Hash.Done;
I := Hash.DigestKeySize;
if I > FKeySize then I := FKeySize; {generaly will truncate to large Keys}
Init(Hash.DigestKey^, I, IVector);
EncodeBuffer(Hash.DigestKey^, Hash.DigestKey^, Hash.DigestKeySize);
Done;
SetFlag(0, True);
end;
procedure TCipher.Done;
begin
if MemCompare(FVector, FFeedback, FBufSize) = 0 then Exit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -