Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.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.util.*;2829import java.security.*;30import java.security.spec.*;3132import javax.crypto.*;33import javax.crypto.spec.*;3435import static sun.security.pkcs11.TemplateManager.*;36import sun.security.pkcs11.wrapper.*;37import static sun.security.pkcs11.wrapper.PKCS11Constants.*;3839/**40* SecretKeyFactory implementation class. This class currently supports41* DES, DESede, AES, ARCFOUR, and Blowfish.42*43* @author Andreas Sterbenz44* @since 1.545*/46final class P11SecretKeyFactory extends SecretKeyFactorySpi {4748// token instance49private final Token token;5051// algorithm name52private final String algorithm;5354P11SecretKeyFactory(Token token, String algorithm) {55super();56this.token = token;57this.algorithm = algorithm;58}5960private static final Map<String,Long> keyTypes;6162static {63keyTypes = new HashMap<String,Long>();64addKeyType("RC4", CKK_RC4);65addKeyType("ARCFOUR", CKK_RC4);66addKeyType("DES", CKK_DES);67addKeyType("DESede", CKK_DES3);68addKeyType("AES", CKK_AES);69addKeyType("Blowfish", CKK_BLOWFISH);70addKeyType("ChaCha20", CKK_CHACHA20);7172// we don't implement RC2 or IDEA, but we want to be able to generate73// keys for those SSL/TLS ciphersuites.74addKeyType("RC2", CKK_RC2);75addKeyType("IDEA", CKK_IDEA);7677addKeyType("TlsPremasterSecret", PCKK_TLSPREMASTER);78addKeyType("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER);79addKeyType("TlsMasterSecret", PCKK_TLSMASTER);80addKeyType("Generic", CKK_GENERIC_SECRET);81}8283private static void addKeyType(String name, long id) {84Long l = Long.valueOf(id);85keyTypes.put(name, l);86keyTypes.put(name.toUpperCase(Locale.ENGLISH), l);87}8889// returns the PKCS11 key type of the specified algorithm90// no psuedo KeyTypes91static long getPKCS11KeyType(String algorithm) {92long kt = getKeyType(algorithm);93if (kt == -1 || kt > PCKK_ANY) {94kt = CKK_GENERIC_SECRET;95}96return kt;97}9899// returns direct lookup result of keyTypes using algorithm100static long getKeyType(String algorithm) {101Long l = keyTypes.get(algorithm);102if (l == null) {103algorithm = algorithm.toUpperCase(Locale.ENGLISH);104l = keyTypes.get(algorithm);105if (l == null) {106if (algorithm.startsWith("HMAC")) {107return PCKK_HMAC;108} else if (algorithm.startsWith("SSLMAC")) {109return PCKK_SSLMAC;110}111}112}113return (l != null) ? l.longValue() : -1;114}115116/**117* Convert an arbitrary key of algorithm into a P11Key of provider.118* Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().119*/120static P11Key convertKey(Token token, Key key, String algo)121throws InvalidKeyException {122return convertKey(token, key, algo, null);123}124125/**126* Convert an arbitrary key of algorithm w/ custom attributes into a127* P11Key of provider.128* Used in P11KeyStore.storeSkey.129*/130static P11Key convertKey(Token token, Key key, String algo,131CK_ATTRIBUTE[] extraAttrs)132throws InvalidKeyException {133token.ensureValid();134if (key == null) {135throw new InvalidKeyException("Key must not be null");136}137if (key instanceof SecretKey == false) {138throw new InvalidKeyException("Key must be a SecretKey");139}140long algoType;141if (algo == null) {142algo = key.getAlgorithm();143algoType = getKeyType(algo);144} else {145algoType = getKeyType(algo);146long keyAlgorithmType = getKeyType(key.getAlgorithm());147if (algoType != keyAlgorithmType) {148if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {149// ignore key algorithm for MACs150} else {151throw new InvalidKeyException152("Key algorithm must be " + algo);153}154}155}156if (key instanceof P11Key) {157P11Key p11Key = (P11Key)key;158if (p11Key.token == token) {159if (extraAttrs != null) {160P11Key newP11Key = null;161Session session = null;162long p11KeyID = p11Key.getKeyID();163try {164session = token.getObjSession();165long newKeyID = token.p11.C_CopyObject(session.id(),166p11KeyID, extraAttrs);167newP11Key = (P11Key) (P11Key.secretKey(session,168newKeyID, p11Key.algorithm, p11Key.keyLength,169extraAttrs));170} catch (PKCS11Exception p11e) {171throw new InvalidKeyException172("Cannot duplicate the PKCS11 key", p11e);173} finally {174p11Key.releaseKeyID();175token.releaseSession(session);176}177p11Key = newP11Key;178}179return p11Key;180}181}182P11Key p11Key = token.secretCache.get(key);183if (p11Key != null) {184return p11Key;185}186if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {187throw new InvalidKeyException("Encoded format must be RAW");188}189byte[] encoded = key.getEncoded();190p11Key = createKey(token, encoded, algo, algoType, extraAttrs);191token.secretCache.put(key, p11Key);192return p11Key;193}194195static void fixDESParity(byte[] key, int offset) {196for (int i = 0; i < 8; i++) {197int b = key[offset] & 0xfe;198b |= (Integer.bitCount(b) & 1) ^ 1;199key[offset++] = (byte)b;200}201}202203private static P11Key createKey(Token token, byte[] encoded,204String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs)205throws InvalidKeyException {206int n = encoded.length << 3;207int keyLength = n;208try {209switch ((int)keyType) {210case (int)CKK_DES:211keyLength =212P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token);213fixDESParity(encoded, 0);214break;215case (int)CKK_DES3:216keyLength =217P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token);218fixDESParity(encoded, 0);219fixDESParity(encoded, 8);220if (keyLength == 112) {221keyType = CKK_DES2;222} else {223keyType = CKK_DES3;224fixDESParity(encoded, 16);225}226break;227case (int)CKK_AES:228keyLength =229P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token);230break;231case (int)CKK_RC4:232keyLength =233P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token);234break;235case (int)CKK_BLOWFISH:236keyLength =237P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n,238token);239break;240case (int)CKK_CHACHA20:241keyLength = P11KeyGenerator.checkKeySize(242CKM_CHACHA20_KEY_GEN, n, token);243break;244case (int)CKK_GENERIC_SECRET:245case (int)PCKK_TLSPREMASTER:246case (int)PCKK_TLSRSAPREMASTER:247case (int)PCKK_TLSMASTER:248keyType = CKK_GENERIC_SECRET;249break;250case (int)PCKK_SSLMAC:251case (int)PCKK_HMAC:252if (n == 0) {253throw new InvalidKeyException254("MAC keys must not be empty");255}256keyType = CKK_GENERIC_SECRET;257break;258default:259throw new InvalidKeyException("Unknown algorithm " +260algorithm);261}262} catch (InvalidAlgorithmParameterException iape) {263throw new InvalidKeyException("Invalid key for " + algorithm,264iape);265} catch (ProviderException pe) {266throw new InvalidKeyException("Could not create key", pe);267}268Session session = null;269try {270CK_ATTRIBUTE[] attributes;271if (extraAttrs != null) {272attributes = new CK_ATTRIBUTE[3 + extraAttrs.length];273System.arraycopy(extraAttrs, 0, attributes, 3,274extraAttrs.length);275} else {276attributes = new CK_ATTRIBUTE[3];277}278attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);279attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType);280attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);281attributes = token.getAttributes282(O_IMPORT, CKO_SECRET_KEY, keyType, attributes);283session = token.getObjSession();284long keyID = token.p11.C_CreateObject(session.id(), attributes);285P11Key p11Key = (P11Key)P11Key.secretKey286(session, keyID, algorithm, keyLength, attributes);287return p11Key;288} catch (PKCS11Exception e) {289throw new InvalidKeyException("Could not create key", e);290} finally {291token.releaseSession(session);292}293}294295// see JCE spec296protected SecretKey engineGenerateSecret(KeySpec keySpec)297throws InvalidKeySpecException {298token.ensureValid();299if (keySpec == null) {300throw new InvalidKeySpecException("KeySpec must not be null");301}302if (keySpec instanceof SecretKeySpec) {303try {304Key key = convertKey(token, (SecretKey)keySpec, algorithm);305return (SecretKey)key;306} catch (InvalidKeyException e) {307throw new InvalidKeySpecException(e);308}309} else if (algorithm.equalsIgnoreCase("DES")) {310if (keySpec instanceof DESKeySpec) {311byte[] keyBytes = ((DESKeySpec)keySpec).getKey();312keySpec = new SecretKeySpec(keyBytes, "DES");313return engineGenerateSecret(keySpec);314}315} else if (algorithm.equalsIgnoreCase("DESede")) {316if (keySpec instanceof DESedeKeySpec) {317byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey();318keySpec = new SecretKeySpec(keyBytes, "DESede");319return engineGenerateSecret(keySpec);320}321}322throw new InvalidKeySpecException323("Unsupported spec: " + keySpec.getClass().getName());324}325326private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException {327try {328key = engineTranslateKey(key);329if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {330throw new InvalidKeySpecException331("Could not obtain key bytes");332}333byte[] k = key.getEncoded();334return k;335} catch (InvalidKeyException e) {336throw new InvalidKeySpecException(e);337}338}339340// see JCE spec341protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpec)342throws InvalidKeySpecException {343token.ensureValid();344if ((key == null) || (keySpec == null)) {345throw new InvalidKeySpecException346("key and keySpec must not be null");347}348if (keySpec.isAssignableFrom(SecretKeySpec.class)) {349return new SecretKeySpec(getKeyBytes(key), algorithm);350} else if (algorithm.equalsIgnoreCase("DES")) {351try {352if (keySpec.isAssignableFrom(DESKeySpec.class)) {353return new DESKeySpec(getKeyBytes(key));354}355} catch (InvalidKeyException e) {356throw new InvalidKeySpecException(e);357}358} else if (algorithm.equalsIgnoreCase("DESede")) {359try {360if (keySpec.isAssignableFrom(DESedeKeySpec.class)) {361return new DESedeKeySpec(getKeyBytes(key));362}363} catch (InvalidKeyException e) {364throw new InvalidKeySpecException(e);365}366}367throw new InvalidKeySpecException368("Unsupported spec: " + keySpec.getName());369}370371// see JCE spec372protected SecretKey engineTranslateKey(SecretKey key)373throws InvalidKeyException {374return (SecretKey)convertKey(token, key, algorithm);375}376377}378379380