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 ;
@@ -43,6 +44,7 @@ public Object run()
4344 });
4445 }
4546
47+ // TODO[tls] Once Java 7 or higher is the baseline, this will always be true
4648 private static final boolean canDoAEAD = checkForAEAD ();
4749
4850 private static String getAlgParamsName (JcaJceHelper helper , String cipherName )
@@ -68,8 +70,10 @@ private static String getAlgParamsName(JcaJceHelper helper, String cipherName)
6870 private final String algorithmParamsName ;
6971
7072 private SecretKey key ;
71- private byte [] nonce ;
72- private int macSize ;
73+
74+ // TODO[tls] These two are only needed while the baseline is pre-Java7
75+ private byte [] noncePre7 ;
76+ private int macSizePre7 ;
7377
7478 public JceAEADCipherImpl (JcaTlsCrypto crypto , JcaJceHelper helper , String cipherName , String algorithm , int keySize ,
7579 boolean isEncrypting )
@@ -120,10 +124,27 @@ public void init(byte[] nonce, int macSize)
120124 }
121125 else
122126 {
123- // Otherwise fall back to the BC-specific AEADParameterSpec
124- cipher .init (cipherMode , key , new AEADParameterSpec (nonce , macSize * 8 , null ), random );
125- this .nonce = Arrays .clone (nonce );
126- this .macSize = macSize ;
127+ /*
128+ * Otherwise fall back to the BC-specific AEADParameterSpec. Since updateAAD is not available, we
129+ * need to use init to pass the associated data (in doFinal), but in order to call getOutputSize we
130+ * technically need to init the cipher first. So we init with a dummy nonce to avoid duplicate nonce
131+ * error from the init in doFinal.
132+ */
133+
134+ if (this .noncePre7 == null || this .noncePre7 .length != nonce .length )
135+ {
136+ this .noncePre7 = new byte [nonce .length ];
137+ }
138+
139+ System .arraycopy (nonce , 0 , this .noncePre7 , 0 , nonce .length );
140+ this .macSizePre7 = macSize ;
141+
142+ this .noncePre7 [0 ] ^= 0x80 ;
143+
144+ AlgorithmParameterSpec params = new AEADParameterSpec (noncePre7 , macSizePre7 * 8 , null );
145+ cipher .init (cipherMode , key , params , random );
146+
147+ this .noncePre7 [0 ] ^= 0x80 ;
127148 }
128149 }
129150 catch (Exception e )
@@ -150,7 +171,11 @@ public int doFinal(byte[] additionalData, byte[] input, int inputOffset, int inp
150171 {
151172 try
152173 {
153- cipher .init (cipherMode , key , new AEADParameterSpec (nonce , macSize * 8 , additionalData ));
174+ // NOTE: Shouldn't need a SecureRandom, but this is cheaper if the provider would auto-create one
175+ SecureRandom random = crypto .getSecureRandom ();
176+
177+ AlgorithmParameterSpec params = new AEADParameterSpec (noncePre7 , macSizePre7 * 8 , additionalData );
178+ cipher .init (cipherMode , key , params , random );
154179 }
155180 catch (Exception e )
156181 {
0 commit comments