Browse Source

Bug 51483 - XSSF locking of specific features not working

Added some documentation to the crypto functions and adapted xor1verifier code to the OFFCrypto-Docs

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1622577 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_11_BETA3
Andreas Beeker 9 years ago
parent
commit
d71574d531

+ 7
- 16
src/java/org/apache/poi/hssf/record/PasswordRecord.java View File



package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;


import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;


field_1_password = in.readShort(); field_1_password = in.readShort();
} }


//this is the world's lamest "security". thanks to Wouter van Vugt for making me
//not have to try real hard. -ACO
/**
* Return the password hash
*
* @deprecated use {@link CryptoFunctions#createXorVerifier1(String)}
*/
public static short hashPassword(String password) { public static short hashPassword(String password) {
byte[] passwordCharacters = password.getBytes();
int hash = 0;
if (passwordCharacters.length > 0) {
int charIndex = passwordCharacters.length;
while (charIndex-- > 0) {
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
hash ^= passwordCharacters[charIndex];
}
// also hash with charcount
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
hash ^= passwordCharacters.length;
hash ^= (0x8000 | ('N' << 8) | 'K');
}
return (short)hash;
return (short)CryptoFunctions.createXorVerifier1(password);
} }


/** /**

+ 2
- 1
src/java/org/apache/poi/hssf/record/aggregates/WorksheetProtectionBlock.java View File

import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFormatException; import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.ScenarioProtectRecord; import org.apache.poi.hssf.record.ScenarioProtectRecord;
import org.apache.poi.poifs.crypt.CryptoFunctions;


/** /**
* Groups the sheet protection records for a worksheet. * Groups the sheet protection records for a worksheet.
ProtectRecord prec = getProtect(); ProtectRecord prec = getProtect();
PasswordRecord pass = getPassword(); PasswordRecord pass = getPassword();
prec.setProtect(true); prec.setProtect(true);
pass.setPassword(PasswordRecord.hashPassword(password));
pass.setPassword((short)CryptoFunctions.createXorVerifier1(password));
if (_objectProtectRecord == null && shouldProtectObjects) { if (_objectProtectRecord == null && shouldProtectObjects) {
ObjectProtectRecord rec = createObjectProtect(); ObjectProtectRecord rec = createObjectProtect();
rec.setProtect(true); rec.setProtect(true);

+ 66
- 17
src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java View File

} }
/** /**
*
* Initialize a new cipher object with the given cipher properties
* If the given algorithm is not implemented in the JCE, it will try to load it from the bouncy castle
* provider.
* *
* @param key
* @param chain
* @param vec
* @param key the secrect key
* @param cipherAlgorithm the cipher algorithm
* @param chain the chaining mode
* @param vec the initialization vector (IV), can be null
* @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE * @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE
* @param padding
* @return the requested cipher * @return the requested cipher
* @throws GeneralSecurityException * @throws GeneralSecurityException
* @throws EncryptedDocumentException if the initialization failed or if an algorithm was specified,
* which depends on a missing bouncy castle provider
*/ */
public static Cipher getCipher(SecretKey key, CipherAlgorithm cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode, String padding) { public static Cipher getCipher(SecretKey key, CipherAlgorithm cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode, String padding) {
int keySizeInBytes = key.getEncoded().length; int keySizeInBytes = key.getEncoded().length;
} }
} }
/**
* Returns a new byte array with a truncated to the given size.
* If the hash has less then size bytes, it will be filled with 0x36-bytes
*
* @param hash the to be truncated/filled hash byte array
* @param size the size of the returned byte array
* @return the padded hash
*/
public static byte[] getBlock36(byte[] hash, int size) { public static byte[] getBlock36(byte[] hash, int size) {
return getBlockX(hash, size, (byte)0x36); return getBlockX(hash, size, (byte)0x36);
} }
/**
* Returns a new byte array with a truncated to the given size.
* If the hash has less then size bytes, it will be filled with 0-bytes
*
* @param hash the to be truncated/filled hash byte array
* @param size the size of the returned byte array
* @return the padded hash
*/
public static byte[] getBlock0(byte[] hash, int size) { public static byte[] getBlock0(byte[] hash, int size) {
return getBlockX(hash, size, (byte)0); return getBlockX(hash, size, (byte)0);
} }
byte[] generatedKey = new byte[4]; byte[] generatedKey = new byte[4];
//Maximum length of the password is 15 chars. //Maximum length of the password is 15 chars.
final int intMaxPasswordLength = 15;
final int maxPasswordLength = 15;
if (!"".equals(password)) { if (!"".equals(password)) {
// Truncate the password to 15 characters // Truncate the password to 15 characters
password = password.substring(0, Math.min(password.length(), intMaxPasswordLength));
password = password.substring(0, Math.min(password.length(), maxPasswordLength));
// Construct a new NULL-terminated string consisting of single-byte characters: // Construct a new NULL-terminated string consisting of single-byte characters:
// -- > Get the single-byte values by iterating through the Unicode characters of the truncated Password. // -- > Get the single-byte values by iterating through the Unicode characters of the truncated Password.
// the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from // the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from
// the Encryption Matrix // the Encryption Matrix
for (int i = 0; i < arrByteChars.length; i++) { for (int i = 0; i < arrByteChars.length; i++) {
int tmp = intMaxPasswordLength - arrByteChars.length + i;
int tmp = maxPasswordLength - arrByteChars.length + i;
for (int intBit = 0; intBit < 7; intBit++) { for (int intBit = 0; intBit < 7; intBit++) {
if ((arrByteChars[i] & (0x0001 << intBit)) != 0) { if ((arrByteChars[i] & (0x0001 << intBit)) != 0) {
highOrderWord ^= EncryptionMatrix[tmp][intBit]; highOrderWord ^= EncryptionMatrix[tmp][intBit];
// Compute the low-order word of the new key: // Compute the low-order word of the new key:
// Initialize with 0
int lowOrderWord = 0;
// SET Verifier TO 0x0000
short verifier = 0;
// For each character in the password, going backwards
for (int i = arrByteChars.length - 1; i >= 0; i--) {
// low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character
lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[i];
// FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
for (int i = arrByteChars.length-1; i >= 0; i--) {
// SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
verifier = rotateLeftBase15Bit(verifier);
verifier ^= arrByteChars[i];
} }
// Lastly,low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR password length XOR 0xCE4B.
lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.length ^ 0xCE4B;
// as we haven't prepended the password length into the input array
// we need to do it now separately ...
verifier = rotateLeftBase15Bit(verifier);
verifier ^= arrByteChars.length;
// RETURN Verifier BITWISE XOR 0xCE4B
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
// The byte order of the result shall be reversed [password "Example": 0x64CEED7E becomes 7EEDCE64], // The byte order of the result shall be reversed [password "Example": 0x64CEED7E becomes 7EEDCE64],
// and that value shall be hashed as defined by the attribute values. // and that value shall be hashed as defined by the attribute values.
LittleEndian.putShort(generatedKey, 0, (short)lowOrderWord);
LittleEndian.putShort(generatedKey, 0, verifier);
LittleEndian.putShort(generatedKey, 2, (short)highOrderWord); LittleEndian.putShort(generatedKey, 2, (short)highOrderWord);
} }
* @see <a href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary Document Password Verifier Derivation Method 2</a> * @see <a href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary Document Password Verifier Derivation Method 2</a>
* *
* @param password the password * @param password the password
* @return the verifier
* @return the verifier (actually a short value)
*/ */
public static int createXorVerifier1(String password) { public static int createXorVerifier1(String password) {
// the verifier for method 1 is part of the verifier for method 2 // the verifier for method 1 is part of the verifier for method 2
private static byte rotateLeft(byte bits, int shift) { private static byte rotateLeft(byte bits, int shift) {
return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 - shift))); return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 - shift)));
} }
private static short rotateLeftBase15Bit(short verifier) {
/*
* IF (Verifier BITWISE AND 0x4000) is 0x0000
* SET Intermediate1 TO 0
* ELSE
* SET Intermediate1 TO 1
* ENDIF
*/
short intermediate1 = (short)(((verifier & 0x4000) == 0) ? 0 : 1);
/*
* SET Intermediate2 TO Verifier MULTIPLED BY 2
* SET most significant bit of Intermediate2 TO 0
*/
short intermediate2 = (short)((verifier<<1) & 0x7FFF);
/*
* SET Intermediate3 TO Intermediate1 BITWISE OR Intermediate2
*/
short intermediate3 = (short)(intermediate1 | intermediate2);
return intermediate3;
}
} }

+ 7
- 0
src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java View File

} }
throw new EncryptedDocumentException("hash algorithm not found"); throw new EncryptedDocumentException("hash algorithm not found");
} }
public static HashAlgorithm fromString(String string) {
for (HashAlgorithm ha : values()) {
if (ha.ecmaString.equalsIgnoreCase(string) || ha.jceId.equalsIgnoreCase(string)) return ha;
}
throw new EncryptedDocumentException("hash algorithm not found");
}
} }

+ 264
- 118
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java View File



package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;


import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;

import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;


import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException; import org.apache.poi.POIXMLException;
import org.apache.poi.hssf.record.PasswordRecord;
import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException; import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.SheetNameFormatter; import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.util.SSCellRange; import org.apache.poi.ss.util.SSCellRange;
import org.apache.poi.ss.util.SheetUtil; import org.apache.poi.ss.util.SheetUtil;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
*/ */
@Override @Override
public boolean getProtect() { public boolean getProtect() {
return worksheet.isSetSheetProtection() && sheetProtectionEnabled();
return isSheetLocked();
} }


/** /**
*/ */
@Override @Override
public void protectSheet(String password) { public void protectSheet(String password) {

if(password != null) {
CTSheetProtection sheetProtection = worksheet.addNewSheetProtection();
sheetProtection.xsetPassword(stringToExcelPassword(password));
if (password != null) {
CTSheetProtection sheetProtection = safeGetProtectionField();
setSheetPassword(password, null); // defaults to xor password
sheetProtection.setSheet(true); sheetProtection.setSheet(true);
sheetProtection.setScenarios(true); sheetProtection.setScenarios(true);
sheetProtection.setObjects(true); sheetProtection.setObjects(true);
} }


/** /**
* Converts a String to a {@link STUnsignedShortHex} value that contains the {@link PasswordRecord#hashPassword(String)}
* value in hexadecimal format
*
* @param password the password string you wish convert to an {@link STUnsignedShortHex}
* @return {@link STUnsignedShortHex} that contains Excel hashed password in Hex format
* Sets the sheet password.
*
* @param password if null, the password will be removed
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
*/ */
private STUnsignedShortHex stringToExcelPassword(String password) {
STUnsignedShortHex hexPassword = STUnsignedShortHex.Factory.newInstance();
hexPassword.setStringValue(String.valueOf(HexDump.shortToHex(PasswordRecord.hashPassword(password))).substring(2));
return hexPassword;
public void setSheetPassword(String password, HashAlgorithm hashAlgo) {
if (password == null && !isSheetProtectionEnabled()) return;
setPassword(safeGetProtectionField(), password, hashAlgo, null);
} }


/**
* Validate the password against the stored hash, the hashing method will be determined
* by the existing password attributes
* @return true, if the hashes match (... though original password may differ ...)
*/
public boolean validateSheetPassword(String password) {
if (!isSheetProtectionEnabled()) return (password == null);
return validatePassword(safeGetProtectionField(), password, null);
}
/** /**
* Returns the logical row ( 0-based). If you ask for a row that is not * Returns the logical row ( 0-based). If you ask for a row that is not
* defined you get a null. This is to say row 4 represents the fifth row on a sheet. * defined you get a null. This is to say row 4 represents the fifth row on a sheet.
worksheet.unsetMergeCells(); worksheet.unsetMergeCells();
} }
} }
/** /**
* Removes a number of merged regions of cells (hence letting them free) * Removes a number of merged regions of cells (hence letting them free)
* *
* @return true when Autofilters are locked and the sheet is protected. * @return true when Autofilters are locked and the sheet is protected.
*/ */
public boolean isAutoFilterLocked() { public boolean isAutoFilterLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getAutoFilter();
if (isSheetLocked()) {
return safeGetProtectionField().getAutoFilter();
}
return false;
} }


/** /**
* @return true when Deleting columns is locked and the sheet is protected. * @return true when Deleting columns is locked and the sheet is protected.
*/ */
public boolean isDeleteColumnsLocked() { public boolean isDeleteColumnsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getDeleteColumns();
if (isSheetLocked()) {
return safeGetProtectionField().getDeleteColumns();
}
return false;
} }


/** /**
* @return true when Deleting rows is locked and the sheet is protected. * @return true when Deleting rows is locked and the sheet is protected.
*/ */
public boolean isDeleteRowsLocked() { public boolean isDeleteRowsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getDeleteRows();
if (isSheetLocked()) {
return safeGetProtectionField().getDeleteRows();
}
return false;
} }


/** /**
* @return true when Formatting cells is locked and the sheet is protected. * @return true when Formatting cells is locked and the sheet is protected.
*/ */
public boolean isFormatCellsLocked() { public boolean isFormatCellsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getFormatCells();
if (isSheetLocked()) {
return safeGetProtectionField().getFormatCells();
}
return false;
} }


/** /**
* @return true when Formatting columns is locked and the sheet is protected. * @return true when Formatting columns is locked and the sheet is protected.
*/ */
public boolean isFormatColumnsLocked() { public boolean isFormatColumnsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getFormatColumns();
if (isSheetLocked()) {
return safeGetProtectionField().getFormatColumns();
}
return false;
} }


/** /**
* @return true when Formatting rows is locked and the sheet is protected. * @return true when Formatting rows is locked and the sheet is protected.
*/ */
public boolean isFormatRowsLocked() { public boolean isFormatRowsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getFormatRows();
if (isSheetLocked()) {
return safeGetProtectionField().getFormatRows();
}
return false;
} }


/** /**
* @return true when Inserting columns is locked and the sheet is protected. * @return true when Inserting columns is locked and the sheet is protected.
*/ */
public boolean isInsertColumnsLocked() { public boolean isInsertColumnsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getInsertColumns();
if (isSheetLocked()) {
return safeGetProtectionField().getInsertColumns();
}
return false;
} }


/** /**
* @return true when Inserting hyperlinks is locked and the sheet is protected. * @return true when Inserting hyperlinks is locked and the sheet is protected.
*/ */
public boolean isInsertHyperlinksLocked() { public boolean isInsertHyperlinksLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getInsertHyperlinks();
if (isSheetLocked()) {
return safeGetProtectionField().getInsertHyperlinks();
}
return false;
} }


/** /**
* @return true when Inserting rows is locked and the sheet is protected. * @return true when Inserting rows is locked and the sheet is protected.
*/ */
public boolean isInsertRowsLocked() { public boolean isInsertRowsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getInsertRows();
if (isSheetLocked()) {
return safeGetProtectionField().getInsertRows();
}
return false;
} }


/** /**
* @return true when Pivot tables are locked and the sheet is protected. * @return true when Pivot tables are locked and the sheet is protected.
*/ */
public boolean isPivotTablesLocked() { public boolean isPivotTablesLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getPivotTables();
if (isSheetLocked()) {
return safeGetProtectionField().getPivotTables();
}
return false;
} }


/** /**
* @return true when Sorting is locked and the sheet is protected. * @return true when Sorting is locked and the sheet is protected.
*/ */
public boolean isSortLocked() { public boolean isSortLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getSort();
if (isSheetLocked()) {
return safeGetProtectionField().getSort();
}
return false;
} }


/** /**
* @return true when Objects are locked and the sheet is protected. * @return true when Objects are locked and the sheet is protected.
*/ */
public boolean isObjectsLocked() { public boolean isObjectsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getObjects();
if (isSheetLocked()) {
return safeGetProtectionField().getObjects();
}
return false;
} }


/** /**
* @return true when Scenarios are locked and the sheet is protected. * @return true when Scenarios are locked and the sheet is protected.
*/ */
public boolean isScenariosLocked() { public boolean isScenariosLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getScenarios();
if (isSheetLocked()) {
return safeGetProtectionField().getScenarios();
}
return false;
} }


/** /**
* @return true when Selection of locked cells is locked and the sheet is protected. * @return true when Selection of locked cells is locked and the sheet is protected.
*/ */
public boolean isSelectLockedCellsLocked() { public boolean isSelectLockedCellsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getSelectLockedCells();
if (isSheetLocked()) {
return safeGetProtectionField().getSelectLockedCells();
}
return false;
} }


/** /**
* @return true when Selection of unlocked cells is locked and the sheet is protected. * @return true when Selection of unlocked cells is locked and the sheet is protected.
*/ */
public boolean isSelectUnlockedCellsLocked() { public boolean isSelectUnlockedCellsLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getSelectUnlockedCells();
if (isSheetLocked()) {
return safeGetProtectionField().getSelectUnlockedCells();
}
return false;
} }


/** /**
* @return true when Sheet is Protected. * @return true when Sheet is Protected.
*/ */
public boolean isSheetLocked() { public boolean isSheetLocked() {
createProtectionFieldIfNotPresent();
return sheetProtectionEnabled() && worksheet.getSheetProtection().getSheet();
if (worksheet.isSetSheetProtection()) {
return safeGetProtectionField().getSheet();
}
return false;
} }


/** /**
* Enable sheet protection * Enable sheet protection
*/ */
public void enableLocking() { public void enableLocking() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setSheet(true);
safeGetProtectionField().setSheet(true);
} }


/** /**
* Disable sheet protection * Disable sheet protection
*/ */
public void disableLocking() { public void disableLocking() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setSheet(false);
safeGetProtectionField().setSheet(false);
} }


/** /**
* Enable Autofilters locking. * Enable Autofilters locking.
* This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* @deprecated use {@link #lockAutoFilter(boolean)}
*/ */
public void lockAutoFilter() { public void lockAutoFilter() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setAutoFilter(true);
lockAutoFilter(true);
} }


/** /**
* Enable Deleting columns locking.
* Enable or disable Autofilters locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockAutoFilter(boolean enabled) {
safeGetProtectionField().setAutoFilter(enabled);
}

/**
* Enable Deleting columns locking.
* @deprecated use {@link #lockDeleteColumns(boolean)}
*/ */
public void lockDeleteColumns() { public void lockDeleteColumns() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setDeleteColumns(true);
lockDeleteColumns(true);
} }


/** /**
* Enable Deleting rows locking.
* Enable or disable Deleting columns locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockDeleteColumns(boolean enabled) {
safeGetProtectionField().setDeleteColumns(enabled);
}

/**
* Enable Deleting rows locking.
* @deprecated use {@link #lockDeleteRows(boolean)}
*/ */
public void lockDeleteRows() { public void lockDeleteRows() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setDeleteRows(true);
lockDeleteRows(true);
} }


/** /**
* Enable Formatting cells locking.
* Enable or disable Deleting rows locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockDeleteRows(boolean enabled) {
safeGetProtectionField().setDeleteRows(enabled);
}

/**
* Enable Formatting cells locking.
* @deprecated use {@link #lockFormatCells(boolean)}
*/ */
public void lockFormatCells() { public void lockFormatCells() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setDeleteColumns(true);
lockFormatCells(true);
} }


/** /**
* Enable Formatting columns locking.
* Enable or disable Formatting cells locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockFormatCells(boolean enabled) {
safeGetProtectionField().setFormatCells(enabled);
}

/**
* Enable Formatting columns locking.
* @deprecated use {@link #lockFormatColumns(boolean)}
*/ */
public void lockFormatColumns() { public void lockFormatColumns() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setFormatColumns(true);
lockFormatColumns(true);
} }


/** /**
* Enable Formatting rows locking.
* Enable or disable Formatting columns locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockFormatColumns(boolean enabled) {
safeGetProtectionField().setFormatColumns(enabled);
}

/**
* Enable Formatting rows locking.
* @deprecated use {@link #lockFormatRows(boolean)}
*/ */
public void lockFormatRows() { public void lockFormatRows() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setFormatRows(true);
lockFormatRows(true);
} }


/** /**
* Enable Inserting columns locking.
* Enable or disable Formatting rows locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockFormatRows(boolean enabled) {
safeGetProtectionField().setFormatRows(enabled);
}

/**
* Enable Inserting columns locking.
* @deprecated use {@link #lockInsertColumns(boolean)}
*/ */
public void lockInsertColumns() { public void lockInsertColumns() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setInsertColumns(true);
lockInsertColumns(true);
} }


/** /**
* Enable Inserting hyperlinks locking.
* Enable or disable Inserting columns locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockInsertColumns(boolean enabled) {
safeGetProtectionField().setInsertColumns(enabled);
}

/**
* Enable Inserting hyperlinks locking.
* @deprecated use {@link #lockInsertHyperlinks(boolean)}
*/ */
public void lockInsertHyperlinks() { public void lockInsertHyperlinks() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setInsertHyperlinks(true);
lockInsertHyperlinks(true);
} }


/** /**
* Enable Inserting rows locking.
* Enable or disable Inserting hyperlinks locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockInsertHyperlinks(boolean enabled) {
safeGetProtectionField().setInsertHyperlinks(enabled);
}

/**
* Enable Inserting rows locking.
* @deprecated use {@link #lockInsertRows(boolean)}
*/ */
public void lockInsertRows() { public void lockInsertRows() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setInsertRows(true);
lockInsertRows(true);
} }


/** /**
* Enable Pivot Tables locking.
* Enable or disable Inserting rows locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockInsertRows(boolean enabled) {
safeGetProtectionField().setInsertRows(enabled);
}

/**
* Enable Pivot Tables locking.
* @deprecated use {@link #lockPivotTables(boolean)}
*/ */
public void lockPivotTables() { public void lockPivotTables() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setPivotTables(true);
lockPivotTables(true);
} }


/** /**
* Enable Sort locking.
* Enable or disable Pivot Tables locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockPivotTables(boolean enabled) {
safeGetProtectionField().setPivotTables(enabled);
}

/**
* Enable Sort locking.
* @deprecated use {@link #lockSort(boolean)}
*/ */
public void lockSort() { public void lockSort() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setSort(true);
lockSort(true);
} }


/** /**
* Enable Objects locking.
* Enable or disable Sort locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockSort(boolean enabled) {
safeGetProtectionField().setSort(enabled);
}

/**
* Enable Objects locking.
* @deprecated use {@link #lockObjects(boolean)}
*/ */
public void lockObjects() { public void lockObjects() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setObjects(true);
lockObjects(true);
} }


/** /**
* Enable Scenarios locking.
* Enable or disable Objects locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockObjects(boolean enabled) {
safeGetProtectionField().setObjects(enabled);
}

/**
* Enable Scenarios locking.
* @deprecated use {@link #lockScenarios(boolean)}
*/ */
public void lockScenarios() { public void lockScenarios() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setScenarios(true);
lockScenarios(true);
} }


/** /**
* Enable Selection of locked cells locking.
* Enable or disable Scenarios locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockScenarios(boolean enabled) {
safeGetProtectionField().setScenarios(enabled);
}

/**
* Enable Selection of locked cells locking.
* @deprecated use {@link #lockSelectLockedCells(boolean)}
*/ */
public void lockSelectLockedCells() { public void lockSelectLockedCells() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setSelectLockedCells(true);
lockSelectLockedCells(true);
} }


/** /**
* Enable Selection of unlocked cells locking.
* Enable or disable Selection of locked cells locking.
* This does not modify sheet protection status. * This does not modify sheet protection status.
* To enforce this locking, call {@link #enableLocking()}
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockSelectLockedCells(boolean enabled) {
safeGetProtectionField().setSelectLockedCells(enabled);
}

/**
* Enable Selection of unlocked cells locking.
* @deprecated use {@link #lockSelectUnlockedCells(boolean)}
*/ */
public void lockSelectUnlockedCells() { public void lockSelectUnlockedCells() {
createProtectionFieldIfNotPresent();
worksheet.getSheetProtection().setSelectUnlockedCells(true);
lockSelectUnlockedCells(true);
}

/**
* Enable or disable Selection of unlocked cells locking.
* This does not modify sheet protection status.
* To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
*/
public void lockSelectUnlockedCells(boolean enabled) {
safeGetProtectionField().setSelectUnlockedCells(enabled);
} }


private void createProtectionFieldIfNotPresent() {
if (worksheet.getSheetProtection() == null) {
worksheet.setSheetProtection(CTSheetProtection.Factory.newInstance());
private CTSheetProtection safeGetProtectionField() {
if (!isSheetProtectionEnabled()) {
return worksheet.addNewSheetProtection();
} }
return worksheet.getSheetProtection();
} }


private boolean sheetProtectionEnabled() {
return worksheet.getSheetProtection().getSheet();
/* package */ boolean isSheetProtectionEnabled() {
return (worksheet.isSetSheetProtection());
} }


/* package */ boolean isCellInArrayFormulaContext(XSSFCell cell) { /* package */ boolean isCellInArrayFormulaContext(XSSFCell cell) {

+ 70
- 18
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java View File



package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;


import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;

import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.ss.formula.SheetNameFormatter; import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.formula.udf.IndexedUDFFinder; import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder; import org.apache.poi.ss.formula.udf.UDFFinder;
* Locks the structure of workbook. * Locks the structure of workbook.
*/ */
public void lockStructure() { public void lockStructure() {
createProtectionFieldIfNotPresent();
workbook.getWorkbookProtection().setLockStructure(true);
safeGetWorkbookProtection().setLockStructure(true);
} }


/** /**
* Unlocks the structure of workbook. * Unlocks the structure of workbook.
*/ */
public void unLockStructure() { public void unLockStructure() {
createProtectionFieldIfNotPresent();
workbook.getWorkbookProtection().setLockStructure(false);
safeGetWorkbookProtection().setLockStructure(false);
} }


/** /**
* Locks the windows that comprise the workbook. * Locks the windows that comprise the workbook.
*/ */
public void lockWindows() { public void lockWindows() {
createProtectionFieldIfNotPresent();
workbook.getWorkbookProtection().setLockWindows(true);
safeGetWorkbookProtection().setLockWindows(true);
} }


/** /**
* Unlocks the windows that comprise the workbook. * Unlocks the windows that comprise the workbook.
*/ */
public void unLockWindows() { public void unLockWindows() {
createProtectionFieldIfNotPresent();
workbook.getWorkbookProtection().setLockWindows(false);
safeGetWorkbookProtection().setLockWindows(false);
} }


/** /**
* Locks the workbook for revisions. * Locks the workbook for revisions.
*/ */
public void lockRevision() { public void lockRevision() {
createProtectionFieldIfNotPresent();
workbook.getWorkbookProtection().setLockRevision(true);
safeGetWorkbookProtection().setLockRevision(true);
} }


/** /**
* Unlocks the workbook for revisions. * Unlocks the workbook for revisions.
*/ */
public void unLockRevision() { public void unLockRevision() {
createProtectionFieldIfNotPresent();
workbook.getWorkbookProtection().setLockRevision(false);
safeGetWorkbookProtection().setLockRevision(false);
} }


private boolean workbookProtectionPresent() {
return workbook.getWorkbookProtection() != null;
/**
* Sets the workbook password.
*
* @param password if null, the password will be removed
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
*/
public void setWorkbookPassword(String password, HashAlgorithm hashAlgo) {
if (password == null && !workbookProtectionPresent()) return;
setPassword(safeGetWorkbookProtection(), password, hashAlgo, "workbook");
} }


private void createProtectionFieldIfNotPresent() {
if (workbook.getWorkbookProtection() == null){
workbook.setWorkbookProtection(CTWorkbookProtection.Factory.newInstance());
}
/**
* Validate the password against the stored hash, the hashing method will be determined
* by the existing password attributes
* @return true, if the hashes match (... though original password may differ ...)
*/
public boolean validateWorkbookPassword(String password) {
if (!workbookProtectionPresent()) return (password == null);
return validatePassword(safeGetWorkbookProtection(), password, "workbook");
}

/**
* Sets the revisions password.
*
* @param password if null, the password will be removed
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
*/
public void setRevisionsPassword(String password, HashAlgorithm hashAlgo) {
if (password == null && !workbookProtectionPresent()) return;
setPassword(safeGetWorkbookProtection(), password, hashAlgo, "revisions");
}

/**
* Validate the password against the stored hash, the hashing method will be determined
* by the existing password attributes
* @return true if the hashes match (... though original password may differ ...)
*/
public boolean validateRevisionsPassword(String password) {
if (!workbookProtectionPresent()) return (password == null);
return validatePassword(safeGetWorkbookProtection(), password, "revisions");
}
/**
* Removes the workbook protection settings
*/
public void unLock() {
if (workbookProtectionPresent()) {
workbook.unsetWorkbookProtection();
}
}
private boolean workbookProtectionPresent() {
return workbook.isSetWorkbookProtection();
} }


private CTWorkbookProtection safeGetWorkbookProtection() {
if (!workbookProtectionPresent()){
return workbook.addNewWorkbookProtection();
}
return workbook.getWorkbookProtection();
}
/** /**
* *
* Returns the locator of user-defined functions. * Returns the locator of user-defined functions.

+ 128
- 0
src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java View File

/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.apache.poi.xssf.usermodel.helpers;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.xml.bind.DatatypeConverter;
import javax.xml.namespace.QName;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
public class XSSFPaswordHelper {
/**
* Sets the XORed or hashed password
*
* @param xobj the xmlbeans object which contains the password attributes
* @param password the password, if null, the password attributes will be removed
* @param hashAlgo the hash algorithm, if null the password will be XORed
* @param prefix the prefix of the password attributes, may be null
*/
public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {
XmlCursor cur = xobj.newCursor();
if (password == null) {
cur.removeAttribute(getAttrName(prefix, "password"));
cur.removeAttribute(getAttrName(prefix, "algorithmName"));
cur.removeAttribute(getAttrName(prefix, "hashValue"));
cur.removeAttribute(getAttrName(prefix, "saltValue"));
cur.removeAttribute(getAttrName(prefix, "spinCount"));
return;
}
cur.toFirstContentToken();
if (hashAlgo == null) {
int hash = CryptoFunctions.createXorVerifier1(password);
cur.insertAttributeWithValue(getAttrName(prefix, "password"), Integer.toHexString(hash).toUpperCase());
} else {
SecureRandom random = new SecureRandom();
byte salt[] = random.generateSeed(16);
// Iterations specifies the number of times the hashing function shall be iteratively run (using each
// iteration's result as the input for the next iteration).
int spinCount = 100000;
// Implementation Notes List:
// --> In this third stage, the reversed byte order legacy hash from the second stage shall
// be converted to Unicode hex string representation
byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);
cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId);
cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));
cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));
cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);
}
cur.dispose();
}
/**
* Validates the password, i.e.
* calculates the hash of the given password and compares it against the stored hash
*
* @param xobj the xmlbeans object which contains the password attributes
* @param password the password, if null the method will always return false,
* even if there's no password set
* @param prefix the prefix of the password attributes, may be null
*
* @return true, if the hashes match
*/
public static boolean validatePassword(XmlObject xobj, String password, String prefix) {
// TODO: is "velvetSweatshop" the default password?
if (password == null) return false;
XmlCursor cur = xobj.newCursor();
String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));
String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));
String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));
String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));
String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));
cur.dispose();
if (xorHashVal != null) {
int hash1 = Integer.parseInt(xorHashVal, 16);
int hash2 = CryptoFunctions.createXorVerifier1(password);
return hash1 == hash2;
} else {
if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {
return false;
}
byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);
HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);
byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);
int spinCnt = Integer.parseInt(spinCount);
byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);
return Arrays.equals(hash1, hash2);
}
}
private static QName getAttrName(String prefix, String name) {
if (prefix == null || "".equals(prefix)) {
return new QName(name);
} else {
return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));
}
}
}

+ 32
- 3
src/ooxml/testcases/org/apache/poi/xssf/TestSheetProtection.java View File

==================================================================== */ ==================================================================== */
package org.apache.poi.xssf; package org.apache.poi.xssf;


import org.apache.poi.xssf.usermodel.XSSFSheet;
import junit.framework.TestCase;


import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;


import junit.framework.TestCase;

public class TestSheetProtection extends TestCase { public class TestSheetProtection extends TestCase {
private XSSFSheet sheet; private XSSFSheet sheet;
assertFalse(sheet.isAutoFilterLocked()); assertFalse(sheet.isAutoFilterLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isAutoFilterLocked()); assertTrue(sheet.isAutoFilterLocked());
sheet.lockAutoFilter(false);
assertFalse(sheet.isAutoFilterLocked());
} }
public void testWriteDeleteColumns() throws Exception { public void testWriteDeleteColumns() throws Exception {
assertFalse(sheet.isDeleteColumnsLocked()); assertFalse(sheet.isDeleteColumnsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isDeleteColumnsLocked()); assertTrue(sheet.isDeleteColumnsLocked());
sheet.lockDeleteColumns(false);
assertFalse(sheet.isDeleteColumnsLocked());
} }
public void testWriteDeleteRows() throws Exception { public void testWriteDeleteRows() throws Exception {
assertFalse(sheet.isDeleteRowsLocked()); assertFalse(sheet.isDeleteRowsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isDeleteRowsLocked()); assertTrue(sheet.isDeleteRowsLocked());
sheet.lockDeleteRows(false);
assertFalse(sheet.isDeleteRowsLocked());
} }
public void testWriteFormatCells() throws Exception { public void testWriteFormatCells() throws Exception {
assertFalse(sheet.isFormatCellsLocked()); assertFalse(sheet.isFormatCellsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isFormatCellsLocked()); assertTrue(sheet.isFormatCellsLocked());
sheet.lockFormatCells(false);
assertFalse(sheet.isFormatCellsLocked());
} }
public void testWriteFormatColumns() throws Exception { public void testWriteFormatColumns() throws Exception {
assertFalse(sheet.isFormatColumnsLocked()); assertFalse(sheet.isFormatColumnsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isFormatColumnsLocked()); assertTrue(sheet.isFormatColumnsLocked());
sheet.lockFormatColumns(false);
assertFalse(sheet.isFormatColumnsLocked());
} }
public void testWriteFormatRows() throws Exception { public void testWriteFormatRows() throws Exception {
assertFalse(sheet.isFormatRowsLocked()); assertFalse(sheet.isFormatRowsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isFormatRowsLocked()); assertTrue(sheet.isFormatRowsLocked());
sheet.lockFormatRows(false);
assertFalse(sheet.isFormatRowsLocked());
} }
public void testWriteInsertColumns() throws Exception { public void testWriteInsertColumns() throws Exception {
assertFalse(sheet.isInsertColumnsLocked()); assertFalse(sheet.isInsertColumnsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isInsertColumnsLocked()); assertTrue(sheet.isInsertColumnsLocked());
sheet.lockInsertColumns(false);
assertFalse(sheet.isInsertColumnsLocked());
} }
public void testWriteInsertHyperlinks() throws Exception { public void testWriteInsertHyperlinks() throws Exception {
assertFalse(sheet.isInsertHyperlinksLocked()); assertFalse(sheet.isInsertHyperlinksLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isInsertHyperlinksLocked()); assertTrue(sheet.isInsertHyperlinksLocked());
sheet.lockInsertHyperlinks(false);
assertFalse(sheet.isInsertHyperlinksLocked());
} }
public void testWriteInsertRows() throws Exception { public void testWriteInsertRows() throws Exception {
assertFalse(sheet.isInsertRowsLocked()); assertFalse(sheet.isInsertRowsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isInsertRowsLocked()); assertTrue(sheet.isInsertRowsLocked());
sheet.lockInsertRows(false);
assertFalse(sheet.isInsertRowsLocked());
} }
public void testWritePivotTables() throws Exception { public void testWritePivotTables() throws Exception {
assertFalse(sheet.isPivotTablesLocked()); assertFalse(sheet.isPivotTablesLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isPivotTablesLocked()); assertTrue(sheet.isPivotTablesLocked());
sheet.lockPivotTables(false);
assertFalse(sheet.isPivotTablesLocked());
} }
public void testWriteSort() throws Exception { public void testWriteSort() throws Exception {
assertFalse(sheet.isSortLocked()); assertFalse(sheet.isSortLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isSortLocked()); assertTrue(sheet.isSortLocked());
sheet.lockSort(false);
assertFalse(sheet.isSortLocked());
} }
public void testWriteObjects() throws Exception { public void testWriteObjects() throws Exception {
assertFalse(sheet.isObjectsLocked()); assertFalse(sheet.isObjectsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isObjectsLocked()); assertTrue(sheet.isObjectsLocked());
sheet.lockObjects(false);
assertFalse(sheet.isObjectsLocked());
} }
public void testWriteScenarios() throws Exception { public void testWriteScenarios() throws Exception {
assertFalse(sheet.isScenariosLocked()); assertFalse(sheet.isScenariosLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isScenariosLocked()); assertTrue(sheet.isScenariosLocked());
sheet.lockScenarios(false);
assertFalse(sheet.isScenariosLocked());
} }
public void testWriteSelectLockedCells() throws Exception { public void testWriteSelectLockedCells() throws Exception {
assertFalse(sheet.isSelectLockedCellsLocked()); assertFalse(sheet.isSelectLockedCellsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isSelectLockedCellsLocked()); assertTrue(sheet.isSelectLockedCellsLocked());
sheet.lockSelectLockedCells(false);
assertFalse(sheet.isSelectLockedCellsLocked());
} }
public void testWriteSelectUnlockedCells() throws Exception { public void testWriteSelectUnlockedCells() throws Exception {
assertFalse(sheet.isSelectUnlockedCellsLocked()); assertFalse(sheet.isSelectUnlockedCellsLocked());
sheet.enableLocking(); sheet.enableLocking();
assertTrue(sheet.isSelectUnlockedCellsLocked()); assertTrue(sheet.isSelectUnlockedCellsLocked());
sheet.lockSelectUnlockedCells(false);
assertFalse(sheet.isSelectUnlockedCellsLocked());
} }


public void testWriteSelectEnableLocking() throws Exception { public void testWriteSelectEnableLocking() throws Exception {

+ 96
- 32
src/ooxml/testcases/org/apache/poi/xssf/TestWorkbookProtection.java View File

==================================================================== */ ==================================================================== */
package org.apache.poi.xssf; package org.apache.poi.xssf;


import java.io.File;

import java.io.FileInputStream;
import java.io.FileOutputStream;

import junit.framework.TestCase;

import org.apache.poi.util.TempFile;
import static org.apache.poi.xssf.XSSFTestDataSamples.openSampleWorkbook;
import static org.apache.poi.xssf.XSSFTestDataSamples.writeOutAndReadBack;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class TestWorkbookProtection extends TestCase {

public void testShouldReadWorkbookProtection() throws Exception {
XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
import org.junit.Test;

public class TestWorkbookProtection {

@Test
public void workbookAndRevisionPassword() throws Exception {
XSSFWorkbook workbook;
String password = "test";
// validate password with an actual office file (Excel 2010)
workbook = openSampleWorkbook("workbookProtection-workbook_password_user_range-2010.xlsx");
assertTrue(workbook.validateWorkbookPassword(password));

// validate with another office file (Excel 2013)
workbook = openSampleWorkbook("workbookProtection-workbook_password-2013.xlsx");
assertTrue(workbook.validateWorkbookPassword(password));

workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx");

// setting a null password shouldn't introduce the protection element
workbook.setWorkbookPassword(null, null);
assertNull(workbook.getCTWorkbook().getWorkbookProtection());

// compare the hashes
workbook.setWorkbookPassword(password, null);
int hashVal = CryptoFunctions.createXorVerifier1(password);
int actualVal = Integer.parseInt(workbook.getCTWorkbook().getWorkbookProtection().xgetWorkbookPassword().getStringValue(),16);
assertEquals(hashVal, actualVal);
assertTrue(workbook.validateWorkbookPassword(password));
// removing the password again
workbook.setWorkbookPassword(null, null);
assertFalse(workbook.getCTWorkbook().getWorkbookProtection().isSetWorkbookPassword());
// removing the whole protection structure
workbook.unLock();
assertNull(workbook.getCTWorkbook().getWorkbookProtection());
// setting a null password shouldn't introduce the protection element
workbook.setRevisionsPassword(null, null);
assertNull(workbook.getCTWorkbook().getWorkbookProtection());

// compare the hashes
password = "T\u0400ST\u0100passwordWhichIsLongerThan15Chars";
workbook.setRevisionsPassword(password, null);
hashVal = CryptoFunctions.createXorVerifier1(password);
actualVal = Integer.parseInt(workbook.getCTWorkbook().getWorkbookProtection().xgetRevisionsPassword().getStringValue(),16);
assertEquals(hashVal, actualVal);
assertTrue(workbook.validateRevisionsPassword(password));
}
@Test
public void shouldReadWorkbookProtection() throws Exception {
XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isStructureLocked());
assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isRevisionLocked()); assertFalse(workbook.isRevisionLocked());


workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx");
workbook = openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx");
assertTrue(workbook.isStructureLocked()); assertTrue(workbook.isStructureLocked());
assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isRevisionLocked()); assertFalse(workbook.isRevisionLocked());


workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx");
workbook = openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx");
assertTrue(workbook.isWindowsLocked()); assertTrue(workbook.isWindowsLocked());
assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isStructureLocked());
assertFalse(workbook.isRevisionLocked()); assertFalse(workbook.isRevisionLocked());


workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx");
workbook = openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx");
assertTrue(workbook.isRevisionLocked()); assertTrue(workbook.isRevisionLocked());
assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isStructureLocked());
} }


public void testShouldWriteStructureLock() throws Exception {
XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
@Test
public void shouldWriteStructureLock() throws Exception {
XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isStructureLocked());


workbook.lockStructure(); workbook.lockStructure();
assertFalse(workbook.isStructureLocked()); assertFalse(workbook.isStructureLocked());
} }


public void testShouldWriteWindowsLock() throws Exception {
XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
@Test
public void shouldWriteWindowsLock() throws Exception {
XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isWindowsLocked());


workbook.lockWindows(); workbook.lockWindows();
assertFalse(workbook.isWindowsLocked()); assertFalse(workbook.isWindowsLocked());
} }


public void testShouldWriteRevisionLock() throws Exception {
XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_not_protected.xlsx");
@Test
public void shouldWriteRevisionLock() throws Exception {
XSSFWorkbook workbook = openSampleWorkbook("workbookProtection_not_protected.xlsx");
assertFalse(workbook.isRevisionLocked()); assertFalse(workbook.isRevisionLocked());


workbook.lockRevision(); workbook.lockRevision();
assertFalse(workbook.isRevisionLocked()); assertFalse(workbook.isRevisionLocked());
} }


@SuppressWarnings("resource")
@Test
public void testHashPassword() throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
wb.lockRevision();
wb.setRevisionsPassword("test", HashAlgorithm.sha1);
wb = writeOutAndReadBack(wb);
assertTrue(wb.isRevisionLocked());
assertTrue(wb.validateRevisionsPassword("test"));
}
@SuppressWarnings("resource")
@Test
public void testIntegration() throws Exception { public void testIntegration() throws Exception {
XSSFWorkbook wb = new XSSFWorkbook(); XSSFWorkbook wb = new XSSFWorkbook();
wb.createSheet("Testing purpose sheet"); wb.createSheet("Testing purpose sheet");
assertFalse(wb.isRevisionLocked()); assertFalse(wb.isRevisionLocked());


wb.lockRevision(); wb.lockRevision();
wb.setRevisionsPassword("test", null);


File tempFile = TempFile.createTempFile("workbookProtection", ".xlsx");
FileOutputStream out = new FileOutputStream(tempFile);
wb.write(out);
out.close();

FileInputStream inputStream = new FileInputStream(tempFile);
XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
inputStream.close();

assertTrue(workbook.isRevisionLocked());
wb = writeOutAndReadBack(wb);
assertTrue(wb.isRevisionLocked());
assertTrue(wb.validateRevisionsPassword("test"));
} }
} }

+ 20
- 4
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java View File



import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import static org.apache.poi.xssf.XSSFTestDataSamples.openSampleWorkbook;
import static org.apache.poi.xssf.XSSFTestDataSamples.writeOutAndReadBack;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNotSame;
import java.util.List; import java.util.List;


import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.PasswordRecord;
import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.ss.usermodel.AutoFilter; import org.apache.poi.ss.usermodel.AutoFilter;
import org.apache.poi.ss.usermodel.BaseTestSheet; import org.apache.poi.ss.usermodel.BaseTestSheet;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.AreaReference; import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.HexDump;
import org.apache.poi.xssf.SXSSFITestDataProvider; import org.apache.poi.xssf.SXSSFITestDataProvider;
import org.apache.poi.xssf.XSSFITestDataProvider; import org.apache.poi.xssf.XSSFITestDataProvider;
import org.apache.poi.xssf.XSSFTestDataSamples; import org.apache.poi.xssf.XSSFTestDataSamples;
assertTrue("sheet protection should be on", pr.isSetSheet()); assertTrue("sheet protection should be on", pr.isSetSheet());
assertTrue("object protection should be on", pr.isSetObjects()); assertTrue("object protection should be on", pr.isSetObjects());
assertTrue("scenario protection should be on", pr.isSetScenarios()); assertTrue("scenario protection should be on", pr.isSetScenarios());
String hash = String.valueOf(HexDump.shortToHex(PasswordRecord.hashPassword(password))).substring(2);
assertEquals("well known value for top secret hash should be "+ hash, hash, pr.xgetPassword().getStringValue());
int hashVal = CryptoFunctions.createXorVerifier1(password);
int actualVal = Integer.parseInt(pr.xgetPassword().getStringValue(),16);
assertEquals("well known value for top secret hash should match", hashVal, actualVal);


sheet.protectSheet(null); sheet.protectSheet(null);
assertNull("protectSheet(null) should unset CTSheetProtection", sheet.getCTWorksheet().getSheetProtection()); assertNull("protectSheet(null) should unset CTSheetProtection", sheet.getCTWorksheet().getSheetProtection());
} }


@Test
public void protectSheet_lowlevel_2013() {
String password = "test";
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet xs = wb.createSheet();
xs.setSheetPassword(password, HashAlgorithm.sha384);
wb = writeOutAndReadBack(wb);
assertTrue(wb.getSheetAt(0).validateSheetPassword(password));
wb = openSampleWorkbook("workbookProtection-sheet_password-2013.xlsx");
assertTrue(wb.getSheetAt(0).validateSheetPassword("pwd"));
}


@Test @Test
public void bug49966() { public void bug49966() {

BIN
test-data/spreadsheet/workbookProtection-sheet_password-2013.xlsx View File


BIN
test-data/spreadsheet/workbookProtection-workbook_password-2013.xlsx View File


BIN
test-data/spreadsheet/workbookProtection-workbook_password_user_range-2010.xlsx View File


Loading…
Cancel
Save