Skip to content

Commit 2ff59a2

Browse files
committed
backport ec7c6be6a9e84c8cd2077fea07930592ddd13669
1 parent 6e1b492 commit 2ff59a2

File tree

2 files changed

+85
-55
lines changed

2 files changed

+85
-55
lines changed

src/java.base/share/classes/javax/crypto/Cipher.java

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -310,20 +310,23 @@ private Cipher(CipherSpi firstSpi, Service firstService,
310310

311311
private static final String SHA512TRUNCATED = "SHA512/2";
312312

313+
+ // Parse the specified cipher transformation for algorithm and the
314+
+ // optional mode and padding. If the transformation contains only
315+
+ // algorithm, then only algorithm is returned. Otherwise, the
316+
+ // transformation must contain all 3 and they must be non-empty.
313317
private static String[] tokenizeTransformation(String transformation)
314318
throws NoSuchAlgorithmException {
315319
if (transformation == null) {
316320
throw new NoSuchAlgorithmException("No transformation given");
317321
}
318322

319323
/*
320-
* array containing the components of a cipher transformation:
324+
* Components of a cipher transformation:
321325
*
322-
* index 0: algorithm component (e.g., AES)
323-
* index 1: feedback component (e.g., CFB)
324-
* index 2: padding component (e.g., PKCS5Padding)
326+
* 1) algorithm component (e.g., AES)
327+
* 2) feedback component (e.g., CFB) - optional
328+
* 3) padding component (e.g., PKCS5Padding) - optional
325329
*/
326-
String[] parts = { "", "", "" };
327330

328331
// check if the transformation contains algorithms with "/" in their
329332
// name which can cause the parsing logic to go wrong
@@ -332,27 +335,35 @@ private static String[] tokenizeTransformation(String transformation)
332335
int startIdx = (sha512Idx == -1 ? 0 :
333336
sha512Idx + SHA512TRUNCATED.length());
334337
int endIdx = transformation.indexOf('/', startIdx);
335-
if (endIdx == -1) {
336-
// algorithm
337-
parts[0] = transformation.trim();
338+
339+
boolean algorithmOnly = (endIdx == -1);
340+
String algo = (algorithmOnly ? transformation.trim() :
341+
transformation.substring(0, endIdx).trim());
342+
if (algo.isEmpty()) {
343+
throw new NoSuchAlgorithmException("Invalid transformation: " +
344+
"algorithm not specified-"
345+
+ transformation);
346+
}
347+
if (algorithmOnly) { // done
348+
return new String[] { algo };
338349
} else {
339-
// algorithm/mode/padding
340-
parts[0] = transformation.substring(0, endIdx).trim();
350+
// continue parsing mode and padding
341351
startIdx = endIdx+1;
342352
endIdx = transformation.indexOf('/', startIdx);
343353
if (endIdx == -1) {
344354
throw new NoSuchAlgorithmException("Invalid transformation"
345355
+ " format:" + transformation);
346356
}
347-
parts[1] = transformation.substring(startIdx, endIdx).trim();
348-
parts[2] = transformation.substring(endIdx+1).trim();
349-
}
350-
if (parts[0].isEmpty()) {
351-
throw new NoSuchAlgorithmException("Invalid transformation: " +
352-
"algorithm not specified-"
357+
String mode = transformation.substring(startIdx, endIdx).trim();
358+
String padding = transformation.substring(endIdx+1).trim();
359+
// ensure mode and padding are specified
360+
if (mode.isEmpty() || padding.isEmpty()) {
361+
throw new NoSuchAlgorithmException("Invalid transformation: " +
362+
"missing mode and/or padding-"
353363
+ transformation);
364+
}
365+
return new String[] { algo, mode, padding };
354366
}
355-
return parts;
356367
}
357368

358369
// Provider attribute name for supported chaining mode
@@ -448,28 +459,17 @@ private static List<Transform> getTransforms(String transformation)
448459
throws NoSuchAlgorithmException {
449460
String[] parts = tokenizeTransformation(transformation);
450461

451-
String alg = parts[0];
452-
String mode = (parts[1].length() == 0 ? null : parts[1]);
453-
String pad = (parts[2].length() == 0 ? null : parts[2]);
454-
455-
if ((mode == null) && (pad == null)) {
462+
if (parts.length == 1) {
456463
// Algorithm only
457-
Transform tr = new Transform(alg, "", null, null);
458-
return Collections.singletonList(tr);
464+
return List.of(new Transform(parts[0], "", null, null));
459465
} else {
460-
// Algorithm w/ at least mode or padding or both
461-
List<Transform> list = new ArrayList<>(4);
462-
if ((mode != null) && (pad != null)) {
463-
list.add(new Transform(alg, "/" + mode + "/" + pad, null, null));
464-
}
465-
if (mode != null) {
466-
list.add(new Transform(alg, "/" + mode, null, pad));
467-
}
468-
if (pad != null) {
469-
list.add(new Transform(alg, "//" + pad, mode, null));
470-
}
471-
list.add(new Transform(alg, "", mode, pad));
472-
return list;
466+
// Algorithm w/ both mode and padding
467+
return List.of(
468+
new Transform(parts[0], "/" + parts[1] + "/" + parts[2],
469+
null, null),
470+
new Transform(parts[0], "/" + parts[1], null, parts[2]),
471+
new Transform(parts[0], "//" + parts[2], parts[1], null),
472+
new Transform(parts[0], "", parts[1], parts[2]));
473473
}
474474
}
475475

test/jdk/javax/crypto/Cipher/TestEmptyModePadding.java

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,33 +24,63 @@
2424

2525
/*
2626
* @test
27-
* @bug 8358159
28-
* @summary test that the Cipher.getInstance() handles
29-
* transformations with empty mode and/or padding
30-
* @run main TestEmptyModePadding
27+
* @bug 8359388
28+
* @summary test that the Cipher.getInstance() would reject improper
29+
* transformations with empty mode and/or padding.
3130
*/
3231

33-
34-
import java.security.*;
35-
import javax.crypto.*;
32+
import java.security.NoSuchAlgorithmException;
33+
import java.security.Provider;
34+
import java.security.Security;
35+
import javax.crypto.Cipher;
3636

3737
public class TestEmptyModePadding {
3838

3939
public static void main(String[] args) throws Exception {
40-
Provider provider = Security.getProvider(System.getProperty("test.provider.name", "SunJCE"));
40+
Provider provider = Security.getProvider(
41+
System.getProperty("test.provider.name", "SunJCE"));
42+
43+
System.out.println("Testing against " + provider.getName());
4144

42-
test("AES", provider);
43-
test("AES/ECB/PKCS5Padding", provider);
44-
test("AES//PKCS5Padding", provider); // Empty mode
45-
test("AES/CBC/", provider); // Empty padding
46-
test("AES/ /NoPadding", provider); // Mode is a space
47-
test("AES/CBC/ ", provider); // Padding is a space
48-
test("AES/ / ", provider); // Both mode and padding are spaces
49-
test("AES//", provider); // Both mode and padding are missing
45+
String[] testTransformations = {
46+
// transformations w/ only 1 component, i.e. algo
47+
" ",
48+
// transformations w/ only 2 components
49+
"AES/",
50+
"AES/ ",
51+
"AES/CBC",
52+
"PBEWithHmacSHA512/224AndAES_128/",
53+
"PBEWithHmacSHA512/256AndAES_128/ ",
54+
"PBEWithHmacSHA512/224AndAES_128/CBC",
55+
// 3-component transformations w/ empty component(s)
56+
"AES//",
57+
"AES/ /",
58+
"AES// ",
59+
"AES/ / ",
60+
"AES/CBC/", "AES/CBC/ ",
61+
"AES//PKCS5Padding", "AES/ /NoPadding",
62+
"PBEWithHmacSHA512/224AndAES_128//",
63+
"PBEWithHmacSHA512/224AndAES_128/ /",
64+
"PBEWithHmacSHA512/224AndAES_128// ",
65+
"PBEWithHmacSHA512/224AndAES_128/ / ",
66+
"PBEWithHmacSHA512/256AndAES_128/CBC/",
67+
"PBEWithHmacSHA512/256AndAES_128/CBC/ ",
68+
"PBEWithHmacSHA512/256AndAES_128//PKCS5Padding",
69+
"PBEWithHmacSHA512/256AndAES_128/ /PKCS5Padding",
70+
};
5071

72+
for (String t : testTransformations) {
73+
test(t, provider);
74+
}
5175
}
5276

53-
private static void test(String transformation, Provider provider) throws Exception {
54-
Cipher c = Cipher.getInstance(transformation, provider);
77+
private static void test(String t, Provider p) throws Exception {
78+
try {
79+
Cipher c = Cipher.getInstance(t, p);
80+
throw new RuntimeException("Should throw NSAE for \'" + t + "\'");
81+
} catch (NoSuchAlgorithmException nsae) {
82+
// transformation info is already in the NSAE message
83+
System.out.println("Expected NSAE: " + nsae.getMessage());
84+
}
5585
}
5686
}

0 commit comments

Comments
 (0)