unit uMulCrypt;

interface

uses    uUtilities, IdTCPClient, DCPRijndael, MD5, SysUtils, DCPTwofish,
        Dialogs;    

const   KeyAnim = 0;
        KeyArt = 1;
        KeyGump = 2;
        KeyTex = 3;

        Keys = 4;

type    TCryptKey = Array[0..15] of Byte;

        TMulCrypt = Class
                private
                        UserName, Password : String;
                        TcpClient : TIdTcpClient;
                        Crypt : TDCP_Rijndael;
                        Crypts : Array[0..Keys] of TDCP_Twofish;
                        KeyLoaded : Array[0..Keys-1] of Boolean;
                        ProgramID : Byte;
                        procedure GetKey( Key : Byte );
                public
                        constructor Create( UserName, Password : String; ProgramID : Byte );
                        destructor Free;
                        function Test( Key : Byte ) : Boolean;
                        procedure InitKey( Key : Byte; CryptKey : TCryptKey );                        
                        function EncryptIndexRecordArt( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function EncryptIndexRecordAnim( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function EncryptIndexRecordGump( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function EncryptIndexRecordTex( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function DecryptIndexRecordArt( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function DecryptIndexRecordAnim( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function DecryptIndexRecordGump( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
                        function DecryptIndexRecordTex( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;                        
        end;

implementation

procedure TMulCrypt.GetKey( Key : Byte );
var     Count, I : Word;
        Buffer, CryptBuffer, ReadBuffer : PByteArray;
        Md5 : TMD5Digest;
        Read, Len : LongWord;
        InitVector : PByteArray;
        Allowed : Boolean;
begin
        GetMem( Buffer, 64 );
        GetMem( CryptBuffer, 64 );

        Buffer^[0] := Random( $FF );
        Buffer^[1] := ProgramID;
        Buffer^[2] := Key;
        Buffer^[3] := Random( $FF );
        
        for I := 1 to Length( UserName ) do begin
                Buffer^[3+I] := Ord( UserName[I] );
        end;
        for I := Length( UserName )+1 to 20 do begin
                Buffer^[3+I] := 0;
        end;

        Md5 := Md5String( PassWord );
        for I := 0 to 15 do begin
                Buffer^[24+I] := Md5.v[I];
        end;

        for I := 40 to 47 do begin
                Buffer^[I] := Random( $FF );
        end;

        for I := 48 to 63 do begin
                Buffer^[I] := Random( $FF );
        end;

        for I := 0 to 3 do
                Crypt.EncryptECB( Buffer^[I*16], CryptBuffer^[I*16] );                       

        GetMem( ReadBuffer, 256 );

        Allowed := False;
        Read := 0;

        try
                TcpClient.Connect;
                Sleep( 10 );
                if TcpClient.Connected then begin
                        TcpClient.OpenWriteBuffer;
                        TcpClient.WriteBuffer( CryptBuffer^[0], 64 );
                        TcpClient.CloseWriteBuffer;

                        Count := 0;
                        while (Read < 17) and (Count < 500) and TcpClient.Connected do begin
                                Len := TcpClient.Socket.Recv( ReadBuffer^[Read], 255 );
                                if Len > 0 then begin
                                        if Read = 0 then begin
                                                if ReadBuffer^[0] = 1 then
                                                        Allowed := True
                                                else
                                                        Break;
                                        end;

                                        Read := Read + Len;
                                end;
                                Sleep( 10 );
                        end;

                        TcpClient.Disconnect;
                end
                else begin
                        ShowMessage( 'Falsches Login oder Passwort oder noch kein freigeschalteter Char vorhanden.' );

                        FreeMem( ReadBuffer );
                        FreeMem( Buffer );
                        FreeMem( CryptBuffer );
                        Exit;
                end;
        except
                ShowMessage( 'Konnte nicht zum Mulcryptserver verbinden.' );
                Halt;
        end;

        for I := 0 to 15 do begin
                ReadBuffer^[ 1+I ] := ReadBuffer^[ 1+I ] xor Buffer^[48+I];
        end;

        if Allowed and (Read >= 17) then begin
                Crypt.DecryptECB( ReadBuffer^[1], CryptBuffer^[0] );

                GetMem( InitVector, 16 );
                for I := 0 to 15 do
                        InitVector^[I] := 0;
                Crypts[ Key ].Init( CryptBuffer^[ 0 ], 128, InitVector );
                FreeMem( InitVector );
                KeyLoaded[ Key ] := True;
        end;

        FreeMem( ReadBuffer );
        FreeMem( Buffer );
        FreeMem( CryptBuffer );
end;

constructor TMulCrypt.Create( UserName, Password : String; ProgramID : Byte );
var     Key : Array[0..15] of Byte;
        InitVektor : PByteArray;
        I : Integer;
begin
        Self.UserName := UserName;
        Self.Password := PassWord;
        Self.ProgramID := ProgramID;

        Key[0] := $8F;
        Key[1] := $BA;
        Key[2] := $F1;
        Key[3] := $86;
        Key[4] := $E0;
        Key[5] := $C4;
        Key[6] := $61;
        Key[7] := $06;
        Key[8] := $2E;
        Key[9] := $94;
        Key[10] := $97;
        Key[11] := $84;
        Key[12] := $05;
        Key[13] := $E7;
        Key[14] := $42;
        Key[15] := $C3;

        TcpClient := TIdTcpClient.Create( nil );
        TcpClient.Host := 'uo-mittelerde.ch';
        TcpClient.Port := 2595;

        Crypt := TDCP_Rijndael.Create( nil );

        GetMem( InitVektor, 16 );
        for I := 0 to 15 do
                InitVektor^[I] := 0;
        
        Crypt.Init( Key, 128, InitVektor );
        FreeMem( InitVektor );

        for I := 0 to Keys-1 do begin
                Crypts[I] := TDCP_Twofish.Create( nil );
                KeyLoaded[I] := False;
        end;
end;

destructor TMulCrypt.Free;
var     I : Integer;
begin
        for I := 0 to Keys-1 do begin
                Crypts[I].Free;
        end;

        Crypt.Free;
        TcpClient.Free;
end;

procedure TMulCrypt.InitKey( Key : Byte; CryptKey : TCryptKey );
var     InitVector : PByteArray;
        I : Integer;
begin
        GetMem( InitVector, 16 );
        for I := 0 to 15 do
                InitVector^[I] := 0;
        Crypts[ Key ].Init( CryptKey, 128, InitVector );
        FreeMem( InitVector );
        KeyLoaded[ Key ] := True;
end;

function TMulCrypt.Test( Key : Byte ) : Boolean;
begin
        if KeyLoaded[ Key ] then begin
                Result := True;
        end
        else begin
                GetKey( Key );
                if KeyLoaded[ Key ] then begin
                        Result := True;
                end
                else begin
                        Result := False;
                end;
        end;
end;

function TMulCrypt.EncryptIndexRecordArt( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyArt ] then begin
                GetKey( KeyArt );

                if not KeyLoaded[ KeyArt ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyArt ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.EncryptIndexRecordAnim( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyAnim ] then begin
                GetKey( KeyAnim );

                if not KeyLoaded[ KeyAnim ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyAnim ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.EncryptIndexRecordGump( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyGump ] then begin
                GetKey( KeyGump );

                if not KeyLoaded[ KeyGump ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyGump ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.EncryptIndexRecordTex( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyTex ] then begin
                GetKey( KeyTex );

                if not KeyLoaded[ KeyTex ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyTex ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.DecryptIndexRecordArt( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyArt ] then begin
                GetKey( KeyArt );

                if not KeyLoaded[ KeyArt ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyArt ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.DecryptIndexRecordAnim( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyAnim ] then begin
                GetKey( KeyAnim );

                if not KeyLoaded[ KeyAnim ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyAnim ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.DecryptIndexRecordGump( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyGump ] then begin
                GetKey( KeyGump );

                if not KeyLoaded[ KeyGump ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyGump ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

function TMulCrypt.DecryptIndexRecordTex( ID : Word; var IndexRecord : TIndexRecord ) : Boolean;
var     Buf, Buf2 : Array[0..15] of Byte;
        Md5 : TMd5Digest;
        I, P : Integer;
begin
        if not KeyLoaded[ KeyTex ] then begin
                GetKey( KeyTex );

                if not KeyLoaded[ KeyTex ] then begin
                        Result := False;
                        Exit;
                end;
        end;

        Md5 := Md5String( Format( '%d-%d-%d-%d', [ID,ID and $FF,(ID and $FF00) shr 8, 42] ) );

        for I := 0 to 15 do
                Buf[ I ] := Md5.v[ I ];

        Crypts[ KeyTex ].EncryptECB( Buf[0], Buf2[0] );

        P := ID mod 4;
        for I := 0 to 11 do begin
                IndexRecord.B[ I ] := IndexRecord.B[ I ] xor Buf2[ P + I ];
        end;

        Result := True;
end;

end.
