- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想使用 Apache POI 对 OOXML 文件启用密码保护。
通过 Office 程序,在保存文件(pptx
、xlsx
...)时,我可以选择工具 > 选项
并那里提示我设置打开和/或更改文件的密码。
现在,我通过谷歌搜索了几个小时,并阅读了一些 API 页面来查找 POI 方法,但什么也没找到。
知道这是否已实现,或者是微软的专业,因为他们根本不在乎自己的标准化?
编辑:由于下面的第一条评论指向 Office 2003 文档,因此我可以明确指出:我正在谈论 XSS* 功能。我想保护 2007 年以来的 OOXML 格式。我在不同的 API 上查找类似的函数,但找不到这些。 HSSWorkBook#writeProtect...我知道。
最佳答案
虽然 Excel
在保存文件时一步完成了此操作,但这是两步。
首先,ReadOnlyRecommended
在 /xl/workbook.xml
中设置,如下所示:
<workbook>
...
<fileSharing readOnlyRecommended="true" userName="user" reservationPassword="DC45"/>
...
可以使用 org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFileSharing 设置 fileSharing
元素您可以在 CTWorkbook
中获取/设置,您可以从 XSSFWorkbook.getCTWorkbook 获取.
reservationPassword
的密码哈希值是通过特殊算法计算的。不幸的是,大多数 Office Open XML 规范都没有正确描述该算法。我在 Office Open XML Part 4 - Transitional Migration Features.pdf, page 229 and 230 中找到了正确的描述.
完成此步骤后,您将拥有一个工作簿,其中建议使用只读权限,并使用密码打开并具有写入权限。
如果完成,您现在可以设置加密,如Apache POI - Encryption support所示.
示例:
import java.io.*;
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.poifs.crypt.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.nio.ByteBuffer;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
public class OOXMLEncryptionTest {
//password hashed using the low-order word algorithm defined in §14.7.1 of ECMA-376
static short getPasswordHash(String szPassword) {
int wPasswordHash;
byte[] pch = szPassword.getBytes();
int cchPassword = pch.length;
wPasswordHash = 0;
if (cchPassword > 0) {
for (int i = cchPassword; i > 0; i--) {
wPasswordHash = ((wPasswordHash >> 14) & 0x01) | ((wPasswordHash << 1) & 0x7FFF);
wPasswordHash ^= pch[i-1];
}
wPasswordHash = ((wPasswordHash >> 14) & 0x01) | ((wPasswordHash << 1) & 0x7FFF);
wPasswordHash ^= cchPassword;
wPasswordHash ^= (0x8000 | ('N' << 8) | 'K');
}
System.out.println(wPasswordHash);
return (short)(wPasswordHash);
}
public static void main(String[] args) throws Exception {
// Open an Excel workbook and set ReadOnlyRecommended
XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("ExcelTest.xlsx"));
CTWorkbook ctWorkbook = workbook.getCTWorkbook();
CTFileSharing ctfilesharing = ctWorkbook.getFileSharing();
if (ctfilesharing == null) ctfilesharing = ctWorkbook.addNewFileSharing();
ctfilesharing.setReadOnlyRecommended(true);
ctfilesharing.setUserName("user");
short passwordhash = getPasswordHash("baafoo");
System.out.println(passwordhash);
byte[] bpasswordhash = ByteBuffer.allocate(2).putShort(passwordhash).array();
ctfilesharing.setReservationPassword(bpasswordhash);
workbook.write(new FileOutputStream("ExcelTestRORecommended.xlsx"));
workbook.close();
// Now do the encryption
POIFSFileSystem fs = new POIFSFileSystem();
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
// EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes192, HashAlgorithm.sha384, -1, -1, null);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("foobaa");
// Read in an existing OOXML file
OPCPackage opc = OPCPackage.open(new File("ExcelTestRORecommended.xlsx"), PackageAccess.READ_WRITE);
OutputStream os = enc.getDataStream(fs);
opc.save(os);
opc.close();
// Write out the encrypted version
FileOutputStream fos = new FileOutputStream("ExcelTestEncrypted.xlsx");
fs.writeFilesystem(fos);
fos.close();
}
}
设置只读建议对于所有 Microsoft Office
文件类型来说似乎都是相同的,因为在所有情况下您都会在文件保存时设置只读建议,但在幕后却并非如此。 Microsoft 将其存储到文件中的方式非常不同。
在 Excel
中,它是工作簿的 FileSharing
元素中的 ReadOnlyRecommended
,并且仅使用非常不安全的 2 字节密码哈希。
在Word
中,它是设置部分中的WriteProtection
元素。它使用现代加密方法加盐密码哈希。
在 PowerPoint
中,它是演示文稿中的 ModifyVerifier
元素,它还使用现代加密方法的加盐密码哈希。
以下示例显示了所有三种方法:
import java.io.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import java.nio.ByteBuffer;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.POIXMLDocumentPart;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.openxmlformats.schemas.presentationml.x2006.main.*;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import java.security.SecureRandom;
import java.math.BigInteger;
import java.lang.reflect.Field;
public class RORecommendedTest {
//password hashed using the low-order word algorithm defined in §14.7.1 of ECMA-376
static short getPasswordHash(String szPassword) {
int wPasswordHash;
byte[] pch = szPassword.getBytes();
int cchPassword = pch.length;
wPasswordHash = 0;
if (cchPassword > 0) {
for (int i = cchPassword; i > 0; i--) {
wPasswordHash = ((wPasswordHash >> 14) & 0x01) | ((wPasswordHash << 1) & 0x7FFF);
wPasswordHash ^= pch[i-1];
}
wPasswordHash = ((wPasswordHash >> 14) & 0x01) | ((wPasswordHash << 1) & 0x7FFF);
wPasswordHash ^= cchPassword;
wPasswordHash ^= (0x8000 | ('N' << 8) | 'K');
}
return (short)(wPasswordHash);
}
public static void main(String[] args) throws Exception {
// Open an Excel workbook and set ReadOnlyRecommended
XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("ExcelTest.xlsx"));
CTWorkbook ctWorkbook = workbook.getCTWorkbook();
CTFileSharing ctfilesharing = ctWorkbook.getFileSharing();
if (ctfilesharing == null) ctfilesharing = ctWorkbook.addNewFileSharing();
ctfilesharing.setReadOnlyRecommended(true);
ctfilesharing.setUserName("user");
short passwordhash = getPasswordHash("baafoo");
byte[] bpasswordhash = ByteBuffer.allocate(2).putShort(passwordhash).array();
ctfilesharing.setReservationPassword(bpasswordhash);
workbook.write(new FileOutputStream("ExcelTestRORecommended.xlsx"));
workbook.close();
// Open a Word document and set read only recommended aka WriteProtection
XWPFDocument document = new XWPFDocument(new FileInputStream("WordTest.docx"));
POIXMLDocumentPart part = null;
for (int i = 0; i < document.getRelations().size(); i++) {
part = document.getRelations().get(i);
if (part instanceof XWPFSettings) break;
}
if (part instanceof XWPFSettings) {
XWPFSettings settings = (XWPFSettings)part;
Field _ctSettings = XWPFSettings.class.getDeclaredField("ctSettings");
_ctSettings.setAccessible(true);
CTSettings ctSettings = (CTSettings)_ctSettings.get(settings);
CTWriteProtection ctwriteprotection = ctSettings.getWriteProtection();
if (ctwriteprotection == null) ctwriteprotection = ctSettings.addNewWriteProtection();
ctwriteprotection.setRecommended(STOnOff.ON);
ctwriteprotection.setCryptProviderType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STCryptProv.RSA_FULL);
ctwriteprotection.setCryptAlgorithmClass(org.openxmlformats.schemas.wordprocessingml.x2006.main.STAlgClass.HASH);
ctwriteprotection.setCryptAlgorithmType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STAlgType.TYPE_ANY);
ctwriteprotection.setCryptAlgorithmSid(BigInteger.valueOf(4)); //SHA-1
ctwriteprotection.setCryptSpinCount(BigInteger.valueOf(100000));
SecureRandom random = new SecureRandom();
byte[] salt = random.generateSeed(16);
byte[] hash = CryptoFunctions.hashPassword("baafoo", HashAlgorithm.sha1, salt, 100000, false);
ctwriteprotection.setHash(hash);
ctwriteprotection.setSalt(salt);
}
document.write(new FileOutputStream("WordTestRORecommended.docx"));
document.close();
// Open a PowerPoint show and set read only recommended aka ModifyVerifier
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("PowerPntTest.pptx"));
CTPresentation ctpresentation = slideShow.getCTPresentation();
CTModifyVerifier ctmodifyverifier = ctpresentation.getModifyVerifier();
if (ctmodifyverifier == null) ctmodifyverifier = ctpresentation.addNewModifyVerifier();
ctmodifyverifier.setCryptProviderType(org.openxmlformats.schemas.presentationml.x2006.main.STCryptProv.RSA_FULL);
ctmodifyverifier.setCryptAlgorithmClass(org.openxmlformats.schemas.presentationml.x2006.main.STAlgClass.HASH);
ctmodifyverifier.setCryptAlgorithmType(org.openxmlformats.schemas.presentationml.x2006.main.STAlgType.TYPE_ANY);
ctmodifyverifier.setCryptAlgorithmSid(4); //SHA-1
ctmodifyverifier.setSpinCount(100000);
SecureRandom random = new SecureRandom();
byte[] salt = random.generateSeed(16);
byte[] hash = CryptoFunctions.hashPassword("baafoo", HashAlgorithm.sha1, salt, 100000, false);
ctmodifyverifier.setHashData(java.util.Base64.getEncoder().encodeToString(hash));
ctmodifyverifier.setSaltData(java.util.Base64.getEncoder().encodeToString(salt));
slideShow.write(new FileOutputStream("PowerPntTestRORecommended.pptx"));
slideShow.close();
}
}
关于java - 兴趣点 : Set password to protect from changes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47771952/
这个问题在这里已经有了答案: How to make a property protected AND internal in C#? (8 个答案) 关闭 9 年前。 我需要声明一个既受又 内部保
我有以下代码: class Base{ protected val alpha ="Alpha"; protected def sayHello = "Hello"; } class
我正在尝试运行一个宏来创建一个工作正常的pdf。 Excel 文件获得签名后,Excel 文件将自动受到保护。 问题:我的工作表上有一个按钮,需要按下该按钮才能创建 pdf 文档网。然而,这是无法完成
子类需要能够使用种子随机数生成器。 使用的优点和缺点是什么 public abstract class AbstractClass { protected Random rnd; public
我们有两个类(class)(A 和 B)。 A类只能由继承它的类创建(A类)B 类可以由用户创建。 A 类,版本 1 有一个private 数据成员,并且有方法访问 A 类中的数据。 A 类,版本 2
当父类受到保护时,我对继承类的默认构造函数有疑问,在我看来,子类也会有一个默认构造函数受到保护,但事实并非如此。 除了在子类上强制默认构造函数外,还有其他方法可以强制保护默认构造函数吗? C++11
我有一个抽象类,我想在其 protected 构造函数中初始化一个只读字段。我希望这个只读字段在派生类中可用。 按照我将所有字段设为私有(private)并公开属性的习惯,我实现如下: abstrac
我在运行大数据时遇到错误。错误已由以下示例示例解释 加载数据 mdata <- as.matrix(read.table('https://gubox.box.com/shared/static
我在获取 时遇到问题非法访问错误 对于以下示例: 我在名为 arch 的 gradle 模块中声明了一个基类 abstract class BaseClass { protected abst
我相信通过 实现 JSF 应用程序的安全性+ + & 通过使用 是两种不同的方式!?他们是吗? 我尝试通过上述第一种方法(使用 + + )来实现安全性,但发现使用 protected 和不
有没有办法确定以下的二传手能见度差异: public Prop { get; protected set; } protected Prop { get; set; } 使用反射?还是那些与 C# 反
我读了一本关于 OOP 的书,并且关于“ protected ”访问修饰符的示例对我来说很奇怪。 例子总结 这个例子是为了测试“protected”保留字对变量的影响。 ClassA 有 2 个 pr
内部——在集会上公开,在其他地方私有(private)。 protected - 只有派生类可以访问父类成员。 Protected internal - protected OR internal -
我有一个类代表 Wicket 中带有“返回”、“前进”和“取消”按钮的基本页面。但并非所有页面都有所有按钮,例如。 G。第一页明显没有“返回”。 我的想法是定义一个通用的ActionHandler p
在了解到嵌套类是嵌套类的成员并因此可以完全访问嵌套类的成员这一事实后(至少对于 C++11,请参见 here),我在尝试创建嵌套类模板: #include using namespace std;
我刚刚使用了 Resharper,并一直在尝试将字段转换为属性。我希望这些属性受到保护,但 Resharper 不想给我这个选项。相反,只有一个 protected 内部选项。这让我思考。要么某处有一
这是 question 的扩展一个小时前问过。 当覆盖派生类中的虚方法时,我们不能修改访问修饰符。考虑 System.Web.UI 命名空间中的 Control 类 public class Cont
有人可以解释一下 C# 中 protected 和 protected internal 修饰符之间的区别吗?看起来他们的行为是相同的。 最佳答案 “protected internal”访问修饰符是
我想知道下面两行代码之间是否有区别: protected $var = null; protected $var; 我已经看到两者都被使用了,我想知道这是否只是一个偏好问题,(也就是 $var; 将变
我正在尝试使用mockito为“另存为”操作编写单元测试。该操作的一部分是制作并显示一个文件对话框,用户可以在其中输入要保存的文件。选择文件不是我可以自动化的操作,因此我想模拟 FileDialog
我是一名优秀的程序员,十分优秀!