protected override DecryptResult Decrypt(IContentEncryptionUi ui, string sourceFile) { object doc = null; string tempfile = Path.GetTempFileName(); var decryptWrapper = new WordApplicationDecryptWrapper(); try { decryptWrapper.CreateHostApplication(); DecryptResult result = OpenDocument(ui, sourceFile, out doc, decryptWrapper); if (result != DecryptResult.Ok) { return result; } // Modify document passwords, save to -another- temporary file (decryptedPath) // Need to save twice, or for some reason the read/modify passwords get kept Logger.LogDebug(string.Format("WordEncryption.Decrypt: Saving attachment to \"{0}\"", sourceFile)); decryptWrapper.SetOpenPassword(doc, string.Empty); decryptWrapper.SetWritePassword(doc, string.Empty); try { decryptWrapper.Save(doc); } catch (InvalidOperationException ex) { // if the document is readonly, Save() throws up UI, so instead it throws an InvalidOperationException, which we ignore... Logger.LogInfo(ex); } // If you have Office 2003 & a .docx file the SaveDocumentAs cannot write over the original // source file as it is currently locked. As a workaround we save to a temporary file // then move the tempfile over the sourceFile decryptWrapper.SaveDocumentAs(doc, tempfile, false, string.Empty, string.Empty); } finally { if (doc != null) { decryptWrapper.CloseDocument(doc, false); } decryptWrapper.Dispose(); } if (File.Exists(sourceFile)) { File.Delete(sourceFile); } File.Move(tempfile, sourceFile); // creates an empty file where sourceFile was -> only do if no error!! return DecryptResult.Ok; }
private DecryptResult OpenDocument(IContentEncryptionUi ui, string sourceFile, out object doc, WordApplicationDecryptWrapper decryptWrapper) { bool bUseDummyModifyPassword = false; doc = null; DecryptResult result = DecryptResult.Skip; // TODO - Fix the handling of Modify passwords to correctly validate them. // Currently any Modify password is stripped from the document when it is saved. // This is due to the fact that we don't correctly verify the Modify password when opening // the document and as a result it might be possible for the user to enter an incorrect password. // When saving, the incorrect password would still be applied causing problems for the receiver. string extension = System.IO.Path.GetExtension(sourceFile); switch (extension.ToLower()) { case ".doc": case ".docx": case ".docm": case ".dotx": case ".dotm": result = this.GetAndCheckPasswords(ui); break; case ".rtf": result = this.GetAndCheckModifyPassword(ui); break; default: result = this.GetAndCheckOpenPassword(ui); break; } if (result == DecryptResult.Ok) { // Don't use the cache to decrypt because password errors leave word in a state where // subsequent calls return RPC_UNAVAIABLE. try { doc = decryptWrapper.Decrypt(sourceFile, false, string.IsNullOrEmpty(OpenPassword) ? DUMMY_PASSWORD : OpenPassword, string.IsNullOrEmpty(ModifyPassword) ? DUMMY_PASSWORD : ModifyPassword, AttachmentFileType); // If the user typed a Modify or Open password for a document that didn't need one // remove it here, otherwise it will be added to the saved document. if (!decryptWrapper.ShouldHandleOpenPassword(doc)) { OpenPassword = ""; } if (!decryptWrapper.ShouldHandleWritePassword(doc)) { ModifyPassword = ""; } // Bug fix for VE: 97 // In OfficeXP, casting Microsoft.Office.Interop.Word.DocumentClass to Microsoft.Office.Interop.Word.Document fails at // runtime. Use _Document instead. Word12Interop._Document wordDoc = doc as Word12Interop._Document; DisableReadingLayout(wordDoc); Logger.LogDebug("Document Protection Type: " + wordDoc.ProtectionType); if( wordDoc.ProtectionType != Microsoft.Office.Interop.Word.WdProtectionType.wdNoProtection ) { m_typeProtect = wordDoc.ProtectionType; if (!CanUnprotectDocument(wordDoc)) { result = this.GetDocumentProtectionPassword(ui); if (result == DecryptResult.Ok) { if (string.IsNullOrEmpty(DocumentProtectionPassword)) { m_typeProtect = Microsoft.Office.Interop.Word.WdProtectionType.wdNoProtection; } else if (m_typeProtect != Microsoft.Office.Interop.Word.WdProtectionType.wdNoProtection) { object password = DocumentProtectionPassword; wordDoc.Unprotect(ref password); Logger.LogDebug(string.Format("WordEncryption.OpenDocument: Successfully unprotected document \"{0}\"", sourceFile)); } } } } } catch(UnauthorizedAccessException) { Logger.LogInfo("Incorrect password. Exit word, and retry"); DocumentProtectionPassword = string.Empty; decryptWrapper.ForceQuit(); throw; } catch (COMException ex) { Logger.LogError("Office Open Exception"); Logger.LogError(ex); // handle exceptions for incorrect encryption passwords and the document preotection password if( ex.ErrorCode == unchecked((int)0x800A03EC) || ex.ErrorCode == unchecked((int)0x800A156D) ) { Logger.LogInfo("Incorrect password. Exit word, and retry"); DocumentProtectionPassword = string.Empty; decryptWrapper.ForceQuit(); throw new UnauthorizedAccessException("Failed to open encrypted file - incorrect password"); } throw; } finally { // Reset any dummy password which may have been used so that the // document doesn't incorrectly get saved with it. if (bUseDummyModifyPassword) { ModifyPassword = ""; } } } return result; }