virtual public bool ReadKey(PdfDictionary enc, byte[] password) { if (password == null) { password = new byte[0]; } byte[] oValue = DocWriter.GetISOBytes(enc.Get(PdfName.O).ToString()); byte[] uValue = DocWriter.GetISOBytes(enc.Get(PdfName.U).ToString()); byte[] oeValue = DocWriter.GetISOBytes(enc.Get(PdfName.OE).ToString()); byte[] ueValue = DocWriter.GetISOBytes(enc.Get(PdfName.UE).ToString()); byte[] perms = DocWriter.GetISOBytes(enc.Get(PdfName.PERMS).ToString()); PdfNumber pValue = (PdfNumber)enc.Get(PdfName.P); this.oeKey = oeValue; this.ueKey = ueValue; this.perms = perms; this.ownerKey = oValue; this.userKey = uValue; this.permissions = pValue.LongValue; bool isUserPass = false; IDigest md = DigestUtilities.GetDigest("SHA-256"); md.BlockUpdate(password, 0, Math.Min(password.Length, 127)); md.BlockUpdate(oValue, VALIDATION_SALT_OFFSET, SALT_LENGHT); md.BlockUpdate(uValue, 0, OU_LENGHT); byte[] hash = DigestUtilities.DoFinal(md); bool isOwnerPass = CompareArray(hash, oValue, 32); AESCipherCBCnoPad ac; if (isOwnerPass) { md.BlockUpdate(password, 0, Math.Min(password.Length, 127)); md.BlockUpdate(oValue, KEY_SALT_OFFSET, SALT_LENGHT); md.BlockUpdate(uValue, 0, OU_LENGHT); md.DoFinal(hash, 0); ac = new AESCipherCBCnoPad(false, hash); key = ac.ProcessBlock(oeValue, 0, oeValue.Length); } else { md.BlockUpdate(password, 0, Math.Min(password.Length, 127)); md.BlockUpdate(uValue, VALIDATION_SALT_OFFSET, SALT_LENGHT); md.DoFinal(hash, 0); isUserPass = CompareArray(hash, uValue, 32); if (!isUserPass) { throw new BadPasswordException(MessageLocalization.GetComposedMessage("bad.user.password")); } md.BlockUpdate(password, 0, Math.Min(password.Length, 127)); md.BlockUpdate(uValue, KEY_SALT_OFFSET, SALT_LENGHT); md.DoFinal(hash, 0); ac = new AESCipherCBCnoPad(false, hash); key = ac.ProcessBlock(ueValue, 0, ueValue.Length); } ac = new AESCipherCBCnoPad(false, key); byte[] decPerms = ac.ProcessBlock(perms, 0, perms.Length); if (decPerms[9] != (byte)'a' || decPerms[10] != (byte)'d' || decPerms[11] != (byte)'b') { throw new BadPasswordException(MessageLocalization.GetComposedMessage("bad.user.password")); } permissions = (decPerms[0] & 0xff) | ((decPerms[1] & 0xff) << 8) | ((decPerms[2] & 0xff) << 16) | ((decPerms[2] & 0xff) << 24); encryptMetadata = decPerms[8] == (byte)'T'; return(isOwnerPass); }
// gets keylength and revision and uses revison to choose the initial values for permissions virtual public void SetupAllKeys(byte[] userPassword, byte[] ownerPassword, int permissions) { if (ownerPassword == null || ownerPassword.Length == 0) { ownerPassword = DigestAlgorithms.Digest("MD5", CreateDocumentId()); } md5.Reset(); permissions |= (int)((revision == STANDARD_ENCRYPTION_128 || revision == AES_128 || revision == AES_256) ? (uint)0xfffff0c0 : (uint)0xffffffc0); permissions &= unchecked ((int)0xfffffffc); this.permissions = permissions; if (revision == AES_256) { if (userPassword == null) { userPassword = new byte[0]; } documentID = CreateDocumentId(); byte[] uvs = IVGenerator.GetIV(8); byte[] uks = IVGenerator.GetIV(8); key = IVGenerator.GetIV(32); // Algorithm 3.8.1 IDigest md = DigestUtilities.GetDigest("SHA-256"); md.BlockUpdate(userPassword, 0, Math.Min(userPassword.Length, 127)); md.BlockUpdate(uvs, 0, uvs.Length); userKey = new byte[48]; md.DoFinal(userKey, 0); System.Array.Copy(uvs, 0, userKey, 32, 8); System.Array.Copy(uks, 0, userKey, 40, 8); // Algorithm 3.8.2 md.BlockUpdate(userPassword, 0, Math.Min(userPassword.Length, 127)); md.BlockUpdate(uks, 0, uks.Length); byte[] tempDigest = new byte[32]; md.DoFinal(tempDigest, 0); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(true, tempDigest); ueKey = ac.ProcessBlock(key, 0, key.Length); // Algorithm 3.9.1 byte[] ovs = IVGenerator.GetIV(8); byte[] oks = IVGenerator.GetIV(8); md.BlockUpdate(ownerPassword, 0, Math.Min(ownerPassword.Length, 127)); md.BlockUpdate(ovs, 0, ovs.Length); md.BlockUpdate(userKey, 0, userKey.Length); ownerKey = new byte[48]; md.DoFinal(ownerKey, 0); System.Array.Copy(ovs, 0, ownerKey, 32, 8); System.Array.Copy(oks, 0, ownerKey, 40, 8); // Algorithm 3.9.2 md.BlockUpdate(ownerPassword, 0, Math.Min(ownerPassword.Length, 127)); md.BlockUpdate(oks, 0, oks.Length); md.BlockUpdate(userKey, 0, userKey.Length); md.DoFinal(tempDigest, 0); ac = new AESCipherCBCnoPad(true, tempDigest); oeKey = ac.ProcessBlock(key, 0, key.Length); // Algorithm 3.10 byte[] permsp = IVGenerator.GetIV(16); permsp[0] = (byte)permissions; permsp[1] = (byte)(permissions >> 8); permsp[2] = (byte)(permissions >> 16); permsp[3] = (byte)(permissions >> 24); permsp[4] = (byte)(255); permsp[5] = (byte)(255); permsp[6] = (byte)(255); permsp[7] = (byte)(255); permsp[8] = encryptMetadata ? (byte)'T' : (byte)'F'; permsp[9] = (byte)'a'; permsp[10] = (byte)'d'; permsp[11] = (byte)'b'; ac = new AESCipherCBCnoPad(true, key); perms = ac.ProcessBlock(permsp, 0, permsp.Length); } else { //PDF refrence 3.5.2 Standard Security Handler, Algorithum 3.3-1 //If there is no owner password, use the user password instead. byte[] userPad = PadPassword(userPassword); byte[] ownerPad = PadPassword(ownerPassword); this.ownerKey = ComputeOwnerKey(userPad, ownerPad); documentID = CreateDocumentId(); SetupByUserPad(this.documentID, userPad, this.ownerKey, permissions); } }
private void InitKeyAndFillDictionary(PdfDictionary encryptionDictionary, byte[] userPassword, byte[] ownerPassword , int permissions, bool encryptMetadata, bool embeddedFilesOnly) { ownerPassword = GenerateOwnerPasswordIfNullOrEmpty(ownerPassword); permissions |= PERMS_MASK_1_FOR_REVISION_3_OR_GREATER; permissions &= PERMS_MASK_2; try { byte[] userKey; byte[] ownerKey; byte[] ueKey; byte[] oeKey; byte[] aes256Perms; if (userPassword == null) { userPassword = new byte[0]; } else { if (userPassword.Length > 127) { userPassword = iText.IO.Util.JavaUtil.ArraysCopyOf(userPassword, 127); } } if (ownerPassword.Length > 127) { ownerPassword = iText.IO.Util.JavaUtil.ArraysCopyOf(ownerPassword, 127); } // first 8 bytes are validation salt; second 8 bytes are key salt byte[] userValAndKeySalt = IVGenerator.GetIV(16); byte[] ownerValAndKeySalt = IVGenerator.GetIV(16); nextObjectKey = IVGenerator.GetIV(32); nextObjectKeySize = 32; byte[] hash; // Algorithm 8.1 hash = ComputeHash(userPassword, userValAndKeySalt, 0, 8); userKey = iText.IO.Util.JavaUtil.ArraysCopyOf(hash, 48); System.Array.Copy(userValAndKeySalt, 0, userKey, 32, 16); // Algorithm 8.2 hash = ComputeHash(userPassword, userValAndKeySalt, 8, 8); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(true, hash); ueKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length); // Algorithm 9.1 hash = ComputeHash(ownerPassword, ownerValAndKeySalt, 0, 8, userKey); ownerKey = iText.IO.Util.JavaUtil.ArraysCopyOf(hash, 48); System.Array.Copy(ownerValAndKeySalt, 0, ownerKey, 32, 16); // Algorithm 9.2 hash = ComputeHash(ownerPassword, ownerValAndKeySalt, 8, 8, userKey); ac = new AESCipherCBCnoPad(true, hash); oeKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length); // Algorithm 10 byte[] permsp = IVGenerator.GetIV(16); permsp[0] = (byte)permissions; permsp[1] = (byte)(permissions >> 8); permsp[2] = (byte)(permissions >> 16); permsp[3] = (byte)(permissions >> 24); permsp[4] = (byte)(255); permsp[5] = (byte)(255); permsp[6] = (byte)(255); permsp[7] = (byte)(255); permsp[8] = encryptMetadata ? (byte)'T' : (byte)'F'; permsp[9] = (byte)'a'; permsp[10] = (byte)'d'; permsp[11] = (byte)'b'; ac = new AESCipherCBCnoPad(true, nextObjectKey); aes256Perms = ac.ProcessBlock(permsp, 0, permsp.Length); this.permissions = permissions; this.encryptMetadata = encryptMetadata; SetStandardHandlerDicEntries(encryptionDictionary, userKey, ownerKey); SetAES256DicEntries(encryptionDictionary, oeKey, ueKey, aes256Perms, encryptMetadata, embeddedFilesOnly); } catch (Exception ex) { throw new PdfException(PdfException.PdfEncryption, ex); } }
/// <exception cref="Org.BouncyCastle.Security.SecurityUtilityException"/> private byte[] ComputeHash(byte[] password, byte[] salt, int saltOffset, int saltLen, byte[] userKey) { IDigest mdSha256 = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-256"); mdSha256.Update(password); mdSha256.Update(salt, saltOffset, saltLen); if (userKey != null) { mdSha256.Update(userKey); } byte[] k = mdSha256.Digest(); if (isPdf2) { // See 7.6.4.3.3 "Algorithm 2.B" IDigest mdSha384 = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-384"); IDigest mdSha512 = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-512"); int userKeyLen = userKey != null ? userKey.Length : 0; int passAndUserKeyLen = password.Length + userKeyLen; // k1 repetition length int k1RepLen; int roundNum = 0; while (true) { // a) k1RepLen = passAndUserKeyLen + k.Length; byte[] k1 = new byte[k1RepLen * 64]; System.Array.Copy(password, 0, k1, 0, password.Length); System.Array.Copy(k, 0, k1, password.Length, k.Length); if (userKey != null) { System.Array.Copy(userKey, 0, k1, password.Length + k.Length, userKeyLen); } for (int i = 1; i < 64; ++i) { System.Array.Copy(k1, 0, k1, k1RepLen * i, k1RepLen); } // b) AESCipherCBCnoPad cipher = new AESCipherCBCnoPad(true, iText.IO.Util.JavaUtil.ArraysCopyOf(k, 16), iText.IO.Util.JavaUtil.ArraysCopyOfRange (k, 16, 32)); byte[] e = cipher.ProcessBlock(k1, 0, k1.Length); // c) IDigest md = null; BigInteger i_1 = new BigInteger(1, iText.IO.Util.JavaUtil.ArraysCopyOf(e, 16)); int remainder = i_1.Remainder(BigInteger.ValueOf(3)).IntValue; switch (remainder) { case 0: { md = mdSha256; break; } case 1: { md = mdSha384; break; } case 2: { md = mdSha512; break; } } // d) k = md.Digest(e); ++roundNum; if (roundNum > 63) { // e) int condVal = e[e.Length - 1] & 0xFF; // interpreting last byte as unsigned integer if (condVal <= roundNum - 32) { break; } } } k = k.Length == 32 ? k : iText.IO.Util.JavaUtil.ArraysCopyOf(k, 32); } return(k); }
private void InitKeyAndReadDictionary(PdfDictionary encryptionDictionary, byte[] password) { try { if (password == null) { password = new byte[0]; } else { if (password.Length > 127) { password = iText.IO.Util.JavaUtil.ArraysCopyOf(password, 127); } } isPdf2 = encryptionDictionary.GetAsNumber(PdfName.R).GetValue() == 6; byte[] oValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.O)); byte[] uValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.U)); byte[] oeValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.OE)); byte[] ueValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.UE)); byte[] perms = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.Perms)); PdfNumber pValue = (PdfNumber)encryptionDictionary.Get(PdfName.P); this.permissions = pValue.LongValue(); byte[] hash; hash = ComputeHash(password, oValue, VALIDATION_SALT_OFFSET, SALT_LENGTH, uValue); usedOwnerPassword = CompareArray(hash, oValue, 32); if (usedOwnerPassword) { hash = ComputeHash(password, oValue, KEY_SALT_OFFSET, SALT_LENGTH, uValue); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash); nextObjectKey = ac.ProcessBlock(oeValue, 0, oeValue.Length); } else { hash = ComputeHash(password, uValue, VALIDATION_SALT_OFFSET, SALT_LENGTH); if (!CompareArray(hash, uValue, 32)) { throw new BadPasswordException(PdfException.BadUserPassword); } hash = ComputeHash(password, uValue, KEY_SALT_OFFSET, SALT_LENGTH); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash); nextObjectKey = ac.ProcessBlock(ueValue, 0, ueValue.Length); } nextObjectKeySize = 32; AESCipherCBCnoPad ac_1 = new AESCipherCBCnoPad(false, nextObjectKey); byte[] decPerms = ac_1.ProcessBlock(perms, 0, perms.Length); if (decPerms[9] != (byte)'a' || decPerms[10] != (byte)'d' || decPerms[11] != (byte)'b') { throw new BadPasswordException(PdfException.BadUserPassword); } int permissionsDecoded = (decPerms[0] & 0xff) | ((decPerms[1] & 0xff) << 8) | ((decPerms[2] & 0xff) << 16) | ((decPerms[3] & 0xff) << 24); bool encryptMetadata = decPerms[8] == (byte)'T'; bool?encryptMetadataEntry = encryptionDictionary.GetAsBool(PdfName.EncryptMetadata); if (permissionsDecoded != permissions || encryptMetadataEntry != null && encryptMetadata != encryptMetadataEntry ) { ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Crypto.Securityhandler.StandardHandlerUsingAes256)); logger.Error(iText.IO.LogMessageConstant.ENCRYPTION_ENTRIES_P_AND_ENCRYPT_METADATA_NOT_CORRESPOND_PERMS_ENTRY ); } this.permissions = permissionsDecoded; this.encryptMetadata = encryptMetadata; } catch (BadPasswordException ex) { throw; } catch (Exception ex) { throw new PdfException(PdfException.PdfEncryption, ex); } }
private void InitKeyAndFillDictionary(PdfDictionary encryptionDictionary, byte[] userPassword, byte[] ownerPassword , int permissions, bool encryptMetadata, bool embeddedFilesOnly) { ownerPassword = GenerateOwnerPasswordIfNullOrEmpty(ownerPassword); permissions |= PERMS_MASK_1_FOR_REVISION_3_OR_GREATER; permissions &= PERMS_MASK_2; try { byte[] userKey; byte[] ownerKey; byte[] ueKey; byte[] oeKey; byte[] aes256Perms; if (userPassword == null) { userPassword = new byte[0]; } byte[] uvs = IVGenerator.GetIV(8); byte[] uks = IVGenerator.GetIV(8); nextObjectKey = IVGenerator.GetIV(32); nextObjectKeySize = 32; // Algorithm 3.8.1 IDigest md = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-256"); md.Update(userPassword, 0, Math.Min(userPassword.Length, 127)); md.Update(uvs); userKey = new byte[48]; md.Digest(userKey, 0, 32); System.Array.Copy(uvs, 0, userKey, 32, 8); System.Array.Copy(uks, 0, userKey, 40, 8); // Algorithm 3.8.2 md.Update(userPassword, 0, Math.Min(userPassword.Length, 127)); md.Update(uks); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(true, md.Digest()); ueKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length); // Algorithm 3.9.1 byte[] ovs = IVGenerator.GetIV(8); byte[] oks = IVGenerator.GetIV(8); md.Update(ownerPassword, 0, Math.Min(ownerPassword.Length, 127)); md.Update(ovs); md.Update(userKey); ownerKey = new byte[48]; md.Digest(ownerKey, 0, 32); System.Array.Copy(ovs, 0, ownerKey, 32, 8); System.Array.Copy(oks, 0, ownerKey, 40, 8); // Algorithm 3.9.2 md.Update(ownerPassword, 0, Math.Min(ownerPassword.Length, 127)); md.Update(oks); md.Update(userKey); ac = new AESCipherCBCnoPad(true, md.Digest()); oeKey = ac.ProcessBlock(nextObjectKey, 0, nextObjectKey.Length); // Algorithm 3.10 byte[] permsp = IVGenerator.GetIV(16); permsp[0] = (byte)permissions; permsp[1] = (byte)(permissions >> 8); permsp[2] = (byte)(permissions >> 16); permsp[3] = (byte)(permissions >> 24); permsp[4] = (byte)(255); permsp[5] = (byte)(255); permsp[6] = (byte)(255); permsp[7] = (byte)(255); permsp[8] = encryptMetadata ? (byte)'T' : (byte)'F'; permsp[9] = (byte)'a'; permsp[10] = (byte)'d'; permsp[11] = (byte)'b'; ac = new AESCipherCBCnoPad(true, nextObjectKey); aes256Perms = ac.ProcessBlock(permsp, 0, permsp.Length); this.permissions = permissions; this.encryptMetadata = encryptMetadata; SetStandardHandlerDicEntries(encryptionDictionary, userKey, ownerKey); SetAES256DicEntries(encryptionDictionary, oeKey, ueKey, aes256Perms, encryptMetadata, embeddedFilesOnly); } catch (Exception ex) { throw new PdfException(PdfException.PdfEncryption, ex); } }
private void InitKeyAndReadDictionary(PdfDictionary encryptionDictionary, byte[] password) { try { if (password == null) { password = new byte[0]; } byte[] oValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.O)); byte[] uValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.U)); byte[] oeValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.OE)); byte[] ueValue = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.UE)); byte[] perms = GetIsoBytes(encryptionDictionary.GetAsString(PdfName.Perms)); PdfNumber pValue = (PdfNumber)encryptionDictionary.Get(PdfName.P); this.permissions = pValue.LongValue(); IDigest md = Org.BouncyCastle.Security.DigestUtilities.GetDigest("SHA-256"); md.Update(password, 0, Math.Min(password.Length, 127)); md.Update(oValue, VALIDATION_SALT_OFFSET, SALT_LENGTH); md.Update(uValue, 0, OU_LENGTH); byte[] hash = md.Digest(); usedOwnerPassword = CompareArray(hash, oValue, 32); if (usedOwnerPassword) { md.Update(password, 0, Math.Min(password.Length, 127)); md.Update(oValue, KEY_SALT_OFFSET, SALT_LENGTH); md.Update(uValue, 0, OU_LENGTH); hash = md.Digest(); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash); nextObjectKey = ac.ProcessBlock(oeValue, 0, oeValue.Length); } else { md.Update(password, 0, Math.Min(password.Length, 127)); md.Update(uValue, VALIDATION_SALT_OFFSET, SALT_LENGTH); hash = md.Digest(); if (!CompareArray(hash, uValue, 32)) { throw new BadPasswordException(PdfException.BadUserPassword); } md.Update(password, 0, Math.Min(password.Length, 127)); md.Update(uValue, KEY_SALT_OFFSET, SALT_LENGTH); hash = md.Digest(); AESCipherCBCnoPad ac = new AESCipherCBCnoPad(false, hash); nextObjectKey = ac.ProcessBlock(ueValue, 0, ueValue.Length); } nextObjectKeySize = 32; AESCipherCBCnoPad ac_1 = new AESCipherCBCnoPad(false, nextObjectKey); byte[] decPerms = ac_1.ProcessBlock(perms, 0, perms.Length); if (decPerms[9] != (byte)'a' || decPerms[10] != (byte)'d' || decPerms[11] != (byte)'b') { throw new BadPasswordException(PdfException.BadUserPassword); } permissions = (decPerms[0] & 0xff) | ((decPerms[1] & 0xff) << 8) | ((decPerms[2] & 0xff) << 16) | ((decPerms [2] & 0xff) << 24); encryptMetadata = decPerms[8] == (byte)'T'; } catch (BadPasswordException ex) { throw; } catch (Exception ex) { throw new PdfException(PdfException.PdfEncryption, ex); } }