-/*\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
-import java.util.Locale;\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"),\r
- String.format(Locale.ROOT, "%04X", hash).toUpperCase(Locale.ROOT));\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
+/*
+ * ====================================================================
+ * 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 java.util.Locale;
+
+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"),
+ String.format(Locale.ROOT, "%04X", hash).toUpperCase(Locale.ROOT));
+ } 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));
+ }
+ }
+}