gpt4 book ai didi

java - 兴趣点 : Set password to protect from changes

转载 作者:行者123 更新时间:2023-11-29 08:31:28 25 4
gpt4 key购买 nike

我想使用 Apache POI 对 OOXML 文件启用密码保护。

通过 Office 程序,在保存文件(pptxxlsx...)时,我可以选择工具 > 选项 并那里提示我设置打开和/或更改文件的密码。

现在,我通过谷歌搜索了几个小时,并阅读了一些 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com