66import java .security .GeneralSecurityException ;
77import java .security .PrivilegedAction ;
88import java .security .SecureRandom ;
9+ import java .security .spec .AlgorithmParameterSpec ;
910
1011import javax .crypto .Cipher ;
1112import javax .crypto .SecretKey ;
@@ -68,6 +69,9 @@ private static String getAlgParamsName(JcaJceHelper helper, String cipherName)
6869
6970 private SecretKey key ;
7071
72+ private byte [] noncePre7 ;
73+ private int macSizePre7 ;
74+
7175 public JceAEADCipherImpl (JcaTlsCrypto crypto , JcaJceHelper helper , String cipherName , String algorithm , int keySize ,
7276 boolean isEncrypting )
7377 throws GeneralSecurityException
@@ -91,9 +95,6 @@ public void setKey(byte[] key, int keyOff, int keyLen)
9195 this .key = new SecretKeySpec (key , keyOff , keyLen , algorithm );
9296 }
9397
94- private byte [] nonce ;
95- private int macSize ;
96-
9798 public void init (byte [] nonce , int macSize )
9899 {
99100 // NOTE: Shouldn't need a SecureRandom, but this is cheaper if the provider would auto-create one
@@ -104,23 +105,44 @@ public void init(byte[] nonce, int macSize)
104105// if (canDoAEAD && algorithmParamsName != null)
105106// {
106107// AlgorithmParameters algParams = helper.createAlgorithmParameters(algorithmParamsName);
107- //
108- // // fortunately CCM and GCM parameters have the same ASN.1 structure
109- // algParams.init(new GCMParameters(nonce, macSize).getEncoded ());
110- //
111- // cipher .init(cipherMode, key, algParams );
112- //
113- // if (additionalData != null && additionalData.length > 0)
108+ //
109+ // // believe it or not but there are things out there that do not support the ASN.1 encoding...
110+ // if (GCMUtil.isGCMParameterSpecAvailable ())
111+ // {
112+ // algParams .init(GCMUtil.createGCMParameterSpec(macSize * 8, nonce) );
113+ // }
114+ // else
114115// {
115- // cipher.updateAAD(additionalData);
116+ // // fortunately CCM and GCM parameters have the same ASN.1 structure
117+ // algParams.init(new GCMParameters(nonce, macSize).getEncoded());
116118// }
119+ //
120+ // cipher.init(cipherMode, key, algParams, random);
117121// }
118122// else
119123// {
120- // Otherwise fall back to the BC-specific AEADParameterSpec
121- this .nonce = Arrays .clone (nonce );
122- this .macSize = macSize ;
123- // }
124+ /*
125+ * Otherwise fall back to the BC-specific AEADParameterSpec. Since updateAAD is not available, we
126+ * need to use init to pass the associated data (in doFinal), but in order to call getOutputSize we
127+ * technically need to init the cipher first. So we init with a dummy nonce to avoid duplicate nonce
128+ * error from the init in doFinal.
129+ */
130+
131+ if (this .noncePre7 == null || this .noncePre7 .length != nonce .length )
132+ {
133+ this .noncePre7 = new byte [nonce .length ];
134+ }
135+
136+ System .arraycopy (nonce , 0 , this .noncePre7 , 0 , nonce .length );
137+ this .macSizePre7 = macSize ;
138+
139+ this .noncePre7 [0 ] ^= 0x80 ;
140+
141+ AlgorithmParameterSpec params = new AEADParameterSpec (noncePre7 , macSizePre7 * 8 , null );
142+ cipher .init (cipherMode , key , params , random );
143+
144+ this .noncePre7 [0 ] ^= 0x80 ;
145+ // }
124146 }
125147 catch (Exception e )
126148 {
@@ -136,20 +158,27 @@ public int getOutputSize(int inputLength)
136158 public int doFinal (byte [] additionalData , byte [] input , int inputOffset , int inputLength , byte [] output , int outputOffset )
137159 throws IOException
138160 {
139- try
140- {
141- if (!Arrays .isNullOrEmpty (additionalData ))
142- {
143- cipher .init (cipherMode , key , new AEADParameterSpec (nonce , macSize * 8 , additionalData ));
144- }
145- else
146- {
147- cipher .init (cipherMode , key , new AEADParameterSpec (nonce , macSize * 8 , null ));
148- }
149- }
150- catch (Exception e )
161+ if (!Arrays .isNullOrEmpty (additionalData ))
151162 {
152- throw new IOException (e .toString ());
163+ // if (canDoAEAD)
164+ // {
165+ // cipher.updateAAD(additionalData);
166+ // }
167+ // else
168+ // {
169+ try
170+ {
171+ // NOTE: Shouldn't need a SecureRandom, but this is cheaper if the provider would auto-create one
172+ SecureRandom random = crypto .getSecureRandom ();
173+
174+ AlgorithmParameterSpec params = new AEADParameterSpec (noncePre7 , macSizePre7 * 8 , additionalData );
175+ cipher .init (cipherMode , key , params , random );
176+ }
177+ catch (Exception e )
178+ {
179+ throw new IOException (e );
180+ }
181+ // }
153182 }
154183
155184 /*
0 commit comments