pdf加密计算/ O.

时间:2015-02-18 14:32:12

标签: java pdf encryption pdfbox

为了正确理解pdf中标准安全处理程序的操作 我正在尝试从先前加密的pdf重建加密字典的条目/ o / u。 / o和/ u上的加密字典包含:

/P -1852
/CF
<<
    /StdCF
    <<
        /AuthEvent /DocOpen
        /Length 16
        /CFM/V2
    >>
>>
/R 4
/StmF /StdCF 
/Filter/Standard

我设法成功重建/ o但我无法重建/ u

主:

public static void main(String[] args) {
    String docID;
    byte[] userPass=null;
    byte[] ownerPass=null;
    try {
        userPass = userPassString.getBytes("ISO-8859-1");
        ownerPass = ownerPassString.getBytes("ISO-8859-1");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    try {
        PDDocument doc=PDDocument.load(outPDfDir + "/EncryptedDocument_rc4_128.pdf");
        if (doc.isEncrypted()){

            EncryptDocument encrypt = new EncryptDocument(userPass,ownerPass,outPDfDir,doc.getEncryptionDictionary().getLength());
            encrypt.setRevision(doc.getEncryptionDictionary().getRevision());
            encrypt.setVersion(doc.getEncryptionDictionary().getVersion());
            COSArray cosArray = doc.getDocument().getDocumentID();
            docID=cosArray.getString(0); //only first entry of the array
            byte[][] keys = encrypt.computeKeys(userPass, ownerPass, doc.getEncryptionDictionary().getPermissions(), docID.getBytes());
            byte[] originalUserKey = doc.getEncryptionDictionary().getUserKey();
            byte[] originalownerKey = doc.getEncryptionDictionary().getOwnerKey();
            System.out.println(toHex(originalUserKey));
            System.out.println(toHex(keys[1]));
            if (Arrays.equals(originalUserKey,keys[1])){
                System.out.println("User correctly authenticated");
            }else{
                System.out.println("wrong user password");
            }
            if (Arrays.equals(originalownerKey,keys[0])){
                System.out.println("Owner correctly authenticated");
            }else{
                System.out.println("wrong user password");
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

加密课程

public class EncryptDocument {

    private ARCFour rc4 = new ARCFour();
    public static final byte[] ENCRYPT_PADDING = new byte[]{(byte)40, (byte)-65, (byte)78, (byte)94, (byte)78, (byte)117, (byte)-118, (byte)65, (byte)100, (byte)0, (byte)78, (byte)86, (byte)-1, (byte)-6, (byte)1, (byte)8, (byte)46, (byte)46, (byte)0, (byte)-74, (byte)-48, (byte)104, (byte)62, (byte)-128, (byte)47, (byte)12, (byte)-87, (byte)-2, (byte)100, (byte)83, (byte)105, (byte)122};
    byte[] userPass;
    byte[] ownerPass;
    String destPath;
    int revision;
    int version;
    private static final byte[] pad = new byte[]{(byte)40, (byte)-65, (byte)78, (byte)94, (byte)78, (byte)117, (byte)-118, (byte)65, (byte)100, (byte)0, (byte)78, (byte)86, (byte)-1, (byte)-6, (byte)1, (byte)8, (byte)46, (byte)46, (byte)0, (byte)-74, (byte)-48, (byte)104, (byte)62, (byte)-128, (byte)47, (byte)12, (byte)-87, (byte)-2, (byte)100, (byte)83, (byte)105, (byte)122};
    private int keyLength;


    public EncryptDocument(byte[] userPass, byte[] ownerPass, String destPath,int keylength) {
        this.userPass = userPass;
        this.ownerPass = ownerPass;
        this.destPath = destPath;
        this.keyLength=keylength;
    }

    public byte[][] computeKeys(byte[] userPass, byte[] ownPass, int permissions, byte[] documentId) {
        //pad both user and owner pass
        byte[] userPad = padPassword(userPass);
        byte[] ownerPad = padPassword(ownPass);
        byte[][] data = new byte[2][32];
        byte[] userKey = new byte[0];
        byte[] encryptionKey;
        permissions= computePermissions(permissions);
        byte[] ownerKey  = new byte[0];
        try {
            ownerKey = computeOwnerKey(userPad, ownerPad);
            encryptionKey = computeEncryptionKey(userPad,ownerKey,documentId,permissions);
            userKey = computeUserKey(userPad,ownerKey,permissions,documentId,encryptionKey);

        } catch (IOException e) {
            e.printStackTrace();
        }
        data[0]=ownerKey;
        data[1]=userKey;
        return data;
    }

    private byte[] computeUserKey(byte[] userPad, byte[] ownerKey, int permissions, byte[] documentId, byte[] mkey) throws IOException {
        //algorithm 5
        byte[] digest;
        ByteArrayOutputStream userKey = new ByteArrayOutputStream();

        ARCFour rc4 = new ARCFour();

        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(pad); // step b
        digest = md5.digest(documentId); //c
        //build the input of rc4 encryption
        userKey.write(digest);
        byte[] iterationKey = new byte[mkey.length];
        //encrypt it first time plus other 19 times
        for (int i = 0; i < 20; ++i) {
            System.arraycopy(mkey, 0, iterationKey, 0, iterationKey.length);
            for (int input = 0; input < iterationKey.length; ++input) {
                iterationKey[input] = (byte) (iterationKey[input] ^ i);
            }
            rc4.setKey(iterationKey);
            ByteArrayInputStream tmpRes = new ByteArrayInputStream(userKey.toByteArray());
            userKey.reset();
            rc4.write(tmpRes, userKey);
        }
        return userKey.toByteArray();
    }

    private byte[] computeEncryptionKey(byte[] userPad,byte[] ownerKey, byte[] documentId,int permissions){
        //initialize hash function
        MessageDigest md5 = null;
        byte[] encryptedKey =new byte[keyLength / 8];
        byte[] digest;
        try {
            md5 = MessageDigest.getInstance("MD5"); //md5.reset()
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        md5.update(userPad);///pass the padded user password (step b)
        md5.update(ownerKey); //pass o entry to the hash function (step c)

        byte[] ext = int_to_bb_le(permissions); //new byte[]{(byte)permissions, (byte)(permissions >> 8), (byte)(permissions >> 16), (byte)(permissions >> 24)};

        md5.update(ext, 0, 4); //pass permission to the hash function stp d
        md5.update(documentId); //pass first element of document id (step e)
        if (this.revision>=4)
        md5.update(new byte[]{(byte)-1, (byte)-1, (byte)-1, (byte)-1}); //metadata not encryped --> add padding  (step f)
        digest = md5.digest();
        //compute encryption key step g


        if(revision == 3 || revision == 4) { //do 50 times step h
            for(int k = 0; k < 50; ++k) {
                md5.reset();
                md5.update(digest,0,keyLength / 8);
                digest=md5.digest();
            }
        }
        System.arraycopy(digest, 0, encryptedKey, 0, encryptedKey.length);
        return encryptedKey;
    }

    private byte[] computeOwnerKey(byte[] userPad, byte[] ownerPad) throws IOException {

        MessageDigest md5 = null;
        ARCFour rc4 = new ARCFour();

        try {
            md5 = MessageDigest.getInstance("MD5"); //md5.reset()
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte[] digest = md5.digest(ownerPad);

        byte[] mkey = new byte[this.keyLength / 8];
        int i;
        for (i = 0; i < 50; ++i) {
            md5.update(digest, 0, mkey.length);
            System.arraycopy(md5.digest(), 0, digest, 0, mkey.length);
        }
        //encrypt the padded user password using the result of md5 computation on owner padded password
        //revision >3 ==> do it 19 times
        ByteArrayOutputStream ownerKey = new ByteArrayOutputStream();
        //System.arraycopy(userPad, 0, ownerKey, 0, 32);
        rc4.write(new ByteArrayInputStream(userPad), ownerKey);
        byte[] iterationKey = new byte[mkey.length];
            for (i = 0; i < 20; ++i) {
                System.arraycopy(mkey, 0, iterationKey, 0, mkey.length);
                //prepare encryption key  bitwhise xor between encrypted owner padded password and iteration counter
                for (int j = 0; j < iterationKey.length; ++j) {
                    iterationKey[j] = (byte) (digest[j] ^ i);
                }
            //encrypt with arc4
            rc4.setKey(iterationKey);
            ByteArrayInputStream tmpres = new ByteArrayInputStream(ownerKey.toByteArray());
            ownerKey.reset();
            rc4.write(tmpres, ownerKey);
        }
        //at the 19 invocation the own key is obtained
        return ownerKey.toByteArray();
    }

    public int computePermissions(int permissions){
        permissions |= this.revision != 3 && this.revision != 4 && this.revision != 5?-64:-3904;
        permissions &= -4;
        return permissions;
    }

    public byte[] padPassword(byte[] password) {
        byte[] userPad = new byte[32];
        if(password == null) {
            System.arraycopy(pad, 0, userPad, 0, 32);
        } else {
            System.arraycopy(password, 0, userPad, 0, Math.min(password.length, 32));
            if(password.length < 32) {
            System.arraycopy(pad, 0, userPad, password.length, 32 - password.length);
            }
        }
        return userPad;
    }
    public static  byte[] int_to_bb_le(int myInteger){
        return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(myInteger).allocatelocaterray();
     }
}
有人能够理解我错在哪里吗?

0 个答案:

没有答案