// 
// Decompiled by Procyon v0.6.0
// 

package com.nimbusds.jose.crypto.impl;

import java.util.Collections;
import java.util.LinkedHashSet;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jose.JWECryptoParts;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JOSEException;
import java.util.Collection;
import javax.crypto.SecretKey;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import java.util.Set;

public abstract class ECDH1PUCryptoProvider extends BaseJWEProvider
{
    public static final Set<JWEAlgorithm> SUPPORTED_ALGORITHMS;
    public static final Set<EncryptionMethod> SUPPORTED_ENCRYPTION_METHODS;
    private final Curve curve;
    private final ConcatKDF concatKDF;
    
    protected ECDH1PUCryptoProvider(final Curve curve, final SecretKey cek) throws JOSEException {
        super(ECDH1PUCryptoProvider.SUPPORTED_ALGORITHMS, ContentCryptoProvider.SUPPORTED_ENCRYPTION_METHODS, cek);
        final Curve definedCurve = (curve != null) ? curve : new Curve("unknown");
        if (!this.supportedEllipticCurves().contains(curve)) {
            throw new JOSEException(AlgorithmSupportMessage.unsupportedEllipticCurve(definedCurve, this.supportedEllipticCurves()));
        }
        this.curve = curve;
        this.concatKDF = new ConcatKDF("SHA-256");
    }
    
    protected ConcatKDF getConcatKDF() {
        return this.concatKDF;
    }
    
    public abstract Set<Curve> supportedEllipticCurves();
    
    public Curve getCurve() {
        return this.curve;
    }
    
    protected JWECryptoParts encryptWithZ(final JWEHeader header, final SecretKey Z, final byte[] clearText, final byte[] aad) throws JOSEException {
        final JWEAlgorithm alg = JWEHeaderValidation.getAlgorithmAndEnsureNotNull(header);
        final ECDH.AlgorithmMode algMode = ECDH1PU.resolveAlgorithmMode(alg);
        final EncryptionMethod enc = header.getEncryptionMethod();
        if (algMode.equals(ECDH.AlgorithmMode.DIRECT)) {
            if (this.isCEKProvided()) {
                throw new JOSEException("The provided CEK is not supported");
            }
            this.getConcatKDF().getJCAContext().setProvider(this.getJCAContext().getMACProvider());
            final SecretKey cek = ECDH1PU.deriveSharedKey(header, Z, this.getConcatKDF());
            return ContentCryptoProvider.encrypt(header, clearText, aad, cek, null, this.getJCAContext());
        }
        else {
            if (!algMode.equals(ECDH.AlgorithmMode.KW)) {
                throw new JOSEException("Unexpected JWE ECDH algorithm mode: " + algMode);
            }
            if (!EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) {
                throw new JOSEException(AlgorithmSupportMessage.unsupportedEncryptionMethod(header.getEncryptionMethod(), EncryptionMethod.Family.AES_CBC_HMAC_SHA));
            }
            final SecretKey cek = this.getCEK(enc);
            final JWECryptoParts encrypted = ContentCryptoProvider.encrypt(header, clearText, aad, cek, null, this.getJCAContext());
            final SecretKey sharedKey = ECDH1PU.deriveSharedKey(header, Z, encrypted.getAuthenticationTag(), this.getConcatKDF());
            final Base64URL encryptedKey = Base64URL.encode(AESKW.wrapCEK(cek, sharedKey, this.getJCAContext().getKeyEncryptionProvider()));
            return new JWECryptoParts(header, encryptedKey, encrypted.getInitializationVector(), encrypted.getCipherText(), encrypted.getAuthenticationTag());
        }
    }
    
    protected byte[] decryptWithZ(final JWEHeader header, final byte[] aad, final SecretKey Z, final Base64URL encryptedKey, final Base64URL iv, final Base64URL cipherText, final Base64URL authTag) throws JOSEException {
        final JWEAlgorithm alg = JWEHeaderValidation.getAlgorithmAndEnsureNotNull(header);
        final ECDH.AlgorithmMode algMode = ECDH1PU.resolveAlgorithmMode(alg);
        this.getConcatKDF().getJCAContext().setProvider(this.getJCAContext().getMACProvider());
        SecretKey cek;
        if (algMode.equals(ECDH.AlgorithmMode.DIRECT)) {
            cek = ECDH1PU.deriveSharedKey(header, Z, this.getConcatKDF());
        }
        else {
            if (!algMode.equals(ECDH.AlgorithmMode.KW)) {
                throw new JOSEException("Unexpected JWE ECDH algorithm mode: " + algMode);
            }
            if (encryptedKey == null) {
                throw new JOSEException("Missing JWE encrypted key");
            }
            final SecretKey sharedKey = ECDH1PU.deriveSharedKey(header, Z, authTag, this.getConcatKDF());
            cek = AESKW.unwrapCEK(sharedKey, encryptedKey.decode(), this.getJCAContext().getKeyEncryptionProvider());
        }
        return ContentCryptoProvider.decrypt(header, aad, null, iv, cipherText, authTag, cek, this.getJCAContext());
    }
    
    static {
        SUPPORTED_ENCRYPTION_METHODS = ContentCryptoProvider.SUPPORTED_ENCRYPTION_METHODS;
        final Set<JWEAlgorithm> algs = new LinkedHashSet<JWEAlgorithm>();
        algs.add(JWEAlgorithm.ECDH_1PU);
        algs.add(JWEAlgorithm.ECDH_1PU_A128KW);
        algs.add(JWEAlgorithm.ECDH_1PU_A192KW);
        algs.add(JWEAlgorithm.ECDH_1PU_A256KW);
        SUPPORTED_ALGORITHMS = Collections.unmodifiableSet((Set<? extends JWEAlgorithm>)algs);
    }
}
