6572331: regression: cipher.wrap operation fails with CKR_ATTRIBUTE_VALUE_INVALID
Summary: Check supported key size range and use encryption if needed
Reviewed-by: andreas
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java Thu Mar 20 16:02:23 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java Thu Mar 20 17:17:10 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -65,10 +65,86 @@
// are supported.
private boolean supportBothKeySizes;
- // min and max key sizes (in bits) for variable-key-length
- // algorithms, e.g. RC4 and Blowfish
- private int minKeySize;
- private int maxKeySize;
+ /**
+ * Utility method for checking if the specified key size is valid
+ * and within the supported range. Return the significant key size
+ * upon successful validation.
+ * @param keyGenMech the PKCS#11 key generation mechanism.
+ * @param keySize the to-be-checked key size for this mechanism.
+ * @param token token which provides this mechanism.
+ * @return the significant key size (in bits) corresponding to the
+ * specified key size.
+ * @throws InvalidParameterException if the specified key size is invalid.
+ * @throws ProviderException if this mechanism isn't supported by SunPKCS11
+ * or underlying native impl.
+ */
+ static int checkKeySize(long keyGenMech, int keySize, Token token)
+ throws InvalidAlgorithmParameterException, ProviderException {
+ int sigKeySize;
+ switch ((int)keyGenMech) {
+ case (int)CKM_DES_KEY_GEN:
+ if ((keySize != 64) && (keySize != 56)) {
+ throw new InvalidAlgorithmParameterException
+ ("DES key length must be 56 bits");
+ }
+ sigKeySize = 56;
+ break;
+ case (int)CKM_DES2_KEY_GEN:
+ case (int)CKM_DES3_KEY_GEN:
+ if ((keySize == 112) || (keySize == 128)) {
+ sigKeySize = 112;
+ } else if ((keySize == 168) || (keySize == 192)) {
+ sigKeySize = 168;
+ } else {
+ throw new InvalidAlgorithmParameterException
+ ("DESede key length must be 112, or 168 bits");
+ }
+ break;
+ default:
+ // Handle all variable-key-length algorithms here
+ CK_MECHANISM_INFO info = null;
+ try {
+ info = token.getMechanismInfo(keyGenMech);
+ } catch (PKCS11Exception p11e) {
+ // Should never happen
+ throw new ProviderException
+ ("Cannot retrieve mechanism info", p11e);
+ }
+ if (info == null) {
+ // XXX Unable to retrieve the supported key length from
+ // the underlying native impl. Skip the checking for now.
+ return keySize;
+ }
+ // PKCS#11 defines these to be in number of bytes except for
+ // RC4 which is in bits. However, some PKCS#11 impls still use
+ // bytes for all mechs, e.g. NSS. We try to detect this
+ // inconsistency if the minKeySize seems unreasonably small.
+ int minKeySize = (int)info.ulMinKeySize;
+ int maxKeySize = (int)info.ulMaxKeySize;
+ if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) {
+ minKeySize = (int)info.ulMinKeySize << 3;
+ maxKeySize = (int)info.ulMaxKeySize << 3;
+ }
+ // Explicitly disallow keys shorter than 40-bits for security
+ if (minKeySize < 40) minKeySize = 40;
+ if (keySize < minKeySize || keySize > maxKeySize) {
+ throw new InvalidAlgorithmParameterException
+ ("Key length must be between " + minKeySize +
+ " and " + maxKeySize + " bits");
+ }
+ if (keyGenMech == CKM_AES_KEY_GEN) {
+ if ((keySize != 128) && (keySize != 192) &&
+ (keySize != 256)) {
+ throw new InvalidAlgorithmParameterException
+ ("AES key length must be " + minKeySize +
+ (maxKeySize >= 192? ", 192":"") +
+ (maxKeySize >= 256? ", or 256":"") + " bits");
+ }
+ }
+ sigKeySize = keySize;
+ }
+ return sigKeySize;
+ }
P11KeyGenerator(Token token, String algorithm, long mechanism)
throws PKCS11Exception {
@@ -85,72 +161,44 @@
supportBothKeySizes =
(token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&
(token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));
- } else if (this.mechanism == CKM_RC4_KEY_GEN) {
- CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
- // Although PKCS#11 spec documented that these are in bits,
- // NSS, for one, uses bytes. Multiple by 8 if the number seems
- // unreasonably small.
- if (info.ulMinKeySize < 8) {
- minKeySize = (int)info.ulMinKeySize << 3;
- maxKeySize = (int)info.ulMaxKeySize << 3;
- } else {
- minKeySize = (int)info.ulMinKeySize;
- maxKeySize = (int)info.ulMaxKeySize;
- }
- // Explicitly disallow keys shorter than 40-bits for security
- if (minKeySize < 40) minKeySize = 40;
- } else if (this.mechanism == CKM_BLOWFISH_KEY_GEN) {
- CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
- maxKeySize = (int)info.ulMaxKeySize << 3;
- minKeySize = (int)info.ulMinKeySize << 3;
- // Explicitly disallow keys shorter than 40-bits for security
- if (minKeySize < 40) minKeySize = 40;
}
-
setDefaultKeySize();
}
// set default keysize and also initialize keyType
private void setDefaultKeySize() {
- // whether to check default key size against the min and max value
- boolean validateKeySize = false;
switch ((int)mechanism) {
case (int)CKM_DES_KEY_GEN:
keySize = 64;
- significantKeySize = 56;
keyType = CKK_DES;
break;
case (int)CKM_DES2_KEY_GEN:
keySize = 128;
- significantKeySize = 112;
keyType = CKK_DES2;
break;
case (int)CKM_DES3_KEY_GEN:
keySize = 192;
- significantKeySize = 168;
keyType = CKK_DES3;
break;
case (int)CKM_AES_KEY_GEN:
+ keySize = 128;
keyType = CKK_AES;
- keySize = 128;
- significantKeySize = 128;
break;
case (int)CKM_RC4_KEY_GEN:
+ keySize = 128;
keyType = CKK_RC4;
- keySize = 128;
- validateKeySize = true;
break;
case (int)CKM_BLOWFISH_KEY_GEN:
+ keySize = 128;
keyType = CKK_BLOWFISH;
- keySize = 128;
- validateKeySize = true;
break;
default:
throw new ProviderException("Unknown mechanism " + mechanism);
}
- if (validateKeySize &&
- ((keySize > maxKeySize) || (keySize < minKeySize))) {
- throw new ProviderException("Unsupported key size");
+ try {
+ significantKeySize = checkKeySize(mechanism, keySize, token);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new ProviderException("Unsupported default key size", iape);
}
}
@@ -170,57 +218,32 @@
// see JCE spec
protected void engineInit(int keySize, SecureRandom random) {
token.ensureValid();
- switch ((int)mechanism) {
- case (int)CKM_DES_KEY_GEN:
- if ((keySize != this.keySize) &&
- (keySize != this.significantKeySize)) {
- throw new InvalidParameterException
- ("DES key length must be 56 bits");
- }
- break;
- case (int)CKM_DES2_KEY_GEN:
- case (int)CKM_DES3_KEY_GEN:
- long newMechanism;
- if ((keySize == 112) || (keySize == 128)) {
- newMechanism = CKM_DES2_KEY_GEN;
- } else if ((keySize == 168) || (keySize == 192)) {
- newMechanism = CKM_DES3_KEY_GEN;
- } else {
- throw new InvalidParameterException
- ("DESede key length must be 112, or 168 bits");
- }
+ int newSignificantKeySize;
+ try {
+ newSignificantKeySize = checkKeySize(mechanism, keySize, token);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw (InvalidParameterException)
+ (new InvalidParameterException().initCause(iape));
+ }
+ if ((mechanism == CKM_DES2_KEY_GEN) ||
+ (mechanism == CKM_DES3_KEY_GEN)) {
+ long newMechanism = (newSignificantKeySize == 112 ?
+ CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);
if (mechanism != newMechanism) {
if (supportBothKeySizes) {
mechanism = newMechanism;
- setDefaultKeySize();
+ // Adjust keyType to reflect the mechanism change
+ keyType = (mechanism == CKM_DES2_KEY_GEN ?
+ CKK_DES2 : CKK_DES3);
} else {
throw new InvalidParameterException
- ("Only " + significantKeySize +
- "-bit DESede key length is supported");
+ ("Only " + significantKeySize +
+ "-bit DESede is supported");
}
}
- break;
- case (int)CKM_AES_KEY_GEN:
- if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
- throw new InvalidParameterException
- ("AES key length must be 128, 192, or 256 bits");
- }
- this.keySize = keySize;
- significantKeySize = keySize;
- break;
- case (int)CKM_RC4_KEY_GEN:
- case (int)CKM_BLOWFISH_KEY_GEN:
- if ((keySize < minKeySize) || (keySize > maxKeySize)) {
- throw new InvalidParameterException
- (algorithm + " key length must be between " +
- minKeySize + " and " + maxKeySize + " bits");
- }
- this.keySize = keySize;
- this.significantKeySize = keySize;
- break;
- default:
- throw new ProviderException("Unknown mechanism " + mechanism);
}
+ this.keySize = keySize;
+ this.significantKeySize = newSignificantKeySize;
}
// see JCE spec
--- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java Thu Mar 20 16:02:23 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java Thu Mar 20 17:17:10 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -98,7 +98,6 @@
this.token = token;
this.algorithm = "RSA";
this.mechanism = mechanism;
- session = token.getOpSession();
}
// modes do not make sense for RSA, but allow ECB
@@ -184,7 +183,8 @@
throw new InvalidKeyException
("Wrap has to be used with public keys");
}
- // No further setup needed for C_Wrap(). We remain uninitialized.
+ // No further setup needed for C_Wrap(). We'll initialize later if
+ // we can't use C_Wrap().
return;
} else if (opmode == Cipher.UNWRAP_MODE) {
if (p11Key.isPrivate() == false) {
@@ -383,7 +383,8 @@
return implDoFinal(out, outOfs, out.length - outOfs);
}
- private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException {
+ private byte[] doFinal() throws BadPaddingException,
+ IllegalBlockSizeException {
byte[] t = new byte[2048];
int n = implDoFinal(t, 0, t.length);
byte[] out = new byte[n];
@@ -394,20 +395,37 @@
// see JCE spec
protected byte[] engineWrap(Key key) throws InvalidKeyException,
IllegalBlockSizeException {
- // XXX Note that if we cannot convert key to a key on this token,
- // we will fail. For example, trying a wrap an AES key on a token that
- // does not support AES.
- // We could implement a fallback that just encrypts the encoding
- // (assuming the key is not sensitive). For now, we are operating under
- // the assumption that this is not necessary.
String keyAlg = key.getAlgorithm();
- P11Key secretKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
+ P11Key sKey = null;
+ try {
+ // The conversion may fail, e.g. trying to wrap an AES key on
+ // a token that does not support AES, or when the key size is
+ // not within the range supported by the token.
+ sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
+ } catch (InvalidKeyException ike) {
+ byte[] toBeWrappedKey = key.getEncoded();
+ if (toBeWrappedKey == null) {
+ throw new InvalidKeyException
+ ("wrap() failed, no encoding available", ike);
+ }
+ // Directly encrypt the key encoding when key conversion failed
+ implInit(Cipher.ENCRYPT_MODE, p11Key);
+ implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);
+ try {
+ return doFinal();
+ } catch (BadPaddingException bpe) {
+ // should not occur
+ throw new InvalidKeyException("wrap() failed", bpe);
+ } finally {
+ // Restore original mode
+ implInit(Cipher.WRAP_MODE, p11Key);
+ }
+ }
Session s = null;
try {
s = token.getOpSession();
- byte[] b = token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
- p11Key.keyID, secretKey.keyID);
- return b;
+ return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
+ p11Key.keyID, sKey.keyID);
} catch (PKCS11Exception e) {
throw new InvalidKeyException("wrap() failed", e);
} finally {
@@ -431,11 +449,13 @@
};
attributes = token.getAttributes
(O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
- long keyID = token.p11.C_UnwrapKey(s.id(), new CK_MECHANISM(mechanism),
- p11Key.keyID, wrappedKey, attributes);
- return P11Key.secretKey(session, keyID, algorithm, 48 << 3, attributes);
+ long keyID = token.p11.C_UnwrapKey(s.id(),
+ new CK_MECHANISM(mechanism), p11Key.keyID, wrappedKey,
+ attributes);
+ return P11Key.secretKey(session, keyID, algorithm, 48 << 3,
+ attributes);
} catch (PKCS11Exception e) {
- throw new InvalidKeyException("wrap() failed", e);
+ throw new InvalidKeyException("unwrap() failed", e);
} finally {
token.releaseSession(s);
}
--- a/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java Thu Mar 20 16:02:23 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java Thu Mar 20 17:17:10 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -104,9 +104,9 @@
/**
* Convert an arbitrary key of algorithm into a P11Key of provider.
- * Used engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
+ * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
*/
- static P11Key convertKey(Token token, Key key, String algorithm)
+ static P11Key convertKey(Token token, Key key, String algo)
throws InvalidKeyException {
token.ensureValid();
if (key == null) {
@@ -115,19 +115,19 @@
if (key instanceof SecretKey == false) {
throw new InvalidKeyException("Key must be a SecretKey");
}
- long algorithmType;
- if (algorithm == null) {
- algorithm = key.getAlgorithm();
- algorithmType = getKeyType(algorithm);
+ long algoType;
+ if (algo == null) {
+ algo = key.getAlgorithm();
+ algoType = getKeyType(algo);
} else {
- algorithmType = getKeyType(algorithm);
+ algoType = getKeyType(algo);
long keyAlgorithmType = getKeyType(key.getAlgorithm());
- if (algorithmType != keyAlgorithmType) {
- if ((algorithmType == PCKK_HMAC) || (algorithmType == PCKK_SSLMAC)) {
+ if (algoType != keyAlgorithmType) {
+ if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
// ignore key algorithm for MACs
} else {
throw new InvalidKeyException
- ("Key algorithm must be " + algorithm);
+ ("Key algorithm must be " + algo);
}
}
}
@@ -145,7 +145,7 @@
throw new InvalidKeyException("Encoded format must be RAW");
}
byte[] encoded = key.getEncoded();
- p11Key = createKey(token, encoded, algorithm, algorithmType);
+ p11Key = createKey(token, encoded, algo, algoType);
token.secretCache.put(key, p11Key);
return p11Key;
}
@@ -160,77 +160,70 @@
private static P11Key createKey(Token token, byte[] encoded,
String algorithm, long keyType) throws InvalidKeyException {
- int n = encoded.length;
- int keyLength;
- switch ((int)keyType) {
- case (int)CKK_RC4:
- if ((n < 5) || (n > 128)) {
- throw new InvalidKeyException
- ("ARCFOUR key length must be between 5 and 128 bytes");
- }
- keyLength = n << 3;
- break;
- case (int)CKK_DES:
- if (n != 8) {
- throw new InvalidKeyException
- ("DES key length must be 8 bytes");
- }
- keyLength = 56;
- fixDESParity(encoded, 0);
- break;
- case (int)CKK_DES3:
- if (n == 16) {
- keyType = CKK_DES2;
- } else if (n == 24) {
- keyType = CKK_DES3;
- fixDESParity(encoded, 16);
- } else {
- throw new InvalidKeyException
- ("DESede key length must be 16 or 24 bytes");
+ int n = encoded.length << 3;
+ int keyLength = n;
+ try {
+ switch ((int)keyType) {
+ case (int)CKK_DES:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token);
+ fixDESParity(encoded, 0);
+ break;
+ case (int)CKK_DES3:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token);
+ fixDESParity(encoded, 0);
+ fixDESParity(encoded, 8);
+ if (keyLength == 112) {
+ keyType = CKK_DES2;
+ } else {
+ keyType = CKK_DES3;
+ fixDESParity(encoded, 16);
+ }
+ break;
+ case (int)CKK_AES:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token);
+ break;
+ case (int)CKK_RC4:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token);
+ break;
+ case (int)CKK_BLOWFISH:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n,
+ token);
+ break;
+ case (int)CKK_GENERIC_SECRET:
+ case (int)PCKK_TLSPREMASTER:
+ case (int)PCKK_TLSRSAPREMASTER:
+ case (int)PCKK_TLSMASTER:
+ keyType = CKK_GENERIC_SECRET;
+ break;
+ case (int)PCKK_SSLMAC:
+ case (int)PCKK_HMAC:
+ if (n == 0) {
+ throw new InvalidKeyException
+ ("MAC keys must not be empty");
+ }
+ keyType = CKK_GENERIC_SECRET;
+ break;
+ default:
+ throw new InvalidKeyException("Unknown algorithm " +
+ algorithm);
}
- fixDESParity(encoded, 0);
- fixDESParity(encoded, 8);
- keyLength = n * 7;
- break;
- case (int)CKK_AES:
- if ((n != 16) && (n != 24) && (n != 32)) {
- throw new InvalidKeyException
- ("AES key length must be 16, 24, or 32 bytes");
- }
- keyLength = n << 3;
- break;
- case (int)CKK_BLOWFISH:
- if ((n < 5) || (n > 56)) {
- throw new InvalidKeyException
- ("Blowfish key length must be between 5 and 56 bytes");
- }
- keyLength = n << 3;
- break;
- case (int)CKK_GENERIC_SECRET:
- case (int)PCKK_TLSPREMASTER:
- case (int)PCKK_TLSRSAPREMASTER:
- case (int)PCKK_TLSMASTER:
- keyType = CKK_GENERIC_SECRET;
- keyLength = n << 3;
- break;
- case (int)PCKK_SSLMAC:
- case (int)PCKK_HMAC:
- if (n == 0) {
- throw new InvalidKeyException
- ("MAC keys must not be empty");
- }
- keyType = CKK_GENERIC_SECRET;
- keyLength = n << 3;
- break;
- default:
- throw new InvalidKeyException("Unknown algorithm " + algorithm);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new InvalidKeyException("Invalid key for " + algorithm,
+ iape);
+ } catch (ProviderException pe) {
+ throw new InvalidKeyException("Could not create key", pe);
}
Session session = null;
try {
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
- new CK_ATTRIBUTE(CKA_VALUE, encoded),
+ new CK_ATTRIBUTE(CKA_VALUE, encoded)
};
attributes = token.getAttributes
(O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java Thu Mar 20 17:17:10 2008 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6572331
+ * @summary basic test for RSA cipher key wrapping functionality
+ * @author Valerie Peng
+ * @library ..
+ */
+import java.io.*;
+import java.util.*;
+
+import java.security.*;
+
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+
+public class TestRSACipherWrap extends PKCS11Test {
+
+ private static final String RSA_ALGO = "RSA/ECB/PKCS1Padding";
+
+ public void main(Provider p) throws Exception {
+ try {
+ Cipher.getInstance(RSA_ALGO, p);
+ } catch (GeneralSecurityException e) {
+ System.out.println("Not supported by provider, skipping");
+ return;
+ }
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p);
+ kpg.initialize(1024);
+ KeyPair kp = kpg.generateKeyPair();
+ PublicKey publicKey = kp.getPublic();
+ PrivateKey privateKey = kp.getPrivate();
+
+ Cipher cipherPKCS11 = Cipher.getInstance(RSA_ALGO, p);
+ Cipher cipherJce = Cipher.getInstance(RSA_ALGO, "SunJCE");
+
+ String algos[] = {"AES", "RC2", "Blowfish"};
+ int keySizes[] = {128, 256};
+
+ for (int j = 0; j < algos.length; j++) {
+ String algorithm = algos[j];
+ KeyGenerator keygen =
+ KeyGenerator.getInstance(algorithm);
+
+ for (int i = 0; i < keySizes.length; i++) {
+ SecretKey secretKey = null;
+ System.out.print("Generate " + keySizes[i] + "-bit " +
+ algorithm + " key using ");
+ try {
+ keygen.init(keySizes[i]);
+ secretKey = keygen.generateKey();
+ System.out.println(keygen.getProvider().getName());
+ } catch (InvalidParameterException ipe) {
+ secretKey = new SecretKeySpec(new byte[32], algorithm);
+ System.out.println("SecretKeySpec class");
+ }
+ test(kp, secretKey, cipherPKCS11, cipherJce);
+ test(kp, secretKey, cipherPKCS11, cipherPKCS11);
+ test(kp, secretKey, cipherJce, cipherPKCS11);
+ }
+ }
+ }
+
+ private static void test(KeyPair kp, SecretKey secretKey,
+ Cipher wrapCipher, Cipher unwrapCipher)
+ throws Exception {
+ String algo = secretKey.getAlgorithm();
+ wrapCipher.init(Cipher.WRAP_MODE, kp.getPublic());
+ byte[] wrappedKey = wrapCipher.wrap(secretKey);
+ unwrapCipher.init(Cipher.UNWRAP_MODE, kp.getPrivate());
+ Key unwrappedKey =
+ unwrapCipher.unwrap(wrappedKey, algo, Cipher.SECRET_KEY);
+
+ System.out.println("Test " + wrapCipher.getProvider().getName() +
+ "/" + unwrapCipher.getProvider().getName() + ": ");
+ if (!Arrays.equals(secretKey.getEncoded(),
+ unwrappedKey.getEncoded())) {
+ throw new Exception("Test Failed!");
+ }
+ System.out.println("Passed");
+ }
+
+ public static void main(String[] args) throws Exception {
+ main(new TestRSACipherWrap());
+ }
+}
+