Skip to content

Commit 8d37cac

Browse files
author
Markus Humm
committed
Merge remote-tracking branch 'origin/master' into development
2 parents 7ac8a72 + e38e915 commit 8d37cac

File tree

7 files changed

+65
-47
lines changed

7 files changed

+65
-47
lines changed

Demos/Cipher_Console/Cipher_Console.dpr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ begin
6363

6464
// Encrypt
6565
Output := Cipher.EncodeBytes(Input);
66-
// clean up inside the cipher instance, which also removes the key from RAM
6766
Cipher.Done;
6867

6968
Write('Encrypted data in hex: ');
@@ -75,7 +74,6 @@ begin
7574
// Decrypt
7675
Cipher.Init(CipherKey, IV, 0);
7776
Output := Cipher.DecodeBytes(Output);
78-
// clean up inside the cipher instance, which also removes the key from RAM
7977
Cipher.Done;
8078

8179
SourceText := RawByteString(System.SysUtils.StringOf(Output));
@@ -89,7 +87,6 @@ begin
8987
CipherKey := 'Password';
9088
Cipher.Init(CipherKey, IV, 0);
9189
Output := Cipher.DecodeBytes(Output);
92-
// clean up inside the cipher instance, which also removes the key from RAM
9390
Cipher.Done;
9491

9592
SourceText := RawByteString(System.SysUtils.StringOf(Output));
@@ -104,6 +101,7 @@ begin
104101

105102
ReadLn;
106103
finally
104+
// clean up inside the cipher instance, which also removes the key from RAM
107105
Cipher.Free;
108106
end;
109107
end.

Demos/Cipher_Console_KDF/Cipher_Console_KDF.dpr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ begin
7171

7272
// Encrypt
7373
Output := Cipher.EncodeBytes(Input);
74-
// clean up inside the cipher instance, which also removes the key from RAM
7574
Cipher.Done;
7675

7776
Write('Encrypted data in hex: ');
@@ -83,7 +82,6 @@ begin
8382
// Decrypt
8483
Cipher.Init(RawByteString(StringOf(KeyKDF)), IV, 0);
8584
Output := Cipher.DecodeBytes(Output);
86-
// clean up inside the cipher instance, which also removes the key from RAM
8785
Cipher.Done;
8886

8987
SourceText := RawByteString(System.SysUtils.StringOf(Output));
@@ -96,6 +94,7 @@ begin
9694

9795
ReadLn;
9896
finally
97+
// clean up inside the cipher instance, which also removes the key from RAM
9998
Cipher.Free;
10099
end;
101100
end.

Demos/Cipher_FMX/MainFormCipherFMX.pas

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ procedure TFormMain.ButtonDecryptClick(Sender: TObject);
294294
PlainTextBuffer := (Cipher as TDECFormattedCipher).DecodeBytes(
295295
CipherTextFormatting.Decode(CipherTextBuffer));
296296
// in case of an authenticated cipher mode like cmGCM the Done method
297-
// will raise an exceptino when the calculated authentication value does
298-
// not match the given expected one
297+
// will raise an exception when the calculated authentication value does
298+
// not match the given expected one set in SetAuthenticationParams().
299299
(Cipher as TDECFormattedCipher).Done;
300300
// If we managed to get to here, the calculated authentication value is
301301
// ok if we're in an authenticated mode and have entered an expected value.

Demos/Hash_Console/Hash_Console.dpr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ begin
4343
WriteLn('RipeMD160 digest (hash value) of ' + s + ' is ' + sLineBreak +
4444
Hash.CalcString(s, TFormat_HEX));
4545

46-
// Securely erase the memory
4746
Hash.Done;
4847
except
4948
on E: Exception do
@@ -52,6 +51,7 @@ begin
5251

5352
ReadLn;
5453
finally
54+
// Securely erase the memory
5555
Hash.Free;
5656
end;
5757
end.

Source/DECCipherBase.pas

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,6 @@ interface
112112
/// csNew : cipher isn't initialized, .Init() must be called before en/decode
113113
/// </para>
114114
/// <para>
115-
/// csNew : cipher isn't initialized, .Init() must be called before en/decode
116-
/// </para>
117-
/// <para>
118115
/// csInitialized : cipher is initialized by .Init(), i.e. Keysetup was processed
119116
/// </para>
120117
/// <para>
@@ -128,10 +125,11 @@ interface
128125
/// be processed, the cipher is blocked
129126
/// </para>
130127
/// <para>
131-
/// csDone : Processing is finished and Cipher.Done was called. Now new En/Decoding
128+
/// csDone : Processing is finished and Cipher.Done was called. Now, new En/Decoding
132129
/// can be started without calling .Init() before. csDone is basically
133130
/// identical to csInitialized, except Cipher.Buffer holds the encrypted
134-
/// last state of Cipher.Feedback, thus Cipher.Buffer can be used as C-MAC.
131+
/// last state of Cipher.Feedback which can be used as
132+
/// Cipher-based message authentication code (CMAC).
135133
/// </para>
136134
/// </summary>
137135
TCipherState = (csNew, csInitialized, csEncode, csDecode, csPadded, csDone);
@@ -252,6 +250,8 @@ TDECCipher = class(TDECObject)
252250
/// Some algorithms, mostly the cipher mode ones, need a temporary buffer
253251
/// to work with. Some other methods like Done or Valid cipher need to pass
254252
/// a buffer as parameter as that is ecpected by the called method.
253+
/// If Done was called, FBuffer contains a C-MAC which is the encryption
254+
/// of the last block concatention feedback.
255255
/// </summary>
256256
FBuffer: PUInt8Array;
257257

@@ -296,7 +296,7 @@ TDECCipher = class(TDECObject)
296296
/// FAdditionalBuffer points to as well, and for some algorithms this part
297297
/// of the memory may not be altered during initialization so it is
298298
/// backupped to this memory location and restored after the IV got encrypted.
299-
/// In DoDone it needs to be restored as well to prevent any unwanted
299+
/// In Done it needs to be restored as well to prevent any unwanted
300300
/// leftovers which might pose a security issue.
301301
/// </summary>
302302
FAdditionalBufferBackup: Pointer;
@@ -444,7 +444,8 @@ TDECCipher = class(TDECObject)
444444
constructor Create; override;
445445
/// <summary>
446446
/// Frees internal structures and where necessary does so in a save way so
447-
/// that data in those structures cannot be "stolen".
447+
/// that data in those structures cannot be "stolen". It removes the key
448+
/// from RAM.
448449
/// </summary>
449450
destructor Destroy; override;
450451

@@ -578,8 +579,9 @@ TDECCipher = class(TDECObject)
578579

579580
/// <summary>
580581
/// Properly finishes the cryptographic operation. It needs to be called
581-
/// at the end of encrypting or decrypting data, otherwise the last block
582-
/// or last byte of the data will not be properly processed.
582+
/// at the end of encrypting or decrypting data. It does NOT remove the
583+
/// keys from RAM (this will be done in the destruction only).
584+
/// You can continue encrypting/decrypting without calling Init() again.
583585
/// </summary>
584586
procedure Done; virtual;
585587

@@ -696,18 +698,34 @@ TDECCipher = class(TDECObject)
696698
/// </exception>
697699
function DecodeBytes(const Source: TBytes; Format: TDECFormatClass): TBytes;
698700

699-
// CalcMACBytes deferred since the current implementation would neither be
700-
// performant (that would require another TFormatBase.Encode variant from
701-
// pointer to TBytes and that would require a new method name as overloads
702-
// may not differ in return values only and it would require a lot of unit
703-
// tests to get implemented. Deferred in particular also due to not yet
704-
// really understanding the purpose of CalcMAC
705-
// function CalcMACByte(Format: TDECFormatClass = nil): TBytes; overload;
701+
/// <summary>
702+
/// Calculates a Cipher-based message authentication code (CMAC).
703+
/// This is the encryption of the last block concatenation feedback value.
704+
/// In decryption scenarios it can be used to check if the data arrived
705+
/// unaltered if the sender provides the MAC value along with the encrypted
706+
/// text. Both need to match after decrypting. Using this method is less
707+
/// secure than using the HMAC algorithm!
708+
/// This method cannot be used in the ECB cipher mode.
709+
/// Side effect: "Done" will be called if it hasn't been called before.
710+
/// </summary>
711+
/// <param name="Format">
712+
/// Optional parameter. Here a formatting method can be passed. The
713+
/// data to be decrypted will be formatted with this function, if one
714+
/// has been passed. Examples are hex or base 64 formatting.
715+
/// This is used for removing a formatting applied by the EncodeRawByteString
716+
/// method.
717+
/// </param>
718+
/// <returns>
719+
/// Calculates a Cipher-based message authentication code (CMAC).
720+
/// </returns>
721+
/// <exception cref="EDECCipherException">
722+
/// Exception raised the cipher mode is ECB.
723+
/// </exception>
724+
{ TODO: Add unit test }
725+
function CalcMAC(Format: TDECFormatClass = nil): RawByteString;
706726

707-
// Deprecated directive commented out, as replacement CalcMACByte has not
708-
// been implemented yet, see remark above. Use case for CalcMAC is not clear
709-
// yet either.
710-
function CalcMAC(Format: TDECFormatClass = nil): RawByteString; overload; //deprecated 'please use the TBytes based overload';
727+
/// Same as CalcMAC, but return TBytes
728+
function CalcMACBytes(Format: TDECFormatClass = nil): TBytes;
711729

712730
// properties
713731

@@ -1156,27 +1174,19 @@ function TDECCipher.DecodeBytes(const Source: TBytes; Format: TDECFormatClass):
11561174
end;
11571175
end;
11581176

1159-
11601177
function TDECCipher.CalcMAC(Format: TDECFormatClass): RawByteString;
11611178
begin
1162-
Done;
1179+
Done; { TODO: This might be considered as unwanted side effect. Maybe we should instead raise an Exception if State is not csDone instead? This would also "teach" the user to don't forget to call "Done". }
11631180
if FMode in [cmECBx] then
11641181
raise EDECException.CreateRes(@sInvalidMACMode)
11651182
else
11661183
Result := ValidFormat(Format).Encode(FBuffer^, FBufferSize);
1167-
{ TODO : How to rewrite? EncodeBytes cannot be called directly like that }
11681184
end;
11691185

1170-
//function TDECCipher.CalcMACByte(Format: TDECFormatClass): TBytes;
1171-
//begin
1172-
// Done;
1173-
// if FMode in [cmECBx] then
1174-
// raise EDECCipherException.Create(sInvalidMACMode)
1175-
// else
1176-
// begin
1177-
// Result := System.SysUtils.BytesOf(ValidFormat(Format).Encode(FBuffer^, FBufferSize));
1178-
// end;
1179-
//end;
1186+
function TDECCipher.CalcMACBytes(Format: TDECFormatClass): TBytes;
1187+
begin
1188+
Result := System.SysUtils.BytesOf(CalcMAC);
1189+
end;
11801190

11811191
{$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF}
11821192
{$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF}

Source/DECHashAuthentication.pas

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ TDECHashAuthentication = class(TDECHash)
116116
class function MGF1(const Data; DataSize, MaskSize: Integer): TBytes; overload;
117117
/// <summary>
118118
/// Mask generation: generates an output based on the data given which is
119-
/// similar to a hash function but incontrast does not have a fixed output
119+
/// similar to a hash function but in contrast does not have a fixed output
120120
/// length. Use of a MGF is desirable in cases where a fixed-size hash
121121
/// would be inadequate. Examples include generating padding, producing
122122
/// one time pads or keystreams in symmetric key encryption, and yielding
@@ -341,7 +341,7 @@ TDECHashAuthentication = class(TDECHash)
341341

342342
/// <summary>
343343
/// Mask generation: generates an output based on the data given which is
344-
/// similar to a hash function but incontrast does not have a fixed output
344+
/// similar to a hash function but in contrast does not have a fixed output
345345
/// length. Use of a MGF is desirable in cases where a fixed-size hash
346346
/// would be inadequate. Examples include generating padding, producing
347347
/// one time pads or keystreams in symmetric key encryption, and yielding
@@ -372,7 +372,7 @@ TDECHashAuthentication = class(TDECHash)
372372
Index: UInt32 = 1): TBytes; overload;
373373
/// <summary>
374374
/// Mask generation: generates an output based on the data given which is
375-
/// similar to a hash function but incontrast does not have a fixed output
375+
/// similar to a hash function but in contrast does not have a fixed output
376376
/// length. Use of a MGF is desirable in cases where a fixed-size hash
377377
/// would be inadequate. Examples include generating padding, producing
378378
/// one time pads or keystreams in symmetric key encryption, and yielding

Unit Tests/Tests/TestDECHashSHA3.pas

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{*****************************************************************************
1+
{*****************************************************************************
22
The DEC team (see file NOTICE.txt) licenses this file
33
to you under the Apache License, Version 2.0 (the
44
"License"); you may not use this file except in compliance
@@ -1829,7 +1829,6 @@ procedure TestTHash_Keccak_224.SetUp;
18291829

18301830
//Source https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-
18311831
// Validation-Program/documents/sha3/sha-3bittestvectors.zip
1832-
18331832
FTestFileNames.Add('..\..\Unit Tests\Data\SHA3_224ShortMsg.rsp');
18341833
FTestFileNames.Add('..\..\Unit Tests\Data\SHA3_224LongMsg.rsp');
18351834
// SourceEnd
@@ -2068,20 +2067,29 @@ procedure TestTHash_Keccak_256.SetUp;
20682067

20692068
// Source https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-
20702069
// and-Guidelines/documents/examples/SHA3-256_Msg5.pdf
2070+
// TODO:
2071+
// expected: <7b0047cf5a456882363cbf0fb05322cf65f4b7059a46365e830132e3b5d957af>
2072+
// but was: <1594a22d1e1dd176e6f35ae26d8efa294589e23676e1fdc917423a1282546528>
20712073
lDataRow := FTestData.AddRow;
20722074
lDataRow.ExpectedOutput := '7b0047cf5a456882363cbf0fb05322cf65f4b705' +
20732075
'9a46365e830132e3b5d957af';
20742076
AddLastByteForCodeTest(lDataRow, #$13, 5);
20752077

20762078
// Source https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-
20772079
// and-Guidelines/documents/examples/SHA3-256_Msg30.pdf
2080+
// TODO:
2081+
// expected: <c8242fef409e5ae9d1f1c857ae4dc624b92b19809f62aa8c07411c54a078b1d0>
2082+
// but was: <ce8c2109c14e5416785a205f34316b50fa11993fac9c7236c643cb5e7b00afbd>
20782083
lDataRow := FTestData.AddRow;
20792084
lDataRow.ExpectedOutput := 'c8242fef409e5ae9d1f1c857ae4dc624b92b1980' +
20802085
'9f62aa8c07411c54a078b1d0';
2081-
AddLastByteForCodeTest(lDataRow, #$53#$58#$7B#$19, 6);
2086+
AddLastByteForCodeTest(lDataRow, #$53#$58#$7B#$19, 30 mod 8);
20822087

20832088
// Source https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-
20842089
// and-Guidelines/documents/examples/SHA3-256_Msg1605.pdf
2090+
// TODO:
2091+
// expected: <81ee769bed0950862b1ddded2e84aaa6ab7bfdd3ceaa471be31163d40336363c>
2092+
// but was: <ffc38f204f021c3adf97c55e0d453904749b6ad71c15612f60d018e946d00c24>
20852093
lDataRow := FTestData.AddRow;
20862094
lDataRow.ExpectedOutput := '81ee769bed0950862b1ddded2e84aaa6ab7bfdd3' +
20872095
'ceaa471be31163d40336363c';
@@ -2110,6 +2118,9 @@ procedure TestTHash_Keccak_256.SetUp;
21102118

21112119
// Source https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-
21122120
// and-Guidelines/documents/examples/SHA3-256_1630.pdf
2121+
// TODO:
2122+
// expected: <52860aa301214c610d922a6b6cab981ccd06012e54ef689d744021e738b9ed20>
2123+
// but was: <96eb974c5cfdfc80fe2e8b0203652998827cda5b8ecd2a99ab90e653ed1eacc1>
21132124
lDataRow := FTestData.AddRow;
21142125
lDataRow.ExpectedOutput := '52860aa301214c610d922a6b6cab981ccd06012e' +
21152126
'54ef689d744021e738b9ed20';

0 commit comments

Comments
 (0)