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 java.security.Provider;
022import javax.crypto.SecretKey;
023import javax.crypto.spec.SecretKeySpec;
024
025import com.nimbusds.jose.JOSEException;
026import com.nimbusds.jose.KeyLengthException;
027import com.nimbusds.jose.util.ByteUtils;
028import com.nimbusds.jose.util.Container;
029import net.jcip.annotations.ThreadSafe;
030
031
032/**
033 * AES GCM methods for Content Encryption Key (CEK) encryption and
034 * decryption. This class is thread-safe.
035 *
036 * <p>See RFC 7518 (JWA), section 4.7.
037 *
038 * @author Melisa Halsband
039 * @author Vladimir Dzhuvinov
040 * @version 2017-06-01
041 */
042@ThreadSafe
043public class AESGCMKW {
044
045
046        /**
047         * Encrypts the specified Content Encryption Key (CEK).
048         *
049         * @param cek      The Content Encryption Key (CEK) to encrypt. Must
050         *                 not be {@code null}.
051         * @param iv       The initialisation vector (IV). Must not be
052         *                 {@code null}. The contained IV must not be
053         *                 {@code null} either.
054         * @param kek      The AES Key Encryption Key (KEK). Must not be
055         *                 {@code null}.
056         * @param provider The specific JCA provider to use, {@code null}
057         *                 implies the default system one.
058         *
059         * @return The encrypted Content Encryption Key (CEK).
060         *
061         * @throws JOSEException If encryption failed.
062         */
063        public static AuthenticatedCipherText encryptCEK(final SecretKey cek,
064                                                         final Container<byte[]> iv,
065                                                         final SecretKey kek,
066                                                         Provider provider)
067                throws JOSEException {
068
069                return AESGCM.encrypt(kek, iv, cek.getEncoded(), new byte[0], provider);
070        }
071
072
073        /**
074         * Decrypts the specified encrypted Content Encryption Key (CEK).
075         *
076         * @param kek          The AES Key Encription Key. Must not be
077         *                     {@code null}.
078         * @param iv           The initialisation vector (IV). Must not be
079         *                     {@code null}.
080         * @param authEncrCEK  The encrypted Content Encryption Key (CEK) to
081         *                     decrypt and authentication tag. Must not be
082         *                     {@code null}.
083         * @param provider     The JCA provider, or {@code null} to use the
084         *                     default one.
085         *
086         * @return The decrypted Content Encryption Key (CEK).
087         *
088         * @throws JOSEException If decryption failed.
089         */
090        public static SecretKey decryptCEK(final SecretKey kek,
091                                           final byte[] iv,
092                                           final AuthenticatedCipherText authEncrCEK,
093                                           final int keyLength,
094                                           final Provider provider)
095                throws JOSEException {
096
097                byte[] keyBytes = AESGCM.decrypt(kek, iv, authEncrCEK.getCipherText(), new byte[0], authEncrCEK.getAuthenticationTag(), provider);
098
099                if (ByteUtils.safeBitLength(keyBytes) != keyLength) {
100
101                        throw new KeyLengthException("CEK key length mismatch: " + ByteUtils.safeBitLength(keyBytes) + " != " + keyLength);
102                }
103
104                return new SecretKeySpec(keyBytes, "AES");
105        }
106
107
108        /**
109         * Prevents public instantiation.
110         */
111        private AESGCMKW() { }
112}