diff --git a/src/main/java/com/ibm/crypto/plus/provider/DHParameters.java b/src/main/java/com/ibm/crypto/plus/provider/DHParameters.java index b4014dd4a..fdc298da9 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/DHParameters.java +++ b/src/main/java/com/ibm/crypto/plus/provider/DHParameters.java @@ -24,8 +24,6 @@ public final class DHParameters extends AlgorithmParametersSpi implements java.io.Serializable { private static final long serialVersionUID = 7137508373627164657L; - private OpenJCEPlusProvider provider; - // The prime (p) private BigInteger p; @@ -35,9 +33,7 @@ public final class DHParameters extends AlgorithmParametersSpi implements java.i // The private-value length (l) private int l; - public DHParameters(OpenJCEPlusProvider provider) { - this.provider = provider; - } + public DHParameters() {} @Override protected void engineInit(AlgorithmParameterSpec paramSpec) @@ -143,7 +139,7 @@ int getL() { @Override protected String engineToString() { - StringBuffer strbuf = new StringBuffer(provider.getName() + " Diffie-Hellman Parameters:\n" + StringBuffer strbuf = new StringBuffer("OpenJCEPlusProvider Diffie-Hellman Parameters:\n" + "p:\n" + this.p.toString() + "\n" + "g:\n" + this.g.toString()); if (this.l != 0) strbuf.append("\nl:\n" + " " + this.l); diff --git a/src/main/java/com/ibm/crypto/plus/provider/DHPrivateKey.java b/src/main/java/com/ibm/crypto/plus/provider/DHPrivateKey.java index 6ede7b969..9b984956c 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/DHPrivateKey.java +++ b/src/main/java/com/ibm/crypto/plus/provider/DHPrivateKey.java @@ -79,7 +79,7 @@ private void initDHPrivateKey(OpenJCEPlusProvider provider, BigInteger x, DHPara this.x = x; if (dhp == null) { - this.dhParams = new DHParameters(provider); + this.dhParams = new DHParameters(); try { this.dhParams.engineInit(new DHParameterSpec(p, g, l)); } catch (InvalidParameterSpecException e) { @@ -194,7 +194,7 @@ private byte[] convertOCKPrivateKeyBytes(byte[] encodedKey) throws IOException { this.key = val.getData().getOctetString(); parseKeyBits(); - dhParams = new DHParameters(provider); + dhParams = new DHParameters(); dhParams.engineInit((l == -1) ? new DHParameterSpec(p, g, x.bitLength()) : new DHParameterSpec(p, g, l)); diff --git a/src/main/java/com/ibm/crypto/plus/provider/DHPublicKey.java b/src/main/java/com/ibm/crypto/plus/provider/DHPublicKey.java index a3c247ab3..c7d8f7524 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/DHPublicKey.java +++ b/src/main/java/com/ibm/crypto/plus/provider/DHPublicKey.java @@ -55,7 +55,7 @@ final class DHPublicKey extends X509Key int l) throws InvalidKeyException { this.provider = provider; this.y = y; - dhParams = new DHParameters(provider); + dhParams = new DHParameters(); try { dhParams.engineInit(new DHParameterSpec(p, g, l)); byte[] keyArray = new DerValue(DerValue.tag_Integer, this.y.toByteArray()).toByteArray(); @@ -198,7 +198,7 @@ private byte[] convertOCKPublicKeyBytes(byte[] encodedKey) throws IOException { throw new InvalidKeyException("Excess key data"); } - dhParams = new DHParameters(provider); + dhParams = new DHParameters(); dhParams.engineInit((l == -1) ? new DHParameterSpec(p, g, y.bitLength()) : new DHParameterSpec(p, g, l)); diff --git a/src/main/java/com/ibm/crypto/plus/provider/HKDFKeyDerivation.java b/src/main/java/com/ibm/crypto/plus/provider/HKDFKeyDerivation.java index 0094c7467..8bdf1cb61 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/HKDFKeyDerivation.java +++ b/src/main/java/com/ibm/crypto/plus/provider/HKDFKeyDerivation.java @@ -290,6 +290,11 @@ private byte[] getKeyBytes(Key key) throws InvalidKeyException { } public static final class HKDFSHA256 extends HKDFKeyDerivation { + public HKDFSHA256(OpenJCEPlusProvider provider, KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(provider, SupportedHmac.SHA256, kdfParameters); + } + public HKDFSHA256(OpenJCEPlusProvider provider) throws InvalidAlgorithmParameterException { super(provider, SupportedHmac.SHA256, null); @@ -297,6 +302,11 @@ public HKDFSHA256(OpenJCEPlusProvider provider) } public static final class HKDFSHA384 extends HKDFKeyDerivation { + public HKDFSHA384(OpenJCEPlusProvider provider, KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(provider, SupportedHmac.SHA384, kdfParameters); + } + public HKDFSHA384(OpenJCEPlusProvider provider) throws InvalidAlgorithmParameterException { super(provider, SupportedHmac.SHA384, null); @@ -304,6 +314,11 @@ public HKDFSHA384(OpenJCEPlusProvider provider) } public static final class HKDFSHA512 extends HKDFKeyDerivation { + public HKDFSHA512(OpenJCEPlusProvider provider, KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException { + super(provider, SupportedHmac.SHA512, kdfParameters); + } + public HKDFSHA512(OpenJCEPlusProvider provider) throws InvalidAlgorithmParameterException { super(provider, SupportedHmac.SHA512, null); diff --git a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java index ae751735e..1f38b8e38 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java +++ b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java @@ -10,19 +10,11 @@ import com.ibm.crypto.plus.provider.ock.OCKContext; import com.ibm.crypto.plus.provider.ock.OCKException; -import java.lang.reflect.Constructor; -import java.security.InvalidParameterException; -import java.security.Key; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.Provider; import java.security.ProviderException; -import java.security.PublicKey; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; -import javax.crypto.SecretKey; public final class OpenJCEPlus extends OpenJCEPlusProvider { @@ -1180,115 +1172,6 @@ private void registerAlgorithms(Provider jce) { "com.ibm.crypto.plus.provider.PQCSignatureImpl$MLDSA87", aliases)); } - private static class OpenJCEPlusService extends Service { - - OpenJCEPlusService(Provider provider, String type, String algorithm, String className, - String[] aliases) { - this(provider, type, algorithm, className, aliases, null); - } - - OpenJCEPlusService(Provider provider, String type, String algorithm, String className, - String[] aliases, Map attributes) { - super(provider, type, algorithm, className, toList(aliases), attributes); - - if (debug != null) { - debug.println("Constructing OpenJCEPlusService: " + provider + ", " + type - + ", " + algorithm + ", " + className); - } - } - - private static List toList(String[] aliases) { - return (aliases == null) ? null : Arrays.asList(aliases); - } - - @Override - public Object newInstance(Object constructorParameter) throws NoSuchAlgorithmException { - Provider provider = getProvider(); - String className = getClassName(); - try { - Class cls = Class.forName(className); - - // Call the constructor that takes an OpenJCEPlusProvider if - // available - // - try { - Class[] parameters = new Class[1]; - parameters[0] = Class - .forName("com.ibm.crypto.plus.provider.OpenJCEPlusProvider"); - Constructor constr = cls.getConstructor(parameters); - - return constr.newInstance(new Object[] {provider}); - } catch (java.lang.NoSuchMethodException e) { - } - } catch (Exception clex) { - throw new NoSuchAlgorithmException(clex); - } - - return super.newInstance(constructorParameter); - } - - @Override - public boolean supportsParameter(Object parameter) { - - if (parameter == null) { - return false; - } - if (parameter instanceof Key == false) { - throw new InvalidParameterException("Parameter must be a Key"); - } - Key key = (Key) parameter; - - if (key instanceof SecretKey) { - - String keyType = ((SecretKey) key).getFormat(); - if (keyType == null) { - // this happens when encoding is not supported - return true; - } - if (keyType.equalsIgnoreCase("RAW") || keyType.equalsIgnoreCase("PKCS5_DERIVED_KEY") - || keyType.equalsIgnoreCase("PKCS5_KEY")) { - return true; - } else { - return false; - } - - } else if (key instanceof PrivateKey) { - String keyType = ((PrivateKey) key).getFormat(); - if (keyType == null) { - // this happens when encoding is not supported - return true; - } - if (keyType.equalsIgnoreCase("PKCS#8")) { - return true; - } else { - return false; - } - } else if (key instanceof PublicKey) { - String keyType = ((PublicKey) key).getFormat(); - if (keyType == null) { - // this happens when encoding is not supported - return true; - } - if (keyType.equalsIgnoreCase("X.509")) { - return true; - } else { - return false; - } - } - - return false; - } - - @Override - public String toString() { - - return (super.toString() + "\n" + "provider = " + this.getProvider().getName() + "\n" - + "algorithm = " + this.getAlgorithm()); - - } - - } - // Return the instance of this class or create one if needed. // static OpenJCEPlus getInstance() { diff --git a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusFIPS.java b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusFIPS.java index d20538cfe..bc241de5f 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusFIPS.java +++ b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusFIPS.java @@ -10,19 +10,12 @@ import com.ibm.crypto.plus.provider.ock.OCKContext; import com.ibm.crypto.plus.provider.ock.OCKException; -import java.lang.reflect.Constructor; -import java.security.InvalidParameterException; -import java.security.Key; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.Provider; import java.security.ProviderException; -import java.security.PublicKey; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.crypto.SecretKey; public final class OpenJCEPlusFIPS extends OpenJCEPlusProvider { @@ -697,115 +690,6 @@ private void registerAlgorithms(Provider jce) { } - private static class OpenJCEPlusService extends Service { - - OpenJCEPlusService(Provider provider, String type, String algorithm, String className, - String[] aliases) { - this(provider, type, algorithm, className, aliases, null); - } - - OpenJCEPlusService(Provider provider, String type, String algorithm, String className, - String[] aliases, Map attributes) { - super(provider, type, algorithm, className, toList(aliases), attributes); - - if (debug != null) { - debug.println("Constructing OpenJCEPlusService: " + provider + ", " + type - + ", " + algorithm + ", " + className); - } - } - - private static List toList(String[] aliases) { - return (aliases == null) ? null : Arrays.asList(aliases); - } - - @Override - public Object newInstance(Object constructorParameter) throws NoSuchAlgorithmException { - Provider provider = getProvider(); - String className = getClassName(); - try { - Class cls = Class.forName(className); - - // Call the constructor that takes an OpenJCEPlusProvider if - // available - // - try { - Class[] parameters = new Class[1]; - parameters[0] = Class - .forName("com.ibm.crypto.plus.provider.OpenJCEPlusProvider"); - Constructor constr = cls.getConstructor(parameters); - - return constr.newInstance(new Object[] {provider}); - } catch (java.lang.NoSuchMethodException e) { - } - } catch (Exception clex) { - throw new NoSuchAlgorithmException(clex); - } - - return super.newInstance(constructorParameter); - } - - @Override - public boolean supportsParameter(Object parameter) { - - if (parameter == null) { - return false; - } - if (parameter instanceof Key == false) { - throw new InvalidParameterException("Parameter must be a Key"); - } - Key key = (Key) parameter; - - if (key instanceof SecretKey) { - - String keyType = ((SecretKey) key).getFormat(); - if (keyType == null) { - // this happens when encoding is not supported - return true; - } - if (keyType.equalsIgnoreCase("RAW") || keyType.equalsIgnoreCase("PKCS5_DERIVED_KEY") - || keyType.equalsIgnoreCase("PKCS5_KEY")) { - return true; - } else { - return false; - } - - } else if (key instanceof PrivateKey) { - String keyType = ((PrivateKey) key).getFormat(); - if (keyType == null) { - // this happens when encoding is not supported - return true; - } - if (keyType.equalsIgnoreCase("PKCS#8")) { - return true; - } else { - return false; - } - } else if (key instanceof PublicKey) { - String keyType = ((PublicKey) key).getFormat(); - if (keyType == null) { - // this happens when encoding is not supported - return true; - } - if (keyType.equalsIgnoreCase("X.509")) { - return true; - } else { - return false; - } - } - - return false; - - } - - @Override - public String toString() { - - return (super.toString() + "\n" + "provider = " + this.getProvider().getName() + "\n" - + "algorithm = " + this.getAlgorithm()); - - } - } - // Return the instance of this class or create one if needed. // static OpenJCEPlusFIPS getInstance() { diff --git a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusProvider.java b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusProvider.java index 9c43c6457..42dc235dc 100644 --- a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusProvider.java +++ b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlusProvider.java @@ -10,8 +10,21 @@ import com.ibm.crypto.plus.provider.ock.OCKContext; import java.lang.ref.Cleaner; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; import java.security.ProviderException; +import java.security.PublicKey; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import javax.crypto.KDFParameters; +import javax.crypto.SecretKey; import sun.security.util.Debug; // Internal interface for OpenJCEPlus and OpenJCEPlus implementation classes. @@ -107,4 +120,168 @@ void setOCKExceptionCause(Exception exception, Throwable ockException) { exception.initCause(ockException); } } + + protected static class OpenJCEPlusService extends Service { + private static Class openjceplusClass; + + OpenJCEPlusService(Provider provider, String type, String algorithm, String className, + String[] aliases) { + this(provider, type, algorithm, className, aliases, null); + } + + OpenJCEPlusService(Provider provider, String type, String algorithm, String className, + String[] aliases, Map attributes) { + super(provider, type, algorithm, className, toList(aliases), attributes); + + if (debug != null) { + debug.println("Constructing OpenJCEPlusService: " + provider + ", " + type + + ", " + algorithm + ", " + className); + } + } + + private static List toList(String[] aliases) { + return (aliases == null) ? null : Arrays.asList(aliases); + } + + private Class getParameterClass(String type) { + if ("KDF".equalsIgnoreCase(type)) { + return KDFParameters.class; + } + + return null; + } + + @Override + public Object newInstance(Object constructorParameter) throws NoSuchAlgorithmException { + Provider provider = getProvider(); + String className = getClassName(); + String type = getType(); + String algorithm = getAlgorithm(); + + // AlgorithmParameters instances don't need the provider as a parameter, + // so the superclass constructor can be used. + if ("AlgorithmParameters".equalsIgnoreCase(type)) { + return super.newInstance(constructorParameter); + } + + Class cls; + try { + cls = Class.forName(className); + } catch (ClassNotFoundException e) { + throw new NoSuchAlgorithmException("class configured for " + type + " (provider: " + + provider.getName() + ") cannot be found.", e); + } + + // Call the constructor that takes an OpenJCEPlusProvider if + // available + // + try { + Class[] parameters; + Class ctrParamClz = null; + if (constructorParameter != null) { + ctrParamClz = getParameterClass(type); + } + if (ctrParamClz != null) { + parameters = new Class[2]; + + Class argClass = constructorParameter.getClass(); + if (!ctrParamClz.isAssignableFrom(argClass)) { + throw new InvalidParameterException("constructorParameter must be " + + "instanceof " + ctrParamClz.getName().replace('$', '.') + + " for type " + type); + } + + parameters[1] = ctrParamClz; + } else { + parameters = new Class[1]; + } + if (openjceplusClass == null) { + openjceplusClass = Class + .forName("com.ibm.crypto.plus.provider.OpenJCEPlusProvider"); + } + parameters[0] = openjceplusClass; + Constructor constr = cls.getConstructor(parameters); + + Object[] ctrParams; + if ((constructorParameter != null) && (ctrParamClz != null)) { + ctrParams = new Object[2]; + ctrParams[1] = constructorParameter; + } else { + ctrParams = new Object[1]; + } + ctrParams[0] = provider; + + return constr.newInstance(ctrParams); + } catch (InvocationTargetException e) { + throw new NoSuchAlgorithmException("Error constructing implementation (algorithm: " + + algorithm + ", provider: " + provider.getName() + + ", class: " + className + ")", e.getCause()); + } catch (Exception e) { + throw new NoSuchAlgorithmException("Error constructing implementation (algorithm: " + + algorithm + ", provider: " + provider.getName() + + ", class: " + className + ")", e); + } + } + + @Override + public boolean supportsParameter(Object parameter) { + + if (parameter == null) { + return false; + } + if (parameter instanceof Key == false) { + throw new InvalidParameterException("Parameter must be a Key"); + } + Key key = (Key) parameter; + + if (key instanceof SecretKey) { + + String keyType = ((SecretKey) key).getFormat(); + if (keyType == null) { + // this happens when encoding is not supported + return true; + } + if (keyType.equalsIgnoreCase("RAW") || keyType.equalsIgnoreCase("PKCS5_DERIVED_KEY") + || keyType.equalsIgnoreCase("PKCS5_KEY")) { + return true; + } else { + return false; + } + + } else if (key instanceof PrivateKey) { + String keyType = ((PrivateKey) key).getFormat(); + if (keyType == null) { + // this happens when encoding is not supported + return true; + } + if (keyType.equalsIgnoreCase("PKCS#8")) { + return true; + } else { + return false; + } + } else if (key instanceof PublicKey) { + String keyType = ((PublicKey) key).getFormat(); + if (keyType == null) { + // this happens when encoding is not supported + return true; + } + if (keyType.equalsIgnoreCase("X.509")) { + return true; + } else { + return false; + } + } + + return false; + } + + @Override + public String toString() { + + return (super.toString() + "\n" + "provider = " + this.getProvider().getName() + "\n" + + "algorithm = " + this.getAlgorithm()); + + } + + } } diff --git a/src/test/java/ibm/jceplus/junit/base/BaseTestHKDF.java b/src/test/java/ibm/jceplus/junit/base/BaseTestHKDF.java index 1f3bc1e09..405cd29c5 100644 --- a/src/test/java/ibm/jceplus/junit/base/BaseTestHKDF.java +++ b/src/test/java/ibm/jceplus/junit/base/BaseTestHKDF.java @@ -25,6 +25,7 @@ import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KDF; +import javax.crypto.KDFParameters; import javax.crypto.KeyAgreement; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; @@ -34,6 +35,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class BaseTestHKDF extends BaseTestJunit5 { @@ -203,6 +205,31 @@ public void testEcdhHKDF512() throws InvalidKeyException, NoSuchAlgorithmExcepti assertTrue(plainStr.equals(strToEncrypt)); } + + @Test + public void testConstructorParameters() throws NoSuchAlgorithmException, NoSuchProviderException { + try { + KDF.getInstance("HKDF-SHA256", new MyKDFParameters()); + fail("Expected InvalidAlgorithmParameterException not thrown."); + } catch (InvalidAlgorithmParameterException iape) { + String expectedMessage = "The KDFParameters supplied could not be used in combination with the " + + "supplied algorithm for the selected Provider"; + assertTrue(expectedMessage.equals(iape.getMessage()), "Exception doesn't have expected message"); + } + + try { + KDF.getInstance("HKDF-SHA256", new MyKDFParameters2(), getProviderName()); + fail("Expected InvalidAlgorithmParameterException not thrown."); + } catch (InvalidAlgorithmParameterException iape) { + String expectedMessage = "HmacSHA256 does not support parameters"; + assertTrue(expectedMessage.equals(iape.getMessage()), "Exception doesn't have expected message"); + } + } + + private static class MyKDFParameters implements KDFParameters {} + + private static class MyKDFParameters2 implements KDFParameters {} + private void aesHKDF(int aesKeySize, String hashAlg, String extractAlg, String expandAlg, String providerName) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException, InvalidKeyException,