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