/
wstartsev
/
jdk
Обзор
Документация
Войти
/
wstartsev
/
jdk
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/sun/security/ec/ECKeyFactory.java
306 строк
11 KB
Anthony Scarpino
8360564: Implement JEP 524: PEM Encodings of Cryptographic Objects (Second Preview)
15 ноя 2025, 00:08
15 ноя 2025, 00:08
ad3dfaf
Код
Авторство
О чём код?
/* * Copyright (c) 2006, 2025, 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.ec; import sun.security.pkcs.PKCS8Key; import sun.security.util.KeyUtil; import java.security.*; import java.security.interfaces.*; import java.security.spec.*; import java.util.Arrays; /** * KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey * and getAlgorithm() must return "EC". For such keys, it supports conversion * between the following: * * For public keys: * . PublicKey with an X.509 encoding * . ECPublicKey * . ECPublicKeySpec * . X509EncodedKeySpec * * For private keys: * . PrivateKey with a PKCS#8 encoding * . ECPrivateKey * . ECPrivateKeySpec * . PKCS8EncodedKeySpec * * @since 1.6 * @author Andreas Sterbenz */ public final class ECKeyFactory extends KeyFactorySpi { // Used by translateKey() private static KeyFactory instance; private static KeyFactory getInstance() { if (instance == null) { try { instance = KeyFactory.getInstance("EC", "SunEC"); } catch (NoSuchProviderException | NoSuchAlgorithmException e) { throw new RuntimeException(e); } } return instance; } public ECKeyFactory() { // empty } /** * Static method to convert Key into a usable instance of * ECPublicKey or ECPrivateKey. Check the key and convert it * to a Sun key if necessary. If the key is not an EC key * or cannot be used, throw an InvalidKeyException. * * The difference between this method and engineTranslateKey() is that * we do not convert keys of other providers that are already an * instance of ECPublicKey or ECPrivateKey. * * To be used by future Java ECDSA and ECDH implementations. */ public static ECKey toECKey(Key key) throws InvalidKeyException { if (key instanceof ECKey ecKey) { checkKey(ecKey); return ecKey; } else { /* * We don't call the engineTranslateKey method directly * because KeyFactory.translateKey adds code to loop through * all key factories. */ return (ECKey)getInstance().translateKey(key); } } /** * Check that the given EC key is valid. */ private static void checkKey(ECKey key) throws InvalidKeyException { // check for subinterfaces, omit additional checks for our keys if (key instanceof ECPublicKey) { if (key instanceof ECPublicKeyImpl) { return; } } else if (key instanceof ECPrivateKey) { if (key instanceof ECPrivateKeyImpl) { return; } } else { throw new InvalidKeyException("Neither a public nor a private key"); } // ECKey does not extend Key, so we need to do a cast String keyAlg = ((Key)key).getAlgorithm(); if (keyAlg.equals("EC") == false) { throw new InvalidKeyException("Not an EC key: " + keyAlg); } // XXX further sanity checks about whether this key uses supported // fields, point formats, etc. would go here } /** * Translate an EC key into a Sun EC key. If conversion is * not possible, throw an InvalidKeyException. * See also JCA doc. */ protected Key engineTranslateKey(Key key) throws InvalidKeyException { if (key == null) { throw new InvalidKeyException("Key must not be null"); } String keyAlg = key.getAlgorithm(); if (keyAlg.equals("EC") == false) { throw new InvalidKeyException("Not an EC key: " + keyAlg); } if (key instanceof PublicKey) { return implTranslatePublicKey((PublicKey)key); } else if (key instanceof PrivateKey) { return implTranslatePrivateKey((PrivateKey)key); } else { throw new InvalidKeyException("Neither a public nor a private key"); } } // see JCA doc protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { try { return implGeneratePublic(keySpec); } catch (InvalidKeySpecException e) { throw e; } catch (GeneralSecurityException e) { throw new InvalidKeySpecException(e); } } // see JCA doc protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { try { return implGeneratePrivate(keySpec); } catch (InvalidKeySpecException e) { throw e; } catch (GeneralSecurityException e) { throw new InvalidKeySpecException(e); } } // internal implementation of translateKey() for public keys. See JCA doc private PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException { if (key instanceof ECPublicKeyImpl) { return key; } else if (key instanceof ECPublicKey ecKey) { return new ECPublicKeyImpl(ecKey.getW(), ecKey.getParams()); } else if ("X.509".equals(key.getFormat())) { return new ECPublicKeyImpl(key.getEncoded()); } else { throw new InvalidKeyException("Public keys must be instance " + "of ECPublicKey or have X.509 encoding"); } } // internal implementation of translateKey() for private keys. See JCA doc private PrivateKey implTranslatePrivateKey(PrivateKey key) throws InvalidKeyException { if (key instanceof ECPrivateKeyImpl) { return key; } else if (key instanceof ECPrivateKey ecKey) { return new ECPrivateKeyImpl(ecKey.getS(), ecKey.getParams()); } else if ("PKCS#8".equals(key.getFormat())) { byte[] encoded = key.getEncoded(); try { return new ECPrivateKeyImpl(encoded); } finally { Arrays.fill(encoded, (byte)0); } } throw new InvalidKeyException("Private keys must be instance " + "of ECPrivateKey or have PKCS#8 encoding"); } // internal implementation of generatePublic. See JCA doc private PublicKey implGeneratePublic(KeySpec keySpec) throws GeneralSecurityException { return switch (keySpec) { case X509EncodedKeySpec x -> new ECPublicKeyImpl(x.getEncoded()); case ECPublicKeySpec e -> new ECPublicKeyImpl(e.getW(), e.getParams()); case PKCS8EncodedKeySpec p8 -> { byte[] encoded = p8.getEncoded(); PKCS8Key p8key = null; try { p8key = new ECPrivateKeyImpl(encoded); if (!p8key.hasPublicKey()) { throw new InvalidKeySpecException("No public key found."); } yield new ECPublicKeyImpl(p8key.getPubKeyEncoded()); } finally { KeyUtil.clear(encoded, p8key); } } case null -> throw new InvalidKeySpecException( "keySpec must not be null"); default -> throw new InvalidKeySpecException(keySpec.getClass().getName() + " not supported."); }; } // internal implementation of generatePrivate. See JCA doc private PrivateKey implGeneratePrivate(KeySpec keySpec) throws GeneralSecurityException { return switch (keySpec) { case PKCS8EncodedKeySpec p8 -> { byte[] encoded = p8.getEncoded(); try { yield new ECPrivateKeyImpl(encoded); } finally { Arrays.fill(encoded, (byte) 0); } } case ECPrivateKeySpec e -> new ECPrivateKeyImpl(e.getS(), e.getParams()); case null -> throw new InvalidKeySpecException( "keySpec must not be null"); default -> throw new InvalidKeySpecException(keySpec.getClass().getName() + " not supported."); }; } protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) throws InvalidKeySpecException { try { // convert key to one of our keys // this also verifies that the key is a valid EC key and ensures // that the encoding is X.509/PKCS#8 for public/private keys key = engineTranslateKey(key); } catch (InvalidKeyException e) { throw new InvalidKeySpecException(e); } if (key instanceof ECPublicKey ecKey) { if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) { return keySpec.cast(new ECPublicKeySpec( ecKey.getW(), ecKey.getParams() )); } else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) { return keySpec.cast(new X509EncodedKeySpec(key.getEncoded())); } else { throw new InvalidKeySpecException ("KeySpec must be ECPublicKeySpec or " + "X509EncodedKeySpec for EC public keys"); } } else if (key instanceof ECPrivateKey) { if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) { byte[] encoded = key.getEncoded(); try { return keySpec.cast(new PKCS8EncodedKeySpec(encoded)); } finally { Arrays.fill(encoded, (byte)0); } } else if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) { ECPrivateKey ecKey = (ECPrivateKey)key; return keySpec.cast(new ECPrivateKeySpec( ecKey.getS(), ecKey.getParams() )); } else { throw new InvalidKeySpecException ("KeySpec must be ECPrivateKeySpec or " + "PKCS8EncodedKeySpec for EC private keys"); } } else { // should not occur, caught in engineTranslateKey() throw new InvalidKeySpecException("Neither public nor private key"); } } }