1 /* 2 * Copyright (c) 2003, 2019, 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 java.security; 27 28 import java.io.*; 29 import java.util.Locale; 30 31 import java.security.spec.PKCS8EncodedKeySpec; 32 import java.security.spec.X509EncodedKeySpec; 33 import java.security.spec.InvalidKeySpecException; 34 35 import javax.crypto.SecretKeyFactory; 36 import javax.crypto.spec.SecretKeySpec; 37 38 /** 39 * Standardized representation for serialized Key objects. 40 * 41 * <p> 42 * 43 * Note that a serialized Key may contain sensitive information 44 * which should not be exposed in untrusted environments. See the 45 * <a href="{@docRoot}/../specs/serialization/security.html"> 46 * Security Appendix</a> 47 * of the Serialization Specification for more information. 48 * 49 * @see Key 50 * @see KeyFactory 51 * @see javax.crypto.spec.SecretKeySpec 52 * @see java.security.spec.X509EncodedKeySpec 53 * @see java.security.spec.PKCS8EncodedKeySpec 54 * 55 * @since 1.5 56 */ 57 58 public class KeyRep implements Serializable { 59 60 @java.io.Serial 61 private static final long serialVersionUID = -4757683898830641853L; 62 63 /** 64 * Key type. 65 * 66 * @since 1.5 67 */ 68 public static enum Type { 69 70 /** Type for secret keys. */ 71 SECRET, 72 73 /** Type for public keys. */ 74 PUBLIC, 75 76 /** Type for private keys. */ 77 PRIVATE, 78 79 } 80 81 private static final String PKCS8 = "PKCS#8"; 82 private static final String X509 = "X.509"; 83 private static final String RAW = "RAW"; 84 85 /** 86 * Either one of Type.SECRET, Type.PUBLIC, or Type.PRIVATE 87 * 88 * @serial 89 */ 90 private Type type; 91 92 /** 93 * The Key algorithm 94 * 95 * @serial 96 */ 97 private String algorithm; 98 99 /** 100 * The Key encoding format 101 * 102 * @serial 103 */ 104 private String format; 105 106 /** 107 * The encoded Key bytes 108 * 109 * @serial 110 */ 111 private byte[] encoded; 112 113 /** 114 * Construct the alternate Key class. 115 * 116 * @param type either one of Type.SECRET, Type.PUBLIC, or Type.PRIVATE 117 * @param algorithm the algorithm returned from 118 * {@code Key.getAlgorithm()} 119 * @param format the encoding format returned from 120 * {@code Key.getFormat()} 121 * @param encoded the encoded bytes returned from 122 * {@code Key.getEncoded()} 123 * 124 * @throws NullPointerException 125 * if type is {@code null}, 126 * if algorithm is {@code null}, 127 * if format is {@code null}, 128 * or if encoded is {@code null} 129 */ 130 public KeyRep(Type type, String algorithm, 131 String format, byte[] encoded) { 132 133 if (type == null || algorithm == null || 134 format == null || encoded == null) { 135 throw new NullPointerException("invalid null input(s)"); 136 } 137 138 this.type = type; 139 this.algorithm = algorithm; 140 this.format = format.toUpperCase(Locale.ENGLISH); 141 this.encoded = encoded.clone(); 142 } 143 144 /** 145 * Resolve the Key object. 146 * 147 * <p> This method supports three Type/format combinations: 148 * <ul> 149 * <li> Type.SECRET/"RAW" - returns a SecretKeySpec object 150 * constructed using encoded key bytes and algorithm 151 * <li> Type.PUBLIC/"X.509" - gets a KeyFactory instance for 152 * the key algorithm, constructs an X509EncodedKeySpec with the 153 * encoded key bytes, and generates a public key from the spec 154 * <li> Type.PRIVATE/"PKCS#8" - gets a KeyFactory instance for 155 * the key algorithm, constructs a PKCS8EncodedKeySpec with the 156 * encoded key bytes, and generates a private key from the spec 157 * </ul> 158 * 159 * @return the resolved Key object 160 * 161 * @throws ObjectStreamException if the Type/format 162 * combination is unrecognized, if the algorithm, key format, or 163 * encoded key bytes are unrecognized/invalid, of if the 164 * resolution of the key fails for any reason 165 */ 166 @java.io.Serial 167 protected Object readResolve() throws ObjectStreamException { 168 try { 169 if (type == Type.SECRET && RAW.equals(format)) { 170 return new SecretKeySpec(encoded, algorithm); 171 } else if (type == Type.PUBLIC && X509.equals(format)) { 172 KeyFactory f = KeyFactory.getInstance(algorithm); 173 return f.generatePublic(new X509EncodedKeySpec(encoded)); 174 } else if (type == Type.PRIVATE && PKCS8.equals(format)) { 175 KeyFactory f = KeyFactory.getInstance(algorithm); 176 return f.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 177 } else { 178 throw new NotSerializableException 179 ("unrecognized type/format combination: " + 180 type + "/" + format); 181 } 182 } catch (NotSerializableException nse) { 183 throw nse; 184 } catch (Exception e) { 185 NotSerializableException nse = new NotSerializableException 186 ("java.security.Key: " + 187 "[" + type + "] " + 188 "[" + algorithm + "] " + 189 "[" + format + "]"); 190 nse.initCause(e); 191 throw nse; 192 } 193 } 194 }