1 /* EncodedKeyFactory.java -- JCE Encoded key factory Adapter 2 Copyright (C) 2006, 2010 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.java.security.jce.sig; 40 41 import gnu.java.security.Configuration; 42 import gnu.java.security.Registry; 43 import gnu.java.security.key.dss.DSSPrivateKey; 44 import gnu.java.security.key.dss.DSSPublicKey; 45 import gnu.java.security.key.rsa.GnuRSAPrivateKey; 46 import gnu.java.security.key.rsa.GnuRSAPublicKey; 47 48 import java.lang.reflect.Constructor; 49 import java.lang.reflect.InvocationTargetException; 50 import java.lang.reflect.Method; 51 import java.math.BigInteger; 52 import java.security.InvalidKeyException; 53 import java.security.InvalidParameterException; 54 import java.security.Key; 55 import java.security.KeyFactorySpi; 56 import java.security.PrivateKey; 57 import java.security.PublicKey; 58 import java.security.spec.DSAPrivateKeySpec; 59 import java.security.spec.DSAPublicKeySpec; 60 import java.security.spec.InvalidKeySpecException; 61 import java.security.spec.KeySpec; 62 import java.security.spec.PKCS8EncodedKeySpec; 63 import java.security.spec.RSAPrivateCrtKeySpec; 64 import java.security.spec.RSAPublicKeySpec; 65 import java.security.spec.X509EncodedKeySpec; 66 import java.util.logging.Level; 67 import java.util.logging.Logger; 68 69 import javax.crypto.interfaces.DHPrivateKey; 70 import javax.crypto.interfaces.DHPublicKey; 71 import javax.crypto.spec.DHPrivateKeySpec; 72 import javax.crypto.spec.DHPublicKeySpec; 73 74 /** 75 * A factory for keys encoded in either the X.509 format (for public keys) or 76 * the PKCS#8 format (for private keys). 77 */ 78 public class EncodedKeyFactory 79 extends KeyFactorySpi 80 { 81 private static final Logger log = Configuration.DEBUG ? 82 Logger.getLogger(EncodedKeyFactory.class.getName()) : null; 83 invokeConstructor(String className, Object[] params)84 private static Object invokeConstructor(String className, Object[] params) 85 throws InvalidKeySpecException 86 { 87 Class clazz = getConcreteClass(className); 88 try 89 { 90 Constructor ctor = getConcreteCtor(clazz); 91 Object result = ctor.newInstance(params); 92 return result; 93 } 94 catch (InstantiationException x) 95 { 96 throw new InvalidKeySpecException(x.getMessage(), x); 97 } 98 catch (IllegalAccessException x) 99 { 100 throw new InvalidKeySpecException(x.getMessage(), x); 101 } 102 catch (InvocationTargetException x) 103 { 104 throw new InvalidKeySpecException(x.getMessage(), x); 105 } 106 } 107 getConcreteClass(String className)108 private static Class getConcreteClass(String className) 109 throws InvalidKeySpecException 110 { 111 try 112 { 113 Class result = Class.forName(className); 114 return result; 115 } 116 catch (ClassNotFoundException x) 117 { 118 throw new InvalidKeySpecException(x.getMessage(), x); 119 } 120 } 121 getConcreteCtor(Class clazz)122 private static Constructor getConcreteCtor(Class clazz) 123 throws InvalidKeySpecException 124 { 125 try 126 { 127 Constructor result = clazz.getConstructor(new Class[] {int.class, 128 BigInteger.class, 129 BigInteger.class, 130 BigInteger.class, 131 BigInteger.class}); 132 return result; 133 } 134 catch (NoSuchMethodException x) 135 { 136 throw new InvalidKeySpecException(x.getMessage(), x); 137 } 138 } 139 invokeValueOf(String className, byte[] encoded)140 private static Object invokeValueOf(String className, byte[] encoded) 141 throws InvalidKeySpecException 142 { 143 Class clazz = getConcreteClass(className); 144 try 145 { 146 Method valueOf = getValueOfMethod(clazz); 147 Object result = valueOf.invoke(null, new Object[] { encoded }); 148 return result; 149 } 150 catch (IllegalAccessException x) 151 { 152 throw new InvalidKeySpecException(x.getMessage(), x); 153 } 154 catch (InvocationTargetException x) 155 { 156 throw new InvalidKeySpecException(x.getMessage(), x); 157 } 158 } 159 getValueOfMethod(Class clazz)160 private static Method getValueOfMethod(Class clazz) 161 throws InvalidKeySpecException 162 { 163 try 164 { 165 Method result = clazz.getMethod("valueOf", new Class[] {byte[].class}); 166 return result; 167 } 168 catch (NoSuchMethodException x) 169 { 170 throw new InvalidKeySpecException(x.getMessage(), x); 171 } 172 } 173 engineGeneratePublic(KeySpec keySpec)174 protected PublicKey engineGeneratePublic(KeySpec keySpec) 175 throws InvalidKeySpecException 176 { 177 if (Configuration.DEBUG) 178 log.entering(this.getClass().getName(), "engineGeneratePublic()", keySpec); 179 PublicKey result = null; 180 if (keySpec instanceof DSAPublicKeySpec) 181 result = decodeDSSPublicKey((DSAPublicKeySpec) keySpec); 182 else if (keySpec instanceof RSAPublicKeySpec) 183 result = decodeRSAPublicKey((RSAPublicKeySpec) keySpec); 184 else if (keySpec instanceof DHPublicKeySpec) 185 result = decodeDHPublicKey((DHPublicKeySpec) keySpec); 186 else 187 { 188 if (! (keySpec instanceof X509EncodedKeySpec)) 189 throw new InvalidKeySpecException("Unsupported key specification"); 190 191 byte[] input = ((X509EncodedKeySpec) keySpec).getEncoded(); 192 boolean ok = false; 193 // try DSS 194 try 195 { 196 result = DSSPublicKey.valueOf(input); 197 ok = true; 198 } 199 catch (InvalidParameterException ignored) 200 { 201 if (Configuration.DEBUG) 202 log.log(Level.FINE, "Exception in DSSPublicKey.valueOf(). Ignore", 203 ignored); 204 } 205 if (! ok) // try RSA 206 try 207 { 208 result = GnuRSAPublicKey.valueOf(input); 209 ok = true; 210 } 211 catch (InvalidParameterException ignored) 212 { 213 if (Configuration.DEBUG) 214 log.log(Level.FINE, 215 "Exception in GnuRSAPublicKey.valueOf(). Ignore", 216 ignored); 217 } 218 if (! ok) // try DH 219 result = decodeDHPublicKey(input); 220 } 221 if (Configuration.DEBUG) 222 log.exiting(this.getClass().getName(), "engineGeneratePublic()", result); 223 return result; 224 } 225 engineGeneratePrivate(KeySpec keySpec)226 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) 227 throws InvalidKeySpecException 228 { 229 if (Configuration.DEBUG) 230 log.entering(this.getClass().getName(), "engineGeneratePrivate()", keySpec); 231 PrivateKey result = null; 232 if (keySpec instanceof DSAPrivateKeySpec) 233 result = decodeDSSPrivateKey((DSAPrivateKeySpec) keySpec); 234 else if (keySpec instanceof RSAPrivateCrtKeySpec) 235 result = decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec); 236 else if (keySpec instanceof DHPrivateKeySpec) 237 result = decodeDHPrivateKey((DHPrivateKeySpec) keySpec); 238 else 239 { 240 if (! (keySpec instanceof PKCS8EncodedKeySpec)) 241 throw new InvalidKeySpecException("Unsupported key specification"); 242 243 byte[] input = ((PKCS8EncodedKeySpec) keySpec).getEncoded(); 244 boolean ok = false; 245 // try DSS 246 try 247 { 248 result = DSSPrivateKey.valueOf(input); 249 ok = true; 250 } 251 catch (InvalidParameterException ignored) 252 { 253 if (Configuration.DEBUG) 254 log.log(Level.FINE, "Exception in DSSPrivateKey.valueOf(). Ignore", 255 ignored); 256 } 257 if (! ok) // try RSA 258 try 259 { 260 result = GnuRSAPrivateKey.valueOf(input); 261 ok = true; 262 } 263 catch (InvalidParameterException ignored) 264 { 265 if (Configuration.DEBUG) 266 log.log(Level.FINE, 267 "Exception in GnuRSAPrivateKey.valueOf(). Ignore", 268 ignored); 269 } 270 if (! ok) // try DH 271 result = decodeDHPrivateKey(input); 272 } 273 if (Configuration.DEBUG) 274 log.exiting(this.getClass().getName(), "engineGeneratePrivate()", result); 275 return result; 276 } 277 engineGetKeySpec(Key key, Class keySpec)278 protected KeySpec engineGetKeySpec(Key key, Class keySpec) 279 throws InvalidKeySpecException 280 { 281 if (key instanceof PublicKey 282 && Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()) 283 && keySpec.isAssignableFrom(X509EncodedKeySpec.class)) 284 return new X509EncodedKeySpec(key.getEncoded()); 285 286 if (key instanceof PrivateKey 287 && Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()) 288 && keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) 289 return new PKCS8EncodedKeySpec(key.getEncoded()); 290 291 throw new InvalidKeySpecException("Unsupported format or invalid key spec class"); 292 } 293 engineTranslateKey(Key key)294 protected Key engineTranslateKey(Key key) throws InvalidKeyException 295 { 296 throw new InvalidKeyException("Key translation not supported"); 297 } 298 299 /** 300 * @param spec an instance of {@link DSAPublicKeySpec} to decode. 301 * @return an instance of {@link DSSPublicKey} constructed from the 302 * information in the designated key-specification. 303 */ decodeDSSPublicKey(DSAPublicKeySpec spec)304 private DSSPublicKey decodeDSSPublicKey(DSAPublicKeySpec spec) 305 { 306 BigInteger p = spec.getP(); 307 BigInteger q = spec.getQ(); 308 BigInteger g = spec.getG(); 309 BigInteger y = spec.getY(); 310 return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); 311 } 312 313 /** 314 * @param spec an instance of {@link RSAPublicKeySpec} to decode. 315 * @return an instance of {@link GnuRSAPublicKey} constructed from the 316 * information in the designated key-specification. 317 */ decodeRSAPublicKey(RSAPublicKeySpec spec)318 private GnuRSAPublicKey decodeRSAPublicKey(RSAPublicKeySpec spec) 319 { 320 BigInteger n = spec.getModulus(); 321 BigInteger e = spec.getPublicExponent(); 322 return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); 323 } 324 325 /** 326 * @param spec an instance of {@link DHPublicKeySpec} to decode. 327 * @return an instance of a {@link DHPublicKey} constructed from the 328 * information in the designated key-specification. 329 * @throws InvalidKeySpecException if no concrete implementation of the 330 * {@link DHPublicKey} interface exists at run-time, or if an 331 * exception occurs during its instantiation. 332 */ decodeDHPublicKey(DHPublicKeySpec spec)333 private DHPublicKey decodeDHPublicKey(DHPublicKeySpec spec) 334 throws InvalidKeySpecException 335 { 336 BigInteger p = spec.getP(); 337 BigInteger g = spec.getG(); 338 BigInteger y = spec.getY(); 339 Object[] params = new Object[] {Integer.valueOf(Registry.X509_ENCODING_ID), 340 null, p, g, y}; 341 Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPublicKey", 342 params); 343 return (DHPublicKey) obj; 344 } 345 346 /** 347 * @param encoded the bytes to decode. 348 * @return an instance of a {@link DHPublicKey} constructed from the 349 * information in the designated key-specification. 350 * @throws InvalidKeySpecException if no concrete implementation of the 351 * {@link DHPublicKey} interface exists at run-time, or if an 352 * exception occurs during its instantiation. 353 */ decodeDHPublicKey(byte[] encoded)354 private DHPublicKey decodeDHPublicKey(byte[] encoded) 355 throws InvalidKeySpecException 356 { 357 Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPublicKey", 358 encoded); 359 return (DHPublicKey) obj; 360 } 361 362 /** 363 * @param spec an instance of {@link DSAPrivateKeySpec} to decode. 364 * @return an instance of {@link DSSPrivateKey} constructed from the 365 * information in the designated key-specification. 366 */ decodeDSSPrivateKey(DSAPrivateKeySpec spec)367 private PrivateKey decodeDSSPrivateKey(DSAPrivateKeySpec spec) 368 { 369 BigInteger p = spec.getP(); 370 BigInteger q = spec.getQ(); 371 BigInteger g = spec.getG(); 372 BigInteger x = spec.getX(); 373 return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); 374 } 375 376 /** 377 * @param spec an instance of {@link RSAPrivateCrtKeySpec} to decode. 378 * @return an instance of {@link GnuRSAPrivateKey} constructed from the 379 * information in the designated key-specification. 380 */ decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec)381 private PrivateKey decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec) 382 { 383 BigInteger n = spec.getModulus(); 384 BigInteger e = spec.getPublicExponent(); 385 BigInteger d = spec.getPrivateExponent(); 386 BigInteger p = spec.getPrimeP(); 387 BigInteger q = spec.getPrimeQ(); 388 BigInteger dP = spec.getPrimeExponentP(); 389 BigInteger dQ = spec.getPrimeExponentQ(); 390 BigInteger qInv = spec.getCrtCoefficient(); 391 return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, 392 n, e, d, p, q, dP, dQ, qInv); 393 } 394 395 /** 396 * @param spec an instance of {@link DHPrivateKeySpec} to decode. 397 * @return an instance of a {@link DHPrivateKey} constructed from the 398 * information in the designated key-specification. 399 * @throws InvalidKeySpecException if no concrete implementation of the 400 * {@link DHPrivateKey} interface exists at run-time, or if an 401 * exception occurs during its instantiation. 402 */ decodeDHPrivateKey(DHPrivateKeySpec spec)403 private DHPrivateKey decodeDHPrivateKey(DHPrivateKeySpec spec) 404 throws InvalidKeySpecException 405 { 406 BigInteger p = spec.getP(); 407 BigInteger g = spec.getG(); 408 BigInteger x = spec.getX(); 409 Object[] params = new Object[] {Integer.valueOf(Registry.PKCS8_ENCODING_ID), 410 null, p, g, x}; 411 Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPrivateKey", 412 params); 413 return (DHPrivateKey) obj; 414 } 415 416 /** 417 * @param encoded the bytes to decode. 418 * @return an instance of a {@link DHPrivateKey} constructed from the 419 * information in the designated key-specification. 420 * @throws InvalidKeySpecException if no concrete implementation of the 421 * {@link DHPrivateKey} interface exists at run-time, or if an 422 * exception occurs during its instantiation. 423 */ decodeDHPrivateKey(byte[] encoded)424 private DHPrivateKey decodeDHPrivateKey(byte[] encoded) 425 throws InvalidKeySpecException 426 { 427 Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPrivateKey", 428 encoded); 429 return (DHPrivateKey) obj; 430 } 431 } 432