8264849: Add KW and KWP support to PKCS11 provider
Reviewed-by: ascarpino
This commit is contained in:
parent
bd2b41dd70
commit
e63c1486dc
@ -39,7 +39,7 @@ import sun.nio.ch.DirectBuffer;
|
||||
import sun.security.jca.JCAUtil;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* P11 AEAD Cipher implementation class. This class currently supports
|
||||
@ -393,7 +393,7 @@ final class P11AEADCipher extends CipherSpi {
|
||||
try {
|
||||
initialize();
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_MECHANISM_PARAM_INVALID) {
|
||||
if (e.match(CKR_MECHANISM_PARAM_INVALID)) {
|
||||
throw new InvalidAlgorithmParameterException("Bad params", e);
|
||||
}
|
||||
throw new InvalidKeyException("Could not initialize cipher", e);
|
||||
@ -416,7 +416,7 @@ final class P11AEADCipher extends CipherSpi {
|
||||
0, buffer, 0, bufLen);
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
|
||||
if (e.match(CKR_OPERATION_NOT_INITIALIZED)) {
|
||||
// Cancel Operation may be invoked after an error on a PKCS#11
|
||||
// call. If the operation inside the token was already cancelled,
|
||||
// do not fail here. This is part of a defensive mechanism for
|
||||
@ -812,17 +812,16 @@ final class P11AEADCipher extends CipherSpi {
|
||||
private void handleException(PKCS11Exception e)
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
long errorCode = e.getErrorCode();
|
||||
if (errorCode == CKR_BUFFER_TOO_SMALL) {
|
||||
if (e.match(CKR_BUFFER_TOO_SMALL)) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
} else if (errorCode == CKR_DATA_LEN_RANGE ||
|
||||
errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {
|
||||
} else if (e.match(CKR_DATA_LEN_RANGE) ||
|
||||
e.match(CKR_ENCRYPTED_DATA_LEN_RANGE)) {
|
||||
throw (IllegalBlockSizeException)
|
||||
(new IllegalBlockSizeException(e.toString()).initCause(e));
|
||||
} else if (errorCode == CKR_ENCRYPTED_DATA_INVALID ||
|
||||
// Solaris-specific
|
||||
errorCode == CKR_GENERAL_ERROR) {
|
||||
} else if (e.match(CKR_ENCRYPTED_DATA_INVALID) ||
|
||||
e.match(CKR_GENERAL_ERROR)) {
|
||||
// CKR_GENERAL_ERROR is Solaris-specific workaround
|
||||
throw (AEADBadTagException)
|
||||
(new AEADBadTagException(e.toString()).initCause(e));
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ import sun.nio.ch.DirectBuffer;
|
||||
import sun.security.jca.JCAUtil;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* Cipher implementation class. This class currently supports
|
||||
@ -456,7 +456,7 @@ final class P11Cipher extends CipherSpi {
|
||||
token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
|
||||
if (e.match(CKR_OPERATION_NOT_INITIALIZED)) {
|
||||
// Cancel Operation may be invoked after an error on a PKCS#11
|
||||
// call. If the operation inside the token was already cancelled,
|
||||
// do not fail here. This is part of a defensive mechanism for
|
||||
@ -656,7 +656,7 @@ final class P11Cipher extends CipherSpi {
|
||||
bytesBuffered += (inLen - k);
|
||||
return k;
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
|
||||
if (e.match(CKR_BUFFER_TOO_SMALL)) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
}
|
||||
@ -780,7 +780,7 @@ final class P11Cipher extends CipherSpi {
|
||||
} catch (PKCS11Exception e) {
|
||||
// Reset input buffer to its original position for
|
||||
inBuffer.position(origPos);
|
||||
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
|
||||
if (e.match(CKR_BUFFER_TOO_SMALL)) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
}
|
||||
@ -962,12 +962,11 @@ final class P11Cipher extends CipherSpi {
|
||||
|
||||
private void handleException(PKCS11Exception e)
|
||||
throws ShortBufferException, IllegalBlockSizeException {
|
||||
long errorCode = e.getErrorCode();
|
||||
if (errorCode == CKR_BUFFER_TOO_SMALL) {
|
||||
if (e.match(CKR_BUFFER_TOO_SMALL)) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException().initCause(e));
|
||||
} else if (errorCode == CKR_DATA_LEN_RANGE ||
|
||||
errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {
|
||||
} else if (e.match(CKR_DATA_LEN_RANGE) ||
|
||||
e.match(CKR_ENCRYPTED_DATA_LEN_RANGE)) {
|
||||
throw (IllegalBlockSizeException)
|
||||
(new IllegalBlockSizeException(e.toString()).initCause(e));
|
||||
}
|
||||
|
@ -27,8 +27,12 @@ package sun.security.pkcs11;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import sun.security.pkcs11.wrapper.PKCS11Exception;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
|
||||
|
||||
/**
|
||||
* KeyFactory base class. Provides common infrastructure for the RSA, DSA,
|
||||
@ -55,6 +59,28 @@ abstract class P11KeyFactory extends KeyFactorySpi {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
private static final Map<String,Long> keyTypes;
|
||||
|
||||
static {
|
||||
keyTypes = new HashMap<String,Long>();
|
||||
addKeyType("RSA", CKK_RSA);
|
||||
addKeyType("DSA", CKK_DSA);
|
||||
addKeyType("DH", CKK_DH);
|
||||
addKeyType("EC", CKK_EC);
|
||||
}
|
||||
|
||||
private static void addKeyType(String name, long id) {
|
||||
Long l = Long.valueOf(id);
|
||||
keyTypes.put(name, l);
|
||||
keyTypes.put(name.toUpperCase(Locale.ENGLISH), l);
|
||||
}
|
||||
|
||||
// returns the PKCS11 key type of the specified algorithm
|
||||
static long getPKCS11KeyType(String algorithm) {
|
||||
Long kt = keyTypes.get(algorithm);
|
||||
return (kt != null) ? kt.longValue() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an arbitrary key of algorithm into a P11Key of token.
|
||||
* Used by P11Signature.init() and RSACipher.init().
|
||||
|
@ -73,7 +73,7 @@ import static sun.security.pkcs11.P11Util.*;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
import sun.security.rsa.RSAKeyFactory;
|
||||
|
||||
@ -757,7 +757,7 @@ final class P11KeyStore extends KeyStoreSpi {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof PKCS11Exception) {
|
||||
PKCS11Exception pe = (PKCS11Exception) cause;
|
||||
if (pe.getErrorCode() == CKR_PIN_INCORRECT) {
|
||||
if (pe.match(CKR_PIN_INCORRECT)) {
|
||||
// if password is wrong, the cause of the IOException
|
||||
// should be an UnrecoverableKeyException
|
||||
throw new IOException("load failed",
|
||||
@ -2330,7 +2330,7 @@ final class P11KeyStore extends KeyStoreSpi {
|
||||
cka_label = new String(attrs[0].getCharArray());
|
||||
}
|
||||
} catch (PKCS11Exception pe) {
|
||||
if (pe.getErrorCode() != CKR_ATTRIBUTE_TYPE_INVALID) {
|
||||
if (!pe.match(CKR_ATTRIBUTE_TYPE_INVALID)) {
|
||||
throw pe;
|
||||
}
|
||||
|
||||
@ -2371,7 +2371,7 @@ final class P11KeyStore extends KeyStoreSpi {
|
||||
(session.id(), handle, trustedAttr);
|
||||
cka_trusted = trustedAttr[0].getBoolean();
|
||||
} catch (PKCS11Exception pe) {
|
||||
if (pe.getErrorCode() == CKR_ATTRIBUTE_TYPE_INVALID) {
|
||||
if (pe.match(CKR_ATTRIBUTE_TYPE_INVALID)) {
|
||||
// XXX NSS, ibutton, sca1000
|
||||
CKA_TRUSTED_SUPPORTED = false;
|
||||
if (debug != null) {
|
||||
|
@ -0,0 +1,811 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package sun.security.pkcs11;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
import java.util.HexFormat;
|
||||
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
import sun.security.jca.JCAUtil;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
import static sun.security.pkcs11.TemplateManager.*;
|
||||
import static sun.security.pkcs11.P11Cipher.*;
|
||||
|
||||
/**
|
||||
* P11 KeyWrap Cipher implementation class for native impl which only support
|
||||
* single part encryption/decryption through C_Encrypt/C_Decrypt() and
|
||||
* key wrap/unwrap through C_WrapKey/C_UnwrapKey() calls.
|
||||
* This class currently supports only AES cipher in KW and KWP modes.
|
||||
*
|
||||
* For multi-part encryption/decryption, this class has to buffer data until
|
||||
* doFinal() is called.
|
||||
*
|
||||
* @since 18
|
||||
*/
|
||||
final class P11KeyWrapCipher extends CipherSpi {
|
||||
|
||||
private static final int BLK_SIZE = 8;
|
||||
|
||||
// supported mode and padding with AES cipher
|
||||
private enum KeyWrapType {
|
||||
KW_NOPADDING("KW", "NOPADDING"),
|
||||
KW_PKCS5PADDING("KW", "PKCS5PADDING"),
|
||||
KWP_NOPADDING("KWP", "NOPADDING");
|
||||
|
||||
private final String mode;
|
||||
private final String padding;
|
||||
private final byte[] defIv;
|
||||
|
||||
KeyWrapType(String mode, String padding) {
|
||||
this.mode = mode;
|
||||
this.padding = padding;
|
||||
if (mode.equalsIgnoreCase("KW")) {
|
||||
this.defIv = new byte[] {
|
||||
(byte)0xA6, (byte)0xA6, (byte)0xA6, (byte)0xA6,
|
||||
(byte)0xA6, (byte)0xA6, (byte)0xA6, (byte)0xA6
|
||||
};
|
||||
} else {
|
||||
this.defIv = new byte[] {
|
||||
(byte)0xA6, (byte)0x59, (byte)0x59, (byte)0xA6
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// token instance
|
||||
private final Token token;
|
||||
|
||||
// mechanism id
|
||||
private final long mechanism;
|
||||
|
||||
// type of this KeyWrap cipher, one of Transformation enum above
|
||||
private final KeyWrapType type;
|
||||
|
||||
// acceptable key size in bytes, -1 if more than 1 key sizes are accepted
|
||||
private final int fixedKeySize;
|
||||
|
||||
// associated session, if any
|
||||
private Session session = null;
|
||||
|
||||
// key, if init() was called
|
||||
private P11Key p11Key = null;
|
||||
|
||||
// flag indicating whether an operation is initialized
|
||||
private boolean initialized = false;
|
||||
|
||||
private int opmode = Cipher.ENCRYPT_MODE;
|
||||
|
||||
// parameters
|
||||
private byte[] iv = null;
|
||||
private SecureRandom random = JCAUtil.getSecureRandom();
|
||||
|
||||
// dataBuffer for storing enc/dec data; cleared upon doFinal calls
|
||||
private ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
|
||||
|
||||
P11KeyWrapCipher(Token token, String algorithm, long mechanism)
|
||||
throws PKCS11Exception, NoSuchAlgorithmException {
|
||||
super();
|
||||
this.token = token;
|
||||
this.mechanism = mechanism;
|
||||
|
||||
// javax.crypto.Cipher ensures algoParts.length == 3
|
||||
String[] algoParts = algorithm.split("/");
|
||||
if (algoParts[0].startsWith("AES")) {
|
||||
int index = algoParts[0].indexOf('_');
|
||||
fixedKeySize = (index == -1? -1 :
|
||||
// should be well-formed since we specify what we support
|
||||
Integer.parseInt(algoParts[0].substring(index+1)) >> 3);
|
||||
try {
|
||||
this.type = KeyWrapType.valueOf(algoParts[1].toUpperCase() +
|
||||
"_" + algoParts[2].toUpperCase());
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new NoSuchAlgorithmException("Unsupported algorithm " +
|
||||
algorithm);
|
||||
}
|
||||
} else {
|
||||
throw new NoSuchAlgorithmException("Unsupported algorithm " +
|
||||
algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
|
||||
if (!mode.toUpperCase(Locale.ENGLISH).equals(type.mode)) {
|
||||
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected void engineSetPadding(String padding)
|
||||
throws NoSuchPaddingException {
|
||||
if (!padding.toUpperCase(Locale.ENGLISH).equals(type.padding)) {
|
||||
throw new NoSuchPaddingException("Unsupported padding " + padding);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineGetBlockSize() {
|
||||
return BLK_SIZE;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineGetOutputSize(int inputLen) {
|
||||
return doFinalLength(inputLen);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected byte[] engineGetIV() {
|
||||
return (iv == null) ? null : iv.clone();
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
// KW and KWP uses but not require parameters, return the default
|
||||
// IV when no IV is supplied by caller
|
||||
byte[] iv = (this.iv == null? type.defIv : this.iv);
|
||||
|
||||
AlgorithmParameterSpec spec = new IvParameterSpec(iv);
|
||||
try {
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
|
||||
params.init(spec);
|
||||
return params;
|
||||
} catch (GeneralSecurityException e) {
|
||||
// NoSuchAlgorithmException, NoSuchProviderException
|
||||
// InvalidParameterSpecException
|
||||
throw new ProviderException("Could not encode parameters", e);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineInit(int opmode, Key key, SecureRandom sr)
|
||||
throws InvalidKeyException {
|
||||
try {
|
||||
implInit(opmode, key, null, sr);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new InvalidKeyException("init() failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineInit(int opmode, Key key,
|
||||
AlgorithmParameterSpec params, SecureRandom sr)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
if (params != null && !(params instanceof IvParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only IvParameterSpec is supported");
|
||||
}
|
||||
|
||||
byte[] ivValue = (params == null? null :
|
||||
((IvParameterSpec)params).getIV());
|
||||
|
||||
implInit(opmode, key, ivValue, sr);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
|
||||
SecureRandom sr)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
AlgorithmParameterSpec paramSpec = null;
|
||||
if (params != null) {
|
||||
try {
|
||||
paramSpec = params.getParameterSpec(IvParameterSpec.class);
|
||||
} catch (InvalidParameterSpecException ex) {
|
||||
throw new InvalidAlgorithmParameterException(ex);
|
||||
}
|
||||
}
|
||||
engineInit(opmode, key, paramSpec, sr);
|
||||
}
|
||||
|
||||
// actual init() implementation
|
||||
private void implInit(int opmode, Key key, byte[] iv, SecureRandom sr)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
reset(true);
|
||||
if (fixedKeySize != -1) {
|
||||
int keySize;
|
||||
if (key instanceof P11Key) {
|
||||
keySize = ((P11Key) key).length() >> 3;
|
||||
} else {
|
||||
byte[] encoding = key.getEncoded();
|
||||
Arrays.fill(encoding, (byte) 0);
|
||||
keySize = encoding.length;
|
||||
}
|
||||
if (keySize != fixedKeySize) {
|
||||
throw new InvalidKeyException("Key size is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
P11Key newKey = P11SecretKeyFactory.convertKey(token, key, "AES");
|
||||
this.opmode = opmode;
|
||||
|
||||
if (iv == null) {
|
||||
iv = type.defIv;
|
||||
} else {
|
||||
if (type == KeyWrapType.KWP_NOPADDING &&
|
||||
!Arrays.equals(iv, type.defIv)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("For KWP mode, IV must has value 0x" +
|
||||
HexFormat.of().withUpperCase().formatHex(type.defIv));
|
||||
} else if (iv.length != type.defIv.length) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Wrong IV length, expected " + type.defIv.length +
|
||||
" but got " + iv.length);
|
||||
}
|
||||
}
|
||||
this.iv = iv;
|
||||
this.p11Key = newKey;
|
||||
if (sr != null) {
|
||||
this.random = sr;
|
||||
}
|
||||
try {
|
||||
initialize();
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.match(CKR_MECHANISM_PARAM_INVALID)) {
|
||||
throw new InvalidAlgorithmParameterException("Bad params", e);
|
||||
}
|
||||
throw new InvalidKeyException("Could not initialize cipher", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelOperation() {
|
||||
// cancel operation by finishing it; avoid killSession as some
|
||||
// hardware vendors may require re-login
|
||||
byte[] in = dataBuffer.toByteArray();
|
||||
int inLen = in.length;
|
||||
int bufLen = doFinalLength(0);
|
||||
byte[] buffer = new byte[bufLen];
|
||||
|
||||
try {
|
||||
if (opmode == Cipher.ENCRYPT_MODE) {
|
||||
token.p11.C_Encrypt(session.id(), 0, in, 0, inLen,
|
||||
0, buffer, 0, bufLen);
|
||||
} else if (opmode == Cipher.DECRYPT_MODE) {
|
||||
token.p11.C_Decrypt(session.id(), 0, in, 0, inLen,
|
||||
0, buffer, 0, bufLen);
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.match(CKR_OPERATION_NOT_INITIALIZED)) {
|
||||
// Cancel Operation may be invoked after an error on a PKCS#11
|
||||
// call. If the operation inside the token was already
|
||||
// cancelled, do not fail here. This is part of a defensive
|
||||
// mechanism for PKCS#11 libraries that do not strictly follow
|
||||
// the standard.
|
||||
return;
|
||||
}
|
||||
// ignore failure for en/decryption since it's likely to fail
|
||||
// due to the minimum length requirement
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureInitialized() throws PKCS11Exception {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() throws PKCS11Exception {
|
||||
if (p11Key == null) {
|
||||
throw new ProviderException("Operation cannot be performed without"
|
||||
+ " calling engineInit first");
|
||||
}
|
||||
|
||||
token.ensureValid();
|
||||
dataBuffer.reset();
|
||||
|
||||
if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.DECRYPT_MODE) {
|
||||
long p11KeyID = p11Key.getKeyID();
|
||||
try {
|
||||
CK_MECHANISM mechWithParams = new CK_MECHANISM(mechanism, iv);
|
||||
|
||||
if (session == null) {
|
||||
session = token.getOpSession();
|
||||
}
|
||||
switch (opmode) {
|
||||
case Cipher.ENCRYPT_MODE:
|
||||
token.p11.C_EncryptInit(session.id(), mechWithParams,
|
||||
p11KeyID);
|
||||
break;
|
||||
case Cipher.DECRYPT_MODE:
|
||||
token.p11.C_DecryptInit(session.id(), mechWithParams,
|
||||
p11KeyID);
|
||||
break;
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
session = token.releaseSession(session);
|
||||
throw e;
|
||||
} finally {
|
||||
p11Key.releaseKeyID();
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// if doFinal(inLen) is called, how big does the output buffer have to be?
|
||||
private int doFinalLength(int inLen) {
|
||||
if (inLen < 0) {
|
||||
throw new ProviderException("Invalid negative input length");
|
||||
}
|
||||
|
||||
int result = inLen + dataBuffer.size();
|
||||
boolean encrypt = (opmode == Cipher.ENCRYPT_MODE ||
|
||||
opmode == Cipher.WRAP_MODE);
|
||||
if (encrypt) {
|
||||
if (type == KeyWrapType.KW_PKCS5PADDING) {
|
||||
// add potential pad length, i.e. 1-8
|
||||
result += (BLK_SIZE - (result & (BLK_SIZE - 1)));
|
||||
} else if (type == KeyWrapType.KWP_NOPADDING &&
|
||||
(result & (BLK_SIZE - 1)) != 0) {
|
||||
// add potential pad length, i.e. 0-7
|
||||
result += (BLK_SIZE - (result & (BLK_SIZE - 1)));
|
||||
}
|
||||
result += BLK_SIZE; // add the leading block including the ICV
|
||||
} else {
|
||||
result -= BLK_SIZE; // minus the leading block including the ICV
|
||||
}
|
||||
return (result > 0? result : 0);
|
||||
}
|
||||
|
||||
// reset the states to the pre-initialized values
|
||||
// set initialized to false, cancel operation, release session, and
|
||||
// reset dataBuffer
|
||||
private void reset(boolean doCancel) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = false;
|
||||
|
||||
try {
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (doCancel && token.explicitCancel) {
|
||||
cancelOperation();
|
||||
}
|
||||
} finally {
|
||||
session = token.releaseSession(session);
|
||||
dataBuffer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
|
||||
int n = implUpdate(in, inOfs, inLen);
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
|
||||
int outOfs) throws ShortBufferException {
|
||||
implUpdate(in, inOfs, inLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
|
||||
throws ShortBufferException {
|
||||
implUpdate(inBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
|
||||
throws IllegalBlockSizeException, BadPaddingException {
|
||||
int maxOutLen = doFinalLength(inLen);
|
||||
try {
|
||||
byte[] out = new byte[maxOutLen];
|
||||
int n = engineDoFinal(in, inOfs, inLen, out, 0);
|
||||
return P11Util.convert(out, 0, n);
|
||||
} catch (ShortBufferException e) {
|
||||
// convert since the output length is calculated by doFinalLength()
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
// see JCE spec
|
||||
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
|
||||
int outOfs) throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
return implDoFinal(in, inOfs, inLen, out, outOfs, out.length - outOfs);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
return implDoFinal(inBuffer, outBuffer);
|
||||
}
|
||||
|
||||
private int implUpdate(byte[] in, int inOfs, int inLen) {
|
||||
if (inLen > 0) {
|
||||
try {
|
||||
ensureInitialized();
|
||||
} catch (PKCS11Exception e) {
|
||||
reset(false);
|
||||
throw new ProviderException("update() failed", e);
|
||||
}
|
||||
dataBuffer.write(in, inOfs, inLen);
|
||||
}
|
||||
// always 0 as NSS only supports single-part encryption/decryption
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int implUpdate(ByteBuffer inBuf) {
|
||||
int inLen = inBuf.remaining();
|
||||
if (inLen > 0) {
|
||||
try {
|
||||
ensureInitialized();
|
||||
} catch (PKCS11Exception e) {
|
||||
reset(false);
|
||||
throw new ProviderException("update() failed", e);
|
||||
}
|
||||
byte[] data = new byte[inLen];
|
||||
inBuf.get(data);
|
||||
dataBuffer.write(data, 0, data.length);
|
||||
}
|
||||
// always 0 as NSS only supports single-part encryption/decryption
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int implDoFinal(byte[] in, int inOfs, int inLen,
|
||||
byte[] out, int outOfs, int outLen)
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
int requiredOutLen = doFinalLength(inLen);
|
||||
if (outLen < requiredOutLen) {
|
||||
throw new ShortBufferException();
|
||||
}
|
||||
|
||||
boolean doCancel = true;
|
||||
int k = 0;
|
||||
try {
|
||||
ensureInitialized();
|
||||
|
||||
if (dataBuffer.size() > 0) {
|
||||
if (in != null && inLen > 0) {
|
||||
dataBuffer.write(in, inOfs, inLen);
|
||||
}
|
||||
in = dataBuffer.toByteArray();
|
||||
inOfs = 0;
|
||||
inLen = in.length;
|
||||
}
|
||||
|
||||
if (opmode == Cipher.ENCRYPT_MODE) {
|
||||
k = token.p11.C_Encrypt(session.id(), 0, in, inOfs, inLen,
|
||||
0, out, outOfs, outLen);
|
||||
doCancel = false;
|
||||
} else {
|
||||
// Special handling to match SunJCE provider behavior
|
||||
if (inLen == 0) {
|
||||
return 0;
|
||||
}
|
||||
k = token.p11.C_Decrypt(session.id(), 0, in, inOfs, inLen,
|
||||
0, out, outOfs, outLen);
|
||||
doCancel = false;
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
// As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only
|
||||
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
|
||||
// successful calls to determine the output length. However,
|
||||
// these cases are not expected here because the output length
|
||||
// is checked in the OpenJDK side before making the PKCS#11 call.
|
||||
// Thus, doCancel can safely be 'false'.
|
||||
doCancel = false;
|
||||
handleEncException("doFinal() failed", e);
|
||||
} finally {
|
||||
reset(doCancel);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
private int implDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
|
||||
throws ShortBufferException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
int outLen = outBuffer.remaining();
|
||||
int inLen = inBuffer.remaining();
|
||||
|
||||
int requiredOutLen = doFinalLength(inLen);
|
||||
if (outLen < requiredOutLen) {
|
||||
throw new ShortBufferException();
|
||||
}
|
||||
|
||||
boolean doCancel = true;
|
||||
int k = 0;
|
||||
try {
|
||||
ensureInitialized();
|
||||
|
||||
long inAddr = 0;
|
||||
byte[] in = null;
|
||||
int inOfs = 0;
|
||||
|
||||
if (dataBuffer.size() > 0) {
|
||||
if (inBuffer != null && inLen > 0) {
|
||||
byte[] temp = new byte[inLen];
|
||||
inBuffer.get(temp);
|
||||
dataBuffer.write(temp, 0, temp.length);
|
||||
}
|
||||
|
||||
in = dataBuffer.toByteArray();
|
||||
inOfs = 0;
|
||||
inLen = in.length;
|
||||
} else {
|
||||
if (inBuffer instanceof DirectBuffer) {
|
||||
inAddr = ((DirectBuffer) inBuffer).address();
|
||||
inOfs = inBuffer.position();
|
||||
} else {
|
||||
if (inBuffer.hasArray()) {
|
||||
in = inBuffer.array();
|
||||
inOfs = inBuffer.position() + inBuffer.arrayOffset();
|
||||
} else {
|
||||
in = new byte[inLen];
|
||||
inBuffer.get(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
long outAddr = 0;
|
||||
byte[] outArray = null;
|
||||
int outOfs = 0;
|
||||
if (outBuffer instanceof DirectBuffer) {
|
||||
outAddr = ((DirectBuffer) outBuffer).address();
|
||||
outOfs = outBuffer.position();
|
||||
} else {
|
||||
if (outBuffer.hasArray()) {
|
||||
outArray = outBuffer.array();
|
||||
outOfs = outBuffer.position() + outBuffer.arrayOffset();
|
||||
} else {
|
||||
outArray = new byte[outLen];
|
||||
}
|
||||
}
|
||||
|
||||
if (opmode == Cipher.ENCRYPT_MODE) {
|
||||
k = token.p11.C_Encrypt(session.id(), inAddr, in, inOfs, inLen,
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
doCancel = false;
|
||||
} else {
|
||||
// Special handling to match SunJCE provider behavior
|
||||
if (inLen == 0) {
|
||||
return 0;
|
||||
}
|
||||
k = token.p11.C_Decrypt(session.id(), inAddr, in, inOfs, inLen,
|
||||
outAddr, outArray, outOfs, outLen);
|
||||
doCancel = false;
|
||||
}
|
||||
inBuffer.position(inBuffer.limit());
|
||||
outBuffer.position(outBuffer.position() + k);
|
||||
} catch (PKCS11Exception e) {
|
||||
// As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only
|
||||
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
|
||||
// successful calls to determine the output length. However,
|
||||
// these cases are not expected here because the output length
|
||||
// is checked in the OpenJDK side before making the PKCS#11 call.
|
||||
// Thus, doCancel can safely be 'false'.
|
||||
doCancel = false;
|
||||
handleEncException("doFinal() failed", e);
|
||||
} finally {
|
||||
reset(doCancel);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
private void handleEncException(String msg, PKCS11Exception e)
|
||||
throws IllegalBlockSizeException, ShortBufferException,
|
||||
ProviderException {
|
||||
if (e.match(CKR_DATA_LEN_RANGE) ||
|
||||
e.match(CKR_ENCRYPTED_DATA_LEN_RANGE)) {
|
||||
throw (IllegalBlockSizeException)
|
||||
(new IllegalBlockSizeException(msg).initCause(e));
|
||||
} else if (e.match(CKR_BUFFER_TOO_SMALL)) {
|
||||
throw (ShortBufferException)
|
||||
(new ShortBufferException(msg).initCause(e));
|
||||
} else {
|
||||
throw new ProviderException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineWrap(Key tbwKey) throws IllegalBlockSizeException,
|
||||
InvalidKeyException {
|
||||
try {
|
||||
ensureInitialized();
|
||||
} catch (PKCS11Exception e) {
|
||||
reset(false);
|
||||
throw new ProviderException("wrap() failed", e);
|
||||
}
|
||||
|
||||
// convert the specified key into P11Key handle
|
||||
P11Key tbwP11Key = null;
|
||||
if (!(tbwKey instanceof P11Key)) {
|
||||
try {
|
||||
tbwP11Key = (tbwKey instanceof SecretKey?
|
||||
P11SecretKeyFactory.convertKey(token, tbwKey,
|
||||
tbwKey.getAlgorithm()) :
|
||||
P11KeyFactory.convertKey(token, tbwKey,
|
||||
tbwKey.getAlgorithm()));
|
||||
} catch (ProviderException pe) {
|
||||
throw new InvalidKeyException("Cannot convert to PKCS11 key",
|
||||
pe);
|
||||
} catch (InvalidKeyException ike) {
|
||||
// could be algorithms NOT supported by PKCS11 library
|
||||
// try single part encryption instead
|
||||
}
|
||||
} else {
|
||||
tbwP11Key = (P11Key) tbwKey;
|
||||
}
|
||||
|
||||
long p11KeyID = 0;
|
||||
try {
|
||||
if (session == null) {
|
||||
session = token.getOpSession();
|
||||
}
|
||||
|
||||
p11KeyID = p11Key.getKeyID();
|
||||
CK_MECHANISM mechWithParams = new CK_MECHANISM(mechanism, iv);
|
||||
if (tbwP11Key != null) {
|
||||
long tbwP11KeyID = tbwP11Key.getKeyID();
|
||||
try {
|
||||
return token.p11.C_WrapKey(session.id(), mechWithParams,
|
||||
p11KeyID, tbwP11KeyID);
|
||||
} finally {
|
||||
tbwP11Key.releaseKeyID();
|
||||
}
|
||||
} else {
|
||||
byte[] in = tbwKey.getEncoded();
|
||||
try {
|
||||
token.p11.C_EncryptInit(session.id(), mechWithParams,
|
||||
p11KeyID);
|
||||
|
||||
int bufLen = doFinalLength(in.length);
|
||||
byte[] buffer = new byte[bufLen];
|
||||
|
||||
token.p11.C_Encrypt(session.id(), 0, in, 0, in.length,
|
||||
0, buffer, 0, bufLen);
|
||||
return buffer;
|
||||
} finally {
|
||||
Arrays.fill(in, (byte)0);
|
||||
}
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
String msg = "wrap() failed";
|
||||
if (e.match(CKR_KEY_SIZE_RANGE) || e.match(CKR_DATA_LEN_RANGE)) {
|
||||
throw (IllegalBlockSizeException)
|
||||
(new IllegalBlockSizeException(msg).initCause(e));
|
||||
} else if (e.match(CKR_KEY_NOT_WRAPPABLE) ||
|
||||
e.match(CKR_KEY_UNEXTRACTABLE) ||
|
||||
e.match(CKR_KEY_HANDLE_INVALID)) {
|
||||
throw new InvalidKeyException(msg, e);
|
||||
} else if (e.match(CKR_MECHANISM_INVALID)) {
|
||||
throw new UnsupportedOperationException(msg, e);
|
||||
} else {
|
||||
throw new ProviderException(msg, e);
|
||||
}
|
||||
} finally {
|
||||
if (p11KeyID != 0) p11Key.releaseKeyID();
|
||||
reset(false);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgo,
|
||||
int wrappedKeyType)
|
||||
throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
try {
|
||||
ensureInitialized();
|
||||
} catch (PKCS11Exception e) {
|
||||
reset(false);
|
||||
throw new ProviderException("unwrap() failed", e);
|
||||
}
|
||||
|
||||
long keyClass;
|
||||
long keyType;
|
||||
switch (wrappedKeyType) {
|
||||
case Cipher.PRIVATE_KEY:
|
||||
keyClass = CKO_PRIVATE_KEY;
|
||||
keyType = P11KeyFactory.getPKCS11KeyType(wrappedKeyAlgo);
|
||||
break;
|
||||
case Cipher.SECRET_KEY:
|
||||
keyClass = CKO_SECRET_KEY;
|
||||
keyType = P11SecretKeyFactory.getPKCS11KeyType(wrappedKeyAlgo);
|
||||
break;
|
||||
case Cipher.PUBLIC_KEY:
|
||||
throw new UnsupportedOperationException
|
||||
("cannot unwrap public keys");
|
||||
default: // should never happen
|
||||
throw new AssertionError();
|
||||
};
|
||||
|
||||
CK_ATTRIBUTE[] attributes;
|
||||
try {
|
||||
attributes = new CK_ATTRIBUTE[] {
|
||||
new CK_ATTRIBUTE(CKA_CLASS, keyClass),
|
||||
new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
|
||||
};
|
||||
attributes = token.getAttributes
|
||||
(O_IMPORT, keyClass, keyType, attributes);
|
||||
} catch (PKCS11Exception e) {
|
||||
reset(false);
|
||||
throw new ProviderException("unwrap() failed", e);
|
||||
}
|
||||
|
||||
CK_MECHANISM mechParams = new CK_MECHANISM(mechanism, iv);
|
||||
|
||||
long p11KeyID = 0;
|
||||
try {
|
||||
if (session == null) {
|
||||
session = token.getOpSession();
|
||||
}
|
||||
|
||||
p11KeyID = p11Key.getKeyID();
|
||||
long unwrappedKeyID = token.p11.C_UnwrapKey(session.id(),
|
||||
mechParams, p11KeyID, wrappedKey, attributes);
|
||||
|
||||
return (switch(wrappedKeyType) {
|
||||
case Cipher.PRIVATE_KEY -> P11Key.privateKey
|
||||
(session, unwrappedKeyID, wrappedKeyAlgo, -1, attributes);
|
||||
case Cipher.SECRET_KEY -> P11Key.secretKey
|
||||
(session, unwrappedKeyID, wrappedKeyAlgo, -1, attributes);
|
||||
default -> null;
|
||||
});
|
||||
} catch (PKCS11Exception e) {
|
||||
String msg = "unwrap() failed";
|
||||
if (e.match(CKR_UNWRAPPING_KEY_SIZE_RANGE) ||
|
||||
e.match(CKR_WRAPPED_KEY_INVALID) ||
|
||||
e.match(CKR_WRAPPED_KEY_LEN_RANGE) ||
|
||||
e.match(CKR_UNWRAPPING_KEY_HANDLE_INVALID) ||
|
||||
e.match(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT)) {
|
||||
throw new InvalidKeyException(msg, e);
|
||||
} else if (e.match(CKR_MECHANISM_INVALID)) {
|
||||
throw new UnsupportedOperationException(msg, e);
|
||||
} else {
|
||||
throw new ProviderException(msg, e);
|
||||
}
|
||||
} finally {
|
||||
if (p11KeyID != 0) p11Key.releaseKeyID();
|
||||
reset(false);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@Override
|
||||
protected int engineGetKeySize(Key key) throws InvalidKeyException {
|
||||
return P11SecretKeyFactory.convertKey(token, key, "AES").length();
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ import sun.nio.ch.DirectBuffer;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* MAC implementation class. This class currently supports HMAC using
|
||||
@ -152,7 +152,7 @@ final class P11Mac extends MacSpi {
|
||||
try {
|
||||
token.p11.C_SignFinal(session.id(), 0);
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
|
||||
if (e.match(CKR_OPERATION_NOT_INITIALIZED)) {
|
||||
// Cancel Operation may be invoked after an error on a PKCS#11
|
||||
// call. If the operation inside the token was already cancelled,
|
||||
// do not fail here. This is part of a defensive mechanism for
|
||||
|
@ -40,7 +40,7 @@ import java.security.interfaces.*;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import sun.security.util.KnownOIDs;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* RSASSA-PSS Signature implementation class. This class currently supports the
|
||||
@ -298,7 +298,7 @@ final class P11PSSSignature extends SignatureSpi {
|
||||
}
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
|
||||
if (e.match(CKR_OPERATION_NOT_INITIALIZED)) {
|
||||
// Cancel Operation may be invoked after an error on a PKCS#11
|
||||
// call. If the operation inside the token was already cancelled,
|
||||
// do not fail here. This is part of a defensive mechanism for
|
||||
@ -705,16 +705,9 @@ final class P11PSSSignature extends SignatureSpi {
|
||||
return true;
|
||||
} catch (PKCS11Exception pe) {
|
||||
doCancel = false;
|
||||
long errorCode = pe.getErrorCode();
|
||||
if (errorCode == CKR_SIGNATURE_INVALID) {
|
||||
return false;
|
||||
}
|
||||
if (errorCode == CKR_SIGNATURE_LEN_RANGE) {
|
||||
// return false rather than throwing an exception
|
||||
return false;
|
||||
}
|
||||
// ECF bug?
|
||||
if (errorCode == CKR_DATA_LEN_RANGE) {
|
||||
if (pe.match(CKR_SIGNATURE_INVALID) ||
|
||||
pe.match(CKR_SIGNATURE_LEN_RANGE) ||
|
||||
pe.match(CKR_DATA_LEN_RANGE)) {
|
||||
return false;
|
||||
}
|
||||
throw new ProviderException(pe);
|
||||
|
@ -42,7 +42,7 @@ import sun.security.rsa.RSAPadding;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
import sun.security.util.KeyUtil;
|
||||
|
||||
/**
|
||||
@ -315,7 +315,7 @@ final class P11Signature extends SignatureSpi {
|
||||
}
|
||||
}
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
|
||||
if (e.match(CKR_OPERATION_NOT_INITIALIZED)) {
|
||||
// Cancel Operation may be invoked after an error on a PKCS#11
|
||||
// call. If the operation inside the token was already cancelled,
|
||||
// do not fail here. This is part of a defensive mechanism for
|
||||
@ -323,9 +323,8 @@ final class P11Signature extends SignatureSpi {
|
||||
return;
|
||||
}
|
||||
if (mode == M_VERIFY) {
|
||||
long errorCode = e.getErrorCode();
|
||||
if ((errorCode == CKR_SIGNATURE_INVALID) ||
|
||||
(errorCode == CKR_SIGNATURE_LEN_RANGE)) {
|
||||
if (e.match(CKR_SIGNATURE_INVALID) ||
|
||||
e.match(CKR_SIGNATURE_LEN_RANGE)) {
|
||||
// expected since signature is incorrect
|
||||
return;
|
||||
}
|
||||
@ -727,16 +726,9 @@ final class P11Signature extends SignatureSpi {
|
||||
return true;
|
||||
} catch (PKCS11Exception pe) {
|
||||
doCancel = false;
|
||||
long errorCode = pe.getErrorCode();
|
||||
if (errorCode == CKR_SIGNATURE_INVALID) {
|
||||
return false;
|
||||
}
|
||||
if (errorCode == CKR_SIGNATURE_LEN_RANGE) {
|
||||
// return false rather than throwing an exception
|
||||
return false;
|
||||
}
|
||||
// ECF bug?
|
||||
if (errorCode == CKR_DATA_LEN_RANGE) {
|
||||
if (pe.match(CKR_SIGNATURE_INVALID) ||
|
||||
pe.match(CKR_SIGNATURE_LEN_RANGE) ||
|
||||
pe.match(CKR_DATA_LEN_RANGE)) { // ECF bug?
|
||||
return false;
|
||||
}
|
||||
throw new ProviderException(pe);
|
||||
|
@ -52,7 +52,7 @@ import sun.security.pkcs11.Secmod.*;
|
||||
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* PKCS#11 provider main class.
|
||||
@ -530,6 +530,7 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
String P11KeyAgreement = "sun.security.pkcs11.P11KeyAgreement";
|
||||
String P11SecretKeyFactory = "sun.security.pkcs11.P11SecretKeyFactory";
|
||||
String P11Cipher = "sun.security.pkcs11.P11Cipher";
|
||||
String P11KeyWrapCipher = "sun.security.pkcs11.P11KeyWrapCipher";
|
||||
String P11RSACipher = "sun.security.pkcs11.P11RSACipher";
|
||||
String P11AEADCipher = "sun.security.pkcs11.P11AEADCipher";
|
||||
String P11Signature = "sun.security.pkcs11.P11Signature";
|
||||
@ -716,35 +717,59 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
m(CKM_DES3_ECB));
|
||||
d(CIP, "AES/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_AES_CBC));
|
||||
dA(CIP, "AES_128/CBC/NoPadding", P11Cipher,
|
||||
dA(CIP, "AES_128/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_AES_CBC));
|
||||
dA(CIP, "AES_192/CBC/NoPadding", P11Cipher,
|
||||
dA(CIP, "AES_192/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_AES_CBC));
|
||||
dA(CIP, "AES_256/CBC/NoPadding", P11Cipher,
|
||||
dA(CIP, "AES_256/CBC/NoPadding", P11Cipher,
|
||||
m(CKM_AES_CBC));
|
||||
d(CIP, "AES/CBC/PKCS5Padding", P11Cipher,
|
||||
m(CKM_AES_CBC_PAD, CKM_AES_CBC));
|
||||
d(CIP, "AES/ECB/NoPadding", P11Cipher,
|
||||
m(CKM_AES_ECB));
|
||||
dA(CIP, "AES_128/ECB/NoPadding", P11Cipher,
|
||||
dA(CIP, "AES_128/ECB/NoPadding", P11Cipher,
|
||||
m(CKM_AES_ECB));
|
||||
dA(CIP, "AES_192/ECB/NoPadding", P11Cipher,
|
||||
dA(CIP, "AES_192/ECB/NoPadding", P11Cipher,
|
||||
m(CKM_AES_ECB));
|
||||
dA(CIP, "AES_256/ECB/NoPadding", P11Cipher,
|
||||
dA(CIP, "AES_256/ECB/NoPadding", P11Cipher,
|
||||
m(CKM_AES_ECB));
|
||||
d(CIP, "AES/ECB/PKCS5Padding", P11Cipher,
|
||||
List.of("AES"),
|
||||
m(CKM_AES_ECB));
|
||||
d(CIP, "AES/CTR/NoPadding", P11Cipher,
|
||||
m(CKM_AES_CTR));
|
||||
dA(CIP, "AES/KW/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP));
|
||||
dA(CIP, "AES_128/KW/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP));
|
||||
dA(CIP, "AES_192/KW/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP));
|
||||
dA(CIP, "AES_256/KW/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP));
|
||||
d(CIP, "AES/KW/PKCS5Padding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_PAD));
|
||||
d(CIP, "AES_128/KW/PKCS5Padding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_PAD));
|
||||
d(CIP, "AES_192/KW/PKCS5Padding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_PAD));
|
||||
d(CIP, "AES_256/KW/PKCS5Padding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_PAD));
|
||||
dA(CIP, "AES/KWP/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_KWP));
|
||||
dA(CIP, "AES_128/KWP/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_KWP));
|
||||
dA(CIP, "AES_192/KWP/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_KWP));
|
||||
dA(CIP, "AES_256/KWP/NoPadding", P11KeyWrapCipher,
|
||||
m(CKM_AES_KEY_WRAP_KWP));
|
||||
|
||||
d(CIP, "AES/GCM/NoPadding", P11AEADCipher,
|
||||
m(CKM_AES_GCM));
|
||||
dA(CIP, "AES_128/GCM/NoPadding", P11AEADCipher,
|
||||
dA(CIP, "AES_128/GCM/NoPadding", P11AEADCipher,
|
||||
m(CKM_AES_GCM));
|
||||
dA(CIP, "AES_192/GCM/NoPadding", P11AEADCipher,
|
||||
dA(CIP, "AES_192/GCM/NoPadding", P11AEADCipher,
|
||||
m(CKM_AES_GCM));
|
||||
dA(CIP, "AES_256/GCM/NoPadding", P11AEADCipher,
|
||||
dA(CIP, "AES_256/GCM/NoPadding", P11AEADCipher,
|
||||
m(CKM_AES_GCM));
|
||||
|
||||
d(CIP, "Blowfish/CBC/NoPadding", P11Cipher,
|
||||
@ -1251,6 +1276,9 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
} else if (algorithm.endsWith("GCM/NoPadding") ||
|
||||
algorithm.startsWith("ChaCha20-Poly1305")) {
|
||||
return new P11AEADCipher(token, algorithm, mechanism);
|
||||
} else if (algorithm.indexOf("/KW/") != -1 ||
|
||||
algorithm.indexOf("/KWP/") != -1) {
|
||||
return new P11KeyWrapCipher(token, algorithm, mechanism);
|
||||
} else {
|
||||
return new P11Cipher(token, algorithm, mechanism);
|
||||
}
|
||||
@ -1505,13 +1533,13 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
debug.println("login succeeded");
|
||||
}
|
||||
} catch (PKCS11Exception pe) {
|
||||
if (pe.getErrorCode() == CKR_USER_ALREADY_LOGGED_IN) {
|
||||
if (pe.match(CKR_USER_ALREADY_LOGGED_IN)) {
|
||||
// let this one go
|
||||
if (debug != null) {
|
||||
debug.println("user already logged in");
|
||||
}
|
||||
return;
|
||||
} else if (pe.getErrorCode() == CKR_PIN_INCORRECT) {
|
||||
} else if (pe.match(CKR_PIN_INCORRECT)) {
|
||||
FailedLoginException fle = new FailedLoginException();
|
||||
fle.initCause(pe);
|
||||
throw fle;
|
||||
@ -1590,7 +1618,7 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
debug.println("logout succeeded");
|
||||
}
|
||||
} catch (PKCS11Exception pe) {
|
||||
if (pe.getErrorCode() == CKR_USER_NOT_LOGGED_IN) {
|
||||
if (pe.match(CKR_USER_NOT_LOGGED_IN)) {
|
||||
// let this one go
|
||||
if (debug != null) {
|
||||
debug.println("user not logged in");
|
||||
|
@ -38,7 +38,7 @@ import sun.security.jca.JCAUtil;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.TemplateManager.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* PKCS#11 token.
|
||||
@ -400,7 +400,7 @@ class Token implements Serializable {
|
||||
mechanism);
|
||||
mechInfoMap.put(mechanism, result);
|
||||
} catch (PKCS11Exception e) {
|
||||
if (e.getErrorCode() != CKR_MECHANISM_INVALID) {
|
||||
if (!e.match(CKR_MECHANISM_INVALID)) {
|
||||
throw e;
|
||||
} else {
|
||||
mechInfoMap.put(mechanism, INVALID_MECH);
|
||||
|
@ -57,7 +57,7 @@ import java.security.PrivilegedAction;
|
||||
import sun.security.util.Debug;
|
||||
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
|
||||
/**
|
||||
* This is the default implementation of the PKCS11 interface. IT connects to
|
||||
@ -169,7 +169,7 @@ public class PKCS11 {
|
||||
} catch (PKCS11Exception e) {
|
||||
// ignore already-initialized error code
|
||||
// rethrow all other errors
|
||||
if (e.getErrorCode() != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
|
||||
if (!e.match(CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -72,37 +72,8 @@ public class PKCS11Exception extends Exception {
|
||||
|
||||
protected String errorMsg;
|
||||
|
||||
public static final long CKR_GENERAL_ERROR = RV.CKR_GENERAL_ERROR.value;
|
||||
public static final long CKR_ATTRIBUTE_TYPE_INVALID =
|
||||
RV.CKR_ATTRIBUTE_TYPE_INVALID.value;
|
||||
public static final long CKR_DATA_LEN_RANGE = RV.CKR_DATA_LEN_RANGE.value;
|
||||
public static final long CKR_ENCRYPTED_DATA_INVALID =
|
||||
RV.CKR_ENCRYPTED_DATA_INVALID.value;
|
||||
public static final long CKR_ENCRYPTED_DATA_LEN_RANGE =
|
||||
RV.CKR_ENCRYPTED_DATA_LEN_RANGE.value;
|
||||
public static final long CKR_MECHANISM_INVALID =
|
||||
RV.CKR_MECHANISM_INVALID.value;
|
||||
public static final long CKR_MECHANISM_PARAM_INVALID =
|
||||
RV.CKR_MECHANISM_PARAM_INVALID.value;
|
||||
public static final long CKR_OPERATION_NOT_INITIALIZED =
|
||||
RV.CKR_OPERATION_NOT_INITIALIZED.value;
|
||||
public static final long CKR_PIN_INCORRECT =
|
||||
RV.CKR_PIN_INCORRECT.value;
|
||||
public static final long CKR_SIGNATURE_INVALID =
|
||||
RV.CKR_SIGNATURE_INVALID.value;
|
||||
public static final long CKR_SIGNATURE_LEN_RANGE =
|
||||
RV.CKR_SIGNATURE_LEN_RANGE.value;
|
||||
public static final long CKR_USER_ALREADY_LOGGED_IN =
|
||||
RV.CKR_USER_ALREADY_LOGGED_IN.value;
|
||||
public static final long CKR_USER_NOT_LOGGED_IN =
|
||||
RV.CKR_USER_NOT_LOGGED_IN.value;
|
||||
public static final long CKR_BUFFER_TOO_SMALL =
|
||||
RV.CKR_BUFFER_TOO_SMALL.value;
|
||||
public static final long CKR_CRYPTOKI_ALREADY_INITIALIZED =
|
||||
RV.CKR_CRYPTOKI_ALREADY_INITIALIZED.value;
|
||||
|
||||
// enum for all PKCS#11 return value
|
||||
static enum RV {
|
||||
public static enum RV {
|
||||
CKR_OK(0x00000000L),
|
||||
CKR_CANCEL(0x00000001L),
|
||||
CKR_HOST_MEMORY(0x00000002L),
|
||||
@ -255,4 +226,14 @@ public class PKCS11Exception extends Exception {
|
||||
public long getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the error code matches the the specified enum value.
|
||||
* @return true if the error code matches the the specified enum value.
|
||||
* @preconditions
|
||||
* @postconditions
|
||||
*/
|
||||
public boolean match(RV errorEnum) {
|
||||
return (errorCode == errorEnum.value);
|
||||
}
|
||||
}
|
||||
|
395
test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java
Normal file
395
test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java
Normal file
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 8264849
|
||||
* @library /test/lib ../..
|
||||
* @run main/othervm NISTWrapKAT
|
||||
* @summary Verify that the AES-Key-Wrap and AES-Key-Wrap-Pad ciphers
|
||||
* work as expected using NIST test vectors.
|
||||
*/
|
||||
import java.security.Key;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.Provider;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
import java.util.Arrays;
|
||||
import java.math.BigInteger;
|
||||
|
||||
// adapted from com/sun/crypto/provider/Cipher/KeyWrap/NISTWrapKAT.java
|
||||
public class NISTWrapKAT extends PKCS11Test {
|
||||
|
||||
private static final String KEK =
|
||||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
|
||||
private static final String DATA =
|
||||
"00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f";
|
||||
// from RFC 3394 sec4
|
||||
private static String KW_AES128_128 =
|
||||
"1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5";
|
||||
private static String KW_AES192_128 =
|
||||
"96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d";
|
||||
private static String KW_AES192_192 =
|
||||
"031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2";
|
||||
private static String KW_AES256_128 =
|
||||
"64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7";
|
||||
private static String KW_AES256_192 =
|
||||
"a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1";
|
||||
private static String KW_AES256_256 =
|
||||
"28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21";
|
||||
|
||||
private static String KWP_AES128_56 = "1B1D4BC2A90B1FA389412B3D40FECB20";
|
||||
private static String KWP_AES128_112 =
|
||||
"EA0BFDE8AF063E8918E811A05D2A4C23A367B45315716B5B";
|
||||
private static String KWP_AES192_56 = "87CE2C5C2D7196E09381056B319D91E9";
|
||||
private static String KWP_AES192_112 =
|
||||
"900484950F84EB6ED74CE81DCDACA26E72BB29D4A6F7AC74";
|
||||
private static String KWP_AES192_168 =
|
||||
"A402348F1956DB968FDDFD8976420F9DDEB7183CF16B91B0AEB74CAB196C343E";
|
||||
private static String KWP_AES256_56 = "809BB1864A18938529E97EFCD9544E9A";
|
||||
private static String KWP_AES256_112 =
|
||||
"C68168173F141E6D5767611574A941259090DA78D7DF9DF7";
|
||||
private static String KWP_AES256_168 =
|
||||
"308D49692B5F8CF638D54BB4B985633504237329964C76EBB3F669870A708DBC";
|
||||
private static String KWP_AES256_224 =
|
||||
"0942747DB07032A3F04CDB2E7DE1CBA038F92BC355393AE9A0E4AE8C901912AC3D3AF0F16D240607";
|
||||
// from RFC 5649 sec6
|
||||
private static String KEK2 = "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8";
|
||||
|
||||
private static byte[] toBytes(String hex, int hexLen) {
|
||||
if (hexLen < hex.length()) {
|
||||
hex = hex.substring(0, hexLen);
|
||||
} else {
|
||||
hexLen = hex.length();
|
||||
}
|
||||
int outLen = hexLen >> 1;
|
||||
BigInteger temp = new BigInteger(hex, 16);
|
||||
byte[] val = temp.toByteArray();
|
||||
if (val.length == outLen) {
|
||||
return val;
|
||||
} else {
|
||||
byte[] out = new byte[outLen];
|
||||
if (val.length < outLen) {
|
||||
// enlarge
|
||||
System.arraycopy(val, 0, out, outLen - val.length, val.length);
|
||||
} else {
|
||||
// truncate
|
||||
System.arraycopy(val, val.length - outLen, out, 0, outLen);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
//@DataProvider
|
||||
public Object[][] testData() {
|
||||
return new Object[][] {
|
||||
{ "AESWrap", KEK, 16, DATA, 16, KW_AES128_128 },
|
||||
{ "AESWrap", KEK, 24, DATA, 16, KW_AES192_128 },
|
||||
{ "AESWrap", KEK, 24, DATA, 24, KW_AES192_192 },
|
||||
{ "AESWrap", KEK, 32, DATA, 16, KW_AES256_128 },
|
||||
{ "AESWrap", KEK, 32, DATA, 24, KW_AES256_192 },
|
||||
{ "AESWrap", KEK, 32, DATA, 32, KW_AES256_256 },
|
||||
{ "AESWrap_128", KEK, 16, DATA, 16, KW_AES128_128 },
|
||||
{ "AESWrap_192", KEK, 24, DATA, 16, KW_AES192_128 },
|
||||
{ "AESWrap_256", KEK, 32, DATA, 16, KW_AES256_128 },
|
||||
{ "AES/KW/NoPadding", KEK, 16, DATA, 16, KW_AES128_128 },
|
||||
{ "AES/KW/NoPadding", KEK, 24, DATA, 16, KW_AES192_128 },
|
||||
{ "AES/KW/NoPadding", KEK, 24, DATA, 24, KW_AES192_192 },
|
||||
{ "AES/KW/NoPadding", KEK, 32, DATA, 16, KW_AES256_128 },
|
||||
{ "AES/KW/NoPadding", KEK, 32, DATA, 24, KW_AES256_192 },
|
||||
{ "AES/KW/NoPadding", KEK, 32, DATA, 32, KW_AES256_256 },
|
||||
{ "AESWrapPad", KEK, 16, DATA, 7, KWP_AES128_56 },
|
||||
{ "AESWrapPad", KEK, 16, DATA, 14, KWP_AES128_112 },
|
||||
{ "AESWrapPad", KEK, 24, DATA, 7, KWP_AES192_56 },
|
||||
{ "AESWrapPad", KEK, 24, DATA, 14, KWP_AES192_112 },
|
||||
{ "AESWrapPad", KEK, 24, DATA, 21, KWP_AES192_168 },
|
||||
{ "AESWrapPad", KEK, 32, DATA, 7, KWP_AES256_56 },
|
||||
{ "AESWrapPad", KEK, 32, DATA, 14, KWP_AES256_112 },
|
||||
{ "AESWrapPad", KEK, 32, DATA, 21, KWP_AES256_168 },
|
||||
{ "AESWrapPad", KEK, 32, DATA, 28, KWP_AES256_224 },
|
||||
{ "AESWrapPad_128", KEK, 16, DATA, 7, KWP_AES128_56 },
|
||||
{ "AESWrapPad_192", KEK, 24, DATA, 7, KWP_AES192_56 },
|
||||
{ "AESWrapPad_256", KEK, 32, DATA, 7, KWP_AES256_56 },
|
||||
{ "AES/KWP/NoPadding", KEK, 16, DATA, 7, KWP_AES128_56 },
|
||||
{ "AES/KWP/NoPadding", KEK, 16, DATA, 14, KWP_AES128_112 },
|
||||
{ "AES/KWP/NoPadding", KEK, 24, DATA, 7, KWP_AES192_56 },
|
||||
{ "AES/KWP/NoPadding", KEK, 24, DATA, 14, KWP_AES192_112 },
|
||||
{ "AES/KWP/NoPadding", KEK, 24, DATA, 21, KWP_AES192_168 },
|
||||
{ "AES/KWP/NoPadding", KEK, 32, DATA, 7, KWP_AES256_56 },
|
||||
{ "AES/KWP/NoPadding", KEK, 32, DATA, 14, KWP_AES256_112 },
|
||||
{ "AES/KWP/NoPadding", KEK, 32, DATA, 21, KWP_AES256_168 },
|
||||
{ "AES/KWP/NoPadding", KEK, 32, DATA, 28, KWP_AES256_224 },
|
||||
{ "AES/KWP/NoPadding", KEK2, 24, "466F7250617369", 7,
|
||||
"AFBEB0F07DFBF5419200F2CCB50BB24F" },
|
||||
{ "AES/KWP/NoPadding", KEK2, 24,
|
||||
"C37B7E6492584340BED12207808941155068F738", 20,
|
||||
"138BDEAA9B8FA7FC61F97742E72248EE5AE6AE5360D1AE6A5F54F373FA543B6A" },
|
||||
// some more test vectors for KW and KWP
|
||||
// from csrc.nist.gov/groups/STM/cavp/documents/mac/kwtestvectors.zip
|
||||
{ "AES/KW/NoPadding", "7575da3a93607cc2bfd8cec7aadfd9a6", 16,
|
||||
"42136d3c384a3eeac95a066fd28fed3f", 16,
|
||||
"031f6bd7e61e643df68594816f64caa3f56fabea2548f5fb" },
|
||||
{ "AES/KW/NoPadding", "e5d058e7f1c22c016c4e1cc9b26b9f8f", 16,
|
||||
"7f604e9b8d39d3c91e193fe6f196c1e3da6211a7c9a33b8873b64b138d1803" +
|
||||
"e4", 32,
|
||||
"60b9f8ac797c56e01e9b5f84d65816a980777869f67991a0e6dc19b8cd75c9" +
|
||||
"b54db4a38456bbd6f3" },
|
||||
{ "AES/KW/NoPadding", "67ae4270bcdd31e8326b7e7f94c80276", 16,
|
||||
"57e748b62fbc37ba25e904ee973d01b136cf7c1d0c8c5c87", 24,
|
||||
"96cec0e3272a21faa550a857957aa38ce3c1cf06f0dd9f5b5c5c422cef6c69" +
|
||||
"a1" },
|
||||
{ "AES/KW/NoPadding", "d7aa53aefad65cd95b57c8eee7b0a906", 16,
|
||||
"4a8daee6774751fc4489e837b8f7fba6896c70bb3d5e53053c92eb58046ee4" +
|
||||
"a7002e542311253b97", 40,
|
||||
"84ebd38cf06c674dcf186977de4a40c6dde3e7f49361a43420a887d2931b29" +
|
||||
"c23e2db72e95e4107001da925181bb7097" },
|
||||
{ "AES/KW/NoPadding", "98311985c4661d7e811ee56070e6fecf", 16,
|
||||
"18840c96813864ef3093b48cdde6ac5d78248b96d4a2cd1f15f0b56f98213d" +
|
||||
"bf87e1ccad04e0d4f1954c233ea3e48fdad8f2b1156e54e19e3b5f4a66d2e9" +
|
||||
"149032b876c51249165fe8c28e112a685b2d228a8ac308017574274af36a4e" +
|
||||
"a3877bcc9850bafe8fc0e0a712faca0dea98396f9143bc5819fe4933a806e9" +
|
||||
"b965133e3c695a45f0fbd6961798c400d7477287df64798b651e0d3009c13f" +
|
||||
"7a2246c28f983509b9e5339919f2cdffcdfc550693cba9491c00334c4a62d8" +
|
||||
"78c4d0ca57b1104bc0174968ea8e3730b9e68db49678b23cd508ebe3e12e94" +
|
||||
"b0ad3791023a8ef95473f0b32f906738f34e94e45a4480ad768072e1853adb" +
|
||||
"63996b9ac27a1dade70804b82290a2274c6dcc3ccd40a8b38a56a5eb03f590" +
|
||||
"75de015e8f9096f53549f6374e02da947fb849287a447f757cc340b6bded71" +
|
||||
"d480988b6d2fcd984fba841470519830304667fef0a577b4cf84f76aef9deb" +
|
||||
"84dde36abfbd76673c17113dbea7a3e24bf9b57a8fd17173a1ef91497b732b" +
|
||||
"3fa8889bed58a503a0d3e20bc27ec4dbf5d13a93cbad05495e3df15e1fe34a" +
|
||||
"3a6d6f648ea4aa60b2f114f30944ae593675dac2db188f90a3c483fb82cec0" +
|
||||
"f0d295544d798b62cdcb51c6c036af1a341d78babf87b92609c1d866e311a4" +
|
||||
"6abccc8ba8c6a41420359bb061d7e752c0ed25990eef57c9f9e190572203f8" +
|
||||
"c473edf8cfc8c26d34e37240f45ded97", 512,
|
||||
"625aea9122b7b57b9f36446f9053acc42c6435a7f69d91b41547026f833291" +
|
||||
"d488e477c7ccba698c143633a304f463d6af4a3e72c189234fcfc360013e65" +
|
||||
"b07b7f7a36c529d3fdbbdbd6224bf100c14bc5354893b44790f54c739a2b1f" +
|
||||
"5bda82d70fb600ed9b0606dbddea52e508b492b72d8779856274aaaaddc0a3" +
|
||||
"edb6cfc788b603101bedfcc3f44baa62336bd950c2e349d5daf04f2e23ec26" +
|
||||
"28893d214e277569c565e5e6aa8b72ffa14118a3b57f814b4deb179980b5ee" +
|
||||
"efa4fd93f1751850466e929be537801babc2120f3ff1ffe5fea813ec7788ea" +
|
||||
"f43f5ef657e5af48395c3ad11aaf741549090b58670695f7c95c68e00576ca" +
|
||||
"18ef0313f2b4b757219fc8db3dc2db28721d6f912547ebfebcd96935c3100a" +
|
||||
"a4e4df9955acae1b4e2c10df1166d46c4285ab631c6d2ce58ad3ae99c07c01" +
|
||||
"9dcd15958694055281ccd6f803af290431f188cc4c429e84a4c30fd9c63968" +
|
||||
"dfd0951c417efb71921c207de172a9546bdd3e2bb35b45e140892c649f88c3" +
|
||||
"1a438f864e801a69f8010aa3d77a26601a7a89067c81b0f7e70d8e82f21f88" +
|
||||
"c7d0bb0c8ca0db875d6c3f8c6f6d709bbb31c7da2e31f3571daa2c5ab13bfc" +
|
||||
"16624cf35abd526e84269fb45bbd2fcd8c383d6fbb700bc4b5205b3ef8c432" +
|
||||
"3dc0d9e0370e56a3d1e5e76aa4de082e4c2a0afd092845bd5dab52a4594318" +
|
||||
"1461b76e3984b95f48bea80a94944241d04b5634c86274e7" },
|
||||
{ "AES/KWP/NoPadding", "6decf10a1caf8e3b80c7a4be8c9c84e8", 16,
|
||||
"49", 1, "01a7d657fc4a5b216f261cca4d052c2b" },
|
||||
{ "AES/KWP/NoPadding", "a8e06da625a65b25cf5030826830b661", 16,
|
||||
"43acff293120dd5d", 8, "b6f967616dd8d772e9fea295a456dba7" },
|
||||
{ "AES/KWP/NoPadding", "7865e20f3c21659ab4690b629cdf3cc4", 16,
|
||||
"bd6843d420378dc896", 9,
|
||||
"41eca956d4aa047eb5cf4efe659661e74db6f8c564e23500" },
|
||||
{ "AES/KWP/NoPadding", "be96dc195ec034d616486ed70e97fe83", 16,
|
||||
"85b5437b6335ebba7635903a4493d12a77d9357a9e0dbc013456d85f1d3201",
|
||||
31,
|
||||
"974769b3a7b4d5d32985f87fddf9990631e5610fbfb278387b58b1f48e05c7" +
|
||||
"7d2fb7575c5169eb0e" },
|
||||
{ "AES/KWP/NoPadding", "0e54956a24c7d4a343f90269fb18a17f", 16,
|
||||
"817ddabdc5d215eee233adff97e92193c6beec52a71340477f70243a794ce9" +
|
||||
"54af51e356c9940e4ab198f0e68c543355f65ad179cb2d60dd369eaeb9ed14" +
|
||||
"1fb18c9e4054ac7fdc83506896990a4d20833d2d6e9a34938796ee67c9d7d2" +
|
||||
"3058544a4a35f2954103ce443a95a7e785602075ca0a73da37899e4568106b" +
|
||||
"b2dbf1f901377d4d3380c70fa5175ebc550481ac6f15986a4407fde5c23ff3" +
|
||||
"17e37544c0a25f87117506597db5bb79850c86247b73a5d0090417d63e4c25" +
|
||||
"7ea0220c2c04db07a34f0ab7954e1dfa2007a1466795c4d0c2aa09ca3986c0" +
|
||||
"28185b43a466526594afc9c891c263a7c608304bc1957c9873f544dc71e6f8" +
|
||||
"47c48d32026ed03b2333825452ee7e12a50e1cd7d678319264c65f78001996" +
|
||||
"d37fae7f9861fbd21cb506c2f8a3b0ee53c7debe17111b6e3f78a5c5677857" +
|
||||
"b082c2c4943dfd1edf6337fea98a44fc25928361156ef38d865948b979cf6f" +
|
||||
"4b46bd2119f12f0891cef7fc9d0638fd105fc05f9968d16948d1cb820751e8" +
|
||||
"2e44cb68e99d4f072ffd1577da6c0631b5827bec7e1b9ec72d18b74cf5f233" +
|
||||
"e85013c1668ceb5d7a1f5e0f016b0ff726a0a9d41e2cea8e14a2f56492b146" +
|
||||
"06d3fafd8ac141335f39f90d56863735628e8f17be90e100ef0785f3cd57db" +
|
||||
"8b9d89a6b2189dc2ea00c285d2657983f8bd7883c215477e67a55556401f1d" +
|
||||
"8b27d4e0d541c7fb7ace370c2e428884", 512,
|
||||
"876f3e53ba9cf4f6a521ac198bc813d0ede0f862ab6082e3e0a06ad82b4f27" +
|
||||
"9582f7c43bb63574608446bc2a05f401a68f74086cf2776b4b3df6b3679c2e" +
|
||||
"dfb91c024db54c6831e0752ae6f86c7596462de905ee0be908c1b9d043ecaf" +
|
||||
"e2ad1cbddb904e18ebc9b7a107031be3a87059516a3d1257812d9c801b0b9f" +
|
||||
"21539e70c47150c128d87c5e58fa6e4371aedde69c7b5cd16b73ac42267632" +
|
||||
"8131f3ac48c602bb6e0741805aad9d23b33b3523b86cf0588cdf9dc6c4d5f9" +
|
||||
"fa43d88ca17976eaf48fb37a41a598266da04144373df5631cc5126341c200" +
|
||||
"a0c8499b29ae96e6e6e6c2bdf8d8903da62bf8ddae970569b695240e77f8ac" +
|
||||
"5b191da5034008b6ef21936858e69bac372bbafd8794f6b03711503c187552" +
|
||||
"8a9348681844edb199a0664d740f0f0b1f866c4248c80fe8b5700a3c4134cd" +
|
||||
"ddb17676e0cd37d6d81831a0f4adfba071bb0935502480eccd48b28be5954e" +
|
||||
"a6c7d873b51b8bd2b709c5b6132ed31296510915073c18f7012f0eff6a9aad" +
|
||||
"5340a19fd5e372d35260b718d9e4807b1954c24e6a4fd48e4dbb8f395474e9" +
|
||||
"9ab577367d2ab5ccaa18c947331047dc3986e213a878b41089aa221019dad4" +
|
||||
"191a4feefd095f8606c2700a46d71cbb13efb6957df925ec26071c04d04d5a" +
|
||||
"94e138e5fc5d1f059236aad76208077dcc607b1dd2086f9c04e33f955822b4" +
|
||||
"57eecd68bd5f24836ecedbac675e6ed93d8a787cb57ad68e" },
|
||||
};
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "testData")
|
||||
public void testKeyWrap(String algo, String key, int keyLen,
|
||||
String data, int dataLen, String expected, Provider p)
|
||||
throws Exception {
|
||||
System.out.println("Testing " + algo + " Cipher with wrapping " +
|
||||
dataLen + "-byte key with " + 8*keyLen + "-bit KEK");
|
||||
int allowed = Cipher.getMaxAllowedKeyLength("AES");
|
||||
if (keyLen > allowed) {
|
||||
System.out.println("=> skip, exceeds max allowed size " + allowed);
|
||||
return;
|
||||
}
|
||||
Cipher c1 = Cipher.getInstance(algo, "SunJCE");
|
||||
Cipher c2 = Cipher.getInstance(algo, "SunJCE");
|
||||
Cipher c3 = Cipher.getInstance(algo, "SunJCE");
|
||||
|
||||
byte[] keyVal = toBytes(key, keyLen << 1);
|
||||
byte[] dataVal = toBytes(data, dataLen << 1);
|
||||
|
||||
SecretKey cipherKey = new SecretKeySpec(keyVal, "AES");
|
||||
SecretKey toBeWrappedKey = new SecretKeySpec(dataVal, "AES");
|
||||
|
||||
c1.init(Cipher.WRAP_MODE, cipherKey);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(c1.getIV());
|
||||
c2.init(Cipher.WRAP_MODE, cipherKey, ivSpec);
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
|
||||
params.init(ivSpec);
|
||||
c3.init(Cipher.WRAP_MODE, cipherKey, params);
|
||||
|
||||
// first test WRAP with known values
|
||||
byte[] wrapped = c1.wrap(toBeWrappedKey);
|
||||
byte[] wrapped2 = c2.wrap(toBeWrappedKey);
|
||||
byte[] wrapped3 = c3.wrap(toBeWrappedKey);
|
||||
|
||||
byte[] expectedVal = toBytes(expected, expected.length());
|
||||
|
||||
if (!Arrays.equals(wrapped, expectedVal) ||
|
||||
!Arrays.equals(wrapped2, expectedVal) ||
|
||||
!Arrays.equals(wrapped3, expectedVal)) {
|
||||
throw new Exception("Wrap test failed; got different result");
|
||||
}
|
||||
|
||||
// then test UNWRAP and compare with the initial values
|
||||
c1.init(Cipher.UNWRAP_MODE, cipherKey);
|
||||
ivSpec = new IvParameterSpec(c1.getIV());
|
||||
c2.init(Cipher.UNWRAP_MODE, cipherKey, ivSpec);
|
||||
params = AlgorithmParameters.getInstance("AES");
|
||||
params.init(ivSpec);
|
||||
c3.init(Cipher.UNWRAP_MODE, cipherKey, params);
|
||||
|
||||
Key unwrapped = c1.unwrap(wrapped, "AES", Cipher.SECRET_KEY);
|
||||
Key unwrapped2 = c2.unwrap(wrapped, "AES", Cipher.SECRET_KEY);
|
||||
Key unwrapped3 = c3.unwrap(wrapped, "AES", Cipher.SECRET_KEY);
|
||||
|
||||
if (!Arrays.equals(unwrapped.getEncoded(), dataVal) ||
|
||||
!Arrays.equals(unwrapped2.getEncoded(), dataVal) ||
|
||||
!Arrays.equals(unwrapped3.getEncoded(), dataVal)) {
|
||||
throw new Exception("Unwrap failed; got different result");
|
||||
}
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "testData")
|
||||
public void testEnc(String algo, String key, int keyLen, String data,
|
||||
int dataLen, String expected, Provider p)
|
||||
throws Exception {
|
||||
System.out.println("Testing " + algo + " Cipher with enc " +
|
||||
dataLen + "-byte data with " + 8*keyLen + "-bit KEK");
|
||||
int allowed = Cipher.getMaxAllowedKeyLength("AES");
|
||||
if (keyLen > allowed) {
|
||||
System.out.println("=> skip, exceeds max allowed size " + allowed);
|
||||
return;
|
||||
}
|
||||
Cipher c1 = Cipher.getInstance(algo, "SunJCE");
|
||||
Cipher c2 = Cipher.getInstance(algo, "SunJCE");
|
||||
Cipher c3 = Cipher.getInstance(algo, "SunJCE");
|
||||
|
||||
byte[] keyVal = toBytes(key, keyLen << 1);
|
||||
byte[] dataVal = toBytes(data, dataLen << 1);
|
||||
|
||||
SecretKey cipherKey = new SecretKeySpec(keyVal, "AES");
|
||||
c1.init(Cipher.ENCRYPT_MODE, cipherKey);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(c1.getIV());
|
||||
c2.init(Cipher.ENCRYPT_MODE, cipherKey, ivSpec);
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
|
||||
params.init(ivSpec);
|
||||
c3.init(Cipher.ENCRYPT_MODE, cipherKey, params);
|
||||
|
||||
// first test encryption with known values
|
||||
byte[] ct11 = c1.update(dataVal);
|
||||
byte[] ct12 = c1.doFinal();
|
||||
byte[] ct2 = c1.doFinal(dataVal);
|
||||
byte[] ct22 = c2.doFinal(dataVal);
|
||||
byte[] ct32 = c3.doFinal(dataVal);
|
||||
|
||||
byte[] expectedVal = toBytes(expected, expected.length());
|
||||
|
||||
if (ct11 != null || !Arrays.equals(ct12, ct2) ||
|
||||
!Arrays.equals(ct2, expectedVal) ||
|
||||
!Arrays.equals(ct22, expectedVal) ||
|
||||
!Arrays.equals(ct32, expectedVal)) {
|
||||
throw new Exception("Encryption failed; got different result");
|
||||
}
|
||||
|
||||
// then test decryption and compare with the initial values
|
||||
c1.init(Cipher.DECRYPT_MODE, cipherKey);
|
||||
ivSpec = new IvParameterSpec(c1.getIV());
|
||||
c2.init(Cipher.DECRYPT_MODE, cipherKey, ivSpec);
|
||||
params = AlgorithmParameters.getInstance("AES");
|
||||
params.init(ivSpec);
|
||||
c3.init(Cipher.DECRYPT_MODE, cipherKey, params);
|
||||
|
||||
byte[] pt11 = c1.update(ct12);
|
||||
byte[] pt12 = c1.doFinal();
|
||||
byte[] pt2 = c1.doFinal(ct2);
|
||||
byte[] pt22 = c2.doFinal(ct2);
|
||||
byte[] pt32 = c3.doFinal(ct2);
|
||||
|
||||
if (pt11 != null || !Arrays.equals(pt12, pt2) ||
|
||||
!Arrays.equals(pt2, dataVal) || !Arrays.equals(pt22, dataVal) ||
|
||||
!Arrays.equals(pt32, dataVal)) {
|
||||
throw new Exception("Decryption failed; got different result");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
main(new NISTWrapKAT(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void main(Provider p) throws Exception {
|
||||
Object[][] testDatum = testData();
|
||||
for (int i = 0; i < testDatum.length; i++) {
|
||||
Object[] td = testDatum[i];
|
||||
String algo = (String) td[0];
|
||||
if (p.getService("Cipher", algo) == null) {
|
||||
System.out.println("Skip, due to no support: " + algo);
|
||||
continue;
|
||||
}
|
||||
testKeyWrap(algo, (String)td[1], (int)td[2], (String)td[3],
|
||||
(int)td[4], (String)td[5], p);
|
||||
testEnc(algo, (String)td[1], (int)td[2], (String)td[3],
|
||||
(int)td[4], (String)td[5], p);
|
||||
}
|
||||
System.out.println("Test Passed");
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
import static java.lang.System.out;
|
||||
|
||||
import java.lang.Integer;
|
||||
import java.lang.String;
|
||||
import java.lang.System;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.PBEParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8264849
|
||||
* @summary Tests for key wrap and unwrap operations
|
||||
* @library /test/lib ../..
|
||||
* @run main/othervm TestCipherKeyWrapperTest
|
||||
*/
|
||||
// adapted from
|
||||
// com/sun/crypto/provider/Cipher/KeyWrap/TestCipherKeyWrapperTest.java
|
||||
public class TestCipherKeyWrapperTest extends PKCS11Test {
|
||||
private static final int LINIMITED_KEYSIZE = 128;
|
||||
|
||||
private static final byte[] DATA_32 =
|
||||
Arrays.copyOf("1234567890123456789012345678901234".getBytes(), 32);
|
||||
|
||||
private enum TestVector {
|
||||
AESWrap("AES", "AESWrap", -1),
|
||||
AESWrap_128("AES", "AESWrap_128", 128),
|
||||
AESWrap_192("AES", "AESWrap_192", 192),
|
||||
AESWrap_256("AES", "AESWrap_256", 256),
|
||||
AESWrapPad("AES", "AESWrapPad", -1),
|
||||
AESWrapPad_128("AES", "AESWrapPad_128", 128),
|
||||
AESWrapPad_192("AES", "AESWrapPad_192", 192),
|
||||
AESWrapPad_256("AES", "AESWrapPad_256", 256);
|
||||
|
||||
final String algo;
|
||||
final String wrapperAlgo;
|
||||
final int keySize; // -1 means no restriction
|
||||
final SecretKey wrapperKey;
|
||||
|
||||
private TestVector(String algo, String wrapperAlgo, int kSize) {
|
||||
this.algo = algo;
|
||||
this.wrapperAlgo = wrapperAlgo;
|
||||
this.keySize = kSize;
|
||||
if (kSize == -1) {
|
||||
this.wrapperKey = new SecretKeySpec(DATA_32, "AES");
|
||||
} else {
|
||||
this.wrapperKey = new SecretKeySpec(DATA_32, 0, kSize >> 3,
|
||||
"AES");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
main(new TestCipherKeyWrapperTest(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void main(Provider p) throws Exception {
|
||||
for (TestVector tv : TestVector.values()) {
|
||||
if (p.getService("Cipher", tv.wrapperAlgo) == null) {
|
||||
System.out.println("Skip, due to no support: " +
|
||||
tv.wrapperAlgo);
|
||||
continue;
|
||||
}
|
||||
|
||||
// only run the tests on longer key lengths if unlimited
|
||||
// version of JCE jurisdiction policy files are installed
|
||||
if (!(Cipher.getMaxAllowedKeyLength(tv.algo) == Integer.MAX_VALUE)
|
||||
&& tv.keySize > LINIMITED_KEYSIZE) {
|
||||
out.println(tv.algo + " will not run if unlimited version of"
|
||||
+ " JCE jurisdiction policy files are installed");
|
||||
continue;
|
||||
}
|
||||
wrapperSecretKeyTest(p, tv.wrapperAlgo, tv.wrapperKey, tv.algo);
|
||||
wrapperPrivateKeyTest(p, tv.wrapperAlgo, tv.wrapperKey, "RSA");
|
||||
}
|
||||
}
|
||||
|
||||
private void wrapperSecretKeyTest(Provider p, String wrapAlgo,
|
||||
SecretKey key, String algo)
|
||||
throws Exception {
|
||||
// Initialization
|
||||
KeyGenerator kg = KeyGenerator.getInstance(algo, p);
|
||||
SecretKey skey = kg.generateKey();
|
||||
wrapTest(p, wrapAlgo, key, skey, Cipher.SECRET_KEY);
|
||||
}
|
||||
|
||||
private void wrapperPrivateKeyTest(Provider p, String wrapAlgo,
|
||||
SecretKey key, String algo)
|
||||
throws Exception {
|
||||
// Key pair generated
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(algo, p);
|
||||
kpg.initialize(2048);
|
||||
System.out.println("Generate key pair (algorithm: " + algo
|
||||
+ ", provider: " + kpg.getProvider().getName() + ")");
|
||||
|
||||
KeyPair kp = kpg.genKeyPair();
|
||||
// key generated
|
||||
wrapTest(p, wrapAlgo, key, kp.getPrivate(), Cipher.PRIVATE_KEY);
|
||||
}
|
||||
|
||||
private void wrapTest(Provider p, String wrapAlgo, SecretKey initKey,
|
||||
Key tbwKey, int keyType)
|
||||
throws Exception {
|
||||
AlgorithmParameters aps = null;
|
||||
|
||||
out.println("Testing " + wrapAlgo + " cipher wrap/unwrap");
|
||||
|
||||
Cipher wrapCI = Cipher.getInstance(wrapAlgo, p);
|
||||
|
||||
byte[] keyEncoding = tbwKey.getEncoded();
|
||||
if (wrapAlgo.indexOf("Pad") == -1 &&
|
||||
(keyEncoding.length % wrapCI.getBlockSize() != 0)) {
|
||||
System.out.println("Skip due to key length: " +
|
||||
keyEncoding.length);
|
||||
return;
|
||||
}
|
||||
// Wrap & Unwrap operation
|
||||
System.out.println("calling wrap()");
|
||||
wrapCI.init(Cipher.WRAP_MODE, initKey);
|
||||
aps = wrapCI.getParameters();
|
||||
byte[] keyWrapped = wrapCI.wrap(tbwKey);
|
||||
|
||||
wrapCI.init(Cipher.UNWRAP_MODE, initKey, aps);
|
||||
Key unwrappedKey = wrapCI.unwrap(keyWrapped, tbwKey.getAlgorithm(),
|
||||
keyType);
|
||||
// Comparison
|
||||
if (!Arrays.equals(tbwKey.getEncoded(), unwrappedKey.getEncoded())) {
|
||||
out.println("key encoding len : " + tbwKey.getEncoded().length);
|
||||
throw new RuntimeException("Comparation failed testing "
|
||||
+ wrapAlgo + ":" + keyType);
|
||||
}
|
||||
}
|
||||
}
|
333
test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java
Normal file
333
test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java
Normal file
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 8264849
|
||||
* @summary Verify general properties of the AES/KW/NoPadding,
|
||||
* AES/KW/PKCS5Padding, and AES/KWP/NoPadding impls of SunPKCS11 provider.
|
||||
* @library /test/lib ../..
|
||||
* @run main/othervm TestGeneral
|
||||
*/
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HexFormat;
|
||||
import java.security.*;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
// adapted from com/sun/crypto/provider/Cipher/KeyWrap/TestGeneral.java
|
||||
public class TestGeneral extends PKCS11Test {
|
||||
|
||||
private static final byte[] DATA_32 =
|
||||
Arrays.copyOf("1234567890123456789012345678901234".getBytes(), 32);
|
||||
private static final SecretKey KEY =
|
||||
new SecretKeySpec(DATA_32, 0, 16, "AES");
|
||||
private static final int KW_IV_LEN = 8;
|
||||
private static final int KWP_IV_LEN = 4;
|
||||
private static final int MAX_KW_PKCS5PAD_LEN = 8; // 1-8
|
||||
private static final int MAX_KWP_PAD_LEN = 7; // 0-7
|
||||
|
||||
public static void testEnc(Cipher c, byte[] in, int startLen, int inc,
|
||||
IvParameterSpec[] ivs, int maxPadLen) throws Exception {
|
||||
|
||||
System.out.println("testEnc, input len=" + startLen + " w/ inc=" +
|
||||
inc);
|
||||
for (IvParameterSpec iv : ivs) {
|
||||
System.out.print("\t=> w/ iv=" + iv);
|
||||
|
||||
for (int inLen = startLen; inLen < in.length; inLen+=inc) {
|
||||
c.init(Cipher.ENCRYPT_MODE, KEY, iv);
|
||||
|
||||
int estOutLen = c.getOutputSize(inLen);
|
||||
System.out.println(", inLen=" + inLen);
|
||||
byte[] out = c.doFinal(in, 0, inLen);
|
||||
|
||||
// check the length of encryption output
|
||||
if (estOutLen != out.length || (out.length % 8 != 0) ||
|
||||
(out.length - inLen < 8)) {
|
||||
System.out.println("=> estimated: " + estOutLen);
|
||||
System.out.println("=> actual: " + out.length);
|
||||
throw new RuntimeException("Failed enc output len check");
|
||||
}
|
||||
|
||||
c.init(Cipher.DECRYPT_MODE, KEY, iv);
|
||||
estOutLen = c.getOutputSize(out.length);
|
||||
byte[] recovered = new byte[estOutLen];
|
||||
|
||||
// do decryption using ByteBuffer and multi-part
|
||||
ByteBuffer outBB = ByteBuffer.wrap(out);
|
||||
ByteBuffer recoveredBB = ByteBuffer.wrap(recovered);
|
||||
int len = c.update(outBB, recoveredBB);
|
||||
len += c.doFinal(outBB, recoveredBB);
|
||||
|
||||
// check the length of decryption output
|
||||
if (estOutLen < len || (estOutLen - len) > maxPadLen) {
|
||||
System.out.println("=> estimated: " + estOutLen);
|
||||
System.out.println("=> actual: " + len);
|
||||
throw new RuntimeException("Failed dec output len check");
|
||||
}
|
||||
|
||||
if (!Arrays.equals(in, 0, inLen, recovered, 0, len)) {
|
||||
throw new RuntimeException("Failed decrypted data check");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void testKAT(Cipher c, String keyStr, String inStr,
|
||||
String expectedStr) throws Exception {
|
||||
|
||||
System.out.println("testKAT, input len: " + inStr.length()/2);
|
||||
|
||||
byte[] keyVal = HexFormat.of().parseHex(keyStr);
|
||||
byte[] in = HexFormat.of().parseHex(inStr);
|
||||
byte[] expected = HexFormat.of().parseHex(expectedStr);
|
||||
|
||||
c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyVal, "AES"));
|
||||
|
||||
byte[] out = c.doFinal(in);
|
||||
|
||||
if (!Arrays.equals(out, expected)) {
|
||||
System.out.println("=> expected: " +
|
||||
HexFormat.of().withUpperCase().formatHex(expected));
|
||||
System.out.println("=> actual: " +
|
||||
HexFormat.of().withUpperCase().formatHex(out));
|
||||
throw new RuntimeException("Failed KAT check");
|
||||
}
|
||||
}
|
||||
|
||||
public static void testWrap(Cipher c, Key[] inKeys, IvParameterSpec[] ivs,
|
||||
int maxPadLen) throws Exception {
|
||||
|
||||
for (Key inKey : inKeys) {
|
||||
System.out.println("testWrap, key: " + inKey);
|
||||
for (IvParameterSpec iv : ivs) {
|
||||
System.out.println("\t=> w/ iv " + iv);
|
||||
|
||||
c.init(Cipher.WRAP_MODE, KEY, iv);
|
||||
|
||||
byte[] out = c.wrap(inKey);
|
||||
|
||||
// output should always be multiple of cipher block size
|
||||
if (out.length % c.getBlockSize() != 0) {
|
||||
throw new RuntimeException("Invalid wrap len: " +
|
||||
out.length);
|
||||
}
|
||||
|
||||
c.init(Cipher.UNWRAP_MODE, KEY, iv);
|
||||
|
||||
// SecretKey or PrivateKey
|
||||
int keyType = (inKey instanceof SecretKey? Cipher.SECRET_KEY :
|
||||
Cipher.PRIVATE_KEY);
|
||||
|
||||
int estOutLen = c.getOutputSize(out.length);
|
||||
Key key2 = c.unwrap(out, inKey.getAlgorithm(), keyType);
|
||||
|
||||
if ((keyType == Cipher.SECRET_KEY &&
|
||||
!(key2 instanceof SecretKey)) ||
|
||||
(keyType == Cipher.PRIVATE_KEY &&
|
||||
!(key2 instanceof PrivateKey))) {
|
||||
throw new RuntimeException("Failed unwrap type check");
|
||||
}
|
||||
|
||||
byte[] in2 = key2.getEncoded();
|
||||
// check decryption output length
|
||||
if (estOutLen < in2.length ||
|
||||
(estOutLen - in2.length) > maxPadLen) {
|
||||
System.out.println("=> estimated: " + estOutLen);
|
||||
System.out.println("=> actual: " + in2.length);
|
||||
throw new RuntimeException("Failed unwrap len check");
|
||||
}
|
||||
|
||||
if (!Arrays.equals(inKey.getEncoded(), in2) ||
|
||||
!(inKey.getAlgorithm().equalsIgnoreCase
|
||||
(key2.getAlgorithm()))) {
|
||||
throw new RuntimeException("Failed unwrap key check");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void testIv(Cipher c, int defIvLen, boolean allowCustomIv)
|
||||
throws Exception {
|
||||
|
||||
System.out.println("testIv: defIvLen = " + defIvLen +
|
||||
" allowCustomIv = " + allowCustomIv);
|
||||
|
||||
// get a fresh Cipher instance so we can test iv with pre-init state
|
||||
c = Cipher.getInstance(c.getAlgorithm(), c.getProvider());
|
||||
if (c.getIV() != null) {
|
||||
throw new RuntimeException("Expects null iv");
|
||||
}
|
||||
|
||||
AlgorithmParameters ivParams = c.getParameters();
|
||||
if (ivParams == null) {
|
||||
throw new RuntimeException("Expects non-null default parameters");
|
||||
}
|
||||
IvParameterSpec ivSpec =
|
||||
ivParams.getParameterSpec(IvParameterSpec.class);
|
||||
byte[] iv = ivSpec.getIV();
|
||||
// try through all opmodes
|
||||
c.init(Cipher.ENCRYPT_MODE, KEY);
|
||||
c.init(Cipher.DECRYPT_MODE, KEY);
|
||||
c.init(Cipher.WRAP_MODE, KEY);
|
||||
c.init(Cipher.UNWRAP_MODE, KEY);
|
||||
|
||||
byte[] defIv = c.getIV();
|
||||
|
||||
// try again through all opmodes
|
||||
c.init(Cipher.ENCRYPT_MODE, KEY);
|
||||
c.init(Cipher.DECRYPT_MODE, KEY);
|
||||
c.init(Cipher.WRAP_MODE, KEY);
|
||||
c.init(Cipher.UNWRAP_MODE, KEY);
|
||||
|
||||
byte[] defIv2 = c.getIV();
|
||||
if (iv.length != defIvLen || !Arrays.equals(iv, defIv) ||
|
||||
!Arrays.equals(defIv, defIv2)) {
|
||||
throw new RuntimeException("Failed default iv check");
|
||||
}
|
||||
if (defIv == defIv2) {
|
||||
throw new RuntimeException("Failed getIV copy check");
|
||||
}
|
||||
|
||||
// try init w/ an iv w/ invalid length
|
||||
try {
|
||||
c.init(Cipher.ENCRYPT_MODE, KEY, new IvParameterSpec(defIv, 0,
|
||||
defIv.length/2));
|
||||
throw new RuntimeException("Invalid iv accepted");
|
||||
} catch (InvalidAlgorithmParameterException iape) {
|
||||
System.out.println("Invalid IV rejected as expected");
|
||||
}
|
||||
|
||||
if (allowCustomIv) {
|
||||
Arrays.fill(defIv, (byte) 0xFF);
|
||||
// try through all opmodes
|
||||
c.init(Cipher.ENCRYPT_MODE, KEY, new IvParameterSpec(defIv));
|
||||
c.init(Cipher.DECRYPT_MODE, KEY, new IvParameterSpec(defIv));
|
||||
c.init(Cipher.WRAP_MODE, KEY, new IvParameterSpec(defIv));
|
||||
c.init(Cipher.UNWRAP_MODE, KEY, new IvParameterSpec(defIv));
|
||||
|
||||
if (!Arrays.equals(defIv, c.getIV())) {
|
||||
throw new RuntimeException("Failed set iv check");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
main(new TestGeneral(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void main(Provider p) throws Exception {
|
||||
byte[] data = DATA_32;
|
||||
|
||||
SecretKey aes256 = new SecretKeySpec(DATA_32, "AES");
|
||||
SecretKey any256 = new SecretKeySpec(DATA_32, "ANY");
|
||||
PrivateKey priv = KeyPairGenerator.getInstance
|
||||
("RSA", "SunRsaSign").generateKeyPair().getPrivate();
|
||||
|
||||
String[] algos = {
|
||||
"AES/KW/PKCS5Padding", "AES/KW/NoPadding", "AES/KWP/NoPadding"
|
||||
};
|
||||
for (String a : algos) {
|
||||
if (p.getService("Cipher", a) == null) {
|
||||
System.out.println("Skip, due to no support: " + a);
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println("Testing " + a);
|
||||
Cipher c = Cipher.getInstance(a, p);
|
||||
|
||||
int blkSize = c.getBlockSize();
|
||||
|
||||
// set the default based on AES/KWP/NoPadding, the other two
|
||||
// override as needed
|
||||
int startLen = data.length - blkSize;
|
||||
int inc = 1;
|
||||
IvParameterSpec[] ivs = new IvParameterSpec[] { null };
|
||||
int padLen = MAX_KWP_PAD_LEN;
|
||||
Key[] keys = new Key[] { aes256, any256, priv };
|
||||
int ivLen = KWP_IV_LEN;
|
||||
boolean allowCustomIv = false;
|
||||
|
||||
switch (a) {
|
||||
case "AES/KW/PKCS5Padding":
|
||||
ivs = new IvParameterSpec[] {
|
||||
null, new IvParameterSpec(DATA_32, 0, KW_IV_LEN) };
|
||||
padLen = MAX_KW_PKCS5PAD_LEN;
|
||||
ivLen = KW_IV_LEN;
|
||||
allowCustomIv = true;
|
||||
break;
|
||||
case "AES/KW/NoPadding":
|
||||
testKAT(c, "000102030405060708090A0B0C0D0E0F",
|
||||
"00112233445566778899AABBCCDDEEFF",
|
||||
"1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5");
|
||||
testKAT(c, "000102030405060708090A0B0C0D0E0F1011121314151617",
|
||||
"00112233445566778899AABBCCDDEEFF",
|
||||
"96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D");
|
||||
testKAT(c, "000102030405060708090A0B0C0D0E0F1011121314151617" +
|
||||
"18191A1B1C1D1E1F",
|
||||
"00112233445566778899AABBCCDDEEFF",
|
||||
"64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7");
|
||||
testKAT(c, "000102030405060708090A0B0C0D0E0F1011121314151617",
|
||||
"00112233445566778899AABBCCDDEEFF0001020304050607",
|
||||
"031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA" +
|
||||
"814915C6762D2");
|
||||
testKAT(c, "000102030405060708090A0B0C0D0E0F1011121314151617" +
|
||||
"18191A1B1C1D1E1F",
|
||||
"00112233445566778899AABBCCDDEEFF0001020304050607",
|
||||
"A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD" +
|
||||
"5D17D6B254DA1");
|
||||
testKAT(c, "000102030405060708090A0B0C0D0E0F1011121314151617" +
|
||||
"18191A1B1C1D1E1F",
|
||||
"00112233445566778899AABBCCDDEEFF0001020304050607080" +
|
||||
"90A0B0C0D0E0F",
|
||||
"28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC" +
|
||||
"7F0E71A99F43BFB988B9B7A02DD21");
|
||||
startLen = data.length >> 1;
|
||||
inc = blkSize;
|
||||
ivs = new IvParameterSpec[] {
|
||||
null, new IvParameterSpec(DATA_32, 0, KW_IV_LEN) };
|
||||
padLen = 0;
|
||||
keys = new Key[] { aes256, any256 };
|
||||
ivLen = KW_IV_LEN;
|
||||
allowCustomIv = true;
|
||||
break;
|
||||
case "AES/KWP/NoPadding":
|
||||
testKAT(c, "5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8",
|
||||
"c37b7e6492584340bed12207808941155068f738",
|
||||
"138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a");
|
||||
testKAT(c, "5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8",
|
||||
"466f7250617369", "afbeb0f07dfbf5419200f2ccb50bb24f");
|
||||
|
||||
break;
|
||||
}
|
||||
// now test based on the configured arguments
|
||||
testEnc(c, data, startLen, inc, ivs, padLen);
|
||||
testWrap(c, keys, ivs, padLen);
|
||||
testIv(c, ivLen, allowCustomIv);
|
||||
}
|
||||
System.out.println("All Tests Passed");
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 8264849
|
||||
* @summary Verify cipher key size restriction is enforced properly with IKE
|
||||
* @library /test/lib ../..
|
||||
* @run main/othervm TestKeySizeCheck
|
||||
*/
|
||||
import java.util.Arrays;
|
||||
import java.security.*;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
// adapted from com/sun/crypto/provider/Cipher/KeyWrap/TestKeySizeCheck.java
|
||||
public class TestKeySizeCheck extends PKCS11Test {
|
||||
|
||||
private static final byte[] BYTES_32 =
|
||||
Arrays.copyOf("1234567890123456789012345678901234".getBytes(), 32);
|
||||
|
||||
private static SecretKey getKey(int sizeInBytes) {
|
||||
if (sizeInBytes <= BYTES_32.length) {
|
||||
return new SecretKeySpec(BYTES_32, 0, sizeInBytes, "AES");
|
||||
} else {
|
||||
return new SecretKeySpec(new byte[sizeInBytes], "AES");
|
||||
}
|
||||
}
|
||||
|
||||
private static String getModeStr(int mode) {
|
||||
return (mode == Cipher.ENCRYPT_MODE? "ENC" : "WRAP");
|
||||
}
|
||||
|
||||
public static void test(Provider p, String algo, int[] invalidKeySizes)
|
||||
throws Exception {
|
||||
|
||||
Cipher c = Cipher.getInstance(algo, p);
|
||||
System.out.println("Testing " + algo);
|
||||
|
||||
int[] modes = { Cipher.ENCRYPT_MODE, Cipher.WRAP_MODE };
|
||||
for (int ks : invalidKeySizes) {
|
||||
System.out.println("keysize: " + ks);
|
||||
SecretKey key = getKey(ks);
|
||||
|
||||
for (int m : modes) {
|
||||
try {
|
||||
c.init(m, key);
|
||||
throw new RuntimeException("Expected IKE not thrown for "
|
||||
+ getModeStr(m));
|
||||
} catch (InvalidKeyException ike) {
|
||||
System.out.println(" => expected IKE thrown for "
|
||||
+ getModeStr(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
main(new TestKeySizeCheck(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void main(Provider p) throws Exception {
|
||||
String[] algos = {
|
||||
"AESWrap", "AESWrapPad",
|
||||
"AES/KW/PKCS5Padding", "AES/KW/NoPadding", "AES/KWP/NoPadding"
|
||||
};
|
||||
int[] keySizes = { 128, 192, 256 };
|
||||
|
||||
for (String a : algos) {
|
||||
if (p.getService("Cipher", a) == null) {
|
||||
System.out.println("Skip, due to no support: " + a);
|
||||
continue;
|
||||
}
|
||||
test(p, a, new int[] { 120, 264 });
|
||||
String from = (a == "AESWrap" || a == "AESWrapPad"? a : "AES");
|
||||
test(p, a.replace(from, from + "_128"), new int[] {192, 256 });
|
||||
test(p, a.replace(from, from + "_192"), new int[] {128, 256 });
|
||||
test(p, a.replace(from, from + "_256"), new int[] {128, 192 });
|
||||
}
|
||||
System.out.println("All Tests Passed");
|
||||
}
|
||||
}
|
151
test/jdk/sun/security/pkcs11/Cipher/KeyWrap/XMLEncKAT.java
Normal file
151
test/jdk/sun/security/pkcs11/Cipher/KeyWrap/XMLEncKAT.java
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 8264849
|
||||
* @summary Verify that the key wrap cipher "AESWrap" work as expected.
|
||||
* @library /test/lib ../..
|
||||
* @run main/othervm XMLEncKAT
|
||||
*/
|
||||
import java.util.Base64;
|
||||
import java.security.Key;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.Provider;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.IOException;
|
||||
|
||||
// adapted from com/sun/crypto/provider/Cipher/KeyWrap/XMLEncKAT.java
|
||||
public class XMLEncKAT extends PKCS11Test {
|
||||
|
||||
private static byte[] aes128Key_1;
|
||||
private static byte[] aes192Key_1;
|
||||
private static byte[] aes256Key_1;
|
||||
private static byte[] aes128Key_2;
|
||||
private static byte[] aes192Key_2;
|
||||
private static byte[] aes256Key_2;
|
||||
|
||||
private static Base64.Decoder base64D = Base64.getDecoder();
|
||||
private static Base64.Encoder base64E = Base64.getEncoder();
|
||||
|
||||
static {
|
||||
try {
|
||||
aes128Key_1 = "abcdefghijklmnop".getBytes("ASCII");
|
||||
aes192Key_1 = "abcdefghijklmnopqrstuvwx".getBytes("ASCII");
|
||||
aes256Key_1 = "abcdefghijklmnopqrstuvwxyz012345".getBytes("ASCII");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// should never happen
|
||||
}
|
||||
|
||||
aes128Key_2 = base64D.decode("01+yuQ2huPS1+Qv0LH+zaQ==");
|
||||
aes192Key_2 = base64D.decode("IlfuS40LvStVU0Mj8ePrrGHVhAb48y++");
|
||||
aes256Key_2 = base64D.decode
|
||||
("ZhZ4v3RlwTlCEOpIrHfLKVyJOBDtEJOOQDat/4xR1bA=");
|
||||
}
|
||||
private static String[] aes128WrappedKey_1 = {
|
||||
"dV45TUpJbidb9iKa34xj1WVtTZ036cnqvym2TBJWR5c=",
|
||||
"rPnY/XoSGCbuwy7vpslf29rs9dbvSCmGFOjEs3LT6g/qyZjfDA+2fQ=="
|
||||
};
|
||||
private static String[] aes128WrappedKey_2 = {
|
||||
"GPl6bneL1jKl0/lGnf9gejlYHRI6XxFz"
|
||||
};
|
||||
private static String[] aes192WrappedKey_1 = {
|
||||
"IbjZH7Mq564oMybpvCHWYM/5ER3eFsAV",
|
||||
"19D633XVohP6UJvaVRAhJek+ahtM3gOiVs6nZyAasDEb+WCUQOcWZw=="
|
||||
};
|
||||
private static String[] aes192WrappedKey_2 = {
|
||||
"5+GpVUQNTAT3uY8pPedEg/PpftiX+fJsTCun+fgmIz0=",
|
||||
"iuZvvGBWScikHld9TtNIOz0Sm7Srg5AcxOBMA8qIvQY=",
|
||||
"PeDwjnCsg6xWzs3SmzUtc2nyUz28nGu7"
|
||||
};
|
||||
private static String[] aes256WrappedKey_1 = {
|
||||
"4AAgyi3M7xNdBimbQZKdGJLn3/cS4Yv8QKuA01+gUnY=",
|
||||
"tPCC89jQShB+WDINCdRfKgf8wTlAx8xRXD73RmEHPBfix8zS1N82KQ==",
|
||||
"bsL63D0hPN6EOyzdgfEmKsAAvoJiGM+Wp9a9KZM92IKdl7s3YSntRg=="
|
||||
};
|
||||
private static String[] aes256WrappedKey_2 = {
|
||||
"IbnoS1cvuIFIGB46jj1V1FGftc92irrCwcC7BoBvxwQ=",
|
||||
"ic+Om6/3ZKcThVN3iv9lUEankNkDv3Et",
|
||||
"jOvQe4SxDqEMvAHcmb3Z+/Uedj23pvL6BRQsl2sjJlQ=",
|
||||
"IMwdsyg89IZ4Txf1SYYZNKUOKuYdDoIi/zEKXCjj4j9PM6BdkZligA=="
|
||||
};
|
||||
|
||||
private void testKeyWrap(Provider p, String cAlg, byte[] cKeyVal,
|
||||
String cKeyAlg, String[] base64Wrapped) throws Exception {
|
||||
System.out.println("Testing " + cAlg + " Cipher with " +
|
||||
8*cKeyVal.length + "-bit key");
|
||||
Cipher c = Cipher.getInstance(cAlg, p);
|
||||
SecretKey cKey = new SecretKeySpec(cKeyVal, cKeyAlg);
|
||||
c.init(Cipher.UNWRAP_MODE, cKey);
|
||||
Key[] key = new SecretKey[base64Wrapped.length];
|
||||
IvParameterSpec[] params =
|
||||
new IvParameterSpec[base64Wrapped.length];
|
||||
// first test UNWRAP with known values
|
||||
for (int i = 0; i < base64Wrapped.length; i++) {
|
||||
byte[] wrappedKey = base64D.decode(base64Wrapped[i]);
|
||||
key[i] = c.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
|
||||
if (c.getIV() != null) {
|
||||
params[i] = new IvParameterSpec(c.getIV());
|
||||
}
|
||||
}
|
||||
// then test WRAP and compare with the known values
|
||||
for (int i = 0; i < key.length; i++) {
|
||||
c.init(Cipher.WRAP_MODE, cKey, params[i]);
|
||||
byte[] wrapped2 = c.wrap(key[i]);
|
||||
String out = base64E.encodeToString(wrapped2);
|
||||
if (!out.equalsIgnoreCase(base64Wrapped[i])) {
|
||||
throw new Exception("Wrap failed; got " + out + ", expect " +
|
||||
base64Wrapped[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
main(new XMLEncKAT(), argv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void main(Provider p) throws Exception {
|
||||
String wrapAlg = "AESWrap";
|
||||
|
||||
if (p.getService("Cipher", wrapAlg) == null) {
|
||||
System.out.println("Skip, due to no support: " + wrapAlg);
|
||||
return;
|
||||
}
|
||||
|
||||
String keyAlg = "AES";
|
||||
testKeyWrap(p, wrapAlg, aes128Key_1, keyAlg, aes128WrappedKey_1);
|
||||
testKeyWrap(p, wrapAlg, aes128Key_2, keyAlg, aes128WrappedKey_2);
|
||||
// only run the tests on longer key lengths if unlimited version
|
||||
// of JCE jurisdiction policy files are installed
|
||||
if (Cipher.getMaxAllowedKeyLength(keyAlg) == Integer.MAX_VALUE) {
|
||||
testKeyWrap(p, wrapAlg, aes192Key_1, keyAlg, aes192WrappedKey_1);
|
||||
testKeyWrap(p, wrapAlg, aes192Key_2, keyAlg, aes192WrappedKey_2);
|
||||
testKeyWrap(p, wrapAlg, aes256Key_1, keyAlg, aes256WrappedKey_1);
|
||||
testKeyWrap(p, wrapAlg, aes256Key_2, keyAlg, aes256WrappedKey_2);
|
||||
}
|
||||
System.out.println("All Tests Passed");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user