1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.security; 19 20 import java.io.IOException; 21 import java.io.NotSerializableException; 22 import java.io.ObjectInputStream; 23 import java.io.ObjectStreamException; 24 import java.io.Serializable; 25 import java.security.spec.InvalidKeySpecException; 26 import java.security.spec.PKCS8EncodedKeySpec; 27 import java.security.spec.X509EncodedKeySpec; 28 import javax.crypto.spec.SecretKeySpec; 29 30 /** 31 * {@code KeyRep} is a standardized representation for serialized {@link Key} 32 * objects. 33 */ 34 public class KeyRep implements Serializable { 35 36 private static final long serialVersionUID = -4757683898830641853L; 37 // Key type 38 private final Type type; 39 // Key algorithm name 40 private final String algorithm; 41 // Key encoding format 42 private final String format; 43 // Key encoding 44 private byte[] encoded; 45 46 /** 47 * Constructs a new instance of {@code KeyRep} with the specified arguments. 48 * The arguments should be obtained from the {@code Key} object that has to 49 * be serialized. 50 * 51 * @param type 52 * the type of the key. 53 * @param algorithm 54 * the algorithm (obtained by {@link Key#getAlgorithm()}). 55 * @param format 56 * the format of the key (obtained by {@link Key#getFormat()}). 57 * @param encoded 58 * the encoded {@code byte[]} (obtained by 59 * {@link Key#getEncoded()}). 60 * @throws NullPointerException 61 * if {@code type, algorithm, format or encoded} is {@code null} 62 * . 63 */ KeyRep(Type type, String algorithm, String format, byte[] encoded)64 public KeyRep(Type type, String algorithm, String format, byte[] encoded) { 65 this.type = type; 66 this.algorithm = algorithm; 67 this.format = format; 68 this.encoded = encoded; 69 if(this.type == null) { 70 throw new NullPointerException("type == null"); 71 } 72 if(this.algorithm == null) { 73 throw new NullPointerException("algorithm == null"); 74 } 75 if(this.format == null) { 76 throw new NullPointerException("format == null"); 77 } 78 if(this.encoded == null) { 79 throw new NullPointerException("encoded == null"); 80 } 81 } 82 83 /** 84 * Resolves and returns the {@code Key} object. Three {@link Type}|format 85 * combinations are supported: 86 * <ul> 87 * <li> {@code Type.PRIVATE} | "PKCS#8" : returns a {@link PrivateKey} 88 * instance, generated from a key factory (suitable for the algorithm) that 89 * is initialized with a {@link PKCS8EncodedKeySpec} using the encoded key 90 * bytes. 91 * <li> {@code Type.SECRET} | "RAW" : returns a {@link SecretKeySpec} 92 * instance, created with the encoded key bytes and the algorithm. 93 * <li> {@code Type.PUBLIC} | "X.509": returns a {@link PublicKey} instance, 94 * generated from a key factory (suitable for the algorithm) that is 95 * initialized with a {@link X509EncodedKeySpec} using the encoded key 96 * bytes. 97 * </ul> 98 * 99 * @return the resolved {@code Key} object. 100 * @throws ObjectStreamException 101 * if the {@code Type}|format combination is not recognized, or 102 * the resolution of any key parameter fails. 103 */ readResolve()104 protected Object readResolve() throws ObjectStreamException { 105 switch (type) { 106 case SECRET: 107 if ("RAW".equals(format)) { 108 try { 109 return new SecretKeySpec(encoded, algorithm); 110 } catch (IllegalArgumentException e) { 111 throw new NotSerializableException("Could not create SecretKeySpec: " + e); 112 } 113 } 114 throw new NotSerializableException("unrecognized type/format combination: " + type + "/" + format); 115 case PUBLIC: 116 if ("X.509".equals(format)) { 117 try { 118 KeyFactory kf = KeyFactory.getInstance(algorithm); 119 return kf.generatePublic(new X509EncodedKeySpec(encoded)); 120 } catch (NoSuchAlgorithmException e) { 121 throw new NotSerializableException("Could not resolve key: " + e); 122 } 123 catch (InvalidKeySpecException e) { 124 throw new NotSerializableException("Could not resolve key: " + e); 125 } 126 } 127 throw new NotSerializableException("unrecognized type/format combination: " + type + "/" + format); 128 case PRIVATE: 129 if ("PKCS#8".equals(format)) { 130 try { 131 KeyFactory kf = KeyFactory.getInstance(algorithm); 132 return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 133 } catch (NoSuchAlgorithmException e) { 134 throw new NotSerializableException("Could not resolve key: " + e); 135 } 136 catch (InvalidKeySpecException e) { 137 throw new NotSerializableException("Could not resolve key: " + e); 138 } 139 } 140 throw new NotSerializableException("unrecognized type/format combination: " + type + "/" + format); 141 } 142 throw new NotSerializableException("unrecognized key type: " + type); 143 } 144 145 // Makes defensive copy of key encoding readObject(ObjectInputStream is)146 private void readObject(ObjectInputStream is) 147 throws IOException, ClassNotFoundException { 148 is.defaultReadObject(); 149 byte[] new_encoded = new byte[encoded.length]; 150 System.arraycopy(encoded, 0, new_encoded, 0, new_encoded.length); 151 encoded = new_encoded; 152 } 153 154 /** 155 * {@code Type} enumerates the supported key types. 156 */ 157 public static enum Type { 158 /** 159 * Type for secret keys. 160 */ 161 SECRET, 162 /** 163 * Type for public keys. 164 */ 165 PUBLIC, 166 /** 167 * Type for private keys. 168 */ 169 PRIVATE 170 } 171 } 172