Skip to content

Commit 1ef935d

Browse files
committed
backport ec7c6be6a9e84c8cd2077fea07930592ddd13669
1 parent bc05ceb commit 1ef935d

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,19 +310,22 @@ 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
/*
319-
* array containing the components of a cipher transformation:
323+
* Components of a cipher transformation:
320324
*
321-
* index 0: algorithm component (e.g., AES)
322-
* index 1: feedback component (e.g., CFB)
323-
* index 2: padding component (e.g., PKCS5Padding)
325+
* 1) algorithm component (e.g., AES)
326+
* 2) feedback component (e.g., CFB) - optional
327+
* 3) padding component (e.g., PKCS5Padding) - optional
324328
*/
325-
String[] parts = { "", "", "" };
326329

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

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

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

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)