Path: blob/master/src/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyFactory.java
41161 views
/*1* Copyright (c) 2006, 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.ec;2627import java.security.*;28import java.security.interfaces.*;29import java.security.spec.*;30import java.util.Arrays;3132/**33* KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey34* and getAlgorithm() must return "EC". For such keys, it supports conversion35* between the following:36*37* For public keys:38* . PublicKey with an X.509 encoding39* . ECPublicKey40* . ECPublicKeySpec41* . X509EncodedKeySpec42*43* For private keys:44* . PrivateKey with a PKCS#8 encoding45* . ECPrivateKey46* . ECPrivateKeySpec47* . PKCS8EncodedKeySpec48*49* @since 1.650* @author Andreas Sterbenz51*/52public final class ECKeyFactory extends KeyFactorySpi {5354// Used by translateKey()55private static KeyFactory instance;5657private static KeyFactory getInstance() {58if (instance == null) {59try {60instance = KeyFactory.getInstance("EC", "SunEC");61} catch (NoSuchProviderException e) {62throw new RuntimeException(e);63} catch (NoSuchAlgorithmException e) {64throw new RuntimeException(e);65}66}6768return instance;69}7071public ECKeyFactory() {72// empty73}7475/**76* Static method to convert Key into a useable instance of77* ECPublicKey or ECPrivateKey. Check the key and convert it78* to a Sun key if necessary. If the key is not an EC key79* or cannot be used, throw an InvalidKeyException.80*81* The difference between this method and engineTranslateKey() is that82* we do not convert keys of other providers that are already an83* instance of ECPublicKey or ECPrivateKey.84*85* To be used by future Java ECDSA and ECDH implementations.86*/87public static ECKey toECKey(Key key) throws InvalidKeyException {88if (key instanceof ECKey) {89ECKey ecKey = (ECKey)key;90checkKey(ecKey);91return ecKey;92} else {93/*94* We don't call the engineTranslateKey method directly95* because KeyFactory.translateKey adds code to loop through96* all key factories.97*/98return (ECKey)getInstance().translateKey(key);99}100}101102/**103* Check that the given EC key is valid.104*/105private static void checkKey(ECKey key) throws InvalidKeyException {106// check for subinterfaces, omit additional checks for our keys107if (key instanceof ECPublicKey) {108if (key instanceof ECPublicKeyImpl) {109return;110}111} else if (key instanceof ECPrivateKey) {112if (key instanceof ECPrivateKeyImpl) {113return;114}115} else {116throw new InvalidKeyException("Neither a public nor a private key");117}118// ECKey does not extend Key, so we need to do a cast119String keyAlg = ((Key)key).getAlgorithm();120if (keyAlg.equals("EC") == false) {121throw new InvalidKeyException("Not an EC key: " + keyAlg);122}123// XXX further sanity checks about whether this key uses supported124// fields, point formats, etc. would go here125}126127/**128* Translate an EC key into a Sun EC key. If conversion is129* not possible, throw an InvalidKeyException.130* See also JCA doc.131*/132protected Key engineTranslateKey(Key key) throws InvalidKeyException {133if (key == null) {134throw new InvalidKeyException("Key must not be null");135}136String keyAlg = key.getAlgorithm();137if (keyAlg.equals("EC") == false) {138throw new InvalidKeyException("Not an EC key: " + keyAlg);139}140if (key instanceof PublicKey) {141return implTranslatePublicKey((PublicKey)key);142} else if (key instanceof PrivateKey) {143return implTranslatePrivateKey((PrivateKey)key);144} else {145throw new InvalidKeyException("Neither a public nor a private key");146}147}148149// see JCA doc150protected PublicKey engineGeneratePublic(KeySpec keySpec)151throws InvalidKeySpecException {152try {153return implGeneratePublic(keySpec);154} catch (InvalidKeySpecException e) {155throw e;156} catch (GeneralSecurityException e) {157throw new InvalidKeySpecException(e);158}159}160161// see JCA doc162protected PrivateKey engineGeneratePrivate(KeySpec keySpec)163throws InvalidKeySpecException {164try {165return implGeneratePrivate(keySpec);166} catch (InvalidKeySpecException e) {167throw e;168} catch (GeneralSecurityException e) {169throw new InvalidKeySpecException(e);170}171}172173// internal implementation of translateKey() for public keys. See JCA doc174private PublicKey implTranslatePublicKey(PublicKey key)175throws InvalidKeyException {176if (key instanceof ECPublicKey) {177if (key instanceof ECPublicKeyImpl) {178return key;179}180ECPublicKey ecKey = (ECPublicKey)key;181return new ECPublicKeyImpl(182ecKey.getW(),183ecKey.getParams()184);185} else if ("X.509".equals(key.getFormat())) {186byte[] encoded = key.getEncoded();187return new ECPublicKeyImpl(encoded);188} else {189throw new InvalidKeyException("Public keys must be instance "190+ "of ECPublicKey or have X.509 encoding");191}192}193194// internal implementation of translateKey() for private keys. See JCA doc195private PrivateKey implTranslatePrivateKey(PrivateKey key)196throws InvalidKeyException {197if (key instanceof ECPrivateKey) {198if (key instanceof ECPrivateKeyImpl) {199return key;200}201ECPrivateKey ecKey = (ECPrivateKey)key;202return new ECPrivateKeyImpl(203ecKey.getS(),204ecKey.getParams()205);206} else if ("PKCS#8".equals(key.getFormat())) {207byte[] encoded = key.getEncoded();208try {209return new ECPrivateKeyImpl(encoded);210} finally {211Arrays.fill(encoded, (byte)0);212}213} else {214throw new InvalidKeyException("Private keys must be instance "215+ "of ECPrivateKey or have PKCS#8 encoding");216}217}218219// internal implementation of generatePublic. See JCA doc220private PublicKey implGeneratePublic(KeySpec keySpec)221throws GeneralSecurityException {222if (keySpec instanceof X509EncodedKeySpec) {223X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;224return new ECPublicKeyImpl(x509Spec.getEncoded());225} else if (keySpec instanceof ECPublicKeySpec) {226ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;227return new ECPublicKeyImpl(228ecSpec.getW(),229ecSpec.getParams()230);231} else {232throw new InvalidKeySpecException("Only ECPublicKeySpec "233+ "and X509EncodedKeySpec supported for EC public keys");234}235}236237// internal implementation of generatePrivate. See JCA doc238private PrivateKey implGeneratePrivate(KeySpec keySpec)239throws GeneralSecurityException {240if (keySpec instanceof PKCS8EncodedKeySpec) {241PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;242byte[] encoded = pkcsSpec.getEncoded();243try {244return new ECPrivateKeyImpl(encoded);245} finally {246Arrays.fill(encoded, (byte) 0);247}248} else if (keySpec instanceof ECPrivateKeySpec) {249ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;250return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());251} else {252throw new InvalidKeySpecException("Only ECPrivateKeySpec "253+ "and PKCS8EncodedKeySpec supported for EC private keys");254}255}256257protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)258throws InvalidKeySpecException {259try {260// convert key to one of our keys261// this also verifies that the key is a valid EC key and ensures262// that the encoding is X.509/PKCS#8 for public/private keys263key = engineTranslateKey(key);264} catch (InvalidKeyException e) {265throw new InvalidKeySpecException(e);266}267if (key instanceof ECPublicKey) {268ECPublicKey ecKey = (ECPublicKey)key;269if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) {270return keySpec.cast(new ECPublicKeySpec(271ecKey.getW(),272ecKey.getParams()273));274} else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) {275return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));276} else {277throw new InvalidKeySpecException278("KeySpec must be ECPublicKeySpec or "279+ "X509EncodedKeySpec for EC public keys");280}281} else if (key instanceof ECPrivateKey) {282if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) {283byte[] encoded = key.getEncoded();284try {285return keySpec.cast(new PKCS8EncodedKeySpec(encoded));286} finally {287Arrays.fill(encoded, (byte)0);288}289} else if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) {290ECPrivateKey ecKey = (ECPrivateKey)key;291return keySpec.cast(new ECPrivateKeySpec(292ecKey.getS(),293ecKey.getParams()294));295} else {296throw new InvalidKeySpecException297("KeySpec must be ECPrivateKeySpec or "298+ "PKCS8EncodedKeySpec for EC private keys");299}300} else {301// should not occur, caught in engineTranslateKey()302throw new InvalidKeySpecException("Neither public nor private key");303}304}305}306307308