@@ -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 ;
11571175end ;
11581176
1159-
11601177function TDECCipher.CalcMAC (Format: TDECFormatClass): RawByteString;
11611178begin
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 }
11681184end ;
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}
0 commit comments