AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Umfrage/Architekturfrage zur DEC

Ein Thema von TurboMagic · begonnen am 17. Mai 2025 · letzter Beitrag vom 21. Mai 2025
Antwort Antwort
Seite 1 von 2  1 2      
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
3.084 Beiträge
 
Delphi 12 Athens
 
#1

Umfrage/Architekturfrage zur DEC

  Alt 17. Mai 2025, 15:27
Hallo,

durch die Meldung gewisser Bugs in der DEC (Delphi Encryption Compendium) kam jetzt die Fragestellung auf,
wie ein gewisses API funktionieren sollte.

Konkret geht es u.a. um diesen Bugreport: https://github.com/MHumm/DelphiEncry...dium/issues/87.

Es gibt für die Blockchiffren auch die Möglichkeit mit Streams zu arbeiten.
Dazu gibt es EncodeStream und DecodeStream (beide DECCipherFormats.pas).
Als Parameter haben diese den Quellstream, den Zielstream, die Anzahl zu
bearbeitender Bytes und einen optionale OnProgress Eventhandler.

Außerdem gibt es eine Done Methode, diese führt Aufräumarbeiten durch, wenn man
das Cipher Objekt nicht gleich freigeben will sondern später für den nächsten Vorgang
wiederverwenden will.

Nun scheint es Problematisch (sowohl mit den vor einiger Zeit hinzugefügten Paddings für
unvollständige letzte Blöcke als auch für Authentifizierte Blockverkettungsmodes wie GCM,
wenn EncodeStream oder DecodeStream mehrfach auf den selben Quellstream angewendet werden,
um die Daten "abschnittsweise" zu verarbeiten.

Die Frage ist also, ob es überhaupt realistisch ist, für ein und den selben Quellstream
(bin nicht 100% fit in Streams, gerne eine gute Quelle nennen die erläutert wie die intern
funktionieren bzw. wie deren Verwendung erwartet wird) mehrfach EncodeStream oder DecodeStream
aufzurufen oder ob nicht sowieso immer erst alles im Quellstream gesammelt wird und dann einmalig
der Aufruf stattfindet.

Nur: was ist mit Datenmengen, die nicht in dem Speicher passen? Behandelt das der interne Stream
Aufbau schon passend? Oder wie würde sowas auf einen verschlüsselten Videostream angewendet
aussehen? WIe wäre da pseudocode mäßig der Ablauf zu erwarten?

Danke für alle Ideen/Meinungen, egal wie kontrovers.
Grüße
TurboMagic
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
436 Beiträge
 
#2

AW: Umfrage/Architekturfrage zur DEC

  Alt 18. Mai 2025, 09:48
Well, first sorry for bad English and for that i will be (very) verbose trying to explain my opinion and my findings on this.

I looked at the code and browsed the concerning files, and now i see the problem(s) and shortcoming in utilizing streams.

So to confirm my doubts i wrote my own test to amplify and pin point the real cause, and my doubts was on the point:
the test project with cherry picked test vectors from DEC own test vectors
Delphi-Quellcode:
program AesGCMStream;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Generics.Collections,
  classes,
  System.Math,
  DECBaseClass,
  DECCipherBase,
  DECCipherModes,
  DECCipherFormats,
  DECFormat,
  DECCiphers;

const
 { TV_Key = '11754cd72aec309bf52f7687212e8957';
  TV_IV = '3c819d9a9bed087615030b65';
  TV_PT = '';
  TV_AAD = '';
  TV_CT = '';
  TV_Tag = '250327c674aaf477aef2675748cf6971';   }


  {TV_Key = 'fe0121f42e599f88ff02a985403e19bb';
  TV_IV = '3bb9eb7724cbe1943d43de21';
  TV_PT = 'fd331ca8646091c29f21e5f0a1';
  TV_AAD = '2662d895035b6519f3510eae0faa3900ad23cfdf';
  TV_CT = '59fe29b07b0de8d869efbbd9b4';
  TV_Tag = 'd24c3e9c1c73c0af1097e26061c857de';  }


  TV_Key = 'a976d8ae4528bff2911094a421f4ed83';
  TV_IV = '6904cb03535dce4b080148df37e81a5c9a9bebfa0037658228456a8a1a3db8e5c0be70c082bfbf50f43ab59cdbf24312ad6dd041e'+
  '1d179df5d36f9fa7b33acb2983f8d66443b44c1478253ee2cdea9840a6698e9be130de46947121af9223d411cc4f7c715da83a30dcd4c54f5b52701ee315b52c44b5d58cb6caaae946ad940';
  TV_PT = 'f235d5c4f71b40d2afe4b85a6d62a5bb426e3606f086bee79f6788d3b7ce82a6';
  TV_AAD = '348ae1548058be59efd0f830ca3b9b0805320632';
  TV_CT = '837af64be0d0bcfb9688e7043f5594e5c483cfc06a5e809fbe091cd702bf419c';
  TV_Tag = '71e22c2b15d4d2caeba54036';

 { TV_Key = '88c81827cb514632c8b0c76b7ecbd1cc';
  TV_IV = 'b3632bb439c8811f1454e6a368c4c9d0bbd3d9507ed1050cac3f19ba085063af9d162eb1c02077a51bad143be939d32c68'+
  '5b6fb3f330b8b382cc6567c55f2f4ecfeff88ff281e1e5ee1cfc813a13c9e69096761f58d13b9cad6221b5aaee03e40ad56f1a61c250ef57f94985ab6a603ded02b513e035ac8b2e3c3b69d35d2918';
  TV_PT = 'e254bf464879b4c48200541d359ecce478c67a62f4f5aaaa047d8e4a4ad6adff19da9a535a0be0758d5e7e992ccbb936d3c496';
  TV_AAD = '';
  TV_CT = '453ca80e69d37a6c8338da0deabb5ed1d5f8c006e67aca5d0bfbcd3aa32290521e91f379b7db57764c2755bf8691451e72a295';
  TV_Tag = '01485fb4f9675740b354bf7557f0f23a';
   }




procedure DoTest(Step:Integer);
var
  CipherAES: TCipher_AES;
  Key, IV, PT, AAD, CT, Tag, OutPut: TBytes;
  ctbStream, ptbStream: TBytesStream;
  dataLeftToEncode: Integer;
begin
  Writeln('Feeding Step = ',Step);
  CipherAES := TCipher_AES.Create;
  try
    CipherAES.Mode := TCipherMode.cmGCM;

    Key := TFormat_HEX.Decode(BytesOf(TV_Key));
    IV := TFormat_HEX.Decode(BytesOf(TV_IV));
    PT := TFormat_HEX.Decode(BytesOf(TV_PT));
    AAD := TFormat_HEX.Decode(BytesOf(TV_AAD));
    CT := TFormat_HEX.Decode(BytesOf(TV_CT));
    Tag := TFormat_HEX.Decode(BytesOf(TV_Tag));

    CipherAES.Init(Key, IV);
    CipherAES.AuthenticationResultBitLength := Length(Tag) * 8;
    CipherAES.DataToAuthenticate := AAD;

    ptbStream := TBytesStream.Create(PT);
    ctbStream := TBytesStream.Create;

    dataLeftToEncode := ptbStream.Size;
    repeat
      CipherAES.EncodeStream(ptbStream, ctbStream, Min(STEP, ptbStream.Size - ptbStream.Position));
      ctbStream.SetSize(ctbStream.Position);
      Writeln('Step : ' + StringOf(TFormat_HEX.Encode(ctbStream.Bytes)));
      Dec(dataLeftToEncode,STEP);
    until dataLeftToEncode <= 0;

    CipherAES.Done;

    ctbStream.SetSize(ctbStream.Position);
    OutPut := ctbStream.Bytes;

    Writeln('Expected : ' + StringOf(TFormat_HEX.Encode(CT)));
    Write('Encrypted: ' + StringOf(TFormat_HEX.Encode(OutPut)));
    if CompareMem(CT,OutPut,Length(ct)) then
      Writeln(#9'OK') else
      Writeln(#9'FAIL');

    Writeln('Tag expected : ' + StringOf(TFormat_HEX.Encode(Tag)));
    Write('Tag encrypted: ' + StringOf(TFormat_HEX.Encode(CipherAES.CalculatedAuthenticationResult)));
    if CompareMem(Tag,CipherAES.CalculatedAuthenticationResult,Length(Tag)) then
      Writeln(#9'OK') else
      Writeln(#9'FAIL');

  finally
    CipherAES.Free;
  end;
  Writeln;
end;

begin
  try
    DoTest(100);
    DoTest(1);
    DoTest(5);
    DoTest(16);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Writeln('Done.');
  Readln;
end.
The output for the above test vector is
Delphi-Quellcode:
Feeding Step = 100
Step : 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C
Expected : 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C
Encrypted: 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C OK
Tag expected : 71E22C2B15D4D2CAEBA54036
Tag encrypted: 71E22C2B15D4D2CAEBA54036 OK

Feeding Step = 1
Step : 83
Step : 83B3
Step : 83B337
Step : 83B33726
Step : 83B3372677
Step : 83B3372677D9
Step : 83B3372677D9C7
Step : 83B3372677D9C7B1
Step : 83B3372677D9C7B17B
Step : 83B3372677D9C7B17B91
Step : 83B3372677D9C7B17B91D3
Step : 83B3372677D9C7B17B91D3FD
Step : 83B3372677D9C7B17B91D3FD0A
Step : 83B3372677D9C7B17B91D3FD0AE5
Step : 83B3372677D9C7B17B91D3FD0AE5CE
Step : 83B3372677D9C7B17B91D3FD0AE5CE7C
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE6013
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE601333
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BC
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F1
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B22
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B2236
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B2236AC
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B2236ACFA
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B2236ACFA90
Step : 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B2236ACFA9047
Expected : 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C
Encrypted: 83B3372677D9C7B17B91D3FD0AE5CE7CBE60133390BCC4D9F15B2236ACFA9047 FAIL
Tag expected : 71E22C2B15D4D2CAEBA54036
Tag encrypted: 92D5435B6AB1ECF5B3AC7B15 FAIL

Feeding Step = 5
Step : 837AF64BE0
Step : 837AF64BE09DAD2B697E
Step : 837AF64BE09DAD2B697E5AF67EBD71
Step : 837AF64BE09DAD2B697E5AF67EBD7159A08E74A9
Step : 837AF64BE09DAD2B697E5AF67EBD7159A08E74A970706309C1
Step : 837AF64BE09DAD2B697E5AF67EBD7159A08E74A970706309C1A5D6D2E10B
Step : 837AF64BE09DAD2B697E5AF67EBD7159A08E74A970706309C1A5D6D2E10B0571
Expected : 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C
Encrypted: 837AF64BE09DAD2B697E5AF67EBD7159A08E74A970706309C1A5D6D2E10B0571 FAIL
Tag expected : 71E22C2B15D4D2CAEBA54036
Tag encrypted: F4904F062055FD0124C1D3A3 FAIL

Feeding Step = 16
Step : 837AF64BE0D0BCFB9688E7043F5594E5
Step : 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C
Expected : 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C
Encrypted: 837AF64BE0D0BCFB9688E7043F5594E5C483CFC06A5E809FBE091CD702BF419C OK
Tag expected : 71E22C2B15D4D2CAEBA54036
Tag encrypted: A7CF85F2D18FD9BC086E2663 FAIL

Done.
This show exactly what went wrong and where, like for 5 bytes the first 5 of the cipher is correct the rest is wrong, and for step=16 the encryption is correct but the tag is off.

First lets apply the AES with GCM correctly and for that i will refer to https://en.wikipedia.org/wiki/Galois...asic_operation
gcm-galois_counter_mode_with_iv.svg.png
This visual representation explain AES in GCM mode, E_k is encrypted block and mult_H is the Galois field multiplication, now both must be 128 bit (16 bytes), this is important, notice
1) E_k is irrelevant to the input (text/Plaintext), and we get the cipher (Ciphertext) by XORing the E_k with Plaintext
2) mult_H is chained on the Ciphertext.

These are the most important details concern us here, now to explain what is going wrong i will take example same as my tests above, lets say we have text length of 20 bytes and want encrypted it in chunks, same as performing using a stream.
assuming we passed 5 bytes then E_k is correct and will be the same no matter how much bytes we feed, as it generate 16 bytes, then we XOR 5 bytes and get the Ciphertext for 5 bytes, this is shown in the output of my example where first 5 bytes is correct, on the second step, i mean another 5 bytes comes the problem and the whole thing collapse,
why ?
Because we should saved E_k that was 16 bytes and used only 5 from it, we should kept the rest and XOR the new input (second 5 bytes) with the rest, and only generate new E_k when we used all the 16 bytes of the last one.

As for the tag correctness, see in my test above the last case where the steps are at 16 bytes, meaning and showing evidently the correctness of the encryption, but the tag is wrong,
why ?
Because similar to above the multiplicaiton must be performed on 16 bytes, not any less, so full block on Ciphertext, if there is no data then a padding should present and only then the multiplication should be performed.


Thoughts here:
1) a refactor and re-structure is due, DoEncodeDecodeStream is wrong and depending on TGCM.EncodeGCM is also short and miss the accumulation.
2) Most important thing is the use of "Done;" this should be the trigger for finalization same or similar to hash functions, don't add any padding unless "Done" being called, otherwise save E_k and incomplete Ciphertext until they are multiple of 16 bytes then drop E_k and calculate the multiplication, for me accessing the tag if there is residue or accumulation should trigger an exception, this is best practice to prevent users from wrongly using encryption and enforcing the correct values, see here if the encryption is not ended (called done) this mean the encrption is correct abut the tag is wrong and only can be accessed after "Done"
3) I think if you managed to fix the code to make my test above pass then it will work for any thing.
4) 8k bytes can't be excessive nor small, should be available to the user to pick or adjust, can be useful for speed, or when want to encrypt big files, i see no problem with it, the problem is in (2)
5) in (2) either save E_k in full or just the rest, as shown in AESGCM representation next chunk should be xored at the right index, and this will fix the tests above.
6) Again voting to raise exception on accessing CalculatedAuthenticationResult if Done is not called.

Hope it was clear and helpful.
Kas
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
3.084 Beiträge
 
Delphi 12 Athens
 
#3

AW: Umfrage/Architekturfrage zur DEC

  Alt 18. Mai 2025, 13:54
Hello,

thanks for this detailed and precise description.
I do think this is really helpful.
It will just take quite some time to work out a real fix for this.
Grüße
TurboMagic
  Mit Zitat antworten Zitat
rabatscher

Registriert seit: 13. Dez 2007
Ort: Bruck an der Mur
77 Beiträge
 
#4

AW: Umfrage/Architekturfrage zur DEC

  Alt 19. Mai 2025, 08:22
Meine Insights bezüglich des Bugreports hast du ja schon

Ich wollte hier nur noch kurz ein paar Anmerkungen machen:
* GCM ist soweit ich weiss ja nur für 128 bit Ciphers möglich
-> es wäre eventuell eine Idee GCM nur in spezialisierten Klassen zu verwenden

-> wäre rauslösen aus den TDECCipherModes eine Option, die GMC Variable ist dort eigentlich nur
für die AES Implemtierung (oder liege ich da falsch?) ?

* Ich bastle gerad am ChaCha20 Poly1305 Encoding scheme - auch dieses Schema ist nur für
256 bit ciphers gedacht (es würde also auch eine Option für AES 256 geben) aber sonst
für keine anderen Cipher. Da die Poly1305 und ChaCha teilweise miteinander verwoben sind
wäre es evt. auch hier sinnvoll eine extra Klasse zu coden...

* Ich denke multiple Calls zu EncodeBytes / EncodeStream sollten evt. doch zugelassen werden -
alle anderen Cipher, die ja nicht voneinander abhängig sind funktionieren ja so auch...
Es bräuchte hier nur etwas mehr "housekeeping" (status, counter, schon initialiert usw.) gemacht.
Ein Call von "Done" würde dann natürlich das Ganze abschließen und das Finale Tag berechnen....
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
436 Beiträge
 
#5

AW: Umfrage/Architekturfrage zur DEC

  Alt 19. Mai 2025, 09:43
Meine Insights bezüglich des Bugreports hast du ja schon
I really lost in the conversation on Github and went right away to put a test based on doubted code behavior, right after downloading your test project the one attached as text file.

Ich wollte hier nur noch kurz ein paar Anmerkungen machen:
* GCM ist soweit ich weiss ja nur für 128 bit Ciphers möglich
-> es wäre eventuell eine Idee GCM nur in spezialisierten Klassen zu verwenden

-> wäre rauslösen aus den TDECCipherModes eine Option, die GMC Variable ist dort eigentlich nur
für die AES Implemtierung (oder liege ich da falsch?) ?
I don't think it worth it, it will work though, AES is de facto standard, not a standard but THE standard, and GCM defined for it, so no point to recommend to use AEAD other than the most proven and compatible schemes, which are AES with GCM and ChaCha20 with Poly1305.
Though GCM is in need for 128bit block and has nothing to do with key size.


* Ich bastle gerad am ChaCha20 Poly1305 Encoding scheme - auch dieses Schema ist nur für
256 bit ciphers gedacht (es würde also auch eine Option für AES 256 geben) aber sonst
für keine anderen Cipher. Da die Poly1305 und ChaCha teilweise miteinander verwoben sind
wäre es evt. auch hier sinnvoll eine extra Klasse zu coden...
Nice, i also have those, yet again mixing between these standards is not a recommended thing, see ChaCha20 is stream cipher by design and it don't define any padding scheme on its own the operation happen on the last row in the state and it is faster than AES when there is no hardware acceleration, yet adding Poly1305 to AES make little sense as if AES is fast with CPU acceleration then most likely the GHASH (GCM) is also accelerated by the CPU with carry-less multiplication, but the real reason why it should not be done is, it will make compatibility with any other library almost non existed, so the data encrypted using different pair will need custom library to handle data from/to other languages or platforms.


* Ich denke multiple Calls zu EncodeBytes / EncodeStream sollten evt. doch zugelassen werden -
alle anderen Cipher, die ja nicht voneinander abhängig sind funktionieren ja so auch...
Es bräuchte hier nur etwas mehr "housekeeping" (status, counter, schon initialiert usw.) gemacht.
Ein Call von "Done" würde dann natürlich das Ganze abschließen und das Finale Tag berechnen....
I am not sure about that,

See stream functionality does need signal to end as it can and most likely used as chunk or repeated calls, "Done" will signal the sealing of the GCM tag calculation by multiply the last chained result with the first block (the one with counter=0), but enforcing requirement will break the one hit EncodeBytes/DecodeBytes, i saw these being used in many places in one line of code, enforcing "Done" with them is wrong, yet i support the functionality itself, but it must be different, may be different pair of functions, like EncodeChunk that accept TBytes or ...

But in general moving GCM into own class is not bad idea, just costly in implementation, and will make the code cleaner as one line operation like EncodeBytes can use that GCM and call done internally, yet it might be not small refactor.
Kas
  Mit Zitat antworten Zitat
rabatscher

Registriert seit: 13. Dez 2007
Ort: Bruck an der Mur
77 Beiträge
 
#6

AW: Umfrage/Architekturfrage zur DEC

  Alt 19. Mai 2025, 19:07
Zitat:
See stream functionality does need signal to end as it can and most likely used as chunk or repeated calls, "Done" will signal the sealing of the GCM tag calculation by multiply the last chained result with the first block (the one with counter=0), but enforcing requirement will break the one hit EncodeBytes/DecodeBytes, i saw these being used in many places in one line of code, enforcing "Done" with them is wrong, yet i support the functionality itself, but it must be different, may be different pair of functions, like EncodeChunk that accept TBytes or ...
By housekeeping I mean that the GCM class would count the bytes and updates the state. When done is called of course everything is finalzed and cannot
be updated further (this ends the stream...). There would also be some housekeeping involved regarding the cipher! If it does not fit the
e.g. AES blocksize one would keep the residual in memory. When Done is called the final block is encrypted + the Tag is calculated.



Zitat:
But in general moving GCM into own class is not bad idea, just costly in implementation, and will make the code cleaner as one line operation like EncodeBytes can use that GCM and call done internally, yet it might be not small refactor.
I think so too... I don't even know how the current implementation would handle a non AES 128 cipher if gcm is selected as mode.
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
3.084 Beiträge
 
Delphi 12 Athens
 
#7

AW: Umfrage/Architekturfrage zur DEC

  Alt 19. Mai 2025, 19:47
Meine Insights bezüglich des Bugreports hast du ja schon

Ich wollte hier nur noch kurz ein paar Anmerkungen machen:
* GCM ist soweit ich weiss ja nur für 128 bit Ciphers möglich
-> es wäre eventuell eine Idee GCM nur in spezialisierten Klassen zu verwenden

-> wäre rauslösen aus den TDECCipherModes eine Option, die GMC Variable ist dort eigentlich nur
für die AES Implemtierung (oder liege ich da falsch?) ?

* Ich bastle gerad am ChaCha20 Poly1305 Encoding scheme - auch dieses Schema ist nur für
256 bit ciphers gedacht (es würde also auch eine Option für AES 256 geben) aber sonst
für keine anderen Cipher. Da die Poly1305 und ChaCha teilweise miteinander verwoben sind
wäre es evt. auch hier sinnvoll eine extra Klasse zu coden...

* Ich denke multiple Calls zu EncodeBytes / EncodeStream sollten evt. doch zugelassen werden -
alle anderen Cipher, die ja nicht voneinander abhängig sind funktionieren ja so auch...
Es bräuchte hier nur etwas mehr "housekeeping" (status, counter, schon initialiert usw.) gemacht.
Ein Call von "Done" würde dann natürlich das Ganze abschließen und das Finale Tag berechnen....
Ich möchte das nicht herauslösen, da AES sicher nicht der einzige Algorithmus mit dieser Blockgröße ist.
In absehbarer Zeit kommt vermutlich noch ein authentifizierender Algorithmus hinzu (Details verrate ich
noch nicht) und der bietet dann diesselbe Schnittstelle wie der GCM, weshalb diese dann in eine gemeinsame
Basisklasse für die beiden ausgelagert wurde.

Die 128 bit sind ja die Blockgröße und nicht die Schlüssellänge, die soweit ich mich erinnere beim AES die
Anzahl Runden bestimmt. Früher gab es in der DEC nur eine AES Klasse und je nach Schlüssellänge wurde daraus
AES128, AES192 und AES256. Inzwischen gibt es auch jeweils eine eigene AES128, AES192 und AES256 Klasse.

Magst du Poly1305 zur DEC beitragen?
Falls ja kann ich dir auch einen Branch und COmmit Rechte geben.

ChaCha und SalSa stehen mittelfristig auch auf meiner ToDo Liste, habe aber auch noch jede Menge anderes
Zeugs zu tun.
Grüße
TurboMagic
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
3.084 Beiträge
 
Delphi 12 Athens
 
#8

AW: Umfrage/Architekturfrage zur DEC

  Alt 19. Mai 2025, 19:59
Ich sehe wenig Sinn darin, die Flexibilität zu beschränken, wenn es auch anders geht.
Ja, GCM wird hautsächlich auf AES angewendet. Das kann man ja so dokumentieren. Aber
wenn ein neuer Standard mal kommt der auch 128 Bit Blöcke nuntzt und GCM für den auch
einigermaßen üblich ist müsste man ja wieder ran.

Lieber die Zeit dafür nutzen und die problematische Umsetzung für Streams ändern.
Das muss man so wie es aussieht für die vor kurzem eingeführten Paddings wie Pkcs#7
sowieso auch tun. Und dann vermutlich zuerst für diese und danach für GCM, oder arbeitet
das auf den ungepaddeten Daten?

Mir schwebt eine überladene Done Variante mit Parametern vor (vermutlich der Input und
der Output Stream). Wenn man will kann man kann man nih ein Flag einbauen, welches beim
Aufruf von Encode/DecodeStream auf True gesetzt werden und würde, wenn das gesetzt ist,
im normalen Done eine Exception werfen. Damit würde man die Entwickler sicher erziehen
(bis auf die, die ihren Code nicht testen)...


* Ich denke multiple Calls zu EncodeBytes / EncodeStream sollten evt. doch zugelassen werden -
alle anderen Cipher, die ja nicht voneinander abhängig sind funktionieren ja so auch...
Es bräuchte hier nur etwas mehr "housekeeping" (status, counter, schon initialiert usw.) gemacht.
Ein Call von "Done" würde dann natürlich das Ganze abschließen und das Finale Tag berechnen....
I am not sure about that,

See stream functionality does need signal to end as it can and most likely used as chunk or repeated calls, "Done" will signal the sealing of the GCM tag calculation by multiply the last chained result with the first block (the one with counter=0), but enforcing requirement will break the one hit EncodeBytes/DecodeBytes, i saw these being used in many places in one line of code, enforcing "Done" with them is wrong, yet i support the functionality itself, but it must be different, may be different pair of functions, like EncodeChunk that accept TBytes or ...

But in general moving GCM into own class is not bad idea, just costly in implementation, and will make the code cleaner as one line operation like EncodeBytes can use that GCM and call done internally, yet it might be not small refactor.[/QUOTE]

GCM ist bereits eine separate Klasse und Unit, weil das komplizierter/aufwändiger als die anderen
Blockmodi ist. Das wird dann halt in DECCipherModes aufgerufen.
Wie oben geschrieben: meine aktuelle Idee ist es, das Ende der Streamoperation per überladener Done Methode zu signalisieren.
Grüße
TurboMagic
  Mit Zitat antworten Zitat
rabatscher

Registriert seit: 13. Dez 2007
Ort: Bruck an der Mur
77 Beiträge
 
#9

AW: Umfrage/Architekturfrage zur DEC

  Alt 20. Mai 2025, 09:30
Ich sehe wenig Sinn darin, die Flexibilität zu beschränken, wenn es auch anders geht.
Ja, GCM wird hautsächlich auf AES angewendet. Das kann man ja so dokumentieren. Aber
wenn ein neuer Standard mal kommt der auch 128 Bit Blöcke nuntzt und GCM für den auch
einigermaßen üblich ist müsste man ja wieder ran.

Lieber die Zeit dafür nutzen und die problematische Umsetzung für Streams ändern.
Das muss man so wie es aussieht für die vor kurzem eingeführten Paddings wie Pkcs#7
sowieso auch tun. Und dann vermutlich zuerst für diese und danach für GCM, oder arbeitet
das auf den ungepaddeten Daten?

Mir schwebt eine überladene Done Variante mit Parametern vor (vermutlich der Input und
der Output Stream). Wenn man will kann man kann man nih ein Flag einbauen, welches beim
Aufruf von Encode/DecodeStream auf True gesetzt werden und würde, wenn das gesetzt ist,
im normalen Done eine Exception werfen. Damit würde man die Entwickler sicher erziehen
(bis auf die, die ihren Code nicht testen)...
Würde dann dasselbe für EncodeBytes/DecodeBytes gelten? Done müsste eventuell noch die
letzten noch zwischegespeicherten Daten zurück liefern....

Ich bin nicht unbedingt ein Fan von super algemeinen Methoden, die niemand benutzt und oft
die Sache nur verkompliziert und fehleranfällig macht...
Gibt es ein RFC dass GCM nicht in Verbindung mit AES enthält?
Selbes gilt für Poly1305 - Es wird praktisch nicht mit AES verwendet!
https://crypto.stackexchange.com/que...is-it-obsolete
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
436 Beiträge
 
#10

AW: Umfrage/Architekturfrage zur DEC

  Alt 20. Mai 2025, 09:51
Well here ChaCha implementation to save you both some time, it is correct and working but i mixed the following code form two different project in haste, also while i tested it for many edge case, it is far from optimized for speed
Delphi-Quellcode:
unit ChaCha;

interface

uses
  SysUtils;

type
  TChaChaRounds = (cr8, cr12, cr20);
  TChaChaKey = array[0..31] of Byte; // 256-bit key
  TChaChaNonce = array[0..11] of Byte; // 96-bit nonce
  TChaChaBlock = array[0..63] of Byte; // 512-bit block

  TChaCha = class
  private
    FState: array[0..15] of Cardinal; // Internal state
    procedure QuarterRound(var a, b, c, d: Cardinal);
    procedure InnerBlock;
    procedure SetupState(const Key: TChaChaKey; const Nonce: TChaChaNonce; Counter: Cardinal);
    {$IFDEF CHACHA_DEBUG}
    procedure DebugState(const DbgStr: string);
    {$ENDIF}
  public
    procedure Encrypt(const Key: TChaChaKey; const Nonce: TChaChaNonce;
      Counter: Cardinal; Rounds: TChaChaRounds; const Input: TBytes; var Output: TBytes);
    class procedure SelfTest;
  end;

implementation

const
  SIGMA: array[0..3] of Cardinal = ($61707865, $3320646e, $79622d32, $6b206574); // "expand 32-byte k"

{ TChaCha }

{$IFDEF CHACHA_DEBUG}
procedure TChaCha.DebugState(const DbgStr: string);
var
  I: Integer;
begin
  WriteLn(DbgStr);
  for I := 0 to 15 do
  begin
    Write(Format('%08x ', [FState[I]]));
    if (I + 1) mod 4 = 0 then WriteLn;
  end;
  WriteLn;
end;
{$ENDIF}

procedure TChaCha.QuarterRound(var a, b, c, d: Cardinal);
begin
{$IFOPT R+}{$DEFINE RND_HasRangeChecks}{$ENDIF}
{$IFOPT Q+}{$DEFINE RND_HasOverflowChecks}{$ENDIF}
{$RANGECHECKS OFF}
{$OVERFLOWCHECKS OFF}
  a := a + b; d := d xor a; d := (d shl 16) or (d shr 16);
  c := c + d; b := b xor c; b := (b shl 12) or (b shr 20);
  a := a + b; d := d xor a; d := (d shl 8) or (d shr 24);
  c := c + d; b := b xor c; b := (b shl 7) or (b shr 25);
{$IFDEF RND_HasRangeChecks}{$RANGECHECKS ON}{$ENDIF}
{$IFDEF RND_HasOverflowChecks}{$OVERFLOWCHECKS ON}{$ENDIF}
end;

procedure TChaCha.InnerBlock;
var
  x: array[0..15] of Cardinal;
begin
  Move(FState, x, SizeOf(x));
  QuarterRound(x[0], x[4], x[8], x[12]);
  QuarterRound(x[1], x[5], x[9], x[13]);
  QuarterRound(x[2], x[6], x[10], x[14]);
  QuarterRound(x[3], x[7], x[11], x[15]);
  QuarterRound(x[0], x[5], x[10], x[15]);
  QuarterRound(x[1], x[6], x[11], x[12]);
  QuarterRound(x[2], x[7], x[8], x[13]);
  QuarterRound(x[3], x[4], x[9], x[14]);
  Move(x, FState, SizeOf(FState));
end;

procedure TChaCha.SetupState(const Key: TChaChaKey; const Nonce: TChaChaNonce; Counter: Cardinal);
begin
  FState[0] := SIGMA[0];
  FState[1] := SIGMA[1];
  FState[2] := SIGMA[2];
  FState[3] := SIGMA[3];
  Move(Key[0], FState[4], 32);
  FState[12] := Counter;
  Move(Nonce[0], FState[13], 12);
end;

procedure ChaChaBlockSIMD(State: Pointer; Rounds: Integer);
{$IF Defined(CPUX86) or Defined(CPUX64)}
asm
  // Save state
  movdqu xmm0, dqword [State+00] // Use movdqa for aligned access or switch to movdqu for unaligned
  movdqu xmm1, dqword [State+16]
  movdqu xmm2, dqword [State+32]
  movdqu xmm3, dqword [State+48]

  // Main loop
@ROUND:
  // Column round
  paddd xmm0, xmm1
  pxor xmm3, xmm0
  pshuflw xmm3, xmm3, 0B1h
  pshufhw xmm3, xmm3, 0B1h
  paddd xmm2, xmm3
  pxor xmm1, xmm2
  movdqa xmm4, xmm1
  pslld xmm1, 12
  psrld xmm4, 20
  por xmm1, xmm4
  paddd xmm0, xmm1
  pxor xmm3, xmm0
  movdqa xmm4, xmm3
  pslld xmm3, 8
  psrld xmm4, 24
  por xmm3, xmm4
  paddd xmm2, xmm3
  pxor xmm1, xmm2
  movdqa xmm4, xmm1
  pslld xmm1, 7
  psrld xmm4, 25
  por xmm1, xmm4

  // Shuffle for diagonal
  pshufd xmm1, xmm1, 39h
  pshufd xmm2, xmm2, 4Eh
  pshufd xmm3, xmm3, 93h

  // Diagonal round
  paddd xmm0, xmm1
  pxor xmm3, xmm0
  pshuflw xmm3, xmm3, 0B1h
  pshufhw xmm3, xmm3, 0B1h
  paddd xmm2, xmm3
  pxor xmm1, xmm2
  movdqa xmm4, xmm1
  pslld xmm1, 12
  psrld xmm4, 20
  por xmm1, xmm4
  paddd xmm0, xmm1
  pxor xmm3, xmm0
  movdqa xmm4, xmm3
  pslld xmm3, 8
  psrld xmm4, 24
  por xmm3, xmm4
  paddd xmm2, xmm3
  pxor xmm1, xmm2
  movdqa xmm4, xmm1
  pslld xmm1, 7
  psrld xmm4, 25
  por xmm1, xmm4

  // Shuffle back
  pshufd xmm1, xmm1, 93h
  pshufd xmm2, xmm2, 4Eh
  pshufd xmm3, xmm3, 39h

  dec Rounds
  jnz @ROUND

  {// Add original state
  paddd xmm0, dqword [State+00]    // Use dqword for aligned access, paddd must have memory aligned !
  paddd xmm1, dqword [State+16]
  paddd xmm2, dqword [State+32]
  paddd xmm3, dqword [State+48]  }

  movdqu xmm4, dqword [State+00] // unaligned memory state addition
  paddd xmm0, xmm4
  movdqu xmm4, dqword [State+16]
  paddd xmm1, xmm4
  movdqu xmm4, dqword [State+32]
  paddd xmm2, xmm4
  movdqu xmm4, dqword [State+48]
  paddd xmm3, xmm4

  // Store result
  movdqu dqword [State+00], xmm0 // Use movdqa for aligned store or switch to movdqu for unaligned
  movdqu dqword [State+16], xmm1
  movdqu dqword [State+32], xmm2
  movdqu dqword [State+48], xmm3

end;
{$ELSE}
begin
  RaiseError(ERR_SIMD_NOT_SUPPORTED);
end;
{$ENDIF}

const SIMDEnabled = true;

procedure TChaCha.Encrypt(const Key: TChaChaKey; const Nonce: TChaChaNonce;
  Counter: Cardinal; Rounds: TChaChaRounds; const Input: TBytes; var Output: TBytes);
var
  I, J, RoundCount: Integer;
  OrigState: array[0..15] of Cardinal;
  Keystream: TChaChaBlock;
  PKeystream: PByte;
begin
  SetLength(Output, Length(Input));
  if Length(Input) = 0 then
    Exit;

  case Rounds of
    cr8: RoundCount := 8;
    cr12: RoundCount := 12;
    cr20: RoundCount := 20;
  else
    RoundCount := 20;
  end;

  for I := 0 to (Length(Input) - 1) div 64 do
  begin
    SetupState(Key, Nonce, Counter + Cardinal(I));
    Move(FState, OrigState, SizeOf(FState));
    {$IFDEF CHACHA_DEBUG}
    DebugState('Before InnerBlock:');
    {$ENDIF}

    if SIMDEnabled then
      begin
        ChaChaBlockSIMD(@FState[0],RoundCount shr 1);
      end else
      begin
        for J := 1 to RoundCount shr 1 do
        begin
          InnerBlock;
          {$IFDEF CHACHA_DEBUG}
          DebugState(Format('After InnerBlock %d:', [J]));
          {$ENDIF}
        end;
        for J := 0 to 15 do
          FState[J] := Cardinal(UInt64(FState[J]) + UInt64(OrigState[J]));
      end;

    {$IFDEF CHACHA_DEBUG}
    DebugState('After adding OrigState:');
    {$ENDIF}
    Move(FState, Keystream, SizeOf(Keystream));
    {$IFDEF CHACHA_DEBUG}
    Write('Keystream: ');
    for J := 0 to 63 do
      Write(Format('%02x ', [Keystream[J]]));
    WriteLn;
    {$ENDIF}
    PKeystream := @Keystream;
    for J := 0 to 63 do
    begin
      if (I * 64 + J) >= Length(Input) then Break;
      Output[I * 64 + J] := Input[I * 64 + J] xor PKeystream^;
      Inc(PKeystream);
    end;
  end;

  // erase memory
  FillChar(FState, SizeOf(FState), 0);
  FillChar(Keystream, SizeOf(Keystream), 0);
  FillChar(OrigState, SizeOf(OrigState), 0);
end;

class procedure TChaCha.SelfTest;
const
  KEY1: TChaChaKey = (
    $00, $01, $02, $03, $04, $05, $06, $07,
    $08, $09, $0a, $0b, $0c, $0d, $0e, $0f,
    $10, $11, $12, $13, $14, $15, $16, $17,
    $18, $19, $1a, $1b, $1c, $1d, $1e, $1f
  );
  NONCE1: TChaChaNonce = (
    $00, $00, $00, $00, $00, $00, $00, $4a, $00, $00, $00, $00
  );
  PLAINTEXT1: array[0..113] of Byte = (
    $4c, $61, $64, $69, $65, $73, $20, $61, $6e, $64, $20, $47, $65, $6e, $74, $6c,
    $65, $6d, $65, $6e, $20, $6f, $66, $20, $74, $68, $65, $20, $63, $6c, $61, $73,
    $73, $20, $6f, $66, $20, $27, $39, $39, $3a, $20, $49, $66, $20, $49, $20, $63,
    $6f, $75, $6c, $64, $20, $6f, $66, $66, $65, $72, $20, $79, $6f, $75, $20, $6f,
    $6e, $6c, $79, $20, $6f, $6e, $65, $20, $74, $69, $70, $20, $66, $6f, $72, $20,
    $74, $68, $65, $20, $66, $75, $74, $75, $72, $65, $2c, $20, $73, $75, $6e, $73,
    $63, $72, $65, $65, $6e, $20, $77, $6f, $75, $6c, $64, $20, $62, $65, $20, $69,
    $74, $2e
  );
  EXPECTED_CIPHERTEXT1: array[0..113] of Byte = (
    $6e, $2e, $35, $9a, $25, $68, $f9, $80, $41, $ba, $07, $28, $dd, $0d, $69, $81,
    $e9, $7e, $7a, $ec, $1d, $43, $60, $c2, $0a, $27, $af, $cc, $fd, $9f, $ae, $0b,
    $f9, $1b, $65, $c5, $52, $47, $33, $ab, $8f, $59, $3d, $ab, $cd, $62, $b3, $57,
    $16, $39, $d6, $24, $e6, $51, $52, $ab, $8f, $53, $0c, $35, $9f, $08, $61, $d8,
    $07, $ca, $0d, $bf, $50, $0d, $6a, $61, $56, $a3, $8e, $08, $8a, $22, $b6, $5e,
    $52, $bc, $51, $4d, $16, $cc, $f8, $06, $81, $8c, $e9, $1a, $b7, $79, $37, $36,
    $5a, $f9, $0b, $bf, $74, $a3, $5b, $e6, $b4, $0b, $8e, $ed, $f2, $78, $5e, $42,
    $87, $4d
  );
  KEY2: TChaChaKey = (
    $00, $00, $00, $00, $00, $00, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $00,
    $00, $00, $00, $00, $00, $00, $00, $01
  );
  NONCE2: TChaChaNonce = (
    $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $02
  );
  PLAINTEXT2: array[0..374] of Byte = (
    $41, $6e, $79, $20, $73, $75, $62, $6d, $69, $73, $73, $69, $6f, $6e, $20, $74,
    $6f, $20, $74, $68, $65, $20, $49, $45, $54, $46, $20, $69, $6e, $74, $65, $6e,
    $64, $65, $64, $20, $62, $79, $20, $74, $68, $65, $20, $43, $6f, $6e, $74, $72,
    $69, $62, $75, $74, $6f, $72, $20, $66, $6f, $72, $20, $70, $75, $62, $6c, $69,
    $63, $61, $74, $69, $6f, $6e, $20, $61, $73, $20, $61, $6c, $6c, $20, $6f, $72,
    $20, $70, $61, $72, $74, $20, $6f, $66, $20, $61, $6e, $20, $49, $45, $54, $46,
    $20, $49, $6e, $74, $65, $72, $6e, $65, $74, $2d, $44, $72, $61, $66, $74, $20,
    $6f, $72, $20, $52, $46, $43, $20, $61, $6e, $64, $20, $61, $6e, $79, $20, $73,
    $74, $61, $74, $65, $6d, $65, $6e, $74, $20, $6d, $61, $64, $65, $20, $77, $69,
    $74, $68, $69, $6e, $20, $74, $68, $65, $20, $63, $6f, $6e, $74, $65, $78, $74,
    $20, $6f, $66, $20, $61, $6e, $20, $49, $45, $54, $46, $20, $61, $63, $74, $69,
    $76, $69, $74, $79, $20, $69, $73, $20, $63, $6f, $6e, $73, $69, $64, $65, $72,
    $65, $64, $20, $61, $6e, $20, $22, $49, $45, $54, $46, $20, $43, $6f, $6e, $74,
    $72, $69, $62, $75, $74, $69, $6f, $6e, $22, $2e, $20, $53, $75, $63, $68, $20,
    $73, $74, $61, $74, $65, $6d, $65, $6e, $74, $73, $20, $69, $6e, $63, $6c, $75,
    $64, $65, $20, $6f, $72, $61, $6c, $20, $73, $74, $61, $74, $65, $6d, $65, $6e,
    $74, $73, $20, $69, $6e, $20, $49, $45, $54, $46, $20, $73, $65, $73, $73, $69,
    $6f, $6e, $73, $2c, $20, $61, $73, $20, $77, $65, $6c, $6c, $20, $61, $73, $20,
    $77, $72, $69, $74, $74, $65, $6e, $20, $61, $6e, $64, $20, $65, $6c, $65, $63,
    $74, $72, $6f, $6e, $69, $63, $20, $63, $6f, $6d, $6d, $75, $6e, $69, $63, $61,
    $74, $69, $6f, $6e, $73, $20, $6d, $61, $64, $65, $20, $61, $74, $20, $61, $6e,
    $79, $20, $74, $69, $6d, $65, $20, $6f, $72, $20, $70, $6c, $61, $63, $65, $2c,
    $20, $77, $68, $69, $63, $68, $20, $61, $72, $65, $20, $61, $64, $64, $72, $65,
    $73, $73, $65, $64, $20, $74, $6f
  );
  EXPECTED_CIPHERTEXT2: array[0..374] of Byte = (
    $a3, $fb, $f0, $7d, $f3, $fa, $2f, $de, $4f, $37, $6c, $a2, $3e, $82, $73, $70,
    $41, $60, $5d, $9f, $4f, $4f, $57, $bd, $8c, $ff, $2c, $1d, $4b, $79, $55, $ec,
    $2a, $97, $94, $8b, $d3, $72, $29, $15, $c8, $f3, $d3, $37, $f7, $d3, $70, $05,
    $0e, $9e, $96, $d6, $47, $b7, $c3, $9f, $56, $e0, $31, $ca, $5e, $b6, $25, $0d,
    $40, $42, $e0, $27, $85, $ec, $ec, $fa, $4b, $4b, $b5, $e8, $ea, $d0, $44, $0e,
    $20, $b6, $e8, $db, $09, $d8, $81, $a7, $c6, $13, $2f, $42, $0e, $52, $79, $50,
    $42, $bd, $fa, $77, $73, $d8, $a9, $05, $14, $47, $b3, $29, $1c, $e1, $41, $1c,
    $68, $04, $65, $55, $2a, $a6, $c4, $05, $b7, $76, $4d, $5e, $87, $be, $a8, $5a,
    $d0, $0f, $84, $49, $ed, $8f, $72, $d0, $d6, $62, $ab, $05, $26, $91, $ca, $66,
    $42, $4b, $c8, $6d, $2d, $f8, $0e, $a4, $1f, $43, $ab, $f9, $37, $d3, $25, $9d,
    $c4, $b2, $d0, $df, $b4, $8a, $6c, $91, $39, $dd, $d7, $f7, $69, $66, $e9, $28,
    $e6, $35, $55, $3b, $a7, $6c, $5c, $87, $9d, $7b, $35, $d4, $9e, $b2, $e6, $2b,
    $08, $71, $cd, $ac, $63, $89, $39, $e2, $5e, $8a, $1e, $0e, $f9, $d5, $28, $0f,
    $a8, $ca, $32, $8b, $35, $1c, $3c, $76, $59, $89, $cb, $cf, $3d, $aa, $8b, $6c,
    $cc, $3a, $af, $9f, $39, $79, $c9, $2b, $37, $20, $fc, $88, $dc, $95, $ed, $84,
    $a1, $be, $05, $9c, $64, $99, $b9, $fd, $a2, $36, $e7, $e8, $18, $b0, $4b, $0b,
    $c3, $9c, $1e, $87, $6b, $19, $3b, $fe, $55, $69, $75, $3f, $88, $12, $8c, $c0,
    $8a, $aa, $9b, $63, $d1, $a1, $6f, $80, $ef, $25, $54, $d7, $18, $9c, $41, $1f,
    $58, $69, $ca, $52, $c5, $b8, $3f, $a3, $6f, $f2, $16, $b9, $c1, $d3, $00, $62,
    $be, $bc, $fd, $2d, $c5, $bc, $e0, $91, $19, $34, $fd, $a7, $9a, $86, $f6, $e6,
    $98, $ce, $d7, $59, $c3, $ff, $9b, $64, $77, $33, $8f, $3d, $a4, $f9, $cd, $85,
    $14, $ea, $99, $82, $cc, $af, $b3, $41, $b2, $38, $4d, $d9, $02, $f3, $d1, $ab,
    $7a, $c6, $1d, $d2, $9c, $6f, $21, $ba, $5b, $86, $2f, $37, $30, $e3, $7c, $fd,
    $c4, $fd, $80, $6c, $22, $f2, $21
  );
var
  ChaCha: TChaCha;
  Input, Output: TBytes;
  I: Integer;
  Pass: Boolean;
begin
  ChaCha := TChaCha.Create;
  try
    SetLength(Input, Length(PLAINTEXT1));
    Move(PLAINTEXT1, Input[0], Length(PLAINTEXT1));
    ChaCha.Encrypt(KEY1, NONCE1, 1, cr20, Input, Output);
    Pass := True;
    if Length(Output) <> Length(EXPECTED_CIPHERTEXT1) then
      Pass := False
    else
      for I := 0 to Length(EXPECTED_CIPHERTEXT1) - 1 do
        if Output[I] <> EXPECTED_CIPHERTEXT1[I] then
        begin
          Pass := False;
          WriteLn(Format('Test Vector 1: Mismatch at byte %d: got %02x, expected %02x', [I, Output[I], EXPECTED_CIPHERTEXT1[I]]));
          Break;
        end;
    if not Pass then
      raise Exception.Create('ChaCha20 Test Vector 1 failed!');

    SetLength(Input, Length(PLAINTEXT2));
    Move(PLAINTEXT2, Input[0], Length(PLAINTEXT2));
    ChaCha.Encrypt(KEY2, NONCE2, 1, cr20, Input, Output);
    Pass := True;
    if Length(Output) <> Length(EXPECTED_CIPHERTEXT2) then
      Pass := False
    else
      for I := 0 to Length(EXPECTED_CIPHERTEXT2) - 1 do
        if Output[I] <> EXPECTED_CIPHERTEXT2[I] then
        begin
          Pass := False;
          WriteLn(Format('Test Vector 2: Mismatch at byte %d: got %02x, expected %02x', [I, Output[I], EXPECTED_CIPHERTEXT2[I]]));
          Break;
        end;
    if not Pass then
      raise Exception.Create('ChaCha20 Test Vector 2 failed!');

    SetLength(Input, Length(PLAINTEXT1));
    Move(PLAINTEXT1, Input[0], Length(PLAINTEXT1));
    ChaCha.Encrypt(KEY1, NONCE1, 1, cr8, Input, Output);
    ChaCha.Encrypt(KEY1, NONCE1, 1, cr12, Input, Output);

    WriteLn('ChaCha self-test passed successfully.');
  finally
    ChaCha.Free;
  end;
end;

end.
Kas
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:04 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz