Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ec/ECKeyFactory.java
38830 views
/*1* Copyright (c) 2006, 2012, 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.ec;2627import java.security.*;28import java.security.interfaces.*;29import java.security.spec.*;3031/**32* KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey33* and getAlgorithm() must return "EC". For such keys, it supports conversion34* between the following:35*36* For public keys:37* . PublicKey with an X.509 encoding38* . ECPublicKey39* . ECPublicKeySpec40* . X509EncodedKeySpec41*42* For private keys:43* . PrivateKey with a PKCS#8 encoding44* . ECPrivateKey45* . ECPrivateKeySpec46* . PKCS8EncodedKeySpec47*48* @since 1.649* @author Andreas Sterbenz50*/51public final class ECKeyFactory extends KeyFactorySpi {5253// Used by translateKey()54private static KeyFactory instance;5556private static KeyFactory getInstance() {57if (instance == null) {58try {59instance = KeyFactory.getInstance("EC", "SunEC");60} catch (NoSuchProviderException e) {61throw new RuntimeException(e);62} catch (NoSuchAlgorithmException e) {63throw new RuntimeException(e);64}65}6667return instance;68}6970public ECKeyFactory() {71// empty72}7374/**75* Static method to convert Key into a useable instance of76* ECPublicKey or ECPrivateKey. Check the key and convert it77* to a Sun key if necessary. If the key is not an EC key78* or cannot be used, throw an InvalidKeyException.79*80* The difference between this method and engineTranslateKey() is that81* we do not convert keys of other providers that are already an82* instance of ECPublicKey or ECPrivateKey.83*84* To be used by future Java ECDSA and ECDH implementations.85*/86public static ECKey toECKey(Key key) throws InvalidKeyException {87if (key instanceof ECKey) {88ECKey ecKey = (ECKey)key;89checkKey(ecKey);90return ecKey;91} else {92/*93* We don't call the engineTranslateKey method directly94* because KeyFactory.translateKey adds code to loop through95* all key factories.96*/97return (ECKey)getInstance().translateKey(key);98}99}100101/**102* Check that the given EC key is valid.103*/104private static void checkKey(ECKey key) throws InvalidKeyException {105// check for subinterfaces, omit additional checks for our keys106if (key instanceof ECPublicKey) {107if (key instanceof ECPublicKeyImpl) {108return;109}110} else if (key instanceof ECPrivateKey) {111if (key instanceof ECPrivateKeyImpl) {112return;113}114} else {115throw new InvalidKeyException("Neither a public nor a private key");116}117// ECKey does not extend Key, so we need to do a cast118String keyAlg = ((Key)key).getAlgorithm();119if (keyAlg.equals("EC") == false) {120throw new InvalidKeyException("Not an EC key: " + keyAlg);121}122// XXX further sanity checks about whether this key uses supported123// fields, point formats, etc. would go here124}125126/**127* Translate an EC key into a Sun EC key. If conversion is128* not possible, throw an InvalidKeyException.129* See also JCA doc.130*/131protected Key engineTranslateKey(Key key) throws InvalidKeyException {132if (key == null) {133throw new InvalidKeyException("Key must not be null");134}135String keyAlg = key.getAlgorithm();136if (keyAlg.equals("EC") == false) {137throw new InvalidKeyException("Not an EC key: " + keyAlg);138}139if (key instanceof PublicKey) {140return implTranslatePublicKey((PublicKey)key);141} else if (key instanceof PrivateKey) {142return implTranslatePrivateKey((PrivateKey)key);143} else {144throw new InvalidKeyException("Neither a public nor a private key");145}146}147148// see JCA doc149protected PublicKey engineGeneratePublic(KeySpec keySpec)150throws InvalidKeySpecException {151try {152return implGeneratePublic(keySpec);153} catch (InvalidKeySpecException e) {154throw e;155} catch (GeneralSecurityException e) {156throw new InvalidKeySpecException(e);157}158}159160// see JCA doc161protected PrivateKey engineGeneratePrivate(KeySpec keySpec)162throws InvalidKeySpecException {163try {164return implGeneratePrivate(keySpec);165} catch (InvalidKeySpecException e) {166throw e;167} catch (GeneralSecurityException e) {168throw new InvalidKeySpecException(e);169}170}171172// internal implementation of translateKey() for public keys. See JCA doc173private PublicKey implTranslatePublicKey(PublicKey key)174throws InvalidKeyException {175if (key instanceof ECPublicKey) {176if (key instanceof ECPublicKeyImpl) {177return key;178}179ECPublicKey ecKey = (ECPublicKey)key;180return new ECPublicKeyImpl(181ecKey.getW(),182ecKey.getParams()183);184} else if ("X.509".equals(key.getFormat())) {185byte[] encoded = key.getEncoded();186return new ECPublicKeyImpl(encoded);187} else {188throw new InvalidKeyException("Public keys must be instance "189+ "of ECPublicKey or have X.509 encoding");190}191}192193// internal implementation of translateKey() for private keys. See JCA doc194private PrivateKey implTranslatePrivateKey(PrivateKey key)195throws InvalidKeyException {196if (key instanceof ECPrivateKey) {197if (key instanceof ECPrivateKeyImpl) {198return key;199}200ECPrivateKey ecKey = (ECPrivateKey)key;201return new ECPrivateKeyImpl(202ecKey.getS(),203ecKey.getParams()204);205} else if ("PKCS#8".equals(key.getFormat())) {206return new ECPrivateKeyImpl(key.getEncoded());207} else {208throw new InvalidKeyException("Private keys must be instance "209+ "of ECPrivateKey or have PKCS#8 encoding");210}211}212213// internal implementation of generatePublic. See JCA doc214private PublicKey implGeneratePublic(KeySpec keySpec)215throws GeneralSecurityException {216if (keySpec instanceof X509EncodedKeySpec) {217X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;218return new ECPublicKeyImpl(x509Spec.getEncoded());219} else if (keySpec instanceof ECPublicKeySpec) {220ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;221return new ECPublicKeyImpl(222ecSpec.getW(),223ecSpec.getParams()224);225} else {226throw new InvalidKeySpecException("Only ECPublicKeySpec "227+ "and X509EncodedKeySpec supported for EC public keys");228}229}230231// internal implementation of generatePrivate. See JCA doc232private PrivateKey implGeneratePrivate(KeySpec keySpec)233throws GeneralSecurityException {234if (keySpec instanceof PKCS8EncodedKeySpec) {235PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;236return new ECPrivateKeyImpl(pkcsSpec.getEncoded());237} else if (keySpec instanceof ECPrivateKeySpec) {238ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;239return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());240} else {241throw new InvalidKeySpecException("Only ECPrivateKeySpec "242+ "and PKCS8EncodedKeySpec supported for EC private keys");243}244}245246protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)247throws InvalidKeySpecException {248try {249// convert key to one of our keys250// this also verifies that the key is a valid EC key and ensures251// that the encoding is X.509/PKCS#8 for public/private keys252key = engineTranslateKey(key);253} catch (InvalidKeyException e) {254throw new InvalidKeySpecException(e);255}256if (key instanceof ECPublicKey) {257ECPublicKey ecKey = (ECPublicKey)key;258if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) {259return keySpec.cast(new ECPublicKeySpec(260ecKey.getW(),261ecKey.getParams()262));263} else if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {264return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));265} else {266throw new InvalidKeySpecException267("KeySpec must be ECPublicKeySpec or "268+ "X509EncodedKeySpec for EC public keys");269}270} else if (key instanceof ECPrivateKey) {271if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {272return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));273} else if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {274ECPrivateKey ecKey = (ECPrivateKey)key;275return keySpec.cast(new ECPrivateKeySpec(276ecKey.getS(),277ecKey.getParams()278));279} else {280throw new InvalidKeySpecException281("KeySpec must be ECPrivateKeySpec or "282+ "PKCS8EncodedKeySpec for EC private keys");283}284} else {285// should not occur, caught in engineTranslateKey()286throw new InvalidKeySpecException("Neither public nor private key");287}288}289}290291292