• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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