All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.io.DecryptionFactory Maven / Gradle / Ivy

There is a newer version: 20151002
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2015 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * DecryptionFactory.java
 * ---------------
 */
package org.jpedal.io;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.BlockCipherPadding;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.jpedal.constants.PDFflags;
import org.jpedal.exception.PdfSecurityException;
import org.jpedal.objects.raw.PdfArrayIterator;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfKeyPairsIterator;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.ObjectCloneFactory;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.Map;

/**
 * Provide AES/RSA decryption support
 */
public class DecryptionFactory {

    private Map cachedObjects=new HashMap();

    /**flag to show if extraction allowed*/
    private boolean extractionIsAllowed = true;

    /**flag to show provider read*/
    private boolean isInitialised;

    private boolean isMetaDataEncypted=true;

    /**flag if password supplied*/
    private boolean isPasswordSupplied;

    private boolean stringsEncoded;

    /**flag to show data encrytped*/
    private boolean isEncrypted;

    /**key used for encryption*/
    private byte[] encryptionKey;

    /** revision used for encryption*/
    private int rev;

    /**P value in encryption*/
    private int P;

    /**O value in encryption*/
    private byte[] O;

    /**U value in encryption*/
    private byte[] U;

    /**additional 5 values*/
    private byte[] OE, Perms,UE;

    //SecOP java ME - removed to remove additional package secop1_0.jar in java ME
    /**cipher used for decryption*/
    Cipher cipher;

    //show if AES encryption
    private boolean isAES;

    private PdfObject StmFObj,StrFObj;

    @SuppressWarnings("CanBeFinal")
    private static boolean alwaysReinitCipher;

    static{
        final String flag=System.getProperty("org.jpedal.cipher.reinit");
        if(flag!=null && flag.equalsIgnoreCase("true")) {
            alwaysReinitCipher = true;
        }
    }

    /**encryption padding*/
    private final String[] pad={"28","BF","4E","5E","4E","75","8A","41","64","00","4E","56","FF","FA","01","08",
            "2E","2E","00","B6","D0","68","3E","80","2F","0C","A9","FE","64","53","69","7A"};

    private boolean isAESIdentity;

    /**length of encryption key used*/
    private int keyLength=5;

    /**flag to show if user can view file*/
    private boolean isFileViewable=true;

    //tell user status on password
    private int passwordStatus;

    /**holds file ID*/
    private final byte[] ID;


    /**encryption password*/
    private byte[] encryptionPassword;

    private Certificate certificate;

    private Key key;

    public DecryptionFactory(final byte[] ID, final byte[] encryptionPassword){
        this.ID=ID;
        this.encryptionPassword=encryptionPassword;
    }

    /**
     * version for using public certificates
     * @param id
     * @param certificate
     * @param key
     */
    public DecryptionFactory(final byte[] id, final Certificate certificate, final PrivateKey key) {
        this.ID=id;
        this.certificate=certificate;
        this.key=key;
    }

    /**see if valid for password*/
    private boolean testPassword() throws PdfSecurityException {

        int count=32;

        final byte[] rawValue=new byte[32];
        byte[] keyValue ;

        for(int i=0;i<32;i++) {
            rawValue[i] = (byte) Integer.parseInt(pad[i], 16);
        }

        byte[] encrypted= ObjectCloneFactory.cloneArray(rawValue);

        if (rev==2) {
            encryptionKey=calculateKey(O,P,ID);
            encrypted=decrypt(encrypted,"", true,null,false,false);

        } else if(rev>=3) {

            //use StmF values in preference
            int keyLength=this.keyLength;

//            if(rev==4 && StmFObj!=null){
//                final int lenKey=StmFObj.getInt(PdfDictionary.Length);
//                if(lenKey!=-1) {
//                    keyLength = lenKey;
//                    if(keyLength>32){
//                        keyLength = keyLength >>3;
//                    }
//                }
//            }

            count=16;
            encryptionKey=calculateKey(O,P,ID);
            final byte[] originalKey= ObjectCloneFactory.cloneArray(encryptionKey);

            MessageDigest md = null;
            try {
                md = MessageDigest.getInstance("MD5");
            } catch (final Exception e) {
                LogWriter.writeLog("Exception " + e + " with digest");
            }

            md.update(encrypted);

            //feed in ID
            keyValue = md.digest(ID);

            keyValue=decrypt(keyValue,"", true,null,true,false);

            final byte[] nextKey = new byte[keyLength];

            for (int i=1; i<=19; i++) {

                for (int j=0; j=3){
                for (int ii=0; ii<50; ii++) {
                    encryptionKey = md.digest(encryptionKey);
                }
            }

        }catch(final Exception e){
            throw new PdfSecurityException("Exception "+e+" generating encryption key");
        }
    }

    /**see if valid for password*/
    private boolean testOwnerPassword() throws PdfSecurityException{

        final byte[] originalPassword=encryptionPassword;

        byte[] userPasswd=new byte[keyLength];
        final byte[] inputValue= ObjectCloneFactory.cloneArray(O);

        
        computeEncryptionKey();

        final byte[] originalKey= ObjectCloneFactory.cloneArray(encryptionKey);

        if(rev==2){
            userPasswd=decrypt(ObjectCloneFactory.cloneArray(O),"", false,null,false,false);
        }else if(rev>=3){

            //use StmF values in preference
            final int keyLength=this.keyLength;
//            if(rev==4 && StmFObj!=null){
//                final int lenKey=StmFObj.getInt(PdfDictionary.Length);
//                if(lenKey!=-1) {
//                    keyLength = lenKey;
//                    if(keyLength>32){
//                        keyLength = keyLength >>3;
//                    }
//                }
//            }

            userPasswd=inputValue;
            final byte[] nextKey = new byte[keyLength];


            for (int i=19; i>=0; i--) {

                for (int j=0; j0) {
                    LogWriter.writeLog("Correct user password supplied ");
                }

                isFileViewable=true;
                isPasswordSupplied=true;

                if((P & 16)==16) {
                    extractionIsAllowed = true;
                }

            }else {
                throw new PdfSecurityException("No valid password supplied");
            }

        }else{
            LogWriter.writeLog("Correct owner password supplied");
            
            isFileViewable=true;
            isPasswordSupplied=true;
            extractionIsAllowed=true;
        }
    }

    /**
     * workout key from OE or UE
     */
    private static byte[] v5Decrypt(final byte[] rawValue, final byte[] key) throws PdfSecurityException {

        final int ELength= rawValue.length;
        final byte[] returnKey = new byte[ELength];
        
        try{

            //setup Cipher
            final BlockCipher cbc = new CBCBlockCipher(new AESFastEngine());
            cbc.init(false, new KeyParameter(key));

            //translate bytes
            int nextBlockSize;
            for(int i=0;i127) {
            passwordLength = 127;
        }

        /**
         * feed in values
         */
        final MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(password, 0, passwordLength);

        if(isOwner){
            md.update(O, offset, 8);
            md.update(U, 0, 48);
        }else {
            md.update(U, offset, 8);
        }

        return md.digest();
    }

    /**
     * routine to create a padded key
     */
    private byte[] getPaddedKey(final byte[] password, final byte[] encryptionPassword){

        /**get 32 bytes for  the key*/
        final byte[] key=new byte[32];
        int passwordLength=0;

        if(password!=null){
            passwordLength=password.length;
            if(passwordLength>32) {
                passwordLength = 32;
            }
        }

        if(encryptionPassword!=null) {
            System.arraycopy(encryptionPassword, 0, key, 0, passwordLength);
        }

        for(int ii=passwordLength;ii<32;ii++){

            key[ii]=(byte)Integer.parseInt(pad[ii-passwordLength],16);

        }


        return key;
    }
    /**
     * calculate the key
     */
    private byte[] calculateKey(final byte[] O, final int P, final byte[] ID) throws PdfSecurityException{

        /**calculate key to use*/
        final byte[] key=getPaddedKey(encryptionPassword,encryptionPassword);
        final byte[] keyValue;

        /**feed into Md5 function*/
        try{

            // Obtain a message digest object.
            final MessageDigest md = MessageDigest.getInstance("MD5");

            //add in padded key
            md.update(key);

            //write in O value
            md.update(O);

            //P value
            md.update(new byte[]{(byte)((P) & 0xff),(byte)((P>>8) & 0xff),(byte)((P>>16) & 0xff),(byte)((P>>24) & 0xff)});

            if(ID!=null) {
                md.update(ID);
            }

            if (rev==4 && !isMetaDataEncypted) {
                md.update(new byte[]{(byte) 255, (byte) 255, (byte) 255, (byte) 255});
            }

            final byte[] digest = new byte[keyLength];
            System.arraycopy(md.digest(), 0, digest, 0, keyLength);

            //for rev 3
            if(rev>=3){
                for (int i = 0; i < 50; ++i) {
                    System.arraycopy(md.digest(digest), 0, digest, 0, keyLength);
                }
            }

            keyValue=new byte[keyLength];
            System.arraycopy(digest, 0, keyValue, 0, keyLength);

        }catch(final Exception e){

            LogWriter.writeLog("Exception: " + e.getMessage());
            
            throw new PdfSecurityException("Exception "+e+" generating encryption key");
        }

        /**put significant bytes into key*/
        final byte[] returnKey = new byte[keyLength];
        System.arraycopy(keyValue,0, returnKey,0, keyLength);

        return returnKey;
    }

    /**extract  metadata for  encryption object
     */
    public void readEncryptionObject(final PdfObject encyptionObj) throws PdfSecurityException {

        //reset flags
        stringsEncoded=false;
        isMetaDataEncypted=true;
        StmFObj=null;
        StrFObj=null;
        isAES=false;

        if (!isInitialised) {
            isInitialised = true;
            SetSecurity.init();
        }

        //check type of filter and type and see if supported
        final int v = encyptionObj.getInt(PdfDictionary.V);

        //get filter value
        final PdfArrayIterator filters = encyptionObj.getMixedArray(PdfDictionary.Filter);
        int firstValue=PdfDictionary.Standard;
        if(filters!=null && filters.hasMoreTokens()) {
            firstValue = filters.getNextValueAsConstant(false);
        }

        //throw exception if we have an unsupported encryption method
        if(v==3) {
            throw new PdfSecurityException("Unsupported Custom Adobe Encryption method");
        } else if ((v > 4) && (firstValue!=PdfDictionary.Standard)) {
                throw new PdfSecurityException("Unsupported Encryption method");
            }
      
        final int newLength=encyptionObj.getInt(PdfDictionary.Length)>>3;
        if(newLength!=-1) {
            this.keyLength = newLength;
        }

        //get rest of the values (which are not optional)
        rev = encyptionObj.getInt(PdfDictionary.R);
        P = encyptionObj.getInt(PdfDictionary.P);
        O = encyptionObj.getTextStreamValueAsByte(PdfDictionary.O);
        U = encyptionObj.getTextStreamValueAsByte(PdfDictionary.U);
        
        //used for v=5
        OE = encyptionObj.getTextStreamValueAsByte(PdfDictionary.OE);
        UE = encyptionObj.getTextStreamValueAsByte(PdfDictionary.UE);
        Perms=encyptionObj.getTextStreamValueAsByte(PdfDictionary.Perms);

        //get additional AES values
        if(v>=4){

            isAES=true;

            String CFkey;

            final PdfObject CF=encyptionObj.getDictionary(PdfDictionary.CF);

            //EFF=encyptionObj.getName(PdfDictionary.EFF);
            //CFM=encyptionObj.getName(PdfDictionary.CFM);

            if(v==4){
                isMetaDataEncypted=encyptionObj.getBoolean(PdfDictionary.EncryptMetadata);
            }
            
            //now set any specific crypt values for StrF (strings) and StmF (streams)
            isAESIdentity=false;
            String key=encyptionObj.getName(PdfDictionary.StrF);

            if(key!=null){

                isAESIdentity=key.equals("Identity");

                stringsEncoded=true;

                final PdfKeyPairsIterator keyPairs=CF.getKeyPairsIterator();

                while(keyPairs.hasMorePairs()){

                    CFkey=keyPairs.getNextKeyAsString();

                    if(CFkey.equals(key)) {
                        StrFObj = keyPairs.getNextValueAsDictionary();
                    }

                    //roll on
                    keyPairs.nextPair();
                }
            }

            key=encyptionObj.getName(PdfDictionary.StmF);

            if(key!=null){

                isAESIdentity=key.equals("Identity");

                final PdfKeyPairsIterator keyPairs=CF.getKeyPairsIterator();

                while(keyPairs.hasMorePairs()){

                    CFkey=keyPairs.getNextKeyAsString();

                    if(CFkey.equals(key)) {
                        StmFObj = keyPairs.getNextValueAsDictionary();
                    }

                    //roll on
                    keyPairs.nextPair();
                }
            }
        }

        isEncrypted = true;
        isFileViewable = false;

        LogWriter.writeLog("File has encryption settings");
        
        //test if encrypted with password (not certificate)
        if(firstValue==PdfDictionary.Standard){
            try{
                verifyAccess();
            }catch(final PdfSecurityException e){
                LogWriter.writeLog("File requires password "+e);
            }
        }else if(certificate!=null){

            /**
             * set flags and assume it will work correctly
             * (no validation at this point - error will be thrown in decrypt if not)
             */
            isFileViewable=true;
            isPasswordSupplied=true;
            extractionIsAllowed=true;

            passwordStatus=PDFflags.VALID_OWNER_PASSWORD;

        }

        //v5 stores this in Perms object and needs to be done after verify access
        if(rev==5){
            /*
            * now decode the permissions
            */
            Perms= v5Decrypt(Perms, encryptionKey);

            //see if metadata encrypted 
            isMetaDataEncypted = Perms[8] == 'T';

            //P set in Perms for v5
            P = (Perms[0] & 255) | ((Perms[1] & 255) << 8) | ((Perms[2] & 255) << 16) | ((Perms[2] & 255) << 24);
        }
    }

    /**
     * setup password value isung certificate passed in by User
     */
    private void setPasswordFromCertificate(final PdfObject AESObj){
        /**
         * if recipients set, use that for calculating key
         */
        final byte[][] recipients = (AESObj.getStringArray(PdfDictionary.Recipients));

        if(recipients!=null){

            final byte[] envelopedData=SetSecurity.extractCertificateData(recipients,certificate,key);

            /**
             * use match to create the key
             */
            if(envelopedData!=null){

                try {
                    final MessageDigest md = MessageDigest.getInstance("SHA-1");
                    md.update(envelopedData, 0, 20);
                    for (final byte[] recipient : recipients) {
                        md.update(recipient);
                    }

                    if (!isMetaDataEncypted) {
                        md.update(new byte[]{(byte) 255, (byte) 255, (byte) 255, (byte) 255});
                    }

                    encryptionKey = md.digest();
                }catch (final Exception e) {
                    LogWriter.writeLog("Exception: " + e.getMessage());
                }
            }
        }
    }

    /**
     * reads the line/s from file which make up an object
     * includes move
     */
    public byte[] decrypt(byte[] data, final String ref, final boolean isEncryption,
                          final String cacheName, final boolean alwaysUseRC4,
                          final boolean isString) throws PdfSecurityException{

        //boolean debug=false;//ref.equals("100 0 R");

        if(getBooleanValue(PDFflags.IS_FILE_ENCRYPTED) || isEncryption){

            BufferedOutputStream streamCache= null;
            BufferedInputStream bis = null;
            //int streamLength=0;

            boolean isAES=false;

            byte[] AESData=null;

            if(cacheName!=null){ //this version is used if we cache large object to disk
                //rename file
                try {

                    //we may need bytes for key
                    if(data==null){
                        AESData=new byte[16];
                        final FileInputStream fis=new FileInputStream(cacheName);
                        fis.read(AESData);
                        fis.close();
                    }

                    //streamLength = (int) new File(cacheName).length();

                    final File tempFile2 = File.createTempFile("jpedal",".raw",new File(ObjectStore.temp_dir));

                    cachedObjects.put(tempFile2.getAbsolutePath(),"x");
                    //System.out.println(">>>"+tempFile2.getAbsolutePath());
                    ObjectStore.copy(cacheName,tempFile2.getAbsolutePath());

                    final File rawFile=new File(cacheName);
                    rawFile.delete();

                    //decrypt
                    streamCache = new BufferedOutputStream(new FileOutputStream(cacheName));
                    bis=new BufferedInputStream(new FileInputStream(tempFile2));

                } catch (final IOException e1) {
                    LogWriter.writeLog("Exception " + e1 + " in decrypt");
                }
            }

            //default values for rsa
            int keyLength=this.keyLength;
            String algorithm="RC4",keyType="RC4";
            //SecOP java ME - removed to remove additional package secop1_0.jar in java ME
            IvParameterSpec ivSpec = null;

            //select for stream or string
            final PdfObject AESObj ;
            if(!isString){
                AESObj=StmFObj;
            }else{
                AESObj=StrFObj;
            }

            /**
             * reset each time as can change
             * (we can add flag later if slow)
             */
            if(certificate!=null){
                setPasswordFromCertificate(AESObj);

                //ensure value set so code below works
                AESObj.setIntNumber(PdfDictionary.Length,16);
            }

            //AES identity
            if(!alwaysUseRC4 && AESObj==null && isAESIdentity) {
                return data;
            }

            //use RC4 as default but override if needed
            if(AESObj!=null){

                //use CF values in preference

//                final int AESLength=AESObj.getInt(PdfDictionary.Length);
//                if(AESLength!=-1) {
//                    keyLength = AESLength;
//                    if(keyLength>32){
//                        keyLength = AESLength >>3;
//                    }
//                }

                final String cryptName=AESObj.getName(PdfDictionary.CFM);

                if(cryptName!=null && !alwaysUseRC4 && ((cryptName.equals("AESV2")|| (cryptName.equals("AESV3"))))){

                    cipher=null; //force reset as may be rsa

                    algorithm="AES/CBC/PKCS5Padding";
                    keyType="AES";

                    isAES=true;

                    //setup CBC
                    final byte[] iv=new byte[16];
                    if(AESData!=null) {
                        System.arraycopy(AESData, 0, iv, 0, 16);
                    } else {
                        System.arraycopy(data, 0, iv, 0, 16);
                    }

                    //SecOP java ME - removed to remove additional package secop1_0.jar in java ME
                    ivSpec = new IvParameterSpec(iv);

                    //and knock off iv data in memory or cache
                    if(data==null){
                        try {
                            bis.skip(16);
                        } catch (final IOException e) {
                            LogWriter.writeLog("Exception: " + e.getMessage());
                        }
                    }else{
                        final int origLen=data.length;
                        final int newLen=origLen-16;
                        byte[] newData=new byte[newLen];
                        System.arraycopy(data, 16, newData, 0, newLen);
                        data=newData;

                        //make sure data correct size
                        final int diff= (data.length & 15);
                        int newLength=data.length;
                        if(diff>0){
                            newLength=newLength+16-diff;

                            newData=new byte[newLength];

                            System.arraycopy(data, 0, newData, 0, data.length);
                            data=newData;
                        }
                        
                        if(rev == 5){
                            try {
                                final byte[] finalKey = new byte[32];
                                System.arraycopy(encryptionKey,0, finalKey,0, finalKey.length);
                                return decodeAES(finalKey,data,iv);
                            } catch (final Exception e) {
                                throw new PdfSecurityException("Exception "+e+" decrypting content in AES revision 5");
                            }
                        }
                    }
                }
            }

            byte[] currentKey=new byte[keyLength];

            if(!ref.isEmpty()) {
                currentKey = new byte[keyLength + 5];
            }

            System.arraycopy(encryptionKey, 0, currentKey, 0, keyLength);

            try{

                final byte[] finalKey;
                if(rev==5){
                    finalKey=new byte[32];
                    System.arraycopy(currentKey,0, finalKey,0, finalKey.length);
                   // finalKey=currentKey;
                }else{
                    //add in Object ref id if any
                    if(!ref.isEmpty()){
                        final int pointer=ref.indexOf(' ');
                        final int pointer2=ref.indexOf(' ',pointer+1);

                        final int obj=Integer.parseInt(ref.substring(0,pointer));
                        final int gen=Integer.parseInt(ref.substring(pointer+1,pointer2));

                        currentKey[keyLength]=((byte)(obj & 0xff));
                        currentKey[keyLength+1]=((byte)((obj>>8) & 0xff));
                        currentKey[keyLength+2]=((byte)((obj>>16) & 0xff));
                        currentKey[keyLength+3]=((byte)(gen & 0xff));
                        currentKey[keyLength+4]=((byte)((gen>>8) & 0xff));
                    }

                    finalKey = new byte[Math.min(currentKey.length,16)];

                    if(!ref.isEmpty()){
                        final MessageDigest currentDigest =MessageDigest.getInstance("MD5");
                        currentDigest.update(currentKey);

                        //add in salt
                        if(isAES && keyLength>=16){
                            final byte[] salt = {(byte)0x73, (byte)0x41, (byte)0x6c, (byte)0x54};

                            currentDigest.update(salt);
                        }
                        System.arraycopy(currentDigest.digest(),0, finalKey,0, finalKey.length);
                    }else{
                        System.arraycopy(currentKey,0, finalKey,0, finalKey.length);
                    }
                }

                //SecOP java ME - removed to remove additional package secop1_0.jar in java ME
                /**only initialise once - seems to take a long time*/
                if(cipher==null) {
                    cipher = Cipher.getInstance(algorithm);
                }

                final SecretKey testKey = new SecretKeySpec(finalKey, keyType);

                if(isEncryption) {
                    cipher.init(Cipher.ENCRYPT_MODE, testKey);
                } else{
                    if(ivSpec==null) {
                        cipher.init(Cipher.DECRYPT_MODE, testKey);
                    } else //aes
                    {
                        cipher.init(Cipher.DECRYPT_MODE, testKey, ivSpec);
                    }
                }

                //if data on disk read a byte at a time and write back

                if(streamCache!=null){
                    final CipherInputStream cis=new CipherInputStream(bis,cipher);
                    int nextByte;
                    while(true){
                        nextByte=cis.read();
                        if(nextByte==-1) {
                            break;
                        }
                        streamCache.write(nextByte);
                    }
                    cis.close();
                    streamCache.close();
                    bis.close();

                }

                if(data!=null) {
                    data = cipher.doFinal(data);
                }

            }catch(final Exception e){
                throw new PdfSecurityException("Exception "+e+" decrypting content");
            }
        }

        //SecOP java ME - removed to remove additional package secop1_0.jar in java ME
        if(alwaysReinitCipher) {
            cipher = null;
        }

        return data;
    }

    /**show if file can be displayed*/
    public boolean getBooleanValue(final int key) {

        switch(key){
            case PDFflags.IS_FILE_VIEWABLE:
                return isFileViewable;

            case PDFflags.IS_FILE_ENCRYPTED:
                return isEncrypted;

            case PDFflags.IS_METADATA_ENCRYPTED:
                return isMetaDataEncypted;

            case PDFflags.IS_EXTRACTION_ALLOWED:
                return extractionIsAllowed;

            case PDFflags.IS_PASSWORD_SUPPLIED:
                return isPasswordSupplied;
        }


        return false;
    }
    
    public boolean isAES(){
        return isAES;
    }

    public byte[] decryptString(byte[] newString, final String objectRef) throws PdfSecurityException {

        try{
            if((!isAES || stringsEncoded || isMetaDataEncypted)) {
                newString = decrypt(newString, objectRef, false, null, false, true);
            }
        }catch(final Exception e){
            LogWriter.writeLog("Unable to decrypt string in Object " + objectRef + ' ' + new String(newString)+ ' ' +e);
        }

        return newString;

    }

    public int getPDFflag(final Integer flag) {

        if(flag.equals(PDFflags.USER_ACCESS_PERMISSIONS)) {
            return P;
        } else if(flag.equals(PDFflags.VALID_PASSWORD_SUPPLIED)) {
            return passwordStatus;
        } else {
            return -1;
        }
    }

    public void reset(final byte[] encryptionPassword) {

        this.encryptionPassword=encryptionPassword;

        //SecOP java ME - removed to remove additional package secop1_0.jar in java ME
        //reset
        cipher=null;
    }

    public void flush() {

        if(cachedObjects!=null){
            for (final Object o : cachedObjects.keySet()) {
                final String fileName = (String) o;
                final File file = new File(fileName);
                //System.out.println("PdfFileReader - deleting file "+fileName);
                file.delete();
            }
        }
    }

    public void dispose() {
        this.cachedObjects=null;

    }

    /**
     * show if U or O value present
     * @return
     */
    public boolean hasPassword() {
        return O!=null || U!=null;
    }
    
    /**
     * decode AES ecnoded data with IV parameters
     * @param password
     * @param encKey
     * @param encData a data gained from deducting IV bytes in beginning (encData = data - ivBytes)
     * @param ivData
     * @return
     * @throws Exception
     */
    private static byte[] decodeAES(final byte[] encKey, final byte[] encData, final byte[] ivData)
            throws Exception {
        
        final KeyParameter keyParam = new KeyParameter(encKey);
        final CipherParameters params = new ParametersWithIV(keyParam, ivData);

        // setup AES cipher in CBC mode with PKCS7 padding
        final BlockCipherPadding padding = new PKCS7Padding();
        final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
                new CBCBlockCipher(new AESEngine()), padding);
        cipher.reset();
        cipher.init(false, params);

        // create a temporary buffer to decode into (it'll include padding)
        final byte[] buf = new byte[cipher.getOutputSize(encData.length)];
        int len = cipher.processBytes(encData, 0, encData.length, buf, 0);
        len += cipher.doFinal(buf, len);

        // remove padding
        final byte[] out = new byte[len];
        System.arraycopy(buf, 0, out, 0, len);

        // return string representation of decoded bytes
        return out;
    }   
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy