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-ffa450edef68tags/REL_3_11_BETA3
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); | |||||
} | } | ||||
/** | /** |
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); |
} | } | ||||
/** | /** | ||||
* | |||||
* 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; | |||||
} | |||||
} | } |
} | } | ||||
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"); | |||||
} | |||||
} | } |
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) { |
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. |
/* | |||||
* ==================================================================== | |||||
* 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)); | |||||
} | |||||
} | |||||
} |
==================================================================== */ | ==================================================================== */ | ||||
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 { |
==================================================================== */ | ==================================================================== */ | ||||
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")); | |||||
} | } | ||||
} | } |
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() { |