001package com.nimbusds.jose.crypto; 002 003 004import java.util.Set; 005import javax.crypto.SecretKey; 006 007import com.nimbusds.jose.*; 008import com.nimbusds.jose.util.Base64URL; 009import com.nimbusds.jose.util.StandardCharset; 010import net.jcip.annotations.ThreadSafe; 011 012 013/** 014 * Password-based decrypter of {@link com.nimbusds.jose.JWEObject JWE objects}. 015 * Expects a password. 016 * 017 * <p>See RFC 7518 018 * <a href="https://tools.ietf.org/html/rfc7518#section-4.8">section 4.8</a> 019 * for more information. 020 * 021 * <p>This class is thread-safe. 022 * 023 * <p>Supports the following key management algorithms: 024 * 025 * <ul> 026 * <li>{@link com.nimbusds.jose.JWEAlgorithm#PBES2_HS256_A128KW} 027 * <li>{@link com.nimbusds.jose.JWEAlgorithm#PBES2_HS384_A192KW} 028 * <li>{@link com.nimbusds.jose.JWEAlgorithm#PBES2_HS512_A256KW} 029 * </ul> 030 * 031 * <p>Supports the following content encryption algorithms: 032 * 033 * <ul> 034 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 035 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 036 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 037 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 038 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 039 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 040 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 041 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 042 * </ul> 043 * 044 * @author Vladimir Dzhuvinov 045 * @version 2016-07-26 046 */ 047@ThreadSafe 048public class PasswordBasedDecrypter extends PasswordBasedCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware { 049 050 051 /** 052 * The critical header policy. 053 */ 054 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 055 056 057 /** 058 * Creates a new password-based decrypter. 059 * 060 * @param password The password bytes. Must not be empty or 061 * {@code null}. 062 */ 063 public PasswordBasedDecrypter(final byte[] password) { 064 065 super(password); 066 } 067 068 069 /** 070 * Creates a new password-based decrypter. 071 * 072 * @param password The password, as a UTF-8 encoded string. Must not be 073 * empty or {@code null}. 074 */ 075 public PasswordBasedDecrypter(final String password) { 076 077 super(password.getBytes(StandardCharset.UTF_8)); 078 } 079 080 081 @Override 082 public Set<String> getProcessedCriticalHeaderParams() { 083 084 return critPolicy.getProcessedCriticalHeaderParams(); 085 } 086 087 088 @Override 089 public Set<String> getDeferredCriticalHeaderParams() { 090 091 return critPolicy.getProcessedCriticalHeaderParams(); 092 } 093 094 095 @Override 096 public byte[] decrypt(final JWEHeader header, 097 final Base64URL encryptedKey, 098 final Base64URL iv, 099 final Base64URL cipherText, 100 final Base64URL authTag) 101 throws JOSEException { 102 103 // Validate required JWE parts 104 if (encryptedKey == null) { 105 throw new JOSEException("Missing JWE encrypted key"); 106 } 107 108 if (iv == null) { 109 throw new JOSEException("Missing JWE initialization vector (IV)"); 110 } 111 112 if (authTag == null) { 113 throw new JOSEException("Missing JWE authentication tag"); 114 } 115 116 if (header.getPBES2Salt() == null) { 117 throw new JOSEException("Missing JWE \"p2s\" header parameter"); 118 } 119 120 final byte[] salt = header.getPBES2Salt().decode(); 121 122 if (header.getPBES2Count() < 1) { 123 throw new JOSEException("Missing JWE \"p2c\" header parameter"); 124 } 125 126 final int iterationCount = header.getPBES2Count(); 127 128 critPolicy.ensureHeaderPasses(header); 129 130 final JWEAlgorithm alg = header.getAlgorithm(); 131 final byte[] formattedSalt = PBKDF2.formatSalt(alg, salt); 132 final PRFParams prfParams = PRFParams.resolve(alg, getJCAContext().getMACProvider()); 133 final SecretKey psKey = PBKDF2.deriveKey(getPassword(), formattedSalt, iterationCount, prfParams); 134 135 final SecretKey cek = AESKW.unwrapCEK(psKey, encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider()); 136 137 return ContentCryptoProvider.decrypt(header, encryptedKey, iv, cipherText, authTag, cek, getJCAContext()); 138 } 139}