0N/A/*
2362N/A * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.ec;
0N/A
0N/Aimport java.security.*;
0N/Aimport java.security.interfaces.*;
0N/Aimport java.security.spec.*;
0N/A
0N/A/**
0N/A * KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey
0N/A * and getAlgorithm() must return "EC". For such keys, it supports conversion
0N/A * between the following:
0N/A *
0N/A * For public keys:
0N/A * . PublicKey with an X.509 encoding
0N/A * . ECPublicKey
0N/A * . ECPublicKeySpec
0N/A * . X509EncodedKeySpec
0N/A *
0N/A * For private keys:
0N/A * . PrivateKey with a PKCS#8 encoding
0N/A * . ECPrivateKey
0N/A * . ECPrivateKeySpec
0N/A * . PKCS8EncodedKeySpec
0N/A *
0N/A * @since 1.6
0N/A * @author Andreas Sterbenz
0N/A */
0N/Apublic final class ECKeyFactory extends KeyFactorySpi {
0N/A
0N/A // Used by translateKey() and the SunPKCS11 provider
0N/A public final static KeyFactory INSTANCE;
0N/A
0N/A // Internal provider object we can obtain the KeyFactory and
0N/A // AlgorithmParameters from. Used by ECParameters and AlgorithmId.
0N/A // This can go away once we have EC always available in the SUN provider.
0N/A // Used by ECParameters and AlgorithmId.
0N/A public final static Provider ecInternalProvider;
0N/A
0N/A static {
0N/A final Provider p = new Provider("SunEC-Internal", 1.0d, null) {};
0N/A AccessController.doPrivileged(new PrivilegedAction<Void>() {
0N/A public Void run() {
0N/A p.put("KeyFactory.EC", "sun.security.ec.ECKeyFactory");
0N/A p.put("AlgorithmParameters.EC", "sun.security.ec.ECParameters");
0N/A p.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC");
0N/A return null;
0N/A }
0N/A });
0N/A try {
0N/A INSTANCE = KeyFactory.getInstance("EC", p);
0N/A } catch (NoSuchAlgorithmException e) {
0N/A throw new RuntimeException(e);
0N/A }
0N/A ecInternalProvider = p;
0N/A }
0N/A
0N/A public ECKeyFactory() {
0N/A // empty
0N/A }
0N/A
0N/A /**
0N/A * Static method to convert Key into a useable instance of
0N/A * ECPublicKey or ECPrivateKey. Check the key and convert it
0N/A * to a Sun key if necessary. If the key is not an EC key
0N/A * or cannot be used, throw an InvalidKeyException.
0N/A *
0N/A * The difference between this method and engineTranslateKey() is that
0N/A * we do not convert keys of other providers that are already an
0N/A * instance of ECPublicKey or ECPrivateKey.
0N/A *
0N/A * To be used by future Java ECDSA and ECDH implementations.
0N/A */
0N/A public static ECKey toECKey(Key key) throws InvalidKeyException {
0N/A if (key instanceof ECKey) {
0N/A ECKey ecKey = (ECKey)key;
0N/A checkKey(ecKey);
0N/A return ecKey;
0N/A } else {
0N/A return (ECKey)INSTANCE.translateKey(key);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Check that the given EC key is valid.
0N/A */
0N/A private static void checkKey(ECKey key) throws InvalidKeyException {
0N/A // check for subinterfaces, omit additional checks for our keys
0N/A if (key instanceof ECPublicKey) {
0N/A if (key instanceof ECPublicKeyImpl) {
0N/A return;
0N/A }
0N/A } else if (key instanceof ECPrivateKey) {
0N/A if (key instanceof ECPrivateKeyImpl) {
0N/A return;
0N/A }
0N/A } else {
0N/A throw new InvalidKeyException("Neither a public nor a private key");
0N/A }
0N/A // ECKey does not extend Key, so we need to do a cast
0N/A String keyAlg = ((Key)key).getAlgorithm();
0N/A if (keyAlg.equals("EC") == false) {
0N/A throw new InvalidKeyException("Not an EC key: " + keyAlg);
0N/A }
0N/A // XXX further sanity checks about whether this key uses supported
0N/A // fields, point formats, etc. would go here
0N/A }
0N/A
0N/A /**
0N/A * Translate an EC key into a Sun EC key. If conversion is
0N/A * not possible, throw an InvalidKeyException.
0N/A * See also JCA doc.
0N/A */
0N/A protected Key engineTranslateKey(Key key) throws InvalidKeyException {
0N/A if (key == null) {
0N/A throw new InvalidKeyException("Key must not be null");
0N/A }
0N/A String keyAlg = key.getAlgorithm();
0N/A if (keyAlg.equals("EC") == false) {
0N/A throw new InvalidKeyException("Not an EC key: " + keyAlg);
0N/A }
0N/A if (key instanceof PublicKey) {
0N/A return implTranslatePublicKey((PublicKey)key);
0N/A } else if (key instanceof PrivateKey) {
0N/A return implTranslatePrivateKey((PrivateKey)key);
0N/A } else {
0N/A throw new InvalidKeyException("Neither a public nor a private key");
0N/A }
0N/A }
0N/A
0N/A // see JCA doc
0N/A protected PublicKey engineGeneratePublic(KeySpec keySpec)
0N/A throws InvalidKeySpecException {
0N/A try {
0N/A return implGeneratePublic(keySpec);
0N/A } catch (InvalidKeySpecException e) {
0N/A throw e;
0N/A } catch (GeneralSecurityException e) {
0N/A throw new InvalidKeySpecException(e);
0N/A }
0N/A }
0N/A
0N/A // see JCA doc
0N/A protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
0N/A throws InvalidKeySpecException {
0N/A try {
0N/A return implGeneratePrivate(keySpec);
0N/A } catch (InvalidKeySpecException e) {
0N/A throw e;
0N/A } catch (GeneralSecurityException e) {
0N/A throw new InvalidKeySpecException(e);
0N/A }
0N/A }
0N/A
0N/A // internal implementation of translateKey() for public keys. See JCA doc
0N/A private PublicKey implTranslatePublicKey(PublicKey key)
0N/A throws InvalidKeyException {
0N/A if (key instanceof ECPublicKey) {
0N/A if (key instanceof ECPublicKeyImpl) {
0N/A return key;
0N/A }
0N/A ECPublicKey ecKey = (ECPublicKey)key;
0N/A return new ECPublicKeyImpl(
0N/A ecKey.getW(),
0N/A ecKey.getParams()
0N/A );
0N/A } else if ("X.509".equals(key.getFormat())) {
0N/A byte[] encoded = key.getEncoded();
0N/A return new ECPublicKeyImpl(encoded);
0N/A } else {
0N/A throw new InvalidKeyException("Public keys must be instance "
0N/A + "of ECPublicKey or have X.509 encoding");
0N/A }
0N/A }
0N/A
0N/A // internal implementation of translateKey() for private keys. See JCA doc
0N/A private PrivateKey implTranslatePrivateKey(PrivateKey key)
0N/A throws InvalidKeyException {
0N/A if (key instanceof ECPrivateKey) {
0N/A if (key instanceof ECPrivateKeyImpl) {
0N/A return key;
0N/A }
0N/A ECPrivateKey ecKey = (ECPrivateKey)key;
0N/A return new ECPrivateKeyImpl(
0N/A ecKey.getS(),
0N/A ecKey.getParams()
0N/A );
0N/A } else if ("PKCS#8".equals(key.getFormat())) {
0N/A return new ECPrivateKeyImpl(key.getEncoded());
0N/A } else {
0N/A throw new InvalidKeyException("Private keys must be instance "
0N/A + "of ECPrivateKey or have PKCS#8 encoding");
0N/A }
0N/A }
0N/A
0N/A // internal implementation of generatePublic. See JCA doc
0N/A private PublicKey implGeneratePublic(KeySpec keySpec)
0N/A throws GeneralSecurityException {
0N/A if (keySpec instanceof X509EncodedKeySpec) {
0N/A X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
0N/A return new ECPublicKeyImpl(x509Spec.getEncoded());
0N/A } else if (keySpec instanceof ECPublicKeySpec) {
0N/A ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;
0N/A return new ECPublicKeyImpl(
0N/A ecSpec.getW(),
0N/A ecSpec.getParams()
0N/A );
0N/A } else {
0N/A throw new InvalidKeySpecException("Only ECPublicKeySpec "
0N/A + "and X509EncodedKeySpec supported for EC public keys");
0N/A }
0N/A }
0N/A
0N/A // internal implementation of generatePrivate. See JCA doc
0N/A private PrivateKey implGeneratePrivate(KeySpec keySpec)
0N/A throws GeneralSecurityException {
0N/A if (keySpec instanceof PKCS8EncodedKeySpec) {
0N/A PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
0N/A return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
0N/A } else if (keySpec instanceof ECPrivateKeySpec) {
0N/A ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
0N/A return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
0N/A } else {
0N/A throw new InvalidKeySpecException("Only ECPrivateKeySpec "
0N/A + "and PKCS8EncodedKeySpec supported for EC private keys");
0N/A }
0N/A }
0N/A
0N/A protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
0N/A throws InvalidKeySpecException {
0N/A try {
0N/A // convert key to one of our keys
0N/A // this also verifies that the key is a valid EC key and ensures
0N/A // that the encoding is X.509/PKCS#8 for public/private keys
0N/A key = engineTranslateKey(key);
0N/A } catch (InvalidKeyException e) {
0N/A throw new InvalidKeySpecException(e);
0N/A }
0N/A if (key instanceof ECPublicKey) {
0N/A ECPublicKey ecKey = (ECPublicKey)key;
0N/A if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
0N/A return (T) new ECPublicKeySpec(
0N/A ecKey.getW(),
0N/A ecKey.getParams()
0N/A );
0N/A } else if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
0N/A return (T) new X509EncodedKeySpec(key.getEncoded());
0N/A } else {
0N/A throw new InvalidKeySpecException
0N/A ("KeySpec must be ECPublicKeySpec or "
0N/A + "X509EncodedKeySpec for EC public keys");
0N/A }
0N/A } else if (key instanceof ECPrivateKey) {
0N/A if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
0N/A return (T) new PKCS8EncodedKeySpec(key.getEncoded());
0N/A } else if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
0N/A ECPrivateKey ecKey = (ECPrivateKey)key;
0N/A return (T) new ECPrivateKeySpec(
0N/A ecKey.getS(),
0N/A ecKey.getParams()
0N/A );
0N/A } else {
0N/A throw new InvalidKeySpecException
0N/A ("KeySpec must be ECPrivateKeySpec or "
0N/A + "PKCS8EncodedKeySpec for EC private keys");
0N/A }
0N/A } else {
0N/A // should not occur, caught in engineTranslateKey()
0N/A throw new InvalidKeySpecException("Neither public nor private key");
0N/A }
0N/A }
0N/A}