001package com.nimbusds.jose.crypto; 002 003 004import javax.crypto.SecretKey; 005 006import com.nimbusds.jose.DefaultJWEHeaderFilter; 007import com.nimbusds.jose.EncryptionMethod; 008import com.nimbusds.jose.JOSEException; 009import com.nimbusds.jose.JWEAlgorithm; 010import com.nimbusds.jose.JWEDecrypter; 011import com.nimbusds.jose.JWEHeaderFilter; 012import com.nimbusds.jose.ReadOnlyJWEHeader; 013import com.nimbusds.jose.util.Base64URL; 014import com.nimbusds.jose.util.StringUtils; 015 016 017/** 018 * Direct decrypter of {@link com.nimbusds.jose.JWEObject JWE objects} with a 019 * shared symmetric key. This class is thread-safe. 020 * 021 * <p>Supports the following JWE algorithms: 022 * 023 * <ul> 024 * <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR} 025 * </ul> 026 * 027 * <p>Supports the following encryption methods: 028 * 029 * <ul> 030 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 031 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 032 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 033 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 034 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 035 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 036 * </ul> 037 * 038 * <p>Accepts all {@link com.nimbusds.jose.JWEHeader#getRegisteredParameterNames 039 * registered JWE header parameters}. Modify the {@link #getJWEHeaderFilter 040 * header filter} properties to restrict the acceptable JWE algorithms, 041 * encryption methods and header parameters, or to allow custom JWE header 042 * parameters. 043 * 044 * @author Vladimir Dzhuvinov 045 * @version $version$ (2014-01-28) 046 */ 047public class DirectDecrypter extends DirectCryptoProvider implements JWEDecrypter { 048 049 050 /** 051 * The JWE header filter. 052 */ 053 private final DefaultJWEHeaderFilter headerFilter; 054 055 056 /** 057 * Creates a new direct decrypter. 058 * 059 * @param key The shared symmetric key. Its algorithm must be "AES". 060 * Must be 128 bits (16 bytes), 256 bits (32 bytes) or 512 061 * bits (64 bytes) long. Must not be {@code null}. 062 * 063 * @throws JOSEException If the key length is unexpected. 064 */ 065 public DirectDecrypter(final SecretKey key) 066 throws JOSEException { 067 068 super(key); 069 070 headerFilter = new DefaultJWEHeaderFilter(supportedAlgorithms(), supportedEncryptionMethods()); 071 } 072 073 074 /** 075 * Creates a new direct decrypter. 076 * 077 * @param keyBytes The shared symmetric key, as a byte array. Must be 078 * 128 bits (16 bytes), 256 bits (32 bytes) or 512 bits 079 * (64 bytes) long. Must not be {@code null}. 080 * 081 * @throws JOSEException If the key length is unexpected. 082 */ 083 public DirectDecrypter(final byte[] keyBytes) 084 throws JOSEException { 085 086 super(keyBytes); 087 088 headerFilter = new DefaultJWEHeaderFilter(supportedAlgorithms(), supportedEncryptionMethods()); 089 } 090 091 092 @Override 093 public JWEHeaderFilter getJWEHeaderFilter() { 094 095 return headerFilter; 096 } 097 098 099 @Override 100 public byte[] decrypt(final ReadOnlyJWEHeader readOnlyJWEHeader, 101 final Base64URL encryptedKey, 102 final Base64URL iv, 103 final Base64URL cipherText, 104 final Base64URL authTag) 105 throws JOSEException { 106 107 // Validate required JWE parts 108 if (encryptedKey != null) { 109 110 throw new JOSEException("Unexpected encrypted key, must be omitted"); 111 } 112 113 if (iv == null) { 114 115 throw new JOSEException("The initialization vector (IV) must not be null"); 116 } 117 118 if (authTag == null) { 119 120 throw new JOSEException("The authentication tag must not be null"); 121 } 122 123 124 JWEAlgorithm alg = readOnlyJWEHeader.getAlgorithm(); 125 126 if (! alg.equals(JWEAlgorithm.DIR)) { 127 128 throw new JOSEException("Unsupported algorithm, must be \"dir\""); 129 } 130 131 // Compose the AAD 132 byte[] aad = StringUtils.toByteArray(readOnlyJWEHeader.toBase64URL().toString()); 133 134 // Decrypt the cipher text according to the JWE enc 135 EncryptionMethod enc = readOnlyJWEHeader.getEncryptionMethod(); 136 137 byte[] plainText; 138 139 if (enc.equals(EncryptionMethod.A128CBC_HS256) || enc.equals(EncryptionMethod.A192CBC_HS384) || enc.equals(EncryptionMethod.A256CBC_HS512)) { 140 141 plainText = AESCBC.decryptAuthenticated(getKey(), iv.decode(), cipherText.decode(), aad, authTag.decode(), contentEncryptionProvider, macProvider); 142 143 } else if (enc.equals(EncryptionMethod.A128GCM) || enc.equals(EncryptionMethod.A192GCM) || enc.equals(EncryptionMethod.A256GCM)) { 144 145 plainText = AESGCM.decrypt(getKey(), iv.decode(), cipherText.decode(), aad, authTag.decode(), contentEncryptionProvider); 146 147 } else { 148 149 throw new JOSEException("Unsupported encryption method, must be A128CBC_HS256, A192CBC_HS384, A256CBC_HS512, A128GCM, A192GCM or A128GCM"); 150 } 151 152 153 // Apply decompression if requested 154 return DeflateHelper.applyDecompression(readOnlyJWEHeader, plainText); 155 } 156} 157