8180392: SunJCE provider should throw exceptions for unsupported mode and padding combinations

Change JCA Cipher class to create obj to ensure the mode and padding combination is supported

Reviewed-by: xuelei
This commit is contained in:
Valerie Peng 2019-07-25 02:16:49 +00:00
parent 74c3432b28
commit 6b662abe74
8 changed files with 188 additions and 69 deletions
src/java.base/share/classes
com/sun/crypto/provider
javax/crypto
test/jdk

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -271,7 +271,9 @@ final class CipherCore {
padding = null;
} else if (paddingScheme.equalsIgnoreCase("ISO10126Padding")) {
padding = new ISO10126Padding(blockSize);
} else if (!paddingScheme.equalsIgnoreCase("PKCS5Padding")) {
} else if (paddingScheme.equalsIgnoreCase("PKCS5Padding")) {
padding = new PKCS5Padding(blockSize);
} else {
throw new NoSuchPaddingException("Padding: " + paddingScheme
+ " not implemented");
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -559,16 +559,16 @@ public class Cipher {
// does not support mode or padding we need, ignore
continue;
}
if (canuse == S_YES) {
// S_YES, S_MAYBE
// even when mode and padding are both supported, they
// may not be used together, try out and see if it works
try {
CipherSpi spi = (CipherSpi)s.newInstance(null);
tr.setModePadding(spi);
// specify null instead of spi for delayed provider selection
return new Cipher(null, s, t, transformation, transforms);
} else { // S_MAYBE, try out if it works
try {
CipherSpi spi = (CipherSpi)s.newInstance(null);
tr.setModePadding(spi);
return new Cipher(spi, s, t, transformation, transforms);
} catch (Exception e) {
failure = e;
}
} catch (Exception e) {
failure = e;
}
}
throw new NoSuchAlgorithmException

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,19 +48,24 @@ public class Padding {
private static final String ALGORITHM = "AES";
private static final String PROVIDER = "SunJCE";
private static final String[] MODES = { "ECb", "CbC", "PCBC", "OFB",
private static final String[] MODES_PKCS5PAD = {
"ECb", "CbC", "PCBC", "OFB",
"OFB150", "cFB", "CFB7", "cFB8", "cFB16", "cFB24", "cFB32",
"Cfb40", "cfB48", "cfB56", "cfB64", "cfB72", "cfB80", "cfB88",
"cfB96", "cfb104", "cfB112", "cfB120", "OFB8", "OFB16", "OFB24",
"OFB32", "OFB40", "OFB48", "OFB56", "OFB64", "OFB72", "OFB80",
"OFB88", "OFB96", "OFB104", "OFB112", "OFB120", "GCM" };
private static final String PADDING = "PKCS5Padding";
"OFB88", "OFB96", "OFB104", "OFB112", "OFB120" };
private static final String[] MODES_NOPAD = { "CTR", "CTS", "GCM" };
private static final int KEY_LENGTH = 128;
public static void main(String argv[]) throws Exception {
Padding test = new Padding();
for (String mode : MODES) {
test.runTest(ALGORITHM, mode, PADDING);
for (String mode : MODES_PKCS5PAD) {
test.runTest(ALGORITHM, mode, "PKCS5Padding");
}
for (String mode : MODES_NOPAD) {
test.runTest(ALGORITHM, mode, "NoPadding");
}
}
@ -92,7 +97,6 @@ public class Padding {
int offset = ci.update(plainText, 0, plainText.length,
cipherText, 0);
ci.doFinal(cipherText, offset);
if (!mo.equalsIgnoreCase("ECB")) {
iv = ci.getIV();
aps = new IvParameterSpec(iv);

@ -0,0 +1,109 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8180392
* @summary Ensure SunJCE provider throws exception for unsupported modes
* and padding combinations
*/
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.*;
public class TestNoPaddingModes {
// SunJCE only supports NoPadding with following modes
private static final String[] MODES = {
"CTR", "CTS", "GCM"
};
private static final String[] PADDINGS = {
"PKCS5Padding", "ISO10126Padding"
};
public static void main(String[] args) throws Exception {
Provider p = Security.getProvider("SunJCE");
String transformation;
for (String mode : MODES) {
for (String padding : PADDINGS) {
transformation = "AES/" + mode + "/" + padding;
System.out.println("Test using " + transformation);
try {
Cipher c = Cipher.getInstance(transformation, "SunJCE");
throw new RuntimeException("=> Fail, no exception thrown");
} catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
System.out.println("=> Expected ex: " + ex);
}
try {
Cipher c = Cipher.getInstance(transformation, p);
throw new RuntimeException("=> Fail, no exception thrown");
} catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
System.out.println("=> Expected ex: " + ex);
}
}
}
System.out.println("Test Passed");
}
public static class MyCipImpl extends CipherSpi {
public MyCipImpl() {
super();
System.out.println("MyCipImpl is created");
}
protected void engineSetMode(String mode)
throws NoSuchAlgorithmException {};
protected void engineSetPadding(String padding)
throws NoSuchPaddingException {};
protected int engineGetBlockSize() { return 16; }
protected int engineGetOutputSize(int inputLen) { return 0; }
protected byte[] engineGetIV() { return null; }
protected AlgorithmParameters engineGetParameters() { return null; }
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {};
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {};
protected void engineInit(int opmode, Key key,
AlgorithmParameters params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {};
protected byte[] engineUpdate(byte[] input, int inputOffset,
int inputLen) { return null; }
protected int engineUpdate(byte[] input, int inputOffset,
int inputLen, byte[] output,
int outputOffset)
throws ShortBufferException { return 0; };
protected byte[] engineDoFinal(byte[] input, int inputOffset,
int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
return null;
}
protected int engineDoFinal(byte[] input, int inputOffset,
int inputLen, byte[] output,
int outputOffset)
throws ShortBufferException, IllegalBlockSizeException,
BadPaddingException { return 0; }
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,20 +32,20 @@ import java.security.NoSuchAlgorithmException;
public class TestCipherBlowfish extends TestCipher {
TestCipherBlowfish() throws NoSuchAlgorithmException {
super("Blowfish",
new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
//CFBx
"CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
"CFB64",
//OFBx
"OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
"OFB64"},
new String[]{"NoPaDDing", "PKCS5Padding"},
32, 448);
TestCipherBlowfish(String[] modes, String[] paddings) throws NoSuchAlgorithmException {
super("Blowfish", modes, paddings, 32, 448);
}
public static void main(String[] args) throws Exception {
new TestCipherBlowfish().runAll();
new TestCipherBlowfish(new String[]{ "CBC", "ECB", "PCBC",
//CFBx
"CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40",
"CFB48", "CFB56", "CFB64",
//OFBx
"OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
"OFB48", "OFB56", "OFB64"},
new String[]{ "NoPaDDing", "PKCS5Padding"}).runAll();
new TestCipherBlowfish(new String[]{ "CTR", "CTS" },
new String[]{ "NoPaDDing" }).runAll();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,19 +30,20 @@
public class TestCipherDES extends TestCipher {
TestCipherDES() {
super("DES",
new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
//CFBx
"CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
"CFB64",
//OFBx
"OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
"OFB64"},
new String[]{"NoPaDDing", "PKCS5Padding"});
TestCipherDES(String[] modes, String[] paddings) {
super("DES", modes, paddings);
}
public static void main(String[] args) throws Exception {
new TestCipherDES().runAll();
new TestCipherDES(new String[]{ "CBC", "ECB", "PCBC",
//CFBx
"CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40",
"CFB48", "CFB56", "CFB64",
//OFBx
"OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
"OFB48", "OFB56", "OFB64" },
new String[]{ "NoPaDDing", "PKCS5Padding" }).runAll();
new TestCipherDES(new String[]{ "CTR", "CTS" },
new String[]{ "NoPaDDing" }).runAll();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,19 +30,22 @@
public class TestCipherDESede extends TestCipher {
TestCipherDESede() {
super("DESede",
new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
//CFBx
"CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
"CFB64",
//OFBx
"OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
"OFB64"},
new String[]{"NoPaDDing", "PKCS5Padding"});
TestCipherDESede(String[] modes, String[] paddings) {
super("DESede", modes, paddings);
}
public static void main(String[] args) throws Exception {
new TestCipherDESede().runAll();
new TestCipherDESede(
new String[]{ "CBC", "ECB", "PCBC",
//CFBx
"CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40",
"CFB48", "CFB56", "CFB64",
//OFBx
"OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40",
"OFB48", "OFB56", "OFB64"},
new String[]{ "NoPaDDing", "PKCS5Padding" }).runAll();
new TestCipherDESede(
new String[]{ "CTR", "CTS" },
new String[]{ "NoPaDDing" }).runAll();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -55,7 +55,7 @@ public class CipherInputStreamExceptions {
/* Full read stream, check that getMoreData() is throwing an exception
* This test
* 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
* 1) Encrypt 100 bytes with AES/GCM/NoPadding
* 2) Changes the last byte to invalidate the authetication tag.
* 3) Fully reads CipherInputStream to decrypt the message and closes
*/
@ -66,7 +66,7 @@ public class CipherInputStreamExceptions {
System.out.println("Running gcm_AEADBadTag");
// Encrypt 100 bytes with AES/GCM/PKCS5Padding
// Encrypt 100 bytes with AES/GCM/NoPadding
byte[] ct = encryptedText("GCM", 100);
// Corrupt the encrypted message
ct = corruptGCM(ct);
@ -92,7 +92,7 @@ public class CipherInputStreamExceptions {
/* Short read stream,
* This test
* 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
* 1) Encrypt 100 bytes with AES/GCM/NoPadding
* 2) Reads 100 bytes from stream to decrypt the message and closes
* 3) Make sure no value is returned by read()
* 4) Make sure no exception is thrown
@ -106,7 +106,7 @@ public class CipherInputStreamExceptions {
byte[] pt = new byte[600];
pt[0] = 1;
// Encrypt provided 600 bytes with AES/GCM/PKCS5Padding
// Encrypt provided 600 bytes with AES/GCM/NoPadding
byte[] ct = encryptedText("GCM", pt);
// Create stream for decryption
CipherInputStream in = getStream("GCM", ct);
@ -134,7 +134,7 @@ public class CipherInputStreamExceptions {
* Verify doFinal() exception is suppressed when input stream is not
* read before it is closed.
* This test:
* 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
* 1) Encrypt 100 bytes with AES/GCM/NoPadding
* 2) Changes the last byte to invalidate the authetication tag.
* 3) Opens a CipherInputStream and the closes it. Never reads from it.
*
@ -146,7 +146,7 @@ public class CipherInputStreamExceptions {
System.out.println("Running supressUnreadCorrupt test");
// Encrypt 100 bytes with AES/GCM/PKCS5Padding
// Encrypt 100 bytes with AES/GCM/NoPadding
byte[] ct = encryptedText("GCM", 100);
// Corrupt the encrypted message
ct = corruptGCM(ct);
@ -166,7 +166,7 @@ public class CipherInputStreamExceptions {
* Verify noexception thrown when 1 byte is read from a GCM stream
* and then closed
* This test:
* 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
* 1) Encrypt 100 bytes with AES/GCM/NoPadding
* 2) Read one byte from the stream, expect no exception thrown.
* 4) Close stream,expect no exception thrown.
*/
@ -174,7 +174,7 @@ public class CipherInputStreamExceptions {
System.out.println("Running gcm_oneReadByte test");
// Encrypt 100 bytes with AES/GCM/PKCS5Padding
// Encrypt 100 bytes with AES/GCM/NoPadding
byte[] ct = encryptedText("GCM", 100);
// Create stream for decryption
CipherInputStream in = getStream("GCM", ct);
@ -192,7 +192,7 @@ public class CipherInputStreamExceptions {
* Verify exception thrown when 1 byte is read from a corrupted GCM stream
* and then closed
* This test:
* 1) Encrypt 100 bytes with AES/GCM/PKCS5Padding
* 1) Encrypt 100 bytes with AES/GCM/NoPadding
* 2) Changes the last byte to invalidate the authetication tag.
* 3) Read one byte from the stream, expect exception thrown.
* 4) Close stream,expect no exception thrown.
@ -201,7 +201,7 @@ public class CipherInputStreamExceptions {
System.out.println("Running gcm_oneReadByteCorrupt test");
// Encrypt 100 bytes with AES/GCM/PKCS5Padding
// Encrypt 100 bytes with AES/GCM/NoPadding
byte[] ct = encryptedText("GCM", 100);
// Corrupt the encrypted message
ct = corruptGCM(ct);
@ -357,7 +357,7 @@ public class CipherInputStreamExceptions {
static byte[] encryptedText(String mode, byte[] pt) throws Exception{
Cipher c;
if (mode.compareTo("GCM") == 0) {
c = Cipher.getInstance("AES/GCM/PKCS5Padding", "SunJCE");
c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
c.init(Cipher.ENCRYPT_MODE, key, gcmspec);
} else if (mode.compareTo("CBC") == 0) {
c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
@ -380,7 +380,7 @@ public class CipherInputStreamExceptions {
Cipher c;
if (mode.compareTo("GCM") == 0) {
c = Cipher.getInstance("AES/GCM/PKCS5Padding", "SunJCE");
c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
c.init(Cipher.DECRYPT_MODE, key, gcmspec);
} else if (mode.compareTo("CBC") == 0) {
c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");