Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java
41154 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.pkcs11;2627import java.security.*;28import java.security.spec.AlgorithmParameterSpec;2930import javax.crypto.*;3132import static sun.security.pkcs11.TemplateManager.*;33import sun.security.pkcs11.wrapper.*;34import static sun.security.pkcs11.wrapper.PKCS11Constants.*;3536/**37* KeyGenerator implementation class. This class currently supports38* DES, DESede, AES, ARCFOUR, Blowfish, Hmac using MD5, SHA, SHA-2 family39* (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256), and SHA-340* family (SHA3-224, SHA3-256, SHA3-384, SHA3-512) of digests.41*42* @author Andreas Sterbenz43* @since 1.544*/45final class P11KeyGenerator extends KeyGeneratorSpi {4647// token instance48private final Token token;4950// algorithm name51private final String algorithm;5253// mechanism id54private long mechanism;5556// raw key size in bits, e.g. 64 for DES. Always valid.57private int keySize;5859// bits of entropy in the key, e.g. 56 for DES. Always valid.60private int significantKeySize;6162// keyType (CKK_*), needed for TemplateManager call only.63private long keyType;6465// for determining if both 112 and 168 bits of DESede key lengths66// are supported.67private boolean supportBothKeySizes;6869// for determining if the specified key size is valid70private final CK_MECHANISM_INFO range;7172// utility method for query the native key sizes and enforcing the73// java-specific lower limit; returned values are in bits74private static CK_MECHANISM_INFO getSupportedRange(Token token,75long mech) throws ProviderException {76// No need to query for fix-length algorithms77if (mech == CKM_DES_KEY_GEN || mech == CKM_DES2_KEY_GEN ||78mech == CKM_DES3_KEY_GEN) {79return null;80}8182// Explicitly disallow keys shorter than 40-bits for security83int lower = 40;84int upper = Integer.MAX_VALUE;85try {86CK_MECHANISM_INFO info = token.getMechanismInfo(mech);87if (info != null) {88boolean isBytes = ((mech != CKM_GENERIC_SECRET_KEY_GEN89&& mech != CKM_RC4_KEY_GEN) || info.iMinKeySize < 8);90lower = Math.max(lower, (isBytes?91Math.multiplyExact(info.iMinKeySize, 8) :92info.iMinKeySize));93// NSS CKM_GENERIC_SECRET_KEY_GEN mech info is not precise;94// its upper limit is too low and does not match its impl95if (mech == CKM_GENERIC_SECRET_KEY_GEN &&96info.iMaxKeySize <= 32) {97// ignore and leave upper limit at MAX_VALUE;98} else if (info.iMaxKeySize != Integer.MAX_VALUE) {99upper = (isBytes?100Math.multiplyExact(info.iMaxKeySize, 8) :101info.iMaxKeySize);102}103}104} catch (PKCS11Exception p11e) {105// Should never happen106throw new ProviderException("Cannot retrieve mechanism info", p11e);107}108return new CK_MECHANISM_INFO(lower, upper, 0 /* flags not used */);109}110111/**112* Utility method for checking if the specified key size is valid113* and within the supported range. Return the significant key size114* upon successful validation.115* @param keyGenMech the PKCS#11 key generation mechanism.116* @param keySize the to-be-checked key size for this mechanism.117* @param token token which provides this mechanism.118* @return the significant key size (in bits) corresponding to the119* specified key size.120* @throws InvalidParameterException if the specified key size is invalid.121* @throws ProviderException if this mechanism isn't supported by SunPKCS11122* or underlying native impl.123*/124// called by P11SecretKeyFactory to check key size125static int checkKeySize(long keyGenMech, int keySize, Token token)126throws InvalidAlgorithmParameterException, ProviderException {127CK_MECHANISM_INFO range = getSupportedRange(token, keyGenMech);128return checkKeySize(keyGenMech, keySize, range);129}130131private static int checkKeySize(long keyGenMech, int keySize,132CK_MECHANISM_INFO range) throws InvalidAlgorithmParameterException {133int sigKeySize;134switch ((int)keyGenMech) {135case (int)CKM_DES_KEY_GEN:136if ((keySize != 64) && (keySize != 56)) {137throw new InvalidAlgorithmParameterException138("DES key length must be 56 bits");139}140sigKeySize = 56;141break;142case (int)CKM_DES2_KEY_GEN:143case (int)CKM_DES3_KEY_GEN:144if ((keySize == 112) || (keySize == 128)) {145sigKeySize = 112;146} else if ((keySize == 168) || (keySize == 192)) {147sigKeySize = 168;148} else {149throw new InvalidAlgorithmParameterException150("DESede key length must be 112, or 168 bits");151}152break;153default:154// Handle all variable-key-length algorithms here155if (range != null && keySize < range.iMinKeySize156|| keySize > range.iMaxKeySize) {157throw new InvalidAlgorithmParameterException158("Key length must be between " + range.iMinKeySize +159" and " + range.iMaxKeySize + " bits");160}161if (keyGenMech == CKM_AES_KEY_GEN) {162if ((keySize != 128) && (keySize != 192) &&163(keySize != 256)) {164throw new InvalidAlgorithmParameterException165("AES key length must be 128, 192, or 256 bits");166}167}168sigKeySize = keySize;169}170return sigKeySize;171}172173// check the supplied keysize (in bits) and adjust it based on the given174// range175private static int adjustKeySize(int ks, CK_MECHANISM_INFO mi) {176// adjust to fit within the supported range177if (mi != null) {178if (ks < mi.iMinKeySize) {179ks = mi.iMinKeySize;180} else if (ks > mi.iMaxKeySize) {181ks = mi.iMaxKeySize;182}183}184return ks;185}186187P11KeyGenerator(Token token, String algorithm, long mechanism)188throws PKCS11Exception {189super();190this.token = token;191this.algorithm = algorithm;192this.mechanism = mechanism;193194if (this.mechanism == CKM_DES3_KEY_GEN) {195/* Given the current lookup order specified in SunPKCS11.java,196if CKM_DES2_KEY_GEN is used to construct this object, it197means that CKM_DES3_KEY_GEN is disabled or unsupported.198*/199supportBothKeySizes =200(token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&201(token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));202}203this.range = getSupportedRange(token, mechanism);204setDefault();205}206207// set default keysize and keyType208private void setDefault() {209significantKeySize = -1;210switch ((int)mechanism) {211case (int)CKM_DES_KEY_GEN:212keySize = 64;213keyType = CKK_DES;214significantKeySize = 56;215break;216case (int)CKM_DES2_KEY_GEN:217keySize = 128;218keyType = CKK_DES2;219significantKeySize = 112;220break;221case (int)CKM_DES3_KEY_GEN:222keySize = 192;223keyType = CKK_DES3;224significantKeySize = 168;225break;226case (int)CKM_AES_KEY_GEN:227keySize = adjustKeySize(128, range);228keyType = CKK_AES;229break;230case (int)CKM_RC4_KEY_GEN:231keySize = adjustKeySize(128, range);232keyType = CKK_RC4;233break;234case (int)CKM_BLOWFISH_KEY_GEN:235keySize = adjustKeySize(128, range);236keyType = CKK_BLOWFISH;237break;238case (int)CKM_CHACHA20_KEY_GEN:239keySize = 256;240keyType = CKK_CHACHA20;241break;242case (int)CKM_SHA_1_KEY_GEN:243keySize = adjustKeySize(160, range);244keyType = CKK_SHA_1_HMAC;245break;246case (int)CKM_SHA224_KEY_GEN:247keySize = adjustKeySize(224, range);248keyType = CKK_SHA224_HMAC;249break;250case (int)CKM_SHA256_KEY_GEN:251keySize = adjustKeySize(256, range);252keyType = CKK_SHA256_HMAC;253break;254case (int)CKM_SHA384_KEY_GEN:255keySize = adjustKeySize(384, range);256keyType = CKK_SHA384_HMAC;257break;258case (int)CKM_SHA512_KEY_GEN:259keySize = adjustKeySize(512, range);260keyType = CKK_SHA512_HMAC;261break;262case (int)CKM_SHA512_224_KEY_GEN:263keySize = adjustKeySize(224, range);264keyType = CKK_SHA512_224_HMAC;265break;266case (int)CKM_SHA512_256_KEY_GEN:267keySize = adjustKeySize(256, range);268keyType = CKK_SHA512_256_HMAC;269break;270case (int)CKM_SHA3_224_KEY_GEN:271keySize = adjustKeySize(224, range);272keyType = CKK_SHA3_224_HMAC;273break;274case (int)CKM_SHA3_256_KEY_GEN:275keySize = adjustKeySize(256, range);276keyType = CKK_SHA3_256_HMAC;277break;278case (int)CKM_SHA3_384_KEY_GEN:279keySize = adjustKeySize(384, range);280keyType = CKK_SHA3_384_HMAC;281break;282case (int)CKM_SHA3_512_KEY_GEN:283keySize = adjustKeySize(512, range);284keyType = CKK_SHA3_512_HMAC;285break;286case (int)CKM_GENERIC_SECRET_KEY_GEN:287if (algorithm.startsWith("Hmac")) {288String digest = algorithm.substring(4);289keySize = adjustKeySize(switch (digest) {290case "MD5" -> 512;291case "SHA1" -> 160;292case "SHA224", "SHA512/224", "SHA3-224" -> 224;293case "SHA256", "SHA512/256", "SHA3-256" -> 256;294case "SHA384", "SHA3-384" -> 384;295case "SHA512", "SHA3-512" -> 512;296default -> {297throw new ProviderException("Unsupported algorithm " +298algorithm);299}300}, range);301} else {302throw new ProviderException("Unsupported algorithm " +303algorithm);304}305keyType = CKK_GENERIC_SECRET;306break;307default:308throw new ProviderException("Unknown mechanism " + mechanism);309}310if (significantKeySize == -1) {311significantKeySize = keySize;312}313}314315// see JCE spec316protected void engineInit(SecureRandom random) {317token.ensureValid();318setDefault();319}320321// see JCE spec322protected void engineInit(AlgorithmParameterSpec params,323SecureRandom random) throws InvalidAlgorithmParameterException {324throw new InvalidAlgorithmParameterException325("AlgorithmParameterSpec not supported");326}327328// see JCE spec329protected void engineInit(int keySize, SecureRandom random) {330token.ensureValid();331int newSignificantKeySize;332try {333newSignificantKeySize = checkKeySize(mechanism, keySize, range);334} catch (InvalidAlgorithmParameterException iape) {335throw (InvalidParameterException)336(new InvalidParameterException().initCause(iape));337}338if ((mechanism == CKM_DES2_KEY_GEN) ||339(mechanism == CKM_DES3_KEY_GEN)) {340long newMechanism = (newSignificantKeySize == 112 ?341CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);342if (mechanism != newMechanism) {343if (supportBothKeySizes) {344mechanism = newMechanism;345// Adjust keyType to reflect the mechanism change346keyType = (mechanism == CKM_DES2_KEY_GEN ?347CKK_DES2 : CKK_DES3);348} else {349throw new InvalidParameterException350("Only " + significantKeySize +351"-bit DESede is supported");352}353}354}355this.keySize = keySize;356this.significantKeySize = newSignificantKeySize;357}358359// see JCE spec360protected SecretKey engineGenerateKey() {361Session session = null;362try {363session = token.getObjSession();364CK_ATTRIBUTE[] attributes;365366switch ((int)mechanism) {367case (int)CKM_DES_KEY_GEN:368case (int)CKM_DES2_KEY_GEN:369case (int)CKM_DES3_KEY_GEN:370// fixed length, do not specify CKA_VALUE_LEN371attributes = new CK_ATTRIBUTE[] {372new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),373};374break;375default:376attributes = new CK_ATTRIBUTE[] {377new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),378new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3),379};380break;381}382attributes = token.getAttributes383(O_GENERATE, CKO_SECRET_KEY, keyType, attributes);384long keyID = token.p11.C_GenerateKey385(session.id(), new CK_MECHANISM(mechanism), attributes);386return P11Key.secretKey387(session, keyID, algorithm, significantKeySize, attributes);388} catch (PKCS11Exception e) {389throw new ProviderException("Could not generate key", e);390} finally {391token.releaseSession(session);392}393}394}395396397