001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.json.jose.jwe; 018 019import java.security.Key; 020 021import org.forgerock.json.jose.jwe.handlers.compression.CompressionHandler; 022import org.forgerock.json.jose.jwe.handlers.encryption.EncryptionHandler; 023import org.forgerock.json.jose.jwt.Jwt; 024import org.forgerock.json.jose.jwt.JwtClaimsSet; 025import org.forgerock.json.jose.jwt.JwtHeader; 026import org.forgerock.json.jose.jwt.Payload; 027import org.forgerock.json.jose.utils.Utils; 028import org.forgerock.util.encode.Base64url; 029 030/** 031 * A JWE implementation of the <tt>Jwt</tt> interface. 032 * <p> 033 * JSON Web Encryption (JWE) is a representing encrypted content using JSON based data structures. 034 * <p> 035 * @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-11"> 036 * JSON Web Encryption Specification</a> 037 * 038 * @since 2.0.0 039 */ 040public class EncryptedJwt implements Jwt, Payload { 041 042 private final EncryptionManager encryptionManager = new EncryptionManager(); 043 private final CompressionManager compressionManager = new CompressionManager(); 044 045 private final JweHeader header; 046 047 private JwtClaimsSet claimsSet; 048 private final Key publicKey; 049 050 private final String encodedHeader; 051 private final byte[] encryptedContentEncryptionKey; 052 private final byte[] initialisationVector; 053 private final byte[] ciphertext; 054 private final byte[] authenticationTag; 055 056 /** 057 * Constructs a fresh, new EncryptedJwt from the given JweHeader and JwtClaimsSet. 058 * <p> 059 * The specified public key will be used to perform the encryption of the JWT. 060 * 061 * @param header The JweHeader containing the header parameters of the JWE. 062 * @param claimsSet The JwtClaimsSet containing the claims of the JWE. 063 * @param publicKey The public key to use to perform the encryption. 064 */ 065 public EncryptedJwt(JweHeader header, JwtClaimsSet claimsSet, Key publicKey) { 066 this.header = header; 067 this.claimsSet = claimsSet; 068 this.publicKey = publicKey; 069 070 this.encodedHeader = null; 071 this.encryptedContentEncryptionKey = null; 072 this.initialisationVector = null; 073 this.ciphertext = null; 074 this.authenticationTag = null; 075 } 076 077 /** 078 * Constructs a reconstructed EncryptedJwt from its constituent parts, the JweHeader, encrypted Content Encryption 079 * Key (CEK), initialisation vector, ciphertext and additional authentication data. 080 * <p> 081 * For use when an encrypted JWT has been reconstructed from its base64url encoded string representation and the 082 * JWT needs decrypting. 083 * 084 * @param header The JweHeader containing the header parameters of the JWE. 085 * @param encodedHeader The Base64url encoded JWE header. 086 * @param encryptedContentEncryptionKey The encrypted Content Encryption Key (CEK). 087 * @param initialisationVector The initialisation vector. 088 * @param ciphertext The ciphertext. 089 * @param authenticationTag The authentication tag. 090 */ 091 public EncryptedJwt(JweHeader header, String encodedHeader, byte[] encryptedContentEncryptionKey, 092 byte[] initialisationVector, byte[] ciphertext, byte[] authenticationTag) { 093 this.header = header; 094 this.encodedHeader = encodedHeader; 095 this.encryptedContentEncryptionKey = encryptedContentEncryptionKey; 096 this.initialisationVector = initialisationVector; 097 this.ciphertext = ciphertext; 098 this.authenticationTag = authenticationTag; 099 100 this.publicKey = null; 101 } 102 103 /** 104 * {@inheritDoc} 105 */ 106 @Override 107 public JwtHeader getHeader() { 108 return header; 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override 115 public JwtClaimsSet getClaimsSet() { 116 return claimsSet; 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 public String build() { 124 125 EncryptionHandler encryptionHandler = encryptionManager.getEncryptionHandler(header); 126 127 Key contentEncryptionKey = encryptionHandler.getContentEncryptionKey(); 128 byte[] encryptedContentEncryptionKey = encryptionHandler.generateJWEEncryptedKey(publicKey, 129 contentEncryptionKey); 130 String encodedEncryptedKey = Base64url.encode(encryptedContentEncryptionKey); 131 132 133 byte[] initialisationVector = encryptionHandler.generateInitialisationVector(); 134 String encodedInitialisationVector = Base64url.encode(initialisationVector); 135 136 137 String jweHeader = header.build(); 138 String encodedJweHeader = Utils.base64urlEncode(jweHeader); 139 byte[] plaintext = compressPlaintext(header.getCompressionAlgorithm(), 140 claimsSet.build().getBytes(Utils.CHARSET)); 141 byte[] additionalAuthenticatedData = encodedJweHeader.getBytes(Utils.CHARSET); 142 JweEncryption cipherTextAndAuthTag = encryptionHandler.encryptPlaintext(contentEncryptionKey, 143 initialisationVector, plaintext, additionalAuthenticatedData); 144 145 String encodedCiphertext = Base64url.encode(cipherTextAndAuthTag.getCiphertext()); 146 String encodedAuthenticationTag = Base64url.encode(cipherTextAndAuthTag.getAuthenticationTag()); 147 148 149 return new StringBuilder(encodedJweHeader) 150 .append(".").append(encodedEncryptedKey) 151 .append(".").append(encodedInitialisationVector) 152 .append(".").append(encodedCiphertext) 153 .append(".").append(encodedAuthenticationTag) 154 .toString(); 155 } 156 157 /** 158 * Performs the compression of the plaintext, if required. 159 * <p> 160 * Whether or not compression is applied is based from the CompressionAlgorithm specified. 161 * 162 * @param compressionAlgorithm The CompressionAlgorithm describing the algorithm to use to compress the plaintext. 163 * @param plaintext The plaintext. 164 * @return A byte array of the (compressed) plaintext. 165 */ 166 private byte[] compressPlaintext(CompressionAlgorithm compressionAlgorithm, byte[] plaintext) { 167 CompressionHandler compressionHandler = compressionManager.getCompressionHandler(compressionAlgorithm); 168 return compressionHandler.compress(plaintext); 169 } 170 171 /** 172 * Decrypts the JWE ciphertext back into a JwtClaimsSet. 173 * <p> 174 * The same private key must be given here that is the pair to the public key that was used to encrypt the JWT. 175 * 176 * @param privateKey The private key pair to the public key that encrypted the JWT. 177 */ 178 public void decrypt(Key privateKey) { 179 180 EncryptionHandler encryptionHandler = encryptionManager.getEncryptionHandler(header); 181 182 Key contentEncryptionKey = encryptionHandler.decryptContentEncryptionKey(privateKey, 183 encryptedContentEncryptionKey); 184 185 byte[] additionalAuthenticatedData = encodedHeader.getBytes(Utils.CHARSET); 186 187 byte[] plaintext = encryptionHandler.decryptCiphertext(contentEncryptionKey, initialisationVector, ciphertext, 188 authenticationTag, additionalAuthenticatedData); 189 190 String claimsSetString = new String(plaintext, Utils.CHARSET); 191 192 claimsSet = new JwtClaimsSet(Utils.parseJson(claimsSetString)); 193 } 194}