Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0 (https://www.delphipraxis.net/214436-hilfe-bei-umstellung-unit-dec5-1-zu-dec6-0-a.html)

haentschman 11. Jan 2024 08:52


Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallöle...8-)
Ich habe eine Unit die einfach Decrypt/Enrypt macht. (Passwörter etc.) Die verschlüsselte Werte stehen z.B. in der DB.

Da ich mal modernisieren wollte, nehme ich eben mal DEC6.0...:wink: Da ich von der Thematik keine Ahnung habe, brauche ich Hilfe. Die Umstellungen sind zu groß. :?
Bis ValidHash(HashClass).KDFx = undeklariert bin ich gekommen. Dann habe ich aufgegeben.

PS: Die alten Passwörter müssen auch wieder lesbar sein...:wink:
PS: Eine Erklärung wäre auch schön. :wink:

Danke.

haentschman 14. Jan 2024 12:53

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
:cry:

TurboMagic 15. Jan 2024 08:20

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Muss ich mir mal anschauen, heute wird's aber eher nix, eher morgen.
Zuerst muss man die Units ändern, die sind ja umbenannt und teilweise weiter
unterteilt.

Kas Ob. 15. Jan 2024 08:43

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hi,
Zitat:

Zitat von haentschman (Beitrag 1531864)
:cry:

TurboMagic said will take a look, i hesitated yesterday to write the following:

I can do it even i have never used DEC v5 and have very shallow knowledge with v6, but i believe i can figure it out, BUT i need few things to make sure not wasting my time and yours:

1) the original code, the code was/is working with DEC v5.1, not a modified one.
2) Three handled/hashed data
A) a v5.1 hashed/encrypted password with length less than 7 chars, the password it self is not needed.
B) a v5.1 hashed/encrypted password with length more than 16 chars, the password it self is not needed.
C) a v5.1 password with hashed/encrypted form, the length preferably less than 7.
D) repeat the above in English chars only, also one more with copy of A,B and C with Unicode chars or some exotic characters if your application allow it.

These are important for every one (specially you) to make sure the new code is compatible and will not break you DB.

haentschman 15. Jan 2024 08:45

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
@TurboMagic
Dankeschön...keinen Stress. 8-)

Vieleicht hast auch dann mal 5 Minuten Zeit, mir das "Grundprinzip" (Was brauche ich wofür...für die Zukunft) zu erkären.

Danke...

Nachtrag:
Ich stelle die Daten mal zusammen...

TurboMagic 15. Jan 2024 20:50

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hast du auch schon mal in den DOCS Unterordner geschaut?
Da ist eine Doku drin... ;-) Ich glaub' sogar einigermaßen umfangreich,
was für ein Open Source Projekt nicht unbedingt üblich ist... ;-)

TurboMagic 15. Jan 2024 20:50

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Yes, that would be good to have!

TurboMagic 15. Jan 2024 21:20

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Zitat:

Zitat von haentschman (Beitrag 1531897)
@TurboMagic
Dankeschön...keinen Stress. 8-)

Vieleicht hast auch dann mal 5 Minuten Zeit, mir das "Grundprinzip" (Was brauche ich wofür...für die Zukunft) zu erkären.

Danke...

Nachtrag:
Ich stelle die Daten mal zusammen...

Hier mal was ungetestetes, aber es compiliert:

Delphi-Quellcode:
unit Tools.Crypt;

interface

uses
  System.SysUtils,
  DECUtil, DECHash,
  //DECCipher, DECFmt;
  DECHashBase, DECCipherBase, DECCiphers, DECFormatBase, DECFormat,
  DECHashAuthentication, DECRandom;

const
  conKey = 'aYr14iaz8u)xO7Ok';

var
  CipherMode: TCipherMode = cmCBCx;
  HashClass: TDECHashClass = THash_SHA256;
  TextFormat: TDECFormatClass = TFormat_MIME64;
  KDFIndex: LongWord = 1;

type
  TToolsCrypt = class
  public
    class function Decrypt(aHash: string; aKey: string = ''): string;
    class function Encrypt(aText: string; aKey: string = ''): string;
  end;

implementation

{ TToolsCrypt }

class function TToolsCrypt.Decrypt(aHash, aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  Salt: RawByteString; //Binary;
  Data: RawByteString;
  Check: RawByteString;
  Pass: RawByteString;
  PassBytes: TBytes;
  Len: Integer;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    Salt := ValidFormat(TextFormat).Decode(RawByteString(aHash));
    Len := Length(Salt) - 16 - Cipher.Context.BufferSize;
    Data := Copy(Salt, 17, Len);
    Check := Copy(Salt, Len + 17, Cipher.Context.BufferSize);
    SetLength(Salt, 16);
    PassBytes := TDECHashAuthentication(ValidHash(HashClass)).KDFx(aKey[1],
                                                                   Length(aKey) * 2,
                                                                   Salt[1],
                                                                   Length(Salt),
                                                                   Cipher.Context.KeySize,
                                                                   KDFIndex);
    SetLength(Pass, Length(PassBytes));
    Move(PassBytes[0], Pass[low(Pass)], Length(PassBytes));

    Cipher.Mode := CipherMode;
    Cipher.Init(Pass);
    SetLength(Result, Len div 2);
    Cipher.Decode(Data[1], Result[1], Len);
    if Check <> Cipher.CalcMAC then
    begin
      Result := '';
    end;
  finally
    Cipher.Free;
    //ProtectBinary(Salt);
    ProtectString(Salt);
    ProtectString(Data);
    ProtectString(Check);
    ProtectString(Pass);
  end;
end;

class function TToolsCrypt.Encrypt(aText, aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  SaltBytes : TBytes;
  Salt: RawByteString; //Binary;
  Data: RawByteString; //Binary;
  Pass: RawByteString; //Binary;
  PassBytes: TBytes;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    SaltBytes := RandomBytes(16); //RandomBinary(16);
    SetLength(Salt, Length(SaltBytes));
    Move(SaltBytes[0], Salt[low(Salt)], Length(SaltBytes));

    PassBytes := TDECHashAuthentication(ValidHash(HashClass)).KDFx(aKey[1],
                                                                   Length(aKey) * 2,
                                                                   Salt[1],
                                                                   Length(Salt),
                                                                   Cipher.Context.KeySize,
                                                                   KDFIndex);
    SetLength(Pass, Length(PassBytes));
    Move(PassBytes[0], Pass[low(Pass)], Length(PassBytes));

    Cipher.Mode := CipherMode;
    Cipher.Init(Pass);
    SetLength(Data, Length(aText) * 2);
    Cipher.Encode(aText[1], Data[1], Length(Data));
    Result := string(ValidFormat(TextFormat).Encode(Salt + Data + Cipher.CalcMAC));
  finally
    Cipher.Free;
    ProtectString(Salt);
    ProtectString(Data);
    ProtectString(Pass);
  end;
end;

end.
  1. Units wurden sprechender benannt
  2. Es wurden Units aufgesplittet, daher sind weitere einzubinden
  3. Der in DEC definierte Datentyp Binary, ein Alias zu AnsiString, wurde entfernt
  4. DEC nutzt heutzutage lieber TBytes oder teilweise RawByteString
  5. Der obige Code basiert auf meiner aktuellen Entwicklungsversion, sollte aber auch mit dem aktuellen Release 6.4.1 kompatibel sein

DU erwänst oben DEC 6.0. Meinst du wirklich 6.0 oder eine neuere? Falls 6.0 warum nutzt du diese und nicht eine neuere?

Grüße
TurboMagic

haentschman 16. Jan 2024 06:24

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Liste der Anhänge anzeigen (Anzahl: 5)
Moin...8-)

Zitat:

Zitat von TurboMagic (Beitrag 1531956)
Meinst du wirklich 6.0

...ich meinte den Wechsel von 5 auf 6. Ich habe auch 5.2 statt 5.1 im alten Code. Das neue DEC im QT ist die letzte Version aus dem GitHub...:wink:

Danke für deine Zeit...:cheer::kiss:

Ich melde mich mit dem Ergebnis. :wink:


Rückmeldung:
Zugriffsverletzung im "TDECHashAuthentication" (Video)

Anbei:
1. Project für Crypt/Decrypt
2. Source 5.2
3. Source 6.4.1
4. Muster SQL normal/Crypt

EdAdvokat 17. Jan 2024 14:54

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Wie es aussieht gibt es in diesem Thread nichts Neues - oder doch? Hat sich TurboMagic mal wieder dazu gemeldet?

Ich habe auch versucht das Projekt zum laufen zu bringen und komme erwartungsgemäß ebenfalls nur bis zur Exception Accsess Violation, wie im Video anschaulich dargestellt.
Meine bescheidenen Debuggig-Versuche erbrachten kein brauchbares Eregnis.
Also wohl Ergebnislosigkeit in dieser Sache KDF.

@haentschman: Welche Werte speicherst Du in der DB?
verwendest Du die Schlüssel für ein symetrisches Chiffrierverfahren oder für andere Zwecke?

In meinem KeyGenerations-Programm erstelle ich aus einem Master-Key diverse Key-Ableitungen, die ich dann nummerisch sortiert speichere. Dazu nutze ich HAMAC und
wahlweise auch BCrypt-Algos.
Somit wäre es möglich, dass ausgehend von einem Master-Key, der den Kommunikationspartnern bekannt ist, diese wiederum Key-Ableitungen vornehmen und speichern.
So könnte dann beispielsweise mit der 5. Key-Ableitung eine AES-Chiffrierung vorgenommen werden.
Diese Key-Liste ist natürlich besonders schützenswert und daher als Ganzes ebenfalls zu sichern.
Welche Erfahrungen hast Du praktisch mit der Key-Ableitung (KDF) gemacht?

TurboMagic 17. Jan 2024 16:59

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hallo,

nun ja, ich kann nicht dauernd DP lesen, so sehr ich evtl. auch möchte.
Es gibt da halt noch sowas, das nennt sich Arbeitgeber...

=> ich hab' das mal soweit abends umgesetzt gehabt, dass es Compiliert.
Dass es jetzt zur Laufzeit crasht is blöd, muss aber nacher weiter untersucht werden.
Aber eines nach dem Anderen...

Grüße
TurboMagic

TurboMagic 17. Jan 2024 20:04

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hallo,

möglicherweise hab' ich es gelöst:

Statt des Typcasts PassBytes := TDECHashAuthentication(...
muss es PassBytes := THash_SHA256(... sein.

Man merkt es schon am letzten Assert in der KDFx drin,
da DigestSize nur in einer konkreten Klasse vernünftig
funktionieren kann.

=> mal mit deinen Testdaten testen.

Grüße
TurboMagic

EdAdvokat 17. Jan 2024 21:20

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
...ja es funktioniert nun. Das wird es wohl gewesen sein.

@haentschman sollte sich das nun mal ansehen und sein ok dazu geben mit den eigenen Werten.

EdAdvokat 17. Jan 2024 21:26

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
auch ein Test mit den SQL-Werten von @haentschman klappt es. Enc und Dec so wie in den SQL-Dateien vermerkt funktioniert nun. Mal schauen was er dazu meint.

haentschman 18. Jan 2024 06:53

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Moin...8-)

...ihr habt mir das Testen schon fast abgenommen. :thumb: Ich werde erst am Wochenende dazu kommen, es live mit dem Projekt zu testen.

Danke an Euch...:cheer: :cheers:

Zitat:

nun ja, ich kann nicht dauernd DP lesen, so sehr ich evtl. auch möchte.
Trotzdem perfekt. Selbst wenn es einen Monat gedauert hätte...:zwinker:

haentschman 26. Jan 2024 06:56

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Liste der Anhänge anzeigen (Anzahl: 1)
Moin...8-)

...hat etwas länger gedauert.:zwinker:

1. PassBytes := THash_SHA256( getauscht
2. schöne Zugriffsverletzung wie vorher :shock: ...wie jetzt?
3. Erinnerung an "...nur in einer konkreten Klasse vernünftig funktionieren kann."
4. Klasse erzeugt (Bild)
5. und siehe da...es funktioniert. :cheer: (Bild)

...und keine Leaks. 8-)

PS: Warnung beseitigt: TextFormat: TDECFormatClass = TFormat_Base64; statt TextFormat: TDECFormatClass = TFormat_MIME64;


Danke nochmal...

EdAdvokat 26. Jan 2024 14:17

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Ich frage mal ganz naiv: muß wirklich HashClass:=TDECHashClass(THash_SHA256.create); und deren Freigabe eingefügt werden.

ich habe in der class function ToolCrypt.Encode und ...Decode lediglich
PassBytes := THash_SHA256.KDFx(aKey[1],...geändert, ohne
HashClass:=TDECHashClass(THash.SHA256.create); und deren Freigabe aufzurufen.
Das hat ohne Fehler und Warnungen compiliert.

Muß ich wirklich das create aufrufen?
TDECFormatClass rufe ich ja auch nicht mit create auf

Ich habe beide Varianten ausprobiert und das gleiche Ergebnis: keine Fehler, keine Warnungen

haentschman 26. Jan 2024 14:44

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi...8-)

im Original ist:
Delphi-Quellcode:
PassBytes := TDECHashAuthentication(ValidHash(HashClass)).KDFx(aKey[1],
...
...da fehlt was bei dir
Delphi-Quellcode:
THash_SHA256.KDFx(aKey[1]
...
-> ValidHash(HashClass)
...mit
Delphi-Quellcode:
PassBytes := THash_SHA256(ValidHash(HashClass)).KDFx(aKey[1],
...
...ergibt es eine Zugriffsverletzung.

Delphi-Quellcode:
THash_SHA256.KDFx(aKey[1]
...probiere ich mal aus. (geht)

PS: Wofür ist diese Prüfung da? (ValidHash)

:wink:

EdAdvokat 26. Jan 2024 15:04

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Damit wir nicht nur über Code-Schnipsel sprechen hier die gesamte unit, die nun funktioniert,
wahlweise ergänzt mit HashClass:= TDECHashClass(THash.SHA256.create); :
Delphi-Quellcode:
unit Tools.Crypt;

interface

uses
  System.SysUtils,
  DECUtil, DECHash,
  DECHashBase, DECCipherBase, DECCiphers, DECFormatBase, DECFormat,
  DECHashAuthentication, DECRandom;

const
  conKey = 'aYr14iaz8u)xO7Ok';

var
  CipherMode: TCipherMode = cmCBCx;
  HashClass: TDECHashClass = THash_SHA256;
  TextFormat: TDECFormatClass = TFormat_Base64;
  KDFIndex: LongWord = 1;

type
  TToolsCrypt = class
  public
    class function Decrypt(aHash: string; aKey: string = ''): string;
    class function Encrypt(aText: string; aKey: string = ''): string;
  end;

implementation

{ TToolsCrypt }

class function TToolsCrypt.Decrypt(aHash, aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  Salt: RawByteString; //Binary;
  Data: RawByteString;
  Check: RawByteString;
  Pass: RawByteString;
  PassBytes: TBytes;
  Len: Integer;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    Salt := ValidFormat(TextFormat).Decode(RawByteString(aHash));
    Len := Length(Salt) - 16 - Cipher.Context.BufferSize;
    Data := Copy(Salt, 17, Len);
    Check := Copy(Salt, Len + 17, Cipher.Context.BufferSize);
    SetLength(Salt, 16);
    PassBytes := THash_SHA256.KDFx(aKey[1],
                                  Length(aKey) * 2,
                                  Salt[1],
                                  Length(Salt),
                                  Cipher.Context.KeySize,
                                  KDFIndex);

    SetLength(Pass, Length(PassBytes));
    Move(PassBytes[0], Pass[low(Pass)], Length(PassBytes));

    Cipher.Mode := CipherMode;
    Cipher.Init(Pass);
    SetLength(Result, Len div 2);
    Cipher.Decode(Data[1], Result[1], Len);
    if Check <> Cipher.CalcMAC then
    begin
      Result := '';
    end;
  finally
    Cipher.Free;
    //ProtectBinary(Salt);
    ProtectString(Salt);
    ProtectString(Data);
    ProtectString(Check);
    ProtectString(Pass);
  end;
end;

class function TToolsCrypt.Encrypt(aText, aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  SaltBytes : TBytes;
  Salt: RawByteString; //Binary;
  Data: RawByteString; //Binary;
  Pass: RawByteString; //Binary;
  PassBytes: TBytes;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    SaltBytes := RandomBytes(16); //RandomBinary(16);
    SetLength(Salt, Length(SaltBytes));
    Move(SaltBytes[0], Salt[low(Salt)], Length(SaltBytes));

    PassBytes := THash_SHA256.KDFx(aKey[1],
                                  Length(aKey) * 2,
                                  Salt[1],
                                  Length(Salt),
                                  Cipher.Context.KeySize,
                                  KDFIndex);

    SetLength(Pass, Length(PassBytes));
    Move(PassBytes[0], Pass[low(Pass)], Length(PassBytes));

    Cipher.Mode := CipherMode;
    Cipher.Init(Pass);
    SetLength(Data, Length(aText) * 2);
    Cipher.Encode(aText[1], Data[1], Length(Data));
    Result := string(ValidFormat(TextFormat).Encode(Salt + Data + Cipher.CalcMAC));
  finally
    Cipher.Free;
    ProtectString(Salt);
    ProtectString(Data);
    ProtectString(Pass);
  end;
end;

end.
Hier wird
Delphi-Quellcode:
PassBytes:= THash_SHA256.KDFx(aKey[1],
                                  Length(aKey) * 2,
                                  Salt[1],
                                  Length(Salt),
                                  Cipher.Context.KeySize,
                                  KDFIndex);
anders als zuvor aufgerufen.
Diese unit funktioniert bei mir mit oder ohne den gesonderten Aufruf von HashClass:=.....
ohne Fehler und Warnungen
Schau noch mal in #12 nach

haentschman 26. Jan 2024 15:10

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Zitat:

Diese unit funktioniert bei mir mit oder ohne den gesonderten Aufruf von HashClass:=.....
ohne Fehler und Warnungen
D10.2 <> D12 ... macht vieleicht was aus. :gruebel:

EdAdvokat 26. Jan 2024 15:28

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
ich nutze aktuell die CE 11.3 auch für dieses Projekt mit Windows 11
TurboMagic nutzt wohl Delphi 12 und der hat den Fehler erkannt und die Änderung beschrieben. Also sollte es nicht an der Delphiversion liegen können.

Kas Ob. 26. Jan 2024 17:29

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
I looked at the library,
ValidFormat and ValidHash supposed to be working as factory design, you feed them a class type and will get a class, this implementation to remove the need to hardcode a switch between algorithms.

https://en.wikipedia.org/wiki/Factory_method_pattern
but with simple function instead of a class.

TurboMagic 26. Jan 2024 17:50

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Zitat:

Zitat von Kas Ob. (Beitrag 1532628)
I looked at the library,
ValidFormat and ValidHash supposed to be working as factory design, you feed them a class type and will get a class, this implementation to remove the need to hardcode a switch between algorithms.

https://en.wikipedia.org/wiki/Factory_method_pattern
but with simple function instead of a class.

I'm not completely sure yet what you want to tell with this.
Is this something which should be changed in DEC?
Did I mess up something? If so, how should it be changed?
Or was this just some explanation of where the OP's problem comes from?

TurboMagic 26. Jan 2024 17:52

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Zitat:

Zitat von EdAdvokat (Beitrag 1532615)
ich nutze aktuell die CE 11.3 auch für dieses Projekt mit Windows 11
TurboMagic nutzt wohl Delphi 12 und der hat den Fehler erkannt und die Änderung beschrieben. Also sollte es nicht an der Delphiversion liegen können.

Nee, liegt nicht an der Delphi version. Ich habe bis vor kurzem noch hauptsächlich die 11.3 genutzt.
Ob ich die 12.0 nutze sag' ich nicht. Ätsch! ;-)

Kas Ob. 27. Jan 2024 13:22

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Zitat:

Zitat von TurboMagic (Beitrag 1532633)
Zitat:

Zitat von Kas Ob. (Beitrag 1532628)
I looked at the library,
ValidFormat and ValidHash supposed to be working as factory design, you feed them a class type and will get a class, this implementation to remove the need to hardcode a switch between algorithms.

https://en.wikipedia.org/wiki/Factory_method_pattern
but with simple function instead of a class.

I'm not completely sure yet what you want to tell with this.
Is this something which should be changed in DEC?
Did I mess up something? If so, how should it be changed?
Or was this just some explanation of where the OP's problem comes from?

ValidFormat is used as generic or general use function that can be used to one hit call, But ValidHash it seems was working in DEC v5 but with all the refactoring and separating code in different specialized units with DEC v6 it did lose the functionality code form TDECHashAuthentication.

I think DEC v6 should add/have an interface (IDECHashAuthentication) to TDECHash like this :
Zitat:

{$IFDEF FPC}
TDECHash = class(TDECObject) // does not find methods of the interface as it
// searches for AnsiString instead of RawByteString
// and thus does not find that
private
{$ELSE}
TDECHash = class(TDECObject, IDECHash, IDECHashAuthentication)
strict private
{$ENDIF}
Code:
  {$IFDEF FPC}
  TDECHash = class(TDECObject) // does not find methods of the interface as it
                                // searches for AnsiString instead of RawByteString
                                // and thus does not find that
  private
  {$ELSE}
  TDECHash = class(TDECObject, IDECHash, IDECHashAuthentication)
  strict private
  {$ENDIF}
That is the cause for the failure or the incompatibility in the code in first place with DECv5.

That one way to fix it, or without an interface with different ValidPasswordHash that solve this, yet it will fail or need more and bigger adjustment to the code, the core problem is TDECHashClass doesn't implement/import/offer the publics/interface of TDECHashAuthentication.

TurboMagic 27. Jan 2024 13:43

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Thanks for this input!
It should be doable to add this.
Is it possible that you add this to the issue tracker
over here so I won't forget it? (just the text of your post)
I'm currently working else but try to get some time for DEC
in the forseable future.

https://github.com/MHumm/DelphiEncry...pendium/issues

Kas Ob. 27. Jan 2024 14:00

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
I am really sorry, but i don't even have an account on GitHub !

TurboMagic 27. Jan 2024 17:01

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Ok, then I'll make a note somewhere to implement this.

TurboMagic 28. Jan 2024 10:05

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Zitat:

Zitat von Kas Ob. (Beitrag 1532664)
Zitat:

Zitat von TurboMagic (Beitrag 1532633)
Zitat:

Zitat von Kas Ob. (Beitrag 1532628)
I looked at the library,
ValidFormat and ValidHash supposed to be working as factory design, you feed them a class type and will get a class, this implementation to remove the need to hardcode a switch between algorithms.

https://en.wikipedia.org/wiki/Factory_method_pattern
but with simple function instead of a class.

I'm not completely sure yet what you want to tell with this.
Is this something which should be changed in DEC?
Did I mess up something? If so, how should it be changed?
Or was this just some explanation of where the OP's problem comes from?

ValidFormat is used as generic or general use function that can be used to one hit call, But ValidHash it seems was working in DEC v5 but with all the refactoring and separating code in different specialized units with DEC v6 it did lose the functionality code form TDECHashAuthentication.

I think DEC v6 should add/have an interface (IDECHashAuthentication) to TDECHash like this :
Zitat:

{$IFDEF FPC}
TDECHash = class(TDECObject) // does not find methods of the interface as it
// searches for AnsiString instead of RawByteString
// and thus does not find that
private
{$ELSE}
TDECHash = class(TDECObject, IDECHash, IDECHashAuthentication)
strict private
{$ENDIF}
Code:
  {$IFDEF FPC}
  TDECHash = class(TDECObject) // does not find methods of the interface as it
                                // searches for AnsiString instead of RawByteString
                                // and thus does not find that
  private
  {$ELSE}
  TDECHash = class(TDECObject, IDECHash, IDECHashAuthentication)
  strict private
  {$ENDIF}
That is the cause for the failure or the incompatibility in the code in first place with DECv5.

That one way to fix it, or without an interface with different ValidPasswordHash that solve this, yet it will fail or need more and bigger adjustment to the code, the core problem is TDECHashClass doesn't implement/import/offer the publics/interface of TDECHashAuthentication.

I try to understand what you propose to implement, but I'm not completely sure yet this fits the architecture.

1. You want to have an IDECHashAUthentication interface, containing all the public class methods of that one.
That's doable and I'll do that in a minute.

2. You want TDECHashClass to declare it implements this interface. In order to do this TDECHash would need to
implement this interface, as TDECHashClass is a meta class. But even then this would be against the current
architecture, as this would mean that the base class already implements all these Authentication related methods.
They have been moved to an own using in order to not let DECHashBase grow unwidely. There might be further
authentication methods added in the future and thus the whole thing might grow.

Cheers
TurboMagic

TurboMagic 28. Jan 2024 10:09

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Ok, the attempt to create an IDECHashAUthentication interface and just add all public class methods
of TDECHashAUthentication to it failed, as the compiler doesn't like class methods in an interface.

How to proceed here?

Cheers
TurboMagic

Kas Ob. 28. Jan 2024 11:47

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Yes, it is tricky to add IDECHashAuthentication because the class methods, and to solve this either add the same naming methods in TDECHash, so you can redirect all these methods to the class ones in TDECHashAuthentication, or introduce new global function ValidPasswordHash just like ValidHash that return TDECHashAuthentication.

Both approaches are not ideals, the best or the better is MAY BE dropping the class methods and making them simple local methods, but i have no idea what this might break in current build, as these class methods popular or even needed as class methods ?
I can't tell, and believe you have better inside knowledge in DEC design.

Kas Ob. 28. Jan 2024 13:17

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
I see this discrepancy in the implementation
Code:
// in DECHash.pas
  THashBaseMD4 = class(TDECHashAuthentication)
  THash_SHA0 = class(THashBaseMD4)
  THash_SHA256 = class(THash_SHA0)

// while in DECHashAuthentication.pas
  TDECHashAuthentication = class(TDECHash)

// but in DECHashBase.pas
  TDECHash = class(TDECObject, IDECHash)
Now we left with TDECHash without visibility to TDECHashAuthentication and its class methods, while all the derived class has full functionality of HashAuthentication,

What is misleading is the naming in TDECHashAuthentication, as the main class (core type) to be used is TDECHashAuthenticationClass from DECHashAuthentication.pas, not TDECHashClass from DECHashBase.

With current implementation, de facto the base class is TDECHashAuthentication !

and that why i suggest to not change anything for now, just add documented global function (like ValidPasswordHash) to serve this functionality where the result is TDECHashAuthenticationClass , but the input is TDECHashClass !!

Kas Ob. 28. Jan 2024 13:43

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Here this is the smallest workaround the problem for this case like what OP presented.

the modification are only in DECHashAuthentication.pas
Code:
function ValidAuthHash(HashClass: TDECHashClass): TDECHashAuthenticationClass;
procedure SetDefaultAuthHashClass(HashClass: TDECHashClass);

implementation

uses
  DECUtil;

resourcestring
  sAuthHashNoDefault         = 'No default hash has been registered';

var

  FDefaultAutheticationHashClass: TDECHashAuthenticationClass = nil;

function ValidAuthHash(HashClass: TDECHashClass): TDECHashAuthenticationClass;
begin
  if Assigned(HashClass) then
    Result := TDECHashAuthenticationClass(HashClass)
  else
    Result := FDefaultAutheticationHashClass;

  if not Assigned(Result) then
    raise EDECHashException.CreateRes(@sAuthHashNoDefault);
end;

procedure SetDefaultAuthHashClass(HashClass: TDECHashClass);
begin
  Assert(Assigned(HashClass), 'Do not set a nil default hash class!');

  FDefaultAutheticationHashClass := TDECHashAuthenticationClass(HashClass);
end;
For (legacy) code like haentschman the need is to add DECHashAuthentication in uses clause and use ValidAuthHash instead ValidHash.

BUT, they are named/called AuthHash while in fact they are just key deriving methods/algorithms, so.... (i am lousy at naming) ... find a better naming as i took the class name only while the functionality has nothing to do with authentication though.

TurboMagic 28. Jan 2024 17:43

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hello,

I copied your implementation now and renamed it.
We now have

function ValidAuthenticationHash(HashClass: TDECHashClass): TDECHashAuthenticationClass;
procedure SetDefaultAuthenticationHashClass

Best regards

TurboMagic

haentschman 29. Jan 2024 09:06

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallöle...8-)

@Kas Ob. / TurboMagic
Könntet ihr bitte die technischen Details im Thred zum DEC erörtern? https://www.delphipraxis.net/206973-...fentlicht.html
Danke... :zwinker:

Ich habe am Freitag die neue Unit ins Release reingenommen... Ich habe die SQL Statements in Ressourcen verschlüsselt in der EXE drin. Bei jedem Aufruf zur Datenbank wird das verschlüsselte SQL genommen, entschlüsselt und der Query zugewiesen. Wenn das schiefläuft, dann ist das SQL = ''.
Dann kommt das raus...(Bild) Bei gefühlten 100+ Aufrufen kommt das richtige Ergebnis raus...dann kommt irgendwann der Fehler. Mein Postfach ist gestresst. :zwinker:
PS: es fällt erst mal auf, daß immer Threads involviert sind...:gruebel:

Ich werde zurückrudern, bis auch mein Tool (SQLCreator), was noch auf V5 läuft, umgestellt ist. Wenn das dann immer noch der Fall ist, kann man sich nicht drauf verlassen...:cry:

Kas Ob. 29. Jan 2024 11:17

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Can you capture/log the exact SQL query when the exception happen ?

I am sorry, can't understand the exception !, is it a fail to find parameter or something, like the there is SQL but broken !?

Anyway, i suspect the use of RawByteString is and as always the root of evil, so i will adjust your code a little to remove this dependency as much as i can.

ps: i asked for specific test vector to guarantee the migration of your code, and you didn't answer with one specific value, the one with strange Unicode would be helpful, yet from my understanding it is working fine, mostly !,
again does the exception due to broken/corrupted SQL or truncated SQL.... only after that we can guess if some combination of Unicode chars lost.

More details will remove the guessing game, and only you can get these details.

Kas Ob. 29. Jan 2024 11:43

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Please try this:
Code:
unit Tools.Crypt;

interface

uses
  System.SysUtils, DECUtil, DECHash, DECCipherBase, DECCiphers, DECHashBase,
  DECFormatBase, DECFormat, DECRandom, DECHashAuthentication;

const
  conKey = 'aYr14iaz8u)xO7Ok';

var
  //CipherAlgo: TCipher_Rijndael;
  CipherMode: TCipherMode = cmCBCx;
  HashClass : TDECHashClass = THash_SHA256;
  TextFormat: TDECFormatClass = TFormat_Base64;
  KDFIndex : Integer = 1; // Iterations

type
  TToolsCrypt = class
  public
    class function Decrypt(aHash: string; aKey: string = ''): string;
    class function Encrypt(aText: string; aKey: string = ''): string;
  end;

implementation

{ TToolsCrypt }

class function TToolsCrypt.Decrypt(aHash, aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  //Cipher: TDECCipher;
  Salt, Data, Check, Pass, Mac: TBytes;
  MacLength, SaltLen, DataLen: Integer;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  //Cipher:=ValidCipher(TCipher_Rijndael).Create;      // the way it should be used ! but it fail now with DecodeBytes
  Cipher := TCipher_Rijndael.Create;
  try
    MacLength := Cipher.Context.BlockSize;
    SaltLen := Cipher.InitVectorSize;

    Salt := ValidFormat(TextFormat).Decode(BytesOf(aHash));
    DataLen := Length(Salt) - MacLength - Cipher.Context.BufferSize;

    Data := Copy(Salt, MacLength, DataLen);
    Check := Copy(Salt, DataLen + SaltLen, Cipher.Context.BufferSize);

    SetLength(Salt, SaltLen);
    Pass := ValidAuthenticationHash(HashClass).KDFx(aKey[Low(aKey)], Length(aKey) * SizeOf(Char), Salt[Low(Salt)], Length(Salt), Cipher.Context.KeySize, KDFIndex);

    Cipher.Mode := CipherMode;
    Cipher.Init(Pass, nil);
    SetLength(Result, DataLen div SizeOf(Char));

    Cipher.Decode(Data[Low(Data)], Result[Low(Result)], DataLen);
    //Result := StringOf(Cipher.DecodeBytes(Data,TFormat_Copy));
    Mac := BytesOf(Cipher.CalcMAC);
    if MacLength < Length(Check) then
      MacLength := Length(Check);

    if (MacLength <> Cipher.Context.BlockSize) or (not CompareMem(Check, Mac, MacLength)) then
    begin
      Result := '';
    end;

  finally
    Cipher.Free;
    ProtectBytes(Salt);
    ProtectBytes(Check);
    ProtectBytes(Data);
    ProtectBytes(Pass);
    ProtectBytes(Mac);
  end;
end;

class function TToolsCrypt.Encrypt(aText, aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  Salt, Pass, Data, Mac: TBytes;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    Salt := RandomBytes(Cipher.InitVectorSize);
    Pass := ValidAuthenticationHash(HashClass).KDFx(aKey[Low(aKey)], Length(aKey) * SizeOf(Char), Salt[Low(Salt)], Length(Salt), Cipher.Context.KeySize, KDFIndex);
    Cipher.Mode := CipherMode;

    Cipher.Mode := cmCBCx;
    Cipher.Init(Pass, nil);

    SetLength(Data, Length(aText) * SizeOf(Char));
    Cipher.Encode(aText[Low(aText)], Data[Low(Data)], Length(Data));

    Mac := BytesOf(Cipher.CalcMAC);
    Result := StringOf(ValidFormat(TextFormat).Encode(Salt + Data + Mac));
  finally
    Cipher.Free;
    ProtectBytes(Salt);
    ProtectBytes(Pass);
    ProtectBytes(Data);
    ProtectBytes(Mac);
  end;
end;

end.

haentschman 30. Jan 2024 08:31

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo...8-)

Zum Verständnis:
Der Fehler kommt NICHT sofort, sondern nach hunderten Aufrufen des GLEICHEN SQL aus der Ressource. :? (Bild + SQL)
Das SQL wird JEDE Minute im Execute des Threads ausgeführt. Im Fehlerfalle (Fehlermeldung von einem anderen SQL) ist das SQL leer = beschädigt.
"[FireDAC][Phys][MSSQL]-306. Anweisungstext [] darf nicht leer sein."
Damit kann er auch den Parameter nicht finden...:roll:
Delphi-Quellcode:
procedure TDatabaseState.OfflineTime(Workstation: string; InstanzID: Integer; TimeStamp: TDateTime);
var
  Qry: TFDQuery;
begin
  Qry := CreateQuery;
  try
    Qry.SQL.Text := GetSQLByName('COM_OFFLINE_TIME');
    Qry.ParamByName('HAN').AsInteger := InstanzID; //<-
    Qry.ParamByName('TIM').AsDateTime := TimeStamp;
    Qry.ParamByName('WOR').AsString := Workstation;
    Qry.ExecSQL;
  finally
    Qry.Free;
  end;
end;
...
function TDatabaseBase.GetSQLByName(SQLName: string): string;
var
  SQLStream: TResourceStream;
  SQLStrings: TStringList;
  SQLStringsDecrypt: TStringList;
begin
  Result := '';
  SQLStrings := TStringList.Create;
  try
    SQLStringsDecrypt := TStringList.Create;
    try
      SQLStream := TResourceStream.Create(HInstance, SQLName, PWideChar(conDatabaseResourceGroupString));
      try
        try
          SQLStrings.LoadFromStream(SQLStream);
          SQLStringsDecrypt.Text := TToolsCrypt.Decrypt(SQLStrings.Text, conKey); //<-
          SQLStringsDecrypt.Delete(0); // Kommentar entfernen
          Result := SQLStringsDecrypt.Text;
        except
          Result := '';
        end;
      finally
        SQLStream.Free;
      end;
    finally
      SQLStringsDecrypt.Free;
    end;
  finally
    SQLStrings.Free;
  end;
end;
Zitat:

i asked for specific test vector to guarantee the migration of your code, and you didn't answer with one specific value
siehe hier: https://www.delphipraxis.net/1531964-post9.html

PS: Nach Umstellung wieder auf V5.2, ist bei den Usern wieder Ruhe...:wink:

Kas Ob. 30. Jan 2024 10:34

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hard bug to catch !, i can't reproduce this so will move to divide and conquer, for that we need to separate the decryption from MAC calculation.

Please try this, if you are in the mood to test deeper or you have time, this will show if the MAC is the failed point or not:
Code:
unit Tools.Crypt;

interface

uses
  System.SysUtils, DECUtil, DECHash, DECCipherBase, DECCiphers, DECHashBase,
  DECFormatBase, DECFormat, DECRandom, DECHashAuthentication;

const
  conKey = 'aYr14iaz8u)xO7Ok';

var
  CipherMode: TCipherMode = cmCBCx;
  HashClass: TDECHashClass = THash_SHA256;
  TextFormat: TDECFormatClass = TFormat_Base64;
  KDFIndex: Integer = 1; // Iterations

type
  TToolsCrypt = class
  public
    class function Decrypt(const aHash: string; out NoAuthResult: string; aKey: string = ''): string;
    class function Encrypt(const aText: string; aKey: string = ''): string;
  end;

implementation

{ TToolsCrypt }

class function TToolsCrypt.Decrypt(const aHash: string; out NoAuthResult: string; aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  Salt, Data, Check, Pass, Mac: TBytes;
  MacLength, SaltLen, DataLen: Integer;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    MacLength := Cipher.Context.BlockSize;
    SaltLen := Cipher.InitVectorSize;

    Salt := ValidFormat(TextFormat).Decode(BytesOf(aHash));
    DataLen := Length(Salt) - MacLength - Cipher.Context.BufferSize;

    Data := Copy(Salt, MacLength, DataLen);
    Check := Copy(Salt, DataLen + SaltLen, Cipher.Context.BufferSize);

    SetLength(Salt, SaltLen);
    Pass := ValidAuthenticationHash(HashClass).KDFx(aKey[Low(aKey)], Length(aKey) * SizeOf(Char), Salt[Low(Salt)], Length(Salt), Cipher.Context.KeySize, KDFIndex);

    Cipher.Mode := CipherMode;
    Cipher.Init(Pass, nil);
    SetLength(Result, DataLen div SizeOf(Char));

    Cipher.Decode(Data[Low(Data)], Result[Low(Result)], DataLen);
    NoAuthResult := Result;

    Mac := BytesOf(Cipher.CalcMAC);
    if MacLength < Length(Check) then
      MacLength := Length(Check);

    if (MacLength <> Cipher.Context.BlockSize) or (not CompareMem(Check, Mac, MacLength)) then
    begin
      Result := '';
    end;

  finally
    Cipher.Free;
    ProtectBytes(Salt);
    ProtectBytes(Check);
    ProtectBytes(Data);
    ProtectBytes(Pass);
    ProtectBytes(Mac);
  end;
end;

class function TToolsCrypt.Encrypt(const aText: string; aKey: string): string;
var
  Cipher: TCipher_Rijndael;
  Salt, Pass, Data, Mac: TBytes;
begin
  if aKey = '' then
  begin
    aKey := conKey;
  end;

  Cipher := TCipher_Rijndael.Create;
  try
    Salt := RandomBytes(Cipher.InitVectorSize);
    Pass := ValidAuthenticationHash(HashClass).KDFx(aKey[Low(aKey)], Length(aKey) * SizeOf(Char), Salt[Low(Salt)], Length(Salt), Cipher.Context.KeySize, KDFIndex);
    Cipher.Mode := CipherMode;

    Cipher.Mode := cmCBCx;
    Cipher.Init(Pass, nil);

    SetLength(Data, Length(aText) * SizeOf(Char));
    Cipher.Encode(aText[Low(aText)], Data[Low(Data)], Length(Data));

    Mac := BytesOf(Cipher.CalcMAC);
    Result := StringOf(ValidFormat(TextFormat).Encode(Salt + Data + Mac));
  finally
    Cipher.Free;
    ProtectBytes(Salt);
    ProtectBytes(Pass);
    ProtectBytes(Data);
    ProtectBytes(Mac);
  end;
end;

end.
When the result is empty check and log the content of NoAuthResult, please if possible log it in plain text and in HEX formatted form.

haentschman 31. Jan 2024 05:45

AW: Hilfe bei Umstellung Unit DEC5.1 zu DEC6.0
 
Hi...8-)
Zitat:

Hard bug to catch !
...du sagst es. :?
Zitat:

or you have time
:cheer: Guter Witz. Welcher Entwickler, der nicht allein ist, hat schon Zeit...:zwinker:

Ich werde das Thema wieder angehen, wenn die großen Themen des Jahres (neuer Quelltext) in Sack und Tüten sind.
In der Entwicklung kann ich über Nacht, im exception Block von GetSQLByName, ein Log schreiben das das Result aus TToolsCrypt protokoliert. In der Hoffnung, daß der Fehler dann auftritt. Das stelle ich dann zur Verfügung.
Im Release kann ich mich leider nicht darum kümmern...:(

Danke erstmal...8-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:01 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz