001package com.nimbusds.jose.jwk;
002
003
004import java.text.ParseException;
005
006import net.jcip.annotations.Immutable;
007import net.minidev.json.JSONObject;
008
009import com.nimbusds.jose.Algorithm;
010import com.nimbusds.jose.util.Base64URL;
011import com.nimbusds.jose.util.JSONObjectUtils;
012
013
014/**
015 * {@link KeyType#OCT Octet sequence} JSON Web Key (JWK), used to represent
016 * symmetric keys. This class is immutable.
017 *
018 * <p>Example JSON object representation of an octet sequence JWK:
019 *
020 * <pre>
021 * {
022 *   "kty" : "oct",
023 *   "alg" : "A128KW",
024 *   "k"   : "GawgguFyGrWKav7AX4VKUg"
025 * }
026 * </pre>
027 * 
028 * @author Justin Richer
029 * @author Vladimir Dzhuvinov
030 * @version $version$ (2013-03-26)
031 */
032@Immutable
033public class OctetSequenceKey extends JWK {
034
035
036        /**
037         * The symmetric key value.
038         */
039        private final Base64URL k;
040
041        
042        /**
043         * Creates a new octet sequence JSON Web Key (JWK) with the specified
044         * parameters.
045         *
046         * @param k   The key value. It is represented as the Base64URL 
047         *            encoding of value's big endian representation. Must not 
048         *            be {@code null}.
049         * @param use The key use. {@code null} if not specified.
050         * @param alg The intended JOSE algorithm for the key, {@code null} if
051         *            not specified.
052         * @param kid The key ID. {@code null} if not specified.
053         */
054        public OctetSequenceKey(final Base64URL k, final Use use, final Algorithm alg, final String kid) {
055        
056                super(KeyType.OCT, use, alg, kid);
057
058                if (k == null) {
059
060                        throw new IllegalArgumentException("The key value must not be null");
061                }
062
063                this.k = k;
064        }
065
066
067        /**
068         * Creates a new octet sequence JSON Web Key (JWK) with the specified
069         * parameters.
070         *
071         * @param k   The key value. It is represented as the value's big 
072         *            endian representation. Must not be {@code null}.
073         * @param use The key use. {@code null} if not specified.
074         * @param alg The intended JOSE algorithm for the key, {@code null} if
075         *            not specified.
076         * @param kid The key ID. {@code null} if not specified.
077         */
078        public OctetSequenceKey(final byte[] k, final Use use, final Algorithm alg, final String kid) {
079        
080                super(KeyType.OCT, use, alg, kid);
081
082                if (k == null) {
083
084                        throw new IllegalArgumentException("The key value must not be null");
085                }
086
087                this.k = Base64URL.encode(k);
088        }
089    
090
091        /**
092         * Returns the value of this octet sequence key. It is represented as 
093         * the Base64URL encoding of the coordinate's big endian 
094         * representation.
095         *
096         * @return The key value. 
097         */
098        public Base64URL getKeyValue() {
099
100                return k;
101        }
102        
103        
104        /**
105         * Returns a copy of this octet sequence key value as a byte array.
106         * 
107         * @return The key value as a byte array.
108         */
109        public byte[] toByteArray() {
110
111                return getKeyValue().decode();
112        }
113
114
115        /**
116         * Octet sequence (symmetric) keys are never considered public, this 
117         * method always returns {@code true}.
118         *
119         * @return {@code true}
120         */
121        @Override
122        public boolean isPrivate() {
123
124                return true;
125        }
126
127
128        /**
129         * Octet sequence (symmetric) keys are never considered public, this 
130         * method always returns {@code null}.
131         *
132         * @return {@code null}
133         */
134        @Override
135        public OctetSequenceKey toPublicJWK() {
136
137                return null;
138        }
139        
140
141        @Override
142        public JSONObject toJSONObject() {
143
144                JSONObject o = super.toJSONObject();
145
146                // Append key value
147                o.put("k", k.toString());
148                
149                return o;
150        }
151
152
153        /**
154         * Parses an octet sequence JWK from the specified JSON object string 
155         * representation.
156         *
157         * @param s The JSON object string to parse. Must not be {@code null}.
158         *
159         * @return The octet sequence JWK.
160         *
161         * @throws ParseException If the string couldn't be parsed to an octet
162         *                        sequence JWK.
163         */
164        public static OctetSequenceKey parse(final String s)
165                throws ParseException {
166
167                return parse(JSONObjectUtils.parseJSONObject(s));
168        }
169
170        
171        /**
172         * Parses an octet sequence JWK from the specified JSON object 
173         * representation.
174         *
175         * @param jsonObject The JSON object to parse. Must not be 
176         *                   @code null}.
177         *
178         * @return The octet sequence JWK.
179         *
180         * @throws ParseException If the JSON object couldn't be parsed to an
181         *                        octet sequence JWK.
182         */
183        public static OctetSequenceKey parse(final JSONObject jsonObject) 
184                throws ParseException {
185
186                // Parse the mandatory parameters first
187                Base64URL k = new Base64URL(JSONObjectUtils.getString(jsonObject, "k"));
188
189                // Check key type
190                KeyType kty = KeyType.parse(JSONObjectUtils.getString(jsonObject, "kty"));
191
192                if (kty != KeyType.OCT) {
193
194                        throw new ParseException("The key type \"kty\" must be oct", 0);
195                }
196                
197                // Get optional key use
198                Use use = JWK.parseKeyUse(jsonObject);
199
200                // Get optional intended algorithm
201                Algorithm alg = JWK.parseAlgorithm(jsonObject);
202
203                // Get optional key ID
204                String kid = JWK.parseKeyID(jsonObject);
205
206                return new OctetSequenceKey(k, use, alg, kid);
207        }
208}