1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ec;
  27 
  28 import java.security.KeyFactorySpi;
  29 import java.security.Key;
  30 import java.security.PublicKey;
  31 import java.security.PrivateKey;
  32 import java.security.InvalidKeyException;
  33 import java.security.interfaces.XECKey;
  34 import java.security.interfaces.XECPrivateKey;
  35 import java.security.interfaces.XECPublicKey;
  36 import java.security.spec.KeySpec;
  37 import java.security.spec.InvalidKeySpecException;
  38 import java.security.spec.PKCS8EncodedKeySpec;
  39 import java.security.spec.X509EncodedKeySpec;
  40 import java.security.spec.XECPublicKeySpec;
  41 import java.security.spec.XECPrivateKeySpec;
  42 
  43 public final class XDHKeyFactory extends KeyFactorySpi {
  44 
  45     @Override
  46     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
  47 
  48         if (key == null) {
  49             throw new InvalidKeyException("Key must not be null");
  50         }
  51 
  52         if (key instanceof XECKey) {
  53             XECKey xecKey = (XECKey) key;
  54             XECParameters params = XECParameters.get(InvalidKeyException::new,
  55                 xecKey.getParams());
  56 
  57             if (xecKey instanceof XECPublicKey) {
  58                 XECPublicKey publicKey = (XECPublicKey) xecKey;
  59                 return new XDHPublicKeyImpl(params, publicKey.getU());
  60             } else if (xecKey instanceof XECPrivateKey) {
  61                 XECPrivateKey privateKey = (XECPrivateKey) xecKey;
  62                 byte[] scalar = privateKey.getScalar().orElseThrow(
  63                     () -> new InvalidKeyException("No private key data"));
  64                 return new XDHPrivateKeyImpl(params, scalar);
  65             } else {
  66                 throw new InvalidKeyException("Unsupported XECKey subclass");
  67             }
  68         } else if (key instanceof PublicKey &&
  69                    key.getFormat().equals("X.509")) {
  70             return new XDHPublicKeyImpl(key.getEncoded());
  71         } else if (key instanceof PrivateKey &&
  72                    key.getFormat().equals("PKCS#8")) {
  73             return new XDHPrivateKeyImpl(key.getEncoded());
  74         } else {
  75             throw new InvalidKeyException("Unsupported key type or format");
  76         }
  77     }
  78 
  79     @Override
  80     protected PublicKey engineGeneratePublic(KeySpec keySpec)
  81         throws InvalidKeySpecException {
  82 
  83         try {
  84              return generatePublicImpl(keySpec);
  85         } catch (InvalidKeyException ex) {
  86             throw new InvalidKeySpecException(ex);
  87         }
  88     }
  89 
  90     @Override
  91     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
  92         throws InvalidKeySpecException {
  93 
  94         try {
  95             return generatePrivateImpl(keySpec);
  96         } catch (InvalidKeyException ex) {
  97             throw new InvalidKeySpecException(ex);
  98         }
  99     }
 100 
 101 
 102     private PublicKey generatePublicImpl(KeySpec keySpec)
 103         throws InvalidKeyException, InvalidKeySpecException {
 104 
 105         if (keySpec instanceof X509EncodedKeySpec) {
 106             X509EncodedKeySpec x509Spec = (X509EncodedKeySpec) keySpec;
 107             return new XDHPublicKeyImpl(x509Spec.getEncoded());
 108         } else if (keySpec instanceof XECPublicKeySpec) {
 109             XECPublicKeySpec publicKeySpec = (XECPublicKeySpec) keySpec;
 110             XECParameters params = XECParameters.get(
 111                 InvalidKeySpecException::new, publicKeySpec.getParams());
 112             return new XDHPublicKeyImpl(params, publicKeySpec.getU());
 113         } else {
 114             throw new InvalidKeySpecException(
 115                 "Only X509EncodedKeySpec and XECPublicKeySpec are supported");
 116         }
 117     }
 118 
 119     private PrivateKey generatePrivateImpl(KeySpec keySpec)
 120         throws InvalidKeyException, InvalidKeySpecException {
 121 
 122         if (keySpec instanceof PKCS8EncodedKeySpec) {
 123             PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec) keySpec;
 124             return new XDHPrivateKeyImpl(pkcsSpec.getEncoded());
 125         } else if (keySpec instanceof XECPrivateKeySpec) {
 126             XECPrivateKeySpec privateKeySpec = (XECPrivateKeySpec) keySpec;
 127             XECParameters params = XECParameters.get(
 128                 InvalidKeySpecException::new, privateKeySpec.getParams());
 129             return new XDHPrivateKeyImpl(params, privateKeySpec.getScalar());
 130         } else {
 131             throw new InvalidKeySpecException(
 132                 "Only PKCS8EncodedKeySpec and XECPrivateKeySpec supported");
 133         }
 134     }
 135 
 136     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
 137             throws InvalidKeySpecException {
 138 
 139         if (key instanceof XECPublicKey) {
 140             if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
 141                 if (!key.getFormat().equals("X.509")) {
 142                     throw new InvalidKeySpecException("Format is not X.509");
 143                 }
 144                 return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
 145             } else if (XECPublicKeySpec.class.isAssignableFrom(keySpec)) {
 146                 XECPublicKey xecKey = (XECPublicKey) key;
 147                 return keySpec.cast(
 148                     new XECPublicKeySpec(xecKey.getParams(), xecKey.getU()));
 149             } else {
 150                 throw new InvalidKeySpecException(
 151                     "KeySpec must be X509EncodedKeySpec or XECPublicKeySpec");
 152             }
 153         } else if (key instanceof XECPrivateKey) {
 154             if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
 155                 if (!key.getFormat().equals("PKCS#8")) {
 156                     throw new InvalidKeySpecException("Format is not PKCS#8");
 157                 }
 158                 return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
 159             } else if (XECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
 160                 XECPrivateKey xecKey = (XECPrivateKey) key;
 161                 byte[] scalar = xecKey.getScalar().orElseThrow(
 162                     () -> new InvalidKeySpecException("No private key value")
 163                 );
 164                 return keySpec.cast(
 165                     new XECPrivateKeySpec(xecKey.getParams(), scalar));
 166             } else {
 167                 throw new InvalidKeySpecException
 168                 ("KeySpec must be PKCS8EncodedKeySpec or XECPrivateKeySpec");
 169             }
 170         } else {
 171             throw new InvalidKeySpecException("Unsupported key type");
 172         }
 173     }
 174 }