2828import java .security .InvalidAlgorithmParameterException ;
2929import java .security .NoSuchAlgorithmException ;
3030import javax .crypto .SecretKey ;
31+ import javax .crypto .spec .GCMParameterSpec ;
32+ import java .io .ByteArrayOutputStream ;
3133
3234import com .wolfssl .wolfcrypt .Md5 ;
3335import com .wolfssl .wolfcrypt .Sha ;
3840import com .wolfssl .wolfcrypt .Sha3 ;
3941import com .wolfssl .wolfcrypt .Hmac ;
4042import com .wolfssl .wolfcrypt .AesCmac ;
43+ import com .wolfssl .wolfcrypt .AesGmac ;
4144import com .wolfssl .wolfcrypt .Aes ;
4245
4346/**
@@ -56,15 +59,22 @@ enum MacType {
5659 WC_HMAC_SHA3_256 ,
5760 WC_HMAC_SHA3_384 ,
5861 WC_HMAC_SHA3_512 ,
59- WC_AES_CMAC
62+ WC_AES_CMAC ,
63+ WC_AES_GMAC
6064 }
6165
6266 private Hmac hmac = null ;
6367 private AesCmac aesCmac = null ;
68+ private AesGmac aesGmac = null ;
6469 private int nativeHmacType = 0 ;
6570 private int digestSize = 0 ;
6671 private MacType macType ;
6772
73+ /* GMAC-specific fields */
74+ private byte [] gmacIv = null ;
75+ private int gmacTagLen = 16 ; /* default tag length */
76+ private ByteArrayOutputStream gmacAuthData = null ;
77+
6878 /* for debug logging */
6979 private String algString ;
7080
@@ -139,6 +149,12 @@ private WolfCryptMac(MacType type)
139149 this .digestSize = Aes .BLOCK_SIZE ;
140150 break ;
141151
152+ case WC_AES_GMAC :
153+ aesGmac = new AesGmac ();
154+ this .digestSize = Aes .BLOCK_SIZE ;
155+ gmacAuthData = new ByteArrayOutputStream ();
156+ break ;
157+
142158 default :
143159 throw new NoSuchAlgorithmException (
144160 "Unsupported MAC type" );
@@ -156,6 +172,12 @@ protected byte[] engineDoFinal() {
156172
157173 if (macType == MacType .WC_AES_CMAC ) {
158174 out = this .aesCmac .doFinal ();
175+ } else if (macType == MacType .WC_AES_GMAC ) {
176+ /* Compute GMAC using accumulated auth data */
177+ byte [] authData = gmacAuthData .toByteArray ();
178+ out = this .aesGmac .update (gmacIv , authData , gmacTagLen );
179+ /* Reset for next operation */
180+ gmacAuthData .reset ();
159181 } else {
160182 out = this .hmac .doFinal ();
161183 }
@@ -192,6 +214,19 @@ protected void engineInit(Key key, AlgorithmParameterSpec params)
192214 try {
193215 if (macType == MacType .WC_AES_CMAC ) {
194216 this .aesCmac .setKey (encodedKey );
217+ } else if (macType == MacType .WC_AES_GMAC ) {
218+ /* GMAC requires GCMParameterSpec with IV */
219+ if (params == null || !(params instanceof GCMParameterSpec )) {
220+ throw new InvalidAlgorithmParameterException (
221+ "AES-GMAC requires GCMParameterSpec with IV" );
222+ }
223+ GCMParameterSpec gcmSpec = (GCMParameterSpec ) params ;
224+ this .gmacIv = gcmSpec .getIV ();
225+ /* Convert bits to bytes */
226+ this .gmacTagLen = gcmSpec .getTLen () / 8 ;
227+ this .aesGmac .setKey (encodedKey );
228+ /* Reset auth data accumulator */
229+ gmacAuthData .reset ();
195230 } else {
196231 this .hmac .setKey (nativeHmacType , encodedKey );
197232 }
@@ -206,6 +241,11 @@ protected void engineInit(Key key, AlgorithmParameterSpec params)
206241 protected void engineReset () {
207242 if (macType == MacType .WC_AES_CMAC ) {
208243 this .aesCmac .reset ();
244+ } else if (macType == MacType .WC_AES_GMAC ) {
245+ /* Reset GMAC auth data accumulator */
246+ if (gmacAuthData != null ) {
247+ gmacAuthData .reset ();
248+ }
209249 } else {
210250 this .hmac .reset ();
211251 }
@@ -217,6 +257,9 @@ protected void engineReset() {
217257 protected void engineUpdate (byte input ) {
218258 if (macType == MacType .WC_AES_CMAC ) {
219259 this .aesCmac .update (input );
260+ } else if (macType == MacType .WC_AES_GMAC ) {
261+ /* Accumulate auth data for GMAC */
262+ gmacAuthData .write (input );
220263 } else {
221264 this .hmac .update (input );
222265 }
@@ -228,6 +271,9 @@ protected void engineUpdate(byte input) {
228271 protected void engineUpdate (byte [] input , int offset , int len ) {
229272 if (macType == MacType .WC_AES_CMAC ) {
230273 this .aesCmac .update (input , offset , len );
274+ } else if (macType == MacType .WC_AES_GMAC ) {
275+ /* Accumulate auth data for GMAC */
276+ gmacAuthData .write (input , offset , len );
231277 } else {
232278 this .hmac .update (input , offset , len );
233279 }
@@ -259,6 +305,8 @@ private String typeToString(MacType type) {
259305 return "SHA3-512" ;
260306 case WC_AES_CMAC :
261307 return "AES-CMAC" ;
308+ case WC_AES_GMAC :
309+ return "AES-GMAC" ;
262310 default :
263311 return "None" ;
264312 }
@@ -277,6 +325,8 @@ protected void finalize() throws Throwable {
277325 this .hmac .releaseNativeStruct ();
278326 if (this .aesCmac != null )
279327 this .aesCmac .releaseNativeStruct ();
328+ if (this .aesGmac != null )
329+ this .aesGmac .releaseNativeStruct ();
280330 } finally {
281331 super .finalize ();
282332 }
@@ -446,4 +496,19 @@ public wcAesCmac() throws NoSuchAlgorithmException {
446496 super (MacType .WC_AES_CMAC );
447497 }
448498 }
499+
500+ /**
501+ * wolfJCE AES-GMAC class
502+ */
503+ public static final class wcAesGmac extends WolfCryptMac {
504+ /**
505+ * Create new wcAesGmac object
506+ *
507+ * @throws NoSuchAlgorithmException if AES-GMAC is not available at
508+ * native wolfCrypt level.
509+ */
510+ public wcAesGmac () throws NoSuchAlgorithmException {
511+ super (MacType .WC_AES_GMAC );
512+ }
513+ }
449514}
0 commit comments