dotnet Open XML 如何判断一份 Office 文档是否被加密

时间:2022-07-25
本文章向大家介绍dotnet Open XML 如何判断一份 Office 文档是否被加密,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在拿到一份 PPTX 文档,或一份 Word 的 docx 文档,如何判断这份文档是被加密的

在 Office 里,对 pptx 文档或 docx 或 xlsx 文档的加密是将文档加密为 OLE 格式,也就是和 Office 2003 的 doc 等文档格式相同的 Ole object 格式

在没加密时,是使用 OPC 格式,也就是 zip 压缩文档。但是加密之后,文档格式使用 OLE Object 格式,就不能用 OpenXML SDK 读取。因为 OpenXML SDK 将使用压缩文档读取方法读取,这个方法不能读取 OLE 文件

如果使用 OpenXML SDK 读取一个加密的 Office 文档,那么将会在读取的时候抛出 OpenXmlPackageException 告诉开发者失败

可以使用 openmcdf 这个开源库读取 OLE 文件,然后判断这个文件是否 Office 加密文件

判断一份文档是否被加密首先需要了解加密的格式,请看 [MS-OFFCRYPTO]: Office Document Cryptography Structure

先创建一份加密的 pptx 文档,接下来尝试判断这个文件是加密的 Office 文件,我在 github 放一份我创建的文件,小伙伴可以随意使用

最简单的方法就是通过 OpenXML SDK 读一下文档,如果抛出 OpenXmlPackageException 那么也许就是被加密了

如果想要通过读取 OLE 判断的方法,需要先在项目里面安装 openmcdf

  <ItemGroup>
    <PackageReference Include="OpenMcdf" Version="2.2.1.6" />
  </ItemGroup>

然后添加下面代码

        private static bool CheckOfficeDocumentWithPassword(FileInfo file)
        {
            CompoundFile cf = new CompoundFile(file.FullName);
            var numDirectories = cf.GetNumDirectories();
            for (int i = 0; i < numDirectories; i++)
            {
                var nameDirEntry = cf.GetNameDirEntry(i);

                if (cf.RootStorage.TryGetStream(nameDirEntry, out var stream))
                {
                    if (nameDirEntry == "EncryptionInfo")
                    {
                        return true;
                    }
                }
            }

            return false;
        }

使用方法如下

        static void Main(string[] args)
        {
            var file = @"带密码的课件PPTX.pptx";

            if (CheckOfficeDocumentWithPassword(new FileInfo(file)))
            {
                Console.WriteLine("带密码");
            }
        }

本文代码放在 github 欢迎小伙伴访问

这个方法判断的原理是加密的 Office 文件里面,将会是 OLE 格式,而 OLE 是一个磁盘格式,可以理解为和 zip 差不多的格式,加密的文件里面将会包含下面内容

而在 Office 的解密方法就是使用用户输入的密码和 EncryptionInfo 内容判断,然后解压缩 EncryptedPackage 文件,所以上面的判断大概是对的