@@ -112,9 +112,6 @@ interface
112
112
// / csNew : cipher isn't initialized, .Init() must be called before en/decode
113
113
// / </para>
114
114
// / <para>
115
- // / csNew : cipher isn't initialized, .Init() must be called before en/decode
116
- // / </para>
117
- // / <para>
118
115
// / csInitialized : cipher is initialized by .Init(), i.e. Keysetup was processed
119
116
// / </para>
120
117
// / <para>
@@ -128,10 +125,11 @@ interface
128
125
// / be processed, the cipher is blocked
129
126
// / </para>
130
127
// / <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
132
129
// / can be started without calling .Init() before. csDone is basically
133
130
// / 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).
135
133
// / </para>
136
134
// / </summary>
137
135
TCipherState = (csNew, csInitialized, csEncode, csDecode, csPadded, csDone);
@@ -252,6 +250,8 @@ TDECCipher = class(TDECObject)
252
250
// / Some algorithms, mostly the cipher mode ones, need a temporary buffer
253
251
// / to work with. Some other methods like Done or Valid cipher need to pass
254
252
// / 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.
255
255
// / </summary>
256
256
FBuffer: PUInt8Array;
257
257
@@ -296,7 +296,7 @@ TDECCipher = class(TDECObject)
296
296
// / FAdditionalBuffer points to as well, and for some algorithms this part
297
297
// / of the memory may not be altered during initialization so it is
298
298
// / 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
300
300
// / leftovers which might pose a security issue.
301
301
// / </summary>
302
302
FAdditionalBufferBackup: Pointer;
@@ -444,7 +444,8 @@ TDECCipher = class(TDECObject)
444
444
constructor Create; override;
445
445
// / <summary>
446
446
// / 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.
448
449
// / </summary>
449
450
destructor Destroy; override;
450
451
@@ -578,8 +579,9 @@ TDECCipher = class(TDECObject)
578
579
579
580
// / <summary>
580
581
// / 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.
583
585
// / </summary>
584
586
procedure Done ; virtual ;
585
587
@@ -696,18 +698,34 @@ TDECCipher = class(TDECObject)
696
698
// / </exception>
697
699
function DecodeBytes (const Source: TBytes; Format: TDECFormatClass): TBytes;
698
700
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;
706
726
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;
711
729
712
730
// properties
713
731
@@ -1156,27 +1174,19 @@ function TDECCipher.DecodeBytes(const Source: TBytes; Format: TDECFormatClass):
1156
1174
end ;
1157
1175
end ;
1158
1176
1159
-
1160
1177
function TDECCipher.CalcMAC (Format: TDECFormatClass): RawByteString;
1161
1178
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". }
1163
1180
if FMode in [cmECBx] then
1164
1181
raise EDECException.CreateRes(@sInvalidMACMode)
1165
1182
else
1166
1183
Result := ValidFormat(Format).Encode(FBuffer^, FBufferSize);
1167
- { TODO : How to rewrite? EncodeBytes cannot be called directly like that }
1168
1184
end ;
1169
1185
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 ;
1180
1190
1181
1191
{ $IFDEF RESTORE_RANGECHECKS}{ $R+}{ $ENDIF}
1182
1192
{ $IFDEF RESTORE_OVERFLOWCHECKS}{ $Q+}{ $ENDIF}
0 commit comments