aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid North <dnorth@apache.org>2016-08-01 12:51:24 +0000
committerDavid North <dnorth@apache.org>2016-08-01 12:51:24 +0000
commit22623b78bc48c3926b506600909b94e3894489b1 (patch)
treee8d61f4ef3fbe66916a636f3d34f40855e54332e
parent9c591aa822ae6c611019d7969019ad802cc18999 (diff)
downloadpoi-22623b78bc48c3926b506600909b94e3894489b1.tar.gz
poi-22623b78bc48c3926b506600909b94e3894489b1.zip
Fix zero-padding and handling of empty passwords (meaning protection on, but no password to remove it) for XSSF workbook protection.
https://bz.apache.org/bugzilla/show_bug.cgi?id=59920 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1754744 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java26
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java4
-rw-r--r--src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java25
3 files changed, 41 insertions, 14 deletions
diff --git a/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java b/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
index f681f3ad1e..69f8d6768b 100644
--- a/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
+++ b/src/java/org/apache/poi/poifs/crypt/CryptoFunctions.java
@@ -374,20 +374,22 @@ public class CryptoFunctions {
// SET Verifier TO 0x0000
short verifier = 0;
- // FOR EACH PasswordByte IN PasswordArray IN REVERSE ORDER
- for (int i = arrByteChars.length-1; i >= 0; i--) {
- // SET Verifier TO Intermediate3 BITWISE XOR PasswordByte
+ if (!"".equals(password)) {
+ // 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];
+ }
+
+ // as we haven't prepended the password length into the input array
+ // we need to do it now separately ...
verifier = rotateLeftBase15Bit(verifier);
- verifier ^= arrByteChars[i];
+ verifier ^= arrByteChars.length;
+
+ // RETURN Verifier BITWISE XOR 0xCE4B
+ verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
}
-
- // 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')
return verifier & 0xFFFF;
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
index c910499485..fd6e2dbd04 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFPaswordHelper.java
@@ -55,8 +55,8 @@ public class XSSFPaswordHelper {
cur.toFirstContentToken();
if (hashAlgo == null) {
int hash = CryptoFunctions.createXorVerifier1(password);
- cur.insertAttributeWithValue(getAttrName(prefix, "password"),
- Integer.toHexString(hash).toUpperCase(Locale.ROOT));
+ cur.insertAttributeWithValue(getAttrName(prefix, "password"),
+ String.format(Locale.ROOT, "%04X", hash).toUpperCase(Locale.ROOT));
} else {
SecureRandom random = new SecureRandom();
byte salt[] = random.generateSeed(16);
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
index a9b0d1f0b5..689e999bcb 100644
--- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
+++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
@@ -80,6 +80,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex;
public final class TestXSSFSheet extends BaseTestXSheet {
@@ -1100,6 +1101,30 @@ public final class TestXSSFSheet extends BaseTestXSheet {
}
@Test
+ public void protectSheet_emptyPassword() throws IOException {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ XSSFSheet sheet = wb.createSheet();
+ CTSheetProtection pr = sheet.getCTWorksheet().getSheetProtection();
+ assertNull("CTSheetProtection should be null by default", pr);
+ String password = "";
+ sheet.protectSheet(password);
+ pr = sheet.getCTWorksheet().getSheetProtection();
+ assertNotNull("CTSheetProtection should be not null", pr);
+ assertTrue("sheet protection should be on", pr.isSetSheet());
+ assertTrue("object protection should be on", pr.isSetObjects());
+ assertTrue("scenario protection should be on", pr.isSetScenarios());
+ int hashVal = CryptoFunctions.createXorVerifier1(password);
+ STUnsignedShortHex xpassword = pr.xgetPassword();
+ int actualVal = Integer.parseInt(xpassword.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());
+
+ wb.close();
+ }
+
+ @Test
public void protectSheet_lowlevel_2013() throws IOException {
String password = "test";
XSSFWorkbook wb1 = new XSSFWorkbook();