PKISecurityHandler.java 17.7 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.internal.pdftoolkit.core.credentials.Credentials
 *  com.adobe.internal.pdftoolkit.core.exceptions.PDFSecurityAuthorizationException
 *  com.adobe.internal.pdftoolkit.core.exceptions.PDFSecurityConfigurationException
 *  com.adobe.internal.pdftoolkit.core.permissionprovider.PermissionProvider
 *  com.adobe.internal.pdftoolkit.core.permissionprovider.PermissionProviderStandard
 *  com.adobe.internal.pdftoolkit.core.securityframework.DecryptedState
 *  com.adobe.internal.pdftoolkit.core.securityframework.EncryptionHandler
 *  com.adobe.internal.pdftoolkit.core.securityframework.PKCS7EnvelopedDataHandler
 *  com.adobe.internal.pdftoolkit.core.securityframework.SecurityHandler
 *  com.adobe.internal.pdftoolkit.core.securityframework.impl.SecurityProvidersImpl
 *  com.adobe.internal.pdftoolkit.core.securityframework.pki.Identities
 */
package com.adobe.internal.pdftoolkit.core.encryption;

import com.adobe.internal.pdftoolkit.core.credentials.Credentials;
import com.adobe.internal.pdftoolkit.core.encryption.DecryptedStatePKI;
import com.adobe.internal.pdftoolkit.core.encryption.EncryptionKeyCalc;
import com.adobe.internal.pdftoolkit.core.encryption.EncryptionKeyImpl;
import com.adobe.internal.pdftoolkit.core.encryption.IdentityEncryptionHandler;
import com.adobe.internal.pdftoolkit.core.exceptions.PDFSecurityAuthorizationException;
import com.adobe.internal.pdftoolkit.core.exceptions.PDFSecurityConfigurationException;
import com.adobe.internal.pdftoolkit.core.permissionprovider.PermissionProvider;
import com.adobe.internal.pdftoolkit.core.permissionprovider.PermissionProviderStandard;
import com.adobe.internal.pdftoolkit.core.securityframework.DecryptedState;
import com.adobe.internal.pdftoolkit.core.securityframework.EncryptionHandler;
import com.adobe.internal.pdftoolkit.core.securityframework.PKCS7EnvelopedDataHandler;
import com.adobe.internal.pdftoolkit.core.securityframework.SecurityHandler;
import com.adobe.internal.pdftoolkit.core.securityframework.impl.SecurityProvidersImpl;
import com.adobe.internal.pdftoolkit.core.securityframework.pki.Identities;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class PKISecurityHandler
implements SecurityHandler {
    static final String RECIPIENTS = "Recipients";
    private DecryptedState decryptedState;
    private boolean decryptedUsingState;
    private int encryptDecryptedStatePerms = 3902;
    private byte[] mSeed = null;
    private Exception mFail = null;
    private Integer mPerms = null;
    private Credentials mRecipient = null;
    private Map mEncryptParams = null;
    private MessageDigest mSHADigest = null;
    private MessageDigest mMD5Digest = null;
    private SecurityProvidersImpl mProviders = null;
    private PKCS7EnvelopedDataHandler mPKCS7Handler = null;

    public PKISecurityHandler(Credentials recipient, SecurityProvidersImpl providers) {
        this.mRecipient = recipient;
        this.mProviders = providers;
        this.setPKCS7Handler();
    }

    public PKISecurityHandler(Map encryptParams, SecurityProvidersImpl providers) throws PDFSecurityConfigurationException {
        try {
            SecureRandom generator;
            this.mProviders = providers;
            SecureRandom secureRandom = generator = this.mProviders != null ? this.mProviders.getRandomGenerator() : null;
            if (generator == null) {
                Provider randomProvider = this.mProviders != null ? this.mProviders.requireSHA1PRNG() : null;
                generator = randomProvider == null ? SecureRandom.getInstance("SHA1PRNG") : SecureRandom.getInstance("SHA1PRNG", randomProvider);
            }
            this.mSeed = generator.generateSeed(20);
            this.mEncryptParams = encryptParams;
            this.setPKCS7Handler();
        }
        catch (NoSuchAlgorithmException e) {
            this.mFail = e;
        }
    }

    private void setPKCS7Handler() {
        if (this.mProviders != null) {
            this.mPKCS7Handler = this.mProviders.getPKCS7EnvelopedDataHandler();
        }
        if (this.mPKCS7Handler == null) {
            try {
                Class pkcs7Handler = Class.forName("com.adobe.internal.pdftoolkit.core.encryption.impl.PKCS7EnvelopedDataRSANonFIPSHandler");
                this.mPKCS7Handler = (PKCS7EnvelopedDataHandler)pkcs7Handler.newInstance();
            }
            catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            catch (InstantiationException e) {
                throw new RuntimeException(e);
            }
            catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public EncryptionHandler getEncryptionHandler(String cryptName, Map encryptParams, byte[] docId) throws PDFSecurityAuthorizationException, PDFSecurityConfigurationException {
        if (this.mFail != null) {
            throw new PDFSecurityConfigurationException("Failure to initialize Security handler", (Throwable)this.mFail);
        }
        if (cryptName.equals("Identity")) {
            return new IdentityEncryptionHandler();
        }
        int keyLength = EncryptionKeyCalc.calculateEncryptionKey(encryptParams, cryptName, 128);
        if (keyLength < 0) {
            throw new PDFSecurityConfigurationException("Encryption with key length greater than 56 is not supported");
        }
        if (keyLength == 0) {
            keyLength = 128;
        }
        this.initDigest(keyLength /= 8);
        byte[] encryptionKey = null;
        if (!this.decryptedUsingState) {
            byte[] seed = this.mSeed;
            if (seed == null) {
                if (this.mRecipient == null) {
                    throw new PDFSecurityAuthorizationException("Absent authorization credentials");
                }
                byte[] envelopedData = this.getEnvelopeData(cryptName, encryptParams, this.mRecipient);
                if (envelopedData == null || envelopedData.length < 20) {
                    throw new PDFSecurityConfigurationException("Failure to get enveloped data");
                }
                seed = envelopedData;
            } else {
                ArrayList recipients = null;
                Map cfDict = EncryptionKeyImpl.getCFDict(encryptParams);
                if (cfDict != null && (recipients = this.getRecipients(cfDict, (String)encryptParams.get("EFF"))) == null) {
                    recipients = this.getRecipients(cfDict, (String)encryptParams.get("StmF"));
                }
                if (recipients == null) {
                    recipients = (ArrayList)encryptParams.get("Recipients");
                }
                if (recipients == null) {
                    throw new PDFSecurityConfigurationException("Failure to find Recipients entry in the encryption parameters map");
                }
            }
            encryptionKey = this.createEncryptionKey(cryptName, encryptParams, keyLength, seed);
            this.decryptedState.setEncryptKey(cryptName, encryptionKey);
            this.decryptedState.setPerms(Integer.valueOf(this.encryptDecryptedStatePerms));
        } else {
            encryptionKey = this.decryptedState.getEncryptKey(cryptName);
        }
        String algorithm = EncryptionKeyImpl.getEncryptionAlgorithm(encryptParams, cryptName);
        return EncryptionKeyImpl.getEncryptionHandler(encryptionKey, algorithm, this.mMD5Digest, encryptParams, this.mProviders);
    }

    private void initDigest(int keyLength) throws PDFSecurityConfigurationException {
        try {
            if (this.mSHADigest == null) {
                Provider sha1Provider;
                Provider provider = sha1Provider = this.mProviders != null ? this.mProviders.requireSHA1() : null;
                if (keyLength <= 16) {
                    this.mSHADigest = sha1Provider == null ? MessageDigest.getInstance("SHA-1") : MessageDigest.getInstance("SHA-1", sha1Provider);
                } else {
                    MessageDigest messageDigest = this.mSHADigest = sha1Provider == null ? MessageDigest.getInstance("SHA-256") : MessageDigest.getInstance("SHA-256", sha1Provider);
                }
            }
            if (this.mMD5Digest == null) {
                Provider md5Provider = this.mProviders != null ? this.mProviders.requireMD5() : null;
                this.mMD5Digest = md5Provider == null ? MessageDigest.getInstance("MD5") : MessageDigest.getInstance("MD5", md5Provider);
            }
        }
        catch (NoSuchAlgorithmException e) {
            throw new PDFSecurityConfigurationException((Throwable)e);
        }
    }

    private byte[] createEncryptionKey(String cryptName, Map encryptParams, int keyLength, byte[] seed) {
        byte[] dataDigest;
        this.mSHADigest.update(seed, 0, 20);
        RecipientsIterator recipientsIterator = new RecipientsIterator(encryptParams, cryptName);
        while (recipientsIterator.hasNext()) {
            byte[] curRecipient = recipientsIterator.next();
            this.mSHADigest.update(curRecipient);
        }
        if (!EncryptionKeyImpl.toEncryptMetadata(encryptParams, cryptName)) {
            this.mSHADigest.update(EncryptionKeyImpl.defaultMetadataMark);
        }
        if (keyLength > (dataDigest = this.mSHADigest.digest()).length) {
            keyLength = dataDigest.length;
        }
        byte[] encryptionKey = new byte[keyLength];
        System.arraycopy(dataDigest, 0, encryptionKey, 0, keyLength);
        return encryptionKey;
    }

    public Map getEncryptParameters() {
        return this.mEncryptParams;
    }

    public boolean authenticate(Map params, byte[] docID) throws PDFSecurityAuthorizationException, PDFSecurityConfigurationException {
        this.decryptedState = new DecryptedStatePKI();
        EncryptionKeyImpl.verifyEncryptionVersion(params, false);
        this.mEncryptParams = params;
        if (this.mRecipient == null) {
            if (this.mFail != null) {
                throw new PDFSecurityConfigurationException("Failure to initialize Security handler", (Throwable)this.mFail);
            }
            if (this.mSeed == null) {
                return false;
            }
            return true;
        }
        String cryptName = null;
        Map cfDict = EncryptionKeyImpl.getCFDict(params);
        if (cfDict != null) {
            for (Map.Entry curCrypt : cfDict.entrySet()) {
                if (!((Map)curCrypt.getValue()).containsKey("AuthEvent")) {
                    cryptName = (String)curCrypt.getKey();
                    break;
                }
                String authEvent = (String)((Map)curCrypt.getValue()).get("AuthEvent");
                if (!"DocOpen".equals(authEvent)) continue;
                cryptName = (String)curCrypt.getKey();
                break;
            }
        }
        if (cryptName == null) {
            String subFilter = params.containsKey("SubFilter") ? params.get("SubFilter") : null;
            if (subFilter != null && subFilter.compareTo("adbe.pkcs7.s3") != 0 && subFilter.compareTo("adbe.pkcs7.s4") != 0) {
                cryptName = "DefEmbeddedFile";
            }
            this.calculateEncryptionKey(params, cryptName);
            return true;
        }
        return this.calculateEncryptionKey(params, cryptName);
    }

    private boolean calculateEncryptionKey(Map params, String cryptName) throws PDFSecurityAuthorizationException, PDFSecurityConfigurationException {
        byte[] envelopedData;
        String handlerName = (String)params.get("Filter");
        if (cryptName == null) {
            cryptName = (String)params.get("StmF");
            if (cryptName == null && params.containsKey("CF")) {
                cryptName = "Identity";
            }
            if (cryptName == null) {
                cryptName = handlerName;
            }
        }
        if ((envelopedData = this.getEnvelopeData(cryptName, params, this.mRecipient)) != null) {
            int keyLength;
            if (envelopedData.length == 24) {
                int perms = (envelopedData[20] & 255) << 24 | (envelopedData[21] & 255) << 16 | (envelopedData[22] & 255) << 8 | envelopedData[23] & 255;
                this.mPerms = perms;
            }
            if ((keyLength = EncryptionKeyCalc.calculateEncryptionKey(params, cryptName, 128)) < 0) {
                throw new PDFSecurityConfigurationException("Encryption with key length greater than 56 is not supported");
            }
            if (keyLength == 0) {
                keyLength = 128;
            }
            this.initDigest(keyLength /= 8);
            byte[] encKey = this.createEncryptionKey(cryptName, params, keyLength, envelopedData);
            this.decryptedState.setEncryptKey(cryptName, encKey);
            this.decryptedState.setPerms(this.mPerms);
            return true;
        }
        return false;
    }

    public PermissionProvider getPermissionProvider() {
        if (this.mPerms == null) {
            return new PermissionProviderStandard(0);
        }
        return new PermissionProviderStandard(this.mPerms.intValue());
    }

    MessageDigest getMD5Digest() {
        return this.mMD5Digest;
    }

    MessageDigest getSHA1Digest() {
        return this.mSHADigest;
    }

    private byte[] getEnvelopeData(String cryptName, Map encryptParams, Credentials recipient) throws PDFSecurityAuthorizationException, PDFSecurityConfigurationException {
        Exception excp = null;
        if (recipient == null) {
            return null;
        }
        String cryptFilter = cryptName == null ? (String)encryptParams.get("StmF") : cryptName;
        RecipientsIterator recipientsIter = new RecipientsIterator(encryptParams, cryptFilter);
        byte[] envelopedData = null;
        while (recipientsIter.hasNext()) {
            byte[] curRecipient = recipientsIter.next();
            try {
                envelopedData = this.mPKCS7Handler.getEnvelopeData(this.mRecipient, curRecipient);
                if (envelopedData == null) continue;
                excp = null;
                break;
            }
            catch (Exception e) {
                excp = e;
                continue;
            }
        }
        if (excp != null) {
            throw new PDFSecurityAuthorizationException((Throwable)excp);
        }
        if (envelopedData == null) {
            throw new PDFSecurityAuthorizationException("Recipient is not authorized");
        }
        return envelopedData;
    }

    public byte[] buildPKCS7(Identities identity, boolean inCrypt, Map encryptParams) throws Exception {
        byte[] envelope;
        if (!inCrypt) {
            PermissionProviderStandard encryptPerms = PermissionProviderStandard.newInstance((PermissionProvider)identity.getPermissions());
            envelope = new byte[24];
            System.arraycopy(this.mSeed, 0, envelope, 0, 20);
            int perms = encryptPerms.getPermissionBits();
            perms |= 1;
            for (int permsInd = 0; permsInd < 4; ++permsInd) {
                envelope[23 - permsInd] = (byte)(perms & 255);
                perms >>= 8;
            }
        } else {
            envelope = new byte[20];
            System.arraycopy(this.mSeed, 0, envelope, 0, 20);
        }
        Credentials[] credentials = identity.getCredentials();
        return this.mPKCS7Handler.buildPKCS7EnvelopedData(credentials, envelope, encryptParams);
    }

    private ArrayList getRecipients(Map cfDict, String stmCrypt) {
        Map stmDict;
        ArrayList recipients = null;
        if (stmCrypt != null && (stmDict = (Map)cfDict.get(stmCrypt)) != null) {
            Object curRecipients = stmDict.get("Recipients");
            if (curRecipients instanceof ArrayList) {
                recipients = (ArrayList)curRecipients;
            } else {
                recipients = new ArrayList();
                recipients.add(curRecipients);
            }
        }
        return recipients;
    }

    public boolean authenticate(Map params, byte[] docID, DecryptedState decryptedState) throws PDFSecurityConfigurationException, PDFSecurityAuthorizationException {
        if (decryptedState != null) {
            this.decryptedState = decryptedState;
            this.decryptedUsingState = true;
            EncryptionKeyImpl.verifyEncryptionVersion(params, false);
            this.mEncryptParams = params;
            this.mPerms = decryptedState.getPerms();
            return true;
        }
        return this.authenticate(params, docID);
    }

    public DecryptedState getDecryptedState() {
        return this.decryptedState;
    }

    static class RecipientsIterator {
        Iterator mIterator = null;
        byte[] mNext = null;

        RecipientsIterator(Map encryptParams, String cryptFilter) {
            Map strDict;
            Object recipients = encryptParams.get("Recipients");
            Map cfDict = EncryptionKeyImpl.getCFDict(encryptParams);
            if (cfDict != null && cryptFilter != null && (strDict = (Map)cfDict.get(cryptFilter)) != null && strDict.containsKey("Recipients")) {
                recipients = strDict.get("Recipients");
            }
            if (recipients instanceof ArrayList) {
                this.mIterator = ((ArrayList)recipients).iterator();
            } else {
                this.mNext = (byte[])recipients;
            }
        }

        boolean hasNext() {
            return this.mIterator != null ? this.mIterator.hasNext() : this.mNext != null;
        }

        byte[] next() {
            if (this.mIterator != null) {
                return (byte[])this.mIterator.next();
            }
            byte[] retNext = this.mNext;
            this.mNext = null;
            return retNext;
        }
    }

}