001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.crypto.impl;
019
020
021import javax.crypto.SecretKey;
022import javax.crypto.spec.SecretKeySpec;
023
024import com.nimbusds.jose.KeyLengthException;
025import net.jcip.annotations.Immutable;
026
027
028/**
029 * Composite key used in AES/CBC/PKCS5Padding/HMAC-SHA2 encryption. This class
030 * is immutable.
031 *
032 * <p>See RFC 7518 (JWA), section 5.2.
033 *
034 * <p>See draft-mcgrew-aead-aes-cbc-hmac-sha2-01
035 *
036 * @author Vladimir Dzhuvinov
037 * @version 2015-06-29
038 */
039@Immutable
040public final class CompositeKey {
041
042
043        /**
044         * The input key.
045         */
046        private final SecretKey inputKey;
047
048
049        /**
050         * The extracted MAC key.
051         */
052        private final SecretKey macKey;
053
054
055        /**
056         * The extracted AES key.
057         */
058        private final SecretKey encKey;
059
060
061        /**
062         * The expected truncated MAC output length.
063         */
064        private final int truncatedMacLength;
065
066
067        /**
068         * Creates a new composite key from the specified secret key.
069         *
070         * @param inputKey The input key. Must be 256, 384 or 512 bits long.
071         *                 Must not be {@code null}.
072         *
073         * @throws KeyLengthException If the input key length is not supported.
074         */
075        public CompositeKey(final SecretKey inputKey)
076                throws KeyLengthException {
077
078                this.inputKey = inputKey;
079
080                byte[] secretKeyBytes = inputKey.getEncoded();
081
082                if (secretKeyBytes.length == 32) {
083
084                        // AES_128_CBC_HMAC_SHA_256
085                        // 256 bit key -> 128 bit MAC key + 128 bit AES key
086                        macKey = new SecretKeySpec(secretKeyBytes, 0, 16, "HMACSHA256");
087                        encKey = new SecretKeySpec(secretKeyBytes, 16, 16, "AES");
088                        truncatedMacLength = 16;
089
090                } else if (secretKeyBytes.length == 48) {
091
092                        // AES_192_CBC_HMAC_SHA_384
093                        // 384 bit key -> 129 bit MAC key + 192 bit AES key
094                        macKey = new SecretKeySpec(secretKeyBytes, 0, 24, "HMACSHA384");
095                        encKey = new SecretKeySpec(secretKeyBytes, 24, 24, "AES");
096                        truncatedMacLength = 24;
097
098
099                } else if (secretKeyBytes.length == 64) {
100
101                        // AES_256_CBC_HMAC_SHA_512
102                        // 512 bit key -> 256 bit MAC key + 256 bit AES key
103                        macKey = new SecretKeySpec(secretKeyBytes, 0, 32, "HMACSHA512");
104                        encKey = new SecretKeySpec(secretKeyBytes, 32, 32, "AES");
105                        truncatedMacLength = 32;
106
107                } else {
108
109                        throw new KeyLengthException("Unsupported AES/CBC/PKCS5Padding/HMAC-SHA2 key length, must be 256, 384 or 512 bits");
110                }
111        }
112
113
114        /**
115         * Gets the input key.
116         *
117         * @return The input key.
118         */
119        public SecretKey getInputKey() {
120
121                return inputKey;
122        }
123
124
125        /**
126         * Gets the extracted MAC key.
127         *
128         * @return The extracted MAC key.
129         */
130        public SecretKey getMACKey() {
131
132                return macKey;
133        }
134
135
136        /**
137         * Gets the expected truncated MAC length.
138         *
139         * @return The expected truncated MAC length, in bytes.
140         */
141        public int getTruncatedMACByteLength() {
142
143                return truncatedMacLength;
144        }
145
146
147        /**
148         * Gets the extracted encryption key.
149         *
150         * @return The extracted encryption key.
151         */
152        public SecretKey getAESKey() {
153
154                return encKey;
155        }
156}