| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.security; |
| |
| import java.io.IOException; |
| import java.io.NotSerializableException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectStreamException; |
| import java.io.Serializable; |
| import java.security.spec.InvalidKeySpecException; |
| import java.security.spec.PKCS8EncodedKeySpec; |
| import java.security.spec.X509EncodedKeySpec; |
| import javax.crypto.spec.SecretKeySpec; |
| |
| /** |
| * {@code KeyRep} is a standardized representation for serialized {@link Key} |
| * objects. |
| */ |
| public class KeyRep implements Serializable { |
| |
| private static final long serialVersionUID = -4757683898830641853L; |
| // Key type |
| private final Type type; |
| // Key algorithm name |
| private final String algorithm; |
| // Key encoding format |
| private final String format; |
| // Key encoding |
| private byte[] encoded; |
| |
| /** |
| * Constructs a new instance of {@code KeyRep} with the specified arguments. |
| * The arguments should be obtained from the {@code Key} object that has to |
| * be serialized. |
| * |
| * @param type |
| * the type of the key. |
| * @param algorithm |
| * the algorithm (obtained by {@link Key#getAlgorithm()}). |
| * @param format |
| * the format of the key (obtained by {@link Key#getFormat()}). |
| * @param encoded |
| * the encoded {@code byte[]} (obtained by |
| * {@link Key#getEncoded()}). |
| * @throws NullPointerException |
| * if {@code type, algorithm, format or encoded} is {@code null} |
| * . |
| */ |
| public KeyRep(Type type, String algorithm, String format, byte[] encoded) { |
| this.type = type; |
| this.algorithm = algorithm; |
| this.format = format; |
| this.encoded = encoded; |
| if(this.type == null) { |
| throw new NullPointerException("type == null"); |
| } |
| if(this.algorithm == null) { |
| throw new NullPointerException("algorithm == null"); |
| } |
| if(this.format == null) { |
| throw new NullPointerException("format == null"); |
| } |
| if(this.encoded == null) { |
| throw new NullPointerException("encoded == null"); |
| } |
| } |
| |
| /** |
| * Resolves and returns the {@code Key} object. Three {@link Type}|format |
| * combinations are supported: |
| * <ul> |
| * <li> {@code Type.PRIVATE} | "PKCS#8" : returns a {@link PrivateKey} |
| * instance, generated from a key factory (suitable for the algorithm) that |
| * is initialized with a {@link PKCS8EncodedKeySpec} using the encoded key |
| * bytes. |
| * <li> {@code Type.SECRET} | "RAW" : returns a {@link SecretKeySpec} |
| * instance, created with the encoded key bytes and the algorithm. |
| * <li> {@code Type.PUBLIC} | "X.509": returns a {@link PublicKey} instance, |
| * generated from a key factory (suitable for the algorithm) that is |
| * initialized with a {@link X509EncodedKeySpec} using the encoded key |
| * bytes. |
| * </ul> |
| * |
| * @return the resolved {@code Key} object. |
| * @throws ObjectStreamException |
| * if the {@code Type}|format combination is not recognized, or |
| * the resolution of any key parameter fails. |
| */ |
| protected Object readResolve() throws ObjectStreamException { |
| switch (type) { |
| case SECRET: |
| if ("RAW".equals(format)) { |
| try { |
| return new SecretKeySpec(encoded, algorithm); |
| } catch (IllegalArgumentException e) { |
| throw new NotSerializableException("Could not create SecretKeySpec: " + e); |
| } |
| } |
| throw new NotSerializableException("unrecognized type/format combination: " + type + "/" + format); |
| case PUBLIC: |
| if ("X.509".equals(format)) { |
| try { |
| KeyFactory kf = KeyFactory.getInstance(algorithm); |
| return kf.generatePublic(new X509EncodedKeySpec(encoded)); |
| } catch (NoSuchAlgorithmException e) { |
| throw new NotSerializableException("Could not resolve key: " + e); |
| } |
| catch (InvalidKeySpecException e) { |
| throw new NotSerializableException("Could not resolve key: " + e); |
| } |
| } |
| throw new NotSerializableException("unrecognized type/format combination: " + type + "/" + format); |
| case PRIVATE: |
| if ("PKCS#8".equals(format)) { |
| try { |
| KeyFactory kf = KeyFactory.getInstance(algorithm); |
| return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded)); |
| } catch (NoSuchAlgorithmException e) { |
| throw new NotSerializableException("Could not resolve key: " + e); |
| } |
| catch (InvalidKeySpecException e) { |
| throw new NotSerializableException("Could not resolve key: " + e); |
| } |
| } |
| throw new NotSerializableException("unrecognized type/format combination: " + type + "/" + format); |
| } |
| throw new NotSerializableException("unrecognized key type: " + type); |
| } |
| |
| // Makes defensive copy of key encoding |
| private void readObject(ObjectInputStream is) |
| throws IOException, ClassNotFoundException { |
| is.defaultReadObject(); |
| byte[] new_encoded = new byte[encoded.length]; |
| System.arraycopy(encoded, 0, new_encoded, 0, new_encoded.length); |
| encoded = new_encoded; |
| } |
| |
| /** |
| * {@code Type} enumerates the supported key types. |
| */ |
| public static enum Type { |
| /** |
| * Type for secret keys. |
| */ |
| SECRET, |
| /** |
| * Type for public keys. |
| */ |
| PUBLIC, |
| /** |
| * Type for private keys. |
| */ |
| PRIVATE |
| } |
| } |