package org.apache.poi.hssf.record;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndianOutput;
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) {
- 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);
}
/**
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.ScenarioProtectRecord;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
/**
* Groups the sheet protection records for a worksheet.
ProtectRecord prec = getProtect();
PasswordRecord pass = getPassword();
prec.setProtect(true);
- pass.setPassword(PasswordRecord.hashPassword(password));
+ pass.setPassword((short)CryptoFunctions.createXorVerifier1(password));
if (_objectProtectRecord == null && shouldProtectObjects) {
ObjectProtectRecord rec = createObjectProtect();
rec.setProtect(true);
}\r
\r
/**\r
- * \r
+ * Initialize a new cipher object with the given cipher properties\r
+ * If the given algorithm is not implemented in the JCE, it will try to load it from the bouncy castle\r
+ * provider.\r
*\r
- * @param key\r
- * @param chain\r
- * @param vec\r
+ * @param key the secrect key\r
+ * @param cipherAlgorithm the cipher algorithm\r
+ * @param chain the chaining mode\r
+ * @param vec the initialization vector (IV), can be null\r
* @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE\r
+ * @param padding\r
* @return the requested cipher\r
* @throws GeneralSecurityException\r
+ * @throws EncryptedDocumentException if the initialization failed or if an algorithm was specified,\r
+ * which depends on a missing bouncy castle provider \r
*/\r
public static Cipher getCipher(SecretKey key, CipherAlgorithm cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode, String padding) {\r
int keySizeInBytes = key.getEncoded().length;\r
}\r
} \r
\r
+ /**\r
+ * Returns a new byte array with a truncated to the given size. \r
+ * If the hash has less then size bytes, it will be filled with 0x36-bytes\r
+ *\r
+ * @param hash the to be truncated/filled hash byte array\r
+ * @param size the size of the returned byte array\r
+ * @return the padded hash\r
+ */\r
public static byte[] getBlock36(byte[] hash, int size) {\r
return getBlockX(hash, size, (byte)0x36);\r
}\r
\r
+ /**\r
+ * Returns a new byte array with a truncated to the given size. \r
+ * If the hash has less then size bytes, it will be filled with 0-bytes\r
+ *\r
+ * @param hash the to be truncated/filled hash byte array\r
+ * @param size the size of the returned byte array\r
+ * @return the padded hash\r
+ */\r
public static byte[] getBlock0(byte[] hash, int size) {\r
return getBlockX(hash, size, (byte)0);\r
}\r
byte[] generatedKey = new byte[4];\r
\r
//Maximum length of the password is 15 chars.\r
- final int intMaxPasswordLength = 15; \r
+ final int maxPasswordLength = 15; \r
\r
if (!"".equals(password)) {\r
// Truncate the password to 15 characters\r
- password = password.substring(0, Math.min(password.length(), intMaxPasswordLength));\r
+ password = password.substring(0, Math.min(password.length(), maxPasswordLength));\r
\r
// Construct a new NULL-terminated string consisting of single-byte characters:\r
// -- > Get the single-byte values by iterating through the Unicode characters of the truncated Password.\r
// the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from \r
// the Encryption Matrix\r
for (int i = 0; i < arrByteChars.length; i++) {\r
- int tmp = intMaxPasswordLength - arrByteChars.length + i;\r
+ int tmp = maxPasswordLength - arrByteChars.length + i;\r
for (int intBit = 0; intBit < 7; intBit++) {\r
if ((arrByteChars[i] & (0x0001 << intBit)) != 0) {\r
highOrderWord ^= EncryptionMatrix[tmp][intBit];\r
\r
// Compute the low-order word of the new key:\r
\r
- // Initialize with 0\r
- int lowOrderWord = 0;\r
+ // SET Verifier TO 0x0000\r
+ short verifier = 0;\r
\r
- // For each character in the password, going backwards\r
- for (int i = arrByteChars.length - 1; i >= 0; i--) {\r
- // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character\r
- lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[i];\r
+ // FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER\r
+ for (int i = arrByteChars.length-1; i >= 0; i--) {\r
+ // SET Verifier TO Intermediate3 BITWISE XOR PasswordByte\r
+ verifier = rotateLeftBase15Bit(verifier);\r
+ verifier ^= arrByteChars[i];\r
}\r
\r
- // Lastly,low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR password length XOR 0xCE4B.\r
- lowOrderWord = (((lowOrderWord >> 14) & 0x0001) | ((lowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.length ^ 0xCE4B;\r
+ // as we haven't prepended the password length into the input array\r
+ // we need to do it now separately ...\r
+ verifier = rotateLeftBase15Bit(verifier);\r
+ verifier ^= arrByteChars.length;\r
+ \r
+ // RETURN Verifier BITWISE XOR 0xCE4B\r
+ verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')\r
\r
// The byte order of the result shall be reversed [password "Example": 0x64CEED7E becomes 7EEDCE64],\r
// and that value shall be hashed as defined by the attribute values.\r
\r
- LittleEndian.putShort(generatedKey, 0, (short)lowOrderWord);\r
+ LittleEndian.putShort(generatedKey, 0, verifier);\r
LittleEndian.putShort(generatedKey, 2, (short)highOrderWord);\r
}\r
\r
* @see <a href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary Document Password Verifier Derivation Method 2</a>\r
* \r
* @param password the password\r
- * @return the verifier\r
+ * @return the verifier (actually a short value)\r
*/\r
public static int createXorVerifier1(String password) {\r
// the verifier for method 1 is part of the verifier for method 2\r
private static byte rotateLeft(byte bits, int shift) {\r
return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 - shift)));\r
}\r
+ \r
+ private static short rotateLeftBase15Bit(short verifier) {\r
+ /*\r
+ * IF (Verifier BITWISE AND 0x4000) is 0x0000\r
+ * SET Intermediate1 TO 0\r
+ * ELSE\r
+ * SET Intermediate1 TO 1\r
+ * ENDIF\r
+ */\r
+ short intermediate1 = (short)(((verifier & 0x4000) == 0) ? 0 : 1);\r
+ /*\r
+ * SET Intermediate2 TO Verifier MULTIPLED BY 2\r
+ * SET most significant bit of Intermediate2 TO 0\r
+ */\r
+ short intermediate2 = (short)((verifier<<1) & 0x7FFF);\r
+ /*\r
+ * SET Intermediate3 TO Intermediate1 BITWISE OR Intermediate2\r
+ */\r
+ short intermediate3 = (short)(intermediate1 | intermediate2);\r
+ return intermediate3;\r
+ }\r
}\r
}\r
throw new EncryptedDocumentException("hash algorithm not found");\r
}\r
+ \r
+ public static HashAlgorithm fromString(String string) {\r
+ for (HashAlgorithm ha : values()) {\r
+ if (ha.ecmaString.equalsIgnoreCase(string) || ha.jceId.equalsIgnoreCase(string)) return ha;\r
+ }\r
+ throw new EncryptedDocumentException("hash algorithm not found");\r
+ }\r
}
\ No newline at end of file
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.InputStream;
import java.io.OutputStream;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
-import org.apache.poi.hssf.record.PasswordRecord;
import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
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.formula.FormulaShifter;
import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.util.SSCellRange;
import org.apache.poi.ss.util.SheetUtil;
import org.apache.poi.util.Beta;
-import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
*/
@Override
public boolean getProtect() {
- return worksheet.isSetSheetProtection() && sheetProtectionEnabled();
+ return isSheetLocked();
}
/**
*/
@Override
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.setScenarios(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
* defined you get a null. This is to say row 4 represents the fifth row on a sheet.
worksheet.unsetMergeCells();
}
}
-
+
/**
* Removes a number of merged regions of cells (hence letting them free)
*
* @return true when Autofilters are locked and the sheet is protected.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
public boolean isSelectUnlockedCellsLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() && worksheet.getSheetProtection().getSelectUnlockedCells();
+ if (isSheetLocked()) {
+ return safeGetProtectionField().getSelectUnlockedCells();
+ }
+ return false;
}
/**
* @return true when Sheet is Protected.
*/
public boolean isSheetLocked() {
- createProtectionFieldIfNotPresent();
- return sheetProtectionEnabled() && worksheet.getSheetProtection().getSheet();
+ if (worksheet.isSetSheetProtection()) {
+ return safeGetProtectionField().getSheet();
+ }
+ return false;
}
/**
* Enable sheet protection
*/
public void enableLocking() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSheet(true);
+ safeGetProtectionField().setSheet(true);
}
/**
* Disable sheet protection
*/
public void disableLocking() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSheet(false);
+ safeGetProtectionField().setSheet(false);
}
/**
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setAutoFilter(true);
+ lockAutoFilter(true);
}
/**
- * Enable Deleting columns locking.
+ * Enable or disable Autofilters locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setDeleteColumns(true);
+ lockDeleteColumns(true);
}
/**
- * Enable Deleting rows locking.
+ * Enable or disable Deleting columns locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setDeleteRows(true);
+ lockDeleteRows(true);
}
/**
- * Enable Formatting cells locking.
+ * Enable or disable Deleting rows locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setDeleteColumns(true);
+ lockFormatCells(true);
}
/**
- * Enable Formatting columns locking.
+ * Enable or disable Formatting cells locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setFormatColumns(true);
+ lockFormatColumns(true);
}
/**
- * Enable Formatting rows locking.
+ * Enable or disable Formatting columns locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setFormatRows(true);
+ lockFormatRows(true);
}
/**
- * Enable Inserting columns locking.
+ * Enable or disable Formatting rows locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setInsertColumns(true);
+ lockInsertColumns(true);
}
/**
- * Enable Inserting hyperlinks locking.
+ * Enable or disable Inserting columns locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setInsertHyperlinks(true);
+ lockInsertHyperlinks(true);
}
/**
- * Enable Inserting rows locking.
+ * Enable or disable Inserting hyperlinks locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setInsertRows(true);
+ lockInsertRows(true);
}
/**
- * Enable Pivot Tables locking.
+ * Enable or disable Inserting rows locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setPivotTables(true);
+ lockPivotTables(true);
}
/**
- * Enable Sort locking.
+ * Enable or disable Pivot Tables locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setSort(true);
+ lockSort(true);
}
/**
- * Enable Objects locking.
+ * Enable or disable Sort locking.
* 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() {
- createProtectionFieldIfNotPresent();
- worksheet.getSheetProtection().setObjects(true);
+ lockObjects(true);
}
/**
- * Enable Scenarios locking.
+ * Enable or disable Objects locking.
* 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() {
- 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.
- * 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() {
- 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.
- * 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() {
- 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 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.ByteArrayOutputStream;
import java.io.File;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
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.udf.IndexedUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
* Locks the structure of workbook.
*/
public void lockStructure() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockStructure(true);
+ safeGetWorkbookProtection().setLockStructure(true);
}
/**
* Unlocks the structure of workbook.
*/
public void unLockStructure() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockStructure(false);
+ safeGetWorkbookProtection().setLockStructure(false);
}
/**
* Locks the windows that comprise the workbook.
*/
public void lockWindows() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockWindows(true);
+ safeGetWorkbookProtection().setLockWindows(true);
}
/**
* Unlocks the windows that comprise the workbook.
*/
public void unLockWindows() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockWindows(false);
+ safeGetWorkbookProtection().setLockWindows(false);
}
/**
* Locks the workbook for revisions.
*/
public void lockRevision() {
- createProtectionFieldIfNotPresent();
- workbook.getWorkbookProtection().setLockRevision(true);
+ safeGetWorkbookProtection().setLockRevision(true);
}
/**
* Unlocks the workbook for revisions.
*/
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.
--- /dev/null
+/*\r
+ * ====================================================================\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ====================================================================\r
+ */\r
+\r
+package org.apache.poi.xssf.usermodel.helpers;\r
+\r
+import java.security.SecureRandom;\r
+import java.util.Arrays;\r
+\r
+import javax.xml.bind.DatatypeConverter;\r
+import javax.xml.namespace.QName;\r
+\r
+import org.apache.poi.poifs.crypt.CryptoFunctions;\r
+import org.apache.poi.poifs.crypt.HashAlgorithm;\r
+import org.apache.xmlbeans.XmlCursor;\r
+import org.apache.xmlbeans.XmlObject;\r
+\r
+public class XSSFPaswordHelper {\r
+ /**\r
+ * Sets the XORed or hashed password \r
+ *\r
+ * @param xobj the xmlbeans object which contains the password attributes\r
+ * @param password the password, if null, the password attributes will be removed\r
+ * @param hashAlgo the hash algorithm, if null the password will be XORed\r
+ * @param prefix the prefix of the password attributes, may be null\r
+ */\r
+ public static void setPassword(XmlObject xobj, String password, HashAlgorithm hashAlgo, String prefix) {\r
+ XmlCursor cur = xobj.newCursor();\r
+\r
+ if (password == null) {\r
+ cur.removeAttribute(getAttrName(prefix, "password"));\r
+ cur.removeAttribute(getAttrName(prefix, "algorithmName"));\r
+ cur.removeAttribute(getAttrName(prefix, "hashValue"));\r
+ cur.removeAttribute(getAttrName(prefix, "saltValue"));\r
+ cur.removeAttribute(getAttrName(prefix, "spinCount"));\r
+ return;\r
+ } \r
+ \r
+ cur.toFirstContentToken();\r
+ if (hashAlgo == null) {\r
+ int hash = CryptoFunctions.createXorVerifier1(password);\r
+ cur.insertAttributeWithValue(getAttrName(prefix, "password"), Integer.toHexString(hash).toUpperCase());\r
+ } else {\r
+ SecureRandom random = new SecureRandom(); \r
+ byte salt[] = random.generateSeed(16);\r
+ \r
+ // Iterations specifies the number of times the hashing function shall be iteratively run (using each\r
+ // iteration's result as the input for the next iteration).\r
+ int spinCount = 100000;\r
+\r
+ // Implementation Notes List:\r
+ // --> In this third stage, the reversed byte order legacy hash from the second stage shall\r
+ // be converted to Unicode hex string representation\r
+ byte hash[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCount, false);\r
+ \r
+ cur.insertAttributeWithValue(getAttrName(prefix, "algorithmName"), hashAlgo.jceId); \r
+ cur.insertAttributeWithValue(getAttrName(prefix, "hashValue"), DatatypeConverter.printBase64Binary(hash));\r
+ cur.insertAttributeWithValue(getAttrName(prefix, "saltValue"), DatatypeConverter.printBase64Binary(salt));\r
+ cur.insertAttributeWithValue(getAttrName(prefix, "spinCount"), ""+spinCount);\r
+ }\r
+ cur.dispose();\r
+ }\r
+\r
+ /**\r
+ * Validates the password, i.e.\r
+ * calculates the hash of the given password and compares it against the stored hash\r
+ *\r
+ * @param xobj the xmlbeans object which contains the password attributes\r
+ * @param password the password, if null the method will always return false,\r
+ * even if there's no password set\r
+ * @param prefix the prefix of the password attributes, may be null\r
+ * \r
+ * @return true, if the hashes match\r
+ */\r
+ public static boolean validatePassword(XmlObject xobj, String password, String prefix) {\r
+ // TODO: is "velvetSweatshop" the default password?\r
+ if (password == null) return false;\r
+ \r
+ XmlCursor cur = xobj.newCursor();\r
+ String xorHashVal = cur.getAttributeText(getAttrName(prefix, "password"));\r
+ String algoName = cur.getAttributeText(getAttrName(prefix, "algorithmName"));\r
+ String hashVal = cur.getAttributeText(getAttrName(prefix, "hashValue"));\r
+ String saltVal = cur.getAttributeText(getAttrName(prefix, "saltValue"));\r
+ String spinCount = cur.getAttributeText(getAttrName(prefix, "spinCount"));\r
+ cur.dispose();\r
+\r
+ if (xorHashVal != null) {\r
+ int hash1 = Integer.parseInt(xorHashVal, 16);\r
+ int hash2 = CryptoFunctions.createXorVerifier1(password);\r
+ return hash1 == hash2;\r
+ } else {\r
+ if (hashVal == null || algoName == null || saltVal == null || spinCount == null) {\r
+ return false;\r
+ }\r
+ \r
+ byte hash1[] = DatatypeConverter.parseBase64Binary(hashVal);\r
+ HashAlgorithm hashAlgo = HashAlgorithm.fromString(algoName);\r
+ byte salt[] = DatatypeConverter.parseBase64Binary(saltVal);\r
+ int spinCnt = Integer.parseInt(spinCount);\r
+ byte hash2[] = CryptoFunctions.hashPassword(password, hashAlgo, salt, spinCnt, false);\r
+ return Arrays.equals(hash1, hash2);\r
+ }\r
+ }\r
+ \r
+ \r
+ private static QName getAttrName(String prefix, String name) {\r
+ if (prefix == null || "".equals(prefix)) {\r
+ return new QName(name);\r
+ } else {\r
+ return new QName(prefix+Character.toUpperCase(name.charAt(0))+name.substring(1));\r
+ }\r
+ }\r
+}\r
==================================================================== */
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 junit.framework.TestCase;
-
public class TestSheetProtection extends TestCase {
private XSSFSheet sheet;
assertFalse(sheet.isAutoFilterLocked());
sheet.enableLocking();
assertTrue(sheet.isAutoFilterLocked());
+ sheet.lockAutoFilter(false);
+ assertFalse(sheet.isAutoFilterLocked());
}
public void testWriteDeleteColumns() throws Exception {
assertFalse(sheet.isDeleteColumnsLocked());
sheet.enableLocking();
assertTrue(sheet.isDeleteColumnsLocked());
+ sheet.lockDeleteColumns(false);
+ assertFalse(sheet.isDeleteColumnsLocked());
}
public void testWriteDeleteRows() throws Exception {
assertFalse(sheet.isDeleteRowsLocked());
sheet.enableLocking();
assertTrue(sheet.isDeleteRowsLocked());
+ sheet.lockDeleteRows(false);
+ assertFalse(sheet.isDeleteRowsLocked());
}
public void testWriteFormatCells() throws Exception {
assertFalse(sheet.isFormatCellsLocked());
sheet.enableLocking();
assertTrue(sheet.isFormatCellsLocked());
+ sheet.lockFormatCells(false);
+ assertFalse(sheet.isFormatCellsLocked());
}
public void testWriteFormatColumns() throws Exception {
assertFalse(sheet.isFormatColumnsLocked());
sheet.enableLocking();
assertTrue(sheet.isFormatColumnsLocked());
+ sheet.lockFormatColumns(false);
+ assertFalse(sheet.isFormatColumnsLocked());
}
public void testWriteFormatRows() throws Exception {
assertFalse(sheet.isFormatRowsLocked());
sheet.enableLocking();
assertTrue(sheet.isFormatRowsLocked());
+ sheet.lockFormatRows(false);
+ assertFalse(sheet.isFormatRowsLocked());
}
public void testWriteInsertColumns() throws Exception {
assertFalse(sheet.isInsertColumnsLocked());
sheet.enableLocking();
assertTrue(sheet.isInsertColumnsLocked());
+ sheet.lockInsertColumns(false);
+ assertFalse(sheet.isInsertColumnsLocked());
}
public void testWriteInsertHyperlinks() throws Exception {
assertFalse(sheet.isInsertHyperlinksLocked());
sheet.enableLocking();
assertTrue(sheet.isInsertHyperlinksLocked());
+ sheet.lockInsertHyperlinks(false);
+ assertFalse(sheet.isInsertHyperlinksLocked());
}
public void testWriteInsertRows() throws Exception {
assertFalse(sheet.isInsertRowsLocked());
sheet.enableLocking();
assertTrue(sheet.isInsertRowsLocked());
+ sheet.lockInsertRows(false);
+ assertFalse(sheet.isInsertRowsLocked());
}
public void testWritePivotTables() throws Exception {
assertFalse(sheet.isPivotTablesLocked());
sheet.enableLocking();
assertTrue(sheet.isPivotTablesLocked());
+ sheet.lockPivotTables(false);
+ assertFalse(sheet.isPivotTablesLocked());
}
public void testWriteSort() throws Exception {
assertFalse(sheet.isSortLocked());
sheet.enableLocking();
assertTrue(sheet.isSortLocked());
+ sheet.lockSort(false);
+ assertFalse(sheet.isSortLocked());
}
public void testWriteObjects() throws Exception {
assertFalse(sheet.isObjectsLocked());
sheet.enableLocking();
assertTrue(sheet.isObjectsLocked());
+ sheet.lockObjects(false);
+ assertFalse(sheet.isObjectsLocked());
}
public void testWriteScenarios() throws Exception {
assertFalse(sheet.isScenariosLocked());
sheet.enableLocking();
assertTrue(sheet.isScenariosLocked());
+ sheet.lockScenarios(false);
+ assertFalse(sheet.isScenariosLocked());
}
public void testWriteSelectLockedCells() throws Exception {
assertFalse(sheet.isSelectLockedCellsLocked());
sheet.enableLocking();
assertTrue(sheet.isSelectLockedCellsLocked());
+ sheet.lockSelectLockedCells(false);
+ assertFalse(sheet.isSelectLockedCellsLocked());
}
public void testWriteSelectUnlockedCells() throws Exception {
assertFalse(sheet.isSelectUnlockedCellsLocked());
sheet.enableLocking();
assertTrue(sheet.isSelectUnlockedCellsLocked());
+ sheet.lockSelectUnlockedCells(false);
+ assertFalse(sheet.isSelectUnlockedCellsLocked());
}
public void testWriteSelectEnableLocking() throws Exception {
==================================================================== */
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;
-
-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.isWindowsLocked());
assertFalse(workbook.isRevisionLocked());
- workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx");
+ workbook = openSampleWorkbook("workbookProtection_workbook_structure_protected.xlsx");
assertTrue(workbook.isStructureLocked());
assertFalse(workbook.isWindowsLocked());
assertFalse(workbook.isRevisionLocked());
- workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx");
+ workbook = openSampleWorkbook("workbookProtection_workbook_windows_protected.xlsx");
assertTrue(workbook.isWindowsLocked());
assertFalse(workbook.isStructureLocked());
assertFalse(workbook.isRevisionLocked());
- workbook = XSSFTestDataSamples.openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx");
+ workbook = openSampleWorkbook("workbookProtection_workbook_revision_protected.xlsx");
assertTrue(workbook.isRevisionLocked());
assertFalse(workbook.isWindowsLocked());
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());
workbook.lockStructure();
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());
workbook.lockWindows();
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());
workbook.lockRevision();
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 {
XSSFWorkbook wb = new XSSFWorkbook();
wb.createSheet("Testing purpose sheet");
assertFalse(wb.isRevisionLocked());
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"));
}
}
import static junit.framework.TestCase.assertNotNull;
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.assertFalse;
import static org.junit.Assert.assertNotSame;
import java.util.List;
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.BaseTestSheet;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.util.HexDump;
import org.apache.poi.xssf.SXSSFITestDataProvider;
import org.apache.poi.xssf.XSSFITestDataProvider;
import org.apache.poi.xssf.XSSFTestDataSamples;
assertTrue("sheet protection should be on", pr.isSetSheet());
assertTrue("object protection should be on", pr.isSetObjects());
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);
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
public void bug49966() {