24
24
import java .security .PrivateKey ;
25
25
import java .security .PublicKey ;
26
26
import java .security .SecureRandom ;
27
+ import java .security .spec .AlgorithmParameterSpec ;
28
+ import java .security .spec .MGF1ParameterSpec ;
27
29
import java .util .ArrayList ;
28
30
import java .util .Arrays ;
29
31
import java .util .Collection ;
30
32
import java .util .List ;
31
33
import java .util .Map ;
32
34
import java .util .logging .Logger ;
35
+ import java .util .regex .Matcher ;
33
36
import java .util .regex .Pattern ;
34
37
35
38
import javax .crypto .Cipher ;
36
39
import javax .crypto .SecretKey ;
37
40
import javax .crypto .spec .GCMParameterSpec ;
41
+ import javax .crypto .spec .OAEPParameterSpec ;
42
+ import javax .crypto .spec .PSource ;
38
43
import javax .crypto .spec .SecretKeySpec ;
39
44
40
45
import com .amazonaws .encryptionsdk .CryptoAlgorithm ;
@@ -237,17 +242,58 @@ public WrappingData(final Cipher cipher, final byte[] extraInfo) {
237
242
}
238
243
239
244
private static class Rsa extends JceMasterKey {
245
+ // MGF1 with SHA-224 isn't really supported, but we include it in the regex because we need it
246
+ // for proper handling of the algorithm.
240
247
private static final Pattern SUPPORTED_TRANSFORMATIONS =
241
- Pattern .compile ("RSA/ECB/(?:PKCS1Padding|OAEPWithSHA -(?:1|256|384|512)AndMGF1Padding)" ,
248
+ Pattern .compile ("RSA/ECB/(?:PKCS1Padding|OAEPWith(SHA -(?:1|224| 256|384|512) )AndMGF1Padding)" ,
242
249
Pattern .CASE_INSENSITIVE );
250
+ private final AlgorithmParameterSpec parameterSpec_ ;
243
251
private final String transformation_ ;
244
252
245
253
private Rsa (PublicKey wrappingKey , PrivateKey unwrappingKey , String providerName , String keyId ,
246
254
String transformation ) {
247
255
super (wrappingKey , unwrappingKey , providerName , keyId );
248
- transformation_ = transformation ;
249
- if (!SUPPORTED_TRANSFORMATIONS .matcher (transformation_ ).matches ()) {
250
- LOGGER .warning (transformation_ + " is not officially supported by the JceMasterKey" );
256
+
257
+ final Matcher matcher = SUPPORTED_TRANSFORMATIONS .matcher (transformation );
258
+ if (matcher .matches ()) {
259
+ final String hashUnknownCase = matcher .group (1 );
260
+ if (hashUnknownCase != null ) {
261
+ // OAEP mode a.k.a PKCS #1v2
262
+ final String hash = hashUnknownCase .toUpperCase ();
263
+ transformation_ = "RSA/ECB/OAEPPadding" ;
264
+
265
+ final MGF1ParameterSpec mgf1Spec ;
266
+ switch (hash ) {
267
+ case "SHA-1" :
268
+ mgf1Spec = MGF1ParameterSpec .SHA1 ;
269
+ break ;
270
+ case "SHA-224" :
271
+ LOGGER .warning (transformation + " is not officially supported by the JceMasterKey" );
272
+ mgf1Spec = MGF1ParameterSpec .SHA224 ;
273
+ break ;
274
+ case "SHA-256" :
275
+ mgf1Spec = MGF1ParameterSpec .SHA256 ;
276
+ break ;
277
+ case "SHA-384" :
278
+ mgf1Spec = MGF1ParameterSpec .SHA384 ;
279
+ break ;
280
+ case "SHA-512" :
281
+ mgf1Spec = MGF1ParameterSpec .SHA512 ;
282
+ break ;
283
+ default :
284
+ throw new IllegalArgumentException ("Unsupported algorithm: " + transformation );
285
+ }
286
+ parameterSpec_ = new OAEPParameterSpec (hash , "MGF1" , mgf1Spec , PSource .PSpecified .DEFAULT );
287
+ } else {
288
+ // PKCS #1 v1.x
289
+ transformation_ = transformation ;
290
+ parameterSpec_ = null ;
291
+ }
292
+ } else {
293
+ LOGGER .warning (transformation + " is not officially supported by the JceMasterKey" );
294
+ // Unsupported transformation, just use exactly what we are given
295
+ transformation_ = transformation ;
296
+ parameterSpec_ = null ;
251
297
}
252
298
}
253
299
@@ -256,8 +302,8 @@ protected WrappingData buildWrappingCipher(Key key, Map<String, String> encrypti
256
302
throws GeneralSecurityException {
257
303
// We require BouncyCastle to avoid some bugs in the default Java implementation
258
304
// of OAEP.
259
- final Cipher cipher = Cipher .getInstance (transformation_ , "BC" );
260
- cipher .init (Cipher .ENCRYPT_MODE , key );
305
+ final Cipher cipher = Cipher .getInstance (transformation_ );
306
+ cipher .init (Cipher .ENCRYPT_MODE , key , parameterSpec_ );
261
307
return new WrappingData (cipher , EMPTY_ARRAY );
262
308
}
263
309
@@ -269,8 +315,8 @@ protected Cipher buildUnwrappingCipher(Key key, byte[] extraInfo, int offset,
269
315
}
270
316
// We require BouncyCastle to avoid some bugs in the default Java implementation
271
317
// of OAEP.
272
- final Cipher cipher = Cipher .getInstance (transformation_ , "BC" );
273
- cipher .init (Cipher .DECRYPT_MODE , key );
318
+ final Cipher cipher = Cipher .getInstance (transformation_ );
319
+ cipher .init (Cipher .DECRYPT_MODE , key , parameterSpec_ );
274
320
return cipher ;
275
321
}
276
322
}
0 commit comments