include/svl/PasswordHelper.hxx                  |    7 +
 sc/CppunitTest_sc_subsequent_export_test.mk     |    2 
 sc/inc/tabprotection.hxx                        |    2 
 sc/qa/unit/data/fods/protection-key1.fods       |   20 ++++
 sc/qa/unit/data/fods/protection-key2.fods       |   20 ++++
 sc/qa/unit/data/fods/protection-key3.fods       |   20 ++++
 sc/qa/unit/data/fods/protection-key4.fods       |   20 ++++
 sc/qa/unit/data/fods/protection-key5.fods       |   20 ++++
 sc/qa/unit/subsequent_export-test.cxx           |  118 +++++++++++++++++++++++-
 sc/source/core/data/tabprotection.cxx           |   27 +++++
 sc/source/filter/xml/xmlexprt.cxx               |   25 +++++
 sc/source/ui/docshell/docsh.cxx                 |    4 
 svl/source/misc/PasswordHelper.cxx              |   52 +++++++++-
 sw/CppunitTest_sw_odfexport.mk                  |    1 
 sw/qa/extras/odfexport/data/protection-key.fodt |   48 +++++++++
 sw/qa/extras/odfexport/odfexport.cxx            |   32 ++++++
 xmloff/source/text/XMLSectionExport.cxx         |    8 +
 17 files changed, 416 insertions(+), 10 deletions(-)

New commits:
commit d28ceb7511a8df9345b1c9818baaad5532853a12
Author: Michael Stahl <mst...@redhat.com>
Date:   Tue Feb 6 17:35:36 2018 +0100

    tdf#115483 svl xmloff sc sw: verify all ODF 1.2 protection-key hashes
    
    ODF 1.2 has added some mandatory requirements for protection-key hashes
    which did not exist in ODF 1.1.
    
    This affects sections and indexes in ODT documents, as well as
    spreadsheets and sheets in ODS documents.
    
    1. Accept the following hashed passwords:
        * UTF16 LE/BE encoded StarOffice-SHA1, OOo legacy and allowed by ODF 1.1
        * UTF8 encoded proper SHA1, as required by ODF 1.2
        * UTF8 encoded SHA256, as required by ODF 1.2
            - specified either with the wrong URL used in the ODF 1.2 spec
              or the correct URL from the W3C spec, see OFFICE-3702
        * Excel+SHA1 double-hash, only in Calc, see OFFICE-2112
    
    2. Round-trip any of the above as-is
        * for SHA256 only write the URL from the ODF 1.2 spec
    
    3. Generate only UTF16 LE encoded SHA1 for now, so that older LO
       releases can still verify the password
        * some time in the future, switch to generating some valid ODF 1.2 hash
    
    More changes are necessary in Calc, which can actually preserve
    different hashes for the same passwords in its runtime data model,
    whereas Writer just has a single buffer without even any metadata.
    
    For the Calc unit tests we need one document per hash because the
    protection-key attribute can be set on the entire spreadsheet, which
    is an unique element in the document.
    
    There are further uses of SvlPasswordHelper for change-tracking passwords,
    but apparently those are stored in settings.xml, so ODF has no
    requirements for them, so let's leave that as it is.
    
    Reviewed-on: https://gerrit.libreoffice.org/49352
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Michael Stahl <mst...@redhat.com>
    (cherry picked from commit 398275ba9f4d65bebcc78864e70eee6212a84397)
    
    Change-Id: Icb720b14ae9c0d9c04d2e082769ae2b74e3af8aa
    Reviewed-on: https://gerrit.libreoffice.org/49390
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Eike Rathke <er...@redhat.com>

diff --git a/include/svl/PasswordHelper.hxx b/include/svl/PasswordHelper.hxx
index ca048ed85924..a71f2ca7c172 100644
--- a/include/svl/PasswordHelper.hxx
+++ b/include/svl/PasswordHelper.hxx
@@ -33,10 +33,15 @@ public:
     SVL_DLLPUBLIC static void     GetHashPassword(css::uno::Sequence 
<sal_Int8>& rPassHash, const sal_Char* pPass, sal_uInt32 nLen);
 
     SVL_DLLPUBLIC static void     
GetHashPassword(css::uno::Sequence<sal_Int8>& rPassHash, const OUString& sPass);
+    SVL_DLLPUBLIC static void     
GetHashPasswordSHA1UTF8(css::uno::Sequence<sal_Int8>& rPassHash, const 
OUString& sPass);
+    SVL_DLLPUBLIC static void     
GetHashPasswordSHA256(css::uno::Sequence<sal_Int8>& rPassHash, const OUString& 
sPass);
     /**
     Use this method to compare a given string with another given Hash value.
     This is necessary, because in older versions exists different hashes of 
the same string. They were endian dependent.
-    We need this to handle old files. This method will compare against big and 
little endian. See #101326#
+    We need this to handle old files. This method will compare against big and
+    little endian UTF-16.
+    tdf#115483: also check 2 different new ways of hashing that were added in
+    ODF 1.2, requiring UTF-8 encoding.
     */
     SVL_DLLPUBLIC static bool     CompareHashPassword(const 
css::uno::Sequence<sal_Int8>& rOldPassHash, const OUString& sNewPass);
 };
diff --git a/sc/CppunitTest_sc_subsequent_export_test.mk 
b/sc/CppunitTest_sc_subsequent_export_test.mk
index b97423e27f89..cf6125f6ef04 100644
--- a/sc/CppunitTest_sc_subsequent_export_test.mk
+++ b/sc/CppunitTest_sc_subsequent_export_test.mk
@@ -72,6 +72,8 @@ $(eval $(call 
gb_CppunitTest_use_components,sc_subsequent_export_test,\
     embeddedobj/util/embobj \
     eventattacher/source/evtatt \
     filter/source/config/cache/filterconfig1 \
+       filter/source/odfflatxml/odfflatxml \
+       filter/source/xmlfilteradaptor/xmlfa \
     forms/util/frm \
     framework/util/fwk \
     i18npool/source/search/i18nsearch \
diff --git a/sc/inc/tabprotection.hxx b/sc/inc/tabprotection.hxx
index 61e0d605e6a8..3f2fc7b4e189 100644
--- a/sc/inc/tabprotection.hxx
+++ b/sc/inc/tabprotection.hxx
@@ -33,6 +33,8 @@ class ScTableProtectionImpl;
 enum ScPasswordHash
 {
     PASSHASH_SHA1 = 0,
+    PASSHASH_SHA1_UTF8, // tdf#115483 this is UTF8, previous one is wrong UTF16
+    PASSHASH_SHA256,
     PASSHASH_XL,
     PASSHASH_UNSPECIFIED
 };
diff --git a/sc/qa/unit/data/fods/protection-key1.fods 
b/sc/qa/unit/data/fods/protection-key1.fods
new file mode 100644
index 000000000000..e15f1e459919
--- /dev/null
+++ b/sc/qa/unit/data/fods/protection-key1.fods
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:scr
 ipt="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:form
 x="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" 
xmlns:css3t="http://www.w3.org/TR/css3-text/"; office:version="1.2" 
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
+ <office:body>
+
+  <!-- UTF-16 LE, bad SHA1 -->
+  <office:spreadsheet table:structure-protected="true" 
table:protection-key="vbnhxyBKtPHCA1wB21zG1Oha8ZA=" 
table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha1";>
+   <table:tracked-changes/>
+   <table:calculation-settings table:automatic-find-labels="false" 
table:use-regular-expressions="false" table:use-wildcards="true"/>
+
+   <table:table table:name="Sheet1" table:protected="true" 
table:protection-key="vbnhxyBKtPHCA1wB21zG1Oha8ZA=" 
table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha1";>
+    <loext:table-protection loext:select-protected-cells="true" 
loext:select-unprotected-cells="true"/>
+    <table:table-row>
+     <table:table-cell/>
+    </table:table-row>
+   </table:table>
+   <table:named-expressions/>
+  </office:spreadsheet>
+ </office:body>
+</office:document>
diff --git a/sc/qa/unit/data/fods/protection-key2.fods 
b/sc/qa/unit/data/fods/protection-key2.fods
new file mode 100644
index 000000000000..b719a195b202
--- /dev/null
+++ b/sc/qa/unit/data/fods/protection-key2.fods
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:scr
 ipt="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:form
 x="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" 
xmlns:css3t="http://www.w3.org/TR/css3-text/"; office:version="1.2" 
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
+ <office:body>
+
+  <!-- UTF-8, good SHA1 -->
+  <office:spreadsheet table:structure-protected="true" 
table:protection-key="nLHas0RIwepGDaH4c2hpyIUvIS8=" 
table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha1";>
+   <table:tracked-changes/>
+   <table:calculation-settings table:automatic-find-labels="false" 
table:use-regular-expressions="false" table:use-wildcards="true"/>
+
+   <table:table table:name="Sheet1" table:protected="true" 
table:protection-key="nLHas0RIwepGDaH4c2hpyIUvIS8=" 
table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha1";>
+    <loext:table-protection loext:select-protected-cells="true" 
loext:select-unprotected-cells="true"/>
+    <table:table-row>
+     <table:table-cell/>
+    </table:table-row>
+   </table:table>
+   <table:named-expressions/>
+  </office:spreadsheet>
+ </office:body>
+</office:document>
diff --git a/sc/qa/unit/data/fods/protection-key3.fods 
b/sc/qa/unit/data/fods/protection-key3.fods
new file mode 100644
index 000000000000..31c149fee0f6
--- /dev/null
+++ b/sc/qa/unit/data/fods/protection-key3.fods
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:scr
 ipt="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:form
 x="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" 
xmlns:css3t="http://www.w3.org/TR/css3-text/"; office:version="1.2" 
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
+ <office:body>
+
+  <!-- UTF-8, SHA256, ODF 1.2 URI -->
+  <office:spreadsheet table:structure-protected="true" 
table:protection-key="1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=" 
table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha256";>
+   <table:tracked-changes/>
+   <table:calculation-settings table:automatic-find-labels="false" 
table:use-regular-expressions="false" table:use-wildcards="true"/>
+
+   <table:table table:name="Sheet1" table:protected="true" 
table:protection-key="1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=" 
table:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha256";>
+    <loext:table-protection loext:select-protected-cells="true" 
loext:select-unprotected-cells="true"/>
+    <table:table-row>
+     <table:table-cell/>
+    </table:table-row>
+   </table:table>
+   <table:named-expressions/>
+  </office:spreadsheet>
+ </office:body>
+</office:document>
diff --git a/sc/qa/unit/data/fods/protection-key4.fods 
b/sc/qa/unit/data/fods/protection-key4.fods
new file mode 100644
index 000000000000..667a9e9b2525
--- /dev/null
+++ b/sc/qa/unit/data/fods/protection-key4.fods
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:scr
 ipt="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:form
 x="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" 
xmlns:css3t="http://www.w3.org/TR/css3-text/"; office:version="1.2" 
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
+ <office:body>
+
+  <!-- UTF-8, SHA256, W3C URI -->
+  <office:spreadsheet table:structure-protected="true" 
table:protection-key="1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=" 
table:protection-key-digest-algorithm="http://www.w3.org/2001/04/xmlenc#sha256";>
+   <table:tracked-changes/>
+   <table:calculation-settings table:automatic-find-labels="false" 
table:use-regular-expressions="false" table:use-wildcards="true"/>
+
+   <table:table table:name="Sheet1" table:protected="true" 
table:protection-key="1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=" 
table:protection-key-digest-algorithm="http://www.w3.org/2001/04/xmlenc#sha256";>
+    <loext:table-protection loext:select-protected-cells="true" 
loext:select-unprotected-cells="true"/>
+    <table:table-row>
+     <table:table-cell/>
+    </table:table-row>
+   </table:table>
+   <table:named-expressions/>
+  </office:spreadsheet>
+ </office:body>
+</office:document>
diff --git a/sc/qa/unit/data/fods/protection-key5.fods 
b/sc/qa/unit/data/fods/protection-key5.fods
new file mode 100644
index 000000000000..b5dfcc83dd92
--- /dev/null
+++ b/sc/qa/unit/data/fods/protection-key5.fods
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:scr
 ipt="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:form
 x="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" 
xmlns:css3t="http://www.w3.org/TR/css3-text/"; office:version="1.2" 
office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
+ <office:body>
+
+  <!-- Excel hash + SHA1 -->
+  <office:spreadsheet table:structure-protected="true" 
table:protection-key="OX3WkEe79fv1PE+FUmfOLdwVoqI=" 
table:protection-key-digest-algorithm="http://docs.oasis-open.org/office/ns/table/legacy-hash-excel";
 
loext:protection-key-digest-algorithm-2="http://www.w3.org/2000/09/xmldsig#sha1";>
+   <table:tracked-changes/>
+   <table:calculation-settings table:automatic-find-labels="false" 
table:use-regular-expressions="false" table:use-wildcards="true"/>
+
+   <table:table table:name="Sheet1" table:style-name="ta1" 
table:protected="true" table:protection-key="OX3WkEe79fv1PE+FUmfOLdwVoqI=" 
table:protection-key-digest-algorithm="http://docs.oasis-open.org/office/ns/table/legacy-hash-excel";
 
loext:protection-key-digest-algorithm-2="http://www.w3.org/2000/09/xmldsig#sha1";>
+    <loext:table-protection loext:select-protected-cells="true" 
loext:select-unprotected-cells="true"/>
+    <table:table-row>
+     <table:table-cell/>
+    </table:table-row>
+   </table:table>
+   <table:named-expressions/>
+  </office:spreadsheet>
+ </office:body>
+</office:document>
diff --git a/sc/qa/unit/subsequent_export-test.cxx 
b/sc/qa/unit/subsequent_export-test.cxx
index 06ed9dcdf9ad..122fad288343 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -96,6 +96,11 @@ public:
     void testConditionalFormatExportODS();
     void testConditionalFormatExportXLSX();
     void testTdf99856_dataValidationTest();
+    void testProtectionKeyODS_UTF16LErtlSHA1();
+    void testProtectionKeyODS_UTF8SHA1();
+    void testProtectionKeyODS_UTF8SHA256ODF12();
+    void testProtectionKeyODS_UTF8SHA256W3C();
+    void testProtectionKeyODS_XL_SHA1();
     void testColorScaleExportODS();
     void testColorScaleExportXLSX();
     void testDataBarExportODS();
@@ -206,6 +211,11 @@ public:
     CPPUNIT_TEST(testConditionalFormatExportODS);
     CPPUNIT_TEST(testConditionalFormatExportXLSX);
     CPPUNIT_TEST(testTdf99856_dataValidationTest);
+    CPPUNIT_TEST(testProtectionKeyODS_UTF16LErtlSHA1);
+    CPPUNIT_TEST(testProtectionKeyODS_UTF8SHA1);
+    CPPUNIT_TEST(testProtectionKeyODS_UTF8SHA256ODF12);
+    CPPUNIT_TEST(testProtectionKeyODS_UTF8SHA256W3C);
+    CPPUNIT_TEST(testProtectionKeyODS_XL_SHA1);
     CPPUNIT_TEST(testColorScaleExportODS);
     CPPUNIT_TEST(testColorScaleExportXLSX);
     CPPUNIT_TEST(testDataBarExportODS);
@@ -328,7 +338,8 @@ void ScExportTest::registerNamespaces(xmlXPathContextPtr& 
pXmlXPathCtx)
         { BAD_CAST("xdr"), 
BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";) 
},
         { BAD_CAST("x"), 
BAD_CAST("http://schemas.openxmlformats.org/spreadsheetml/2006/main";) },
         { BAD_CAST("r"), 
BAD_CAST("http://schemas.openxmlformats.org/package/2006/relationships";) },
-        { BAD_CAST("number"), 
BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0") }
+        { BAD_CAST("number"), 
BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0") },
+        { BAD_CAST("loext"), 
BAD_CAST("urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0")
 },
     };
     for(size_t i = 0; i < SAL_N_ELEMENTS(aNamespaces); ++i)
     {
@@ -495,6 +506,111 @@ void ScExportTest::testTdf99856_dataValidationTest()
     xDocSh->DoClose();
 }
 
+void ScExportTest::testProtectionKeyODS_UTF16LErtlSHA1()
+{
+    OUString const 
password("1012345678901234567890123456789012345678901234567890");
+
+    ScDocShellRef xShell = loadDoc("protection-key1.", FORMAT_FODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load doc", xShell.is());
+
+    ScDocument& rDoc = xShell->GetDocument();
+    ScDocProtection *const pDocProt(rDoc.GetDocProtection());
+    CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+    ScTableProtection *const pTabProt(rDoc.GetTabProtection(0));
+    CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+    // we can't assume that the user entered the password; check that we
+    // round-trip the password as-is
+    std::shared_ptr<utl::TempFile> pXPathFile = 
ScBootstrapFixture::exportTo(&(*xShell), FORMAT_ODS);
+    xmlDocPtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, 
"content.xml");
+    assertXPath(pXmlDoc, 
"//office:spreadsheet[@table:structure-protected='true' and 
@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']");
+    assertXPath(pXmlDoc, "//table:table[@table:protected='true' and 
@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']");
+}
+
+void ScExportTest::testProtectionKeyODS_UTF8SHA1()
+{
+    OUString const 
password("1012345678901234567890123456789012345678901234567890");
+
+    ScDocShellRef xShell = loadDoc("protection-key2.", FORMAT_FODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load doc", xShell.is());
+
+    ScDocument& rDoc = xShell->GetDocument();
+    ScDocProtection *const pDocProt(rDoc.GetDocProtection());
+    CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+    ScTableProtection *const pTabProt(rDoc.GetTabProtection(0));
+    CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+    // we can't assume that the user entered the password; check that we
+    // round-trip the password as-is
+    std::shared_ptr<utl::TempFile> pXPathFile = 
ScBootstrapFixture::exportTo(&(*xShell), FORMAT_ODS);
+    xmlDocPtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, 
"content.xml");
+    assertXPath(pXmlDoc, 
"//office:spreadsheet[@table:structure-protected='true' and 
@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']");
+    assertXPath(pXmlDoc, "//table:table[@table:protected='true' and 
@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']");
+}
+
+void ScExportTest::testProtectionKeyODS_UTF8SHA256ODF12()
+{
+    OUString const 
password("1012345678901234567890123456789012345678901234567890");
+
+    ScDocShellRef xShell = loadDoc("protection-key3.", FORMAT_FODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load doc", xShell.is());
+
+    ScDocument& rDoc = xShell->GetDocument();
+    ScDocProtection *const pDocProt(rDoc.GetDocProtection());
+    CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+    ScTableProtection *const pTabProt(rDoc.GetTabProtection(0));
+    CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+    // we can't assume that the user entered the password; check that we
+    // round-trip the password as-is
+    std::shared_ptr<utl::TempFile> pXPathFile = 
ScBootstrapFixture::exportTo(&(*xShell), FORMAT_ODS);
+    xmlDocPtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, 
"content.xml");
+    assertXPath(pXmlDoc, 
"//office:spreadsheet[@table:structure-protected='true' and 
@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']");
+    assertXPath(pXmlDoc, "//table:table[@table:protected='true' and 
@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']");
+}
+
+void ScExportTest::testProtectionKeyODS_UTF8SHA256W3C()
+{
+    OUString const 
password("1012345678901234567890123456789012345678901234567890");
+
+    ScDocShellRef xShell = loadDoc("protection-key4.", FORMAT_FODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load doc", xShell.is());
+
+    ScDocument& rDoc = xShell->GetDocument();
+    ScDocProtection *const pDocProt(rDoc.GetDocProtection());
+    CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+    ScTableProtection *const pTabProt(rDoc.GetTabProtection(0));
+    CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+    // we can't assume that the user entered the password; check that we
+    // round-trip the password as-is
+    std::shared_ptr<utl::TempFile> pXPathFile = 
ScBootstrapFixture::exportTo(&(*xShell), FORMAT_ODS);
+    xmlDocPtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, 
"content.xml");
+    assertXPath(pXmlDoc, 
"//office:spreadsheet[@table:structure-protected='true' and 
@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']");
+    assertXPath(pXmlDoc, "//table:table[@table:protected='true' and 
@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and 
@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']");
+}
+
+void ScExportTest::testProtectionKeyODS_XL_SHA1()
+{
+    OUString const 
password("1012345678901234567890123456789012345678901234567890");
+
+    ScDocShellRef xShell = loadDoc("protection-key5.", FORMAT_FODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load doc", xShell.is());
+
+    ScDocument& rDoc = xShell->GetDocument();
+    ScDocProtection *const pDocProt(rDoc.GetDocProtection());
+    CPPUNIT_ASSERT(pDocProt->verifyPassword(password));
+    ScTableProtection *const pTabProt(rDoc.GetTabProtection(0));
+    CPPUNIT_ASSERT(pTabProt->verifyPassword(password));
+
+    // we can't assume that the user entered the password; check that we
+    // round-trip the password as-is
+    std::shared_ptr<utl::TempFile> pXPathFile = 
ScBootstrapFixture::exportTo(&(*xShell), FORMAT_ODS);
+    xmlDocPtr pXmlDoc = XPathHelper::parseExport(pXPathFile, m_xSFactory, 
"content.xml");
+    assertXPath(pXmlDoc, 
"//office:spreadsheet[@table:structure-protected='true' and 
@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and 
@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/legacy-hash-excel'
 and 
@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']");
+    assertXPath(pXmlDoc, "//table:table[@table:protected='true' and 
@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and 
@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/legacy-hash-excel'
 and 
@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']");
+}
+
 void ScExportTest::testColorScaleExportODS()
 {
     ScDocShellRef xShell = loadDoc("colorscale.", FORMAT_ODS);
diff --git a/sc/source/core/data/tabprotection.cxx 
b/sc/source/core/data/tabprotection.cxx
index 21a3f686a44f..9a4a8bdde26d 100644
--- a/sc/source/core/data/tabprotection.cxx
+++ b/sc/source/core/data/tabprotection.cxx
@@ -28,6 +28,8 @@
 #define DEBUG_TAB_PROTECTION 0
 
 #define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1";
+#define URI_SHA256_ODF12 "http://www.w3.org/2000/09/xmldsig#sha256";
+#define URI_SHA256_W3C "http://www.w3.org/2001/04/xmlenc#sha256";
 #define URI_XLS_LEGACY 
"http://docs.oasis-open.org/office/ns/table/legacy-hash-excel";
 
 using namespace ::com::sun::star;
@@ -62,6 +64,8 @@ OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
 {
     switch (eHash)
     {
+        case PASSHASH_SHA256:
+            return OUString(URI_SHA256_ODF12);
         case PASSHASH_SHA1:
             return OUString(URI_SHA1);
         case PASSHASH_XL:
@@ -75,6 +79,8 @@ OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
 
 ScPasswordHash ScPassHashHelper::getHashTypeFromURI(const OUString& rURI)
 {
+    if (rURI == URI_SHA256_ODF12 || rURI == URI_SHA256_W3C)
+        return PASSHASH_SHA256;
     if ( rURI == URI_SHA1 )
         return PASSHASH_SHA1;
     else if ( rURI == URI_XLS_LEGACY )
@@ -140,6 +146,12 @@ Sequence<sal_Int8> 
ScTableProtectionImpl::hashPassword(const OUString& aPassText
         case PASSHASH_SHA1:
             SvPasswordHelper::GetHashPassword(aHash, aPassText);
         break;
+        case PASSHASH_SHA1_UTF8:
+            SvPasswordHelper::GetHashPasswordSHA1UTF8(aHash, aPassText);
+        break;
+        case PASSHASH_SHA256:
+            SvPasswordHelper::GetHashPasswordSHA256(aHash, aPassText);
+        break;
         default:
             ;
     }
@@ -320,7 +332,20 @@ bool ScTableProtectionImpl::verifyPassword(const OUString& 
aPassText) const
     printf("\n");
 #endif
 
-    return aHash == maPassHash;
+    if (aHash == maPassHash)
+    {
+        return true;
+    }
+
+    // tdf#115483 compat hack for ODF 1.2; for now UTF8-SHA1 passwords are only
+    // verified, not generated
+    if (meHash1 == PASSHASH_SHA1 && meHash2 == PASSHASH_UNSPECIFIED)
+    {
+        Sequence<sal_Int8> const aHash2 = hashPassword(aPassText, 
PASSHASH_SHA1_UTF8);
+        return aHash2 == maPassHash;
+    }
+
+    return false;
 }
 
 bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
diff --git a/sc/source/filter/xml/xmlexprt.cxx 
b/sc/source/filter/xml/xmlexprt.cxx
index 5db0920c020d..6026ec7e7483 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -1702,6 +1702,11 @@ void ScXMLExport::SetBodyAttributes()
                 aPassHash = p->getPasswordHash(PASSHASH_SHA1);
                 eHashUsed = PASSHASH_SHA1;
             }
+            else if (p->hasPasswordHash(PASSHASH_SHA256))
+            {
+                aPassHash = p->getPasswordHash(PASSHASH_SHA256);
+                eHashUsed = PASSHASH_SHA256;
+            }
             else if (p->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
             {
                 aPassHash = p->getPasswordHash(PASSHASH_XL, PASSHASH_SHA1);
@@ -1723,8 +1728,15 @@ void ScXMLExport::SetBodyAttributes()
                                 ScPassHashHelper::getHashURI(PASSHASH_SHA1));
                 }
                 else if (eHashUsed == PASSHASH_SHA1)
+                {
                     AddAttribute(XML_NAMESPACE_TABLE, 
XML_PROTECTION_KEY_DIGEST_ALGORITHM,
                                  ScPassHashHelper::getHashURI(PASSHASH_SHA1));
+                }
+                else if (eHashUsed == PASSHASH_SHA256)
+                {
+                    AddAttribute(XML_NAMESPACE_TABLE, 
XML_PROTECTION_KEY_DIGEST_ALGORITHM,
+                                 
ScPassHashHelper::getHashURI(PASSHASH_SHA256));
+                }
             }
         }
     }
@@ -2840,6 +2852,12 @@ void ScXMLExport::WriteTable(sal_Int32 nTable, const 
uno::Reference<sheet::XSpre
                         pProtect->getPasswordHash(PASSHASH_SHA1));
                     eHashUsed = PASSHASH_SHA1;
                 }
+                else if (pProtect->hasPasswordHash(PASSHASH_SHA256))
+                {
+                    ::sax::Converter::encodeBase64(aBuffer,
+                        pProtect->getPasswordHash(PASSHASH_SHA256));
+                    eHashUsed = PASSHASH_SHA256;
+                }
                 else if (pProtect->hasPasswordHash(PASSHASH_XL, PASSHASH_SHA1))
                 {
                     // Double-hash this by SHA1 on top of the legacy xls hash.
@@ -2861,8 +2879,15 @@ void ScXMLExport::WriteTable(sal_Int32 nTable, const 
uno::Reference<sheet::XSpre
                                         
ScPassHashHelper::getHashURI(PASSHASH_SHA1));
                         }
                         else if (eHashUsed == PASSHASH_SHA1)
+                        {
                             AddAttribute(XML_NAMESPACE_TABLE, 
XML_PROTECTION_KEY_DIGEST_ALGORITHM,
                                          
ScPassHashHelper::getHashURI(PASSHASH_SHA1));
+                        }
+                        else if (eHashUsed == PASSHASH_SHA256)
+                        {
+                            AddAttribute(XML_NAMESPACE_TABLE, 
XML_PROTECTION_KEY_DIGEST_ALGORITHM,
+                                         
ScPassHashHelper::getHashURI(PASSHASH_SHA256));
+                        }
                     }
                 }
             }
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
index a5cea0179018..865e7c4ad2b1 100644
--- a/sc/source/ui/docshell/docsh.cxx
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -1705,6 +1705,10 @@ bool ScDocShell::SaveAs( SfxMedium& rMedium )
     if (bNeedsRehash)
         // legacy xls hash double-hashed by SHA1 is also supported.
         bNeedsRehash = ScPassHashHelper::needsPassHashRegen(aDocument, 
PASSHASH_XL, PASSHASH_SHA1);
+    if (bNeedsRehash)
+    {   // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
+        bNeedsRehash = ScPassHashHelper::needsPassHashRegen(aDocument, 
PASSHASH_SHA256);
+    }
 
     if (pViewShell && bNeedsRehash)
     {
diff --git a/svl/source/misc/PasswordHelper.cxx 
b/svl/source/misc/PasswordHelper.cxx
index 00558f6a1630..48aa165507ee 100644
--- a/svl/source/misc/PasswordHelper.cxx
+++ b/svl/source/misc/PasswordHelper.cxx
@@ -19,11 +19,32 @@
 
 
 #include <svl/PasswordHelper.hxx>
+#include <comphelper/hash.hxx>
 #include <rtl/digest.h>
 #include <memory>
 
 using namespace com::sun::star;
 
+void SvPasswordHelper::GetHashPasswordSHA256(uno::Sequence<sal_Int8>& 
rPassHash, OUString const& rPassword)
+{
+    OString const tmp(OUStringToOString(rPassword, RTL_TEXTENCODING_UTF8));
+    ::std::vector<unsigned char> const hash(::comphelper::Hash::calculateHash(
+        reinterpret_cast<unsigned char const*>(tmp.getStr()), tmp.getLength(),
+        ::comphelper::HashType::SHA256));
+    rPassHash.realloc(hash.size());
+    ::std::copy(hash.begin(), hash.end(), rPassHash.begin());
+}
+
+void SvPasswordHelper::GetHashPasswordSHA1UTF8(uno::Sequence<sal_Int8>& 
rPassHash, OUString const& rPassword)
+{
+    OString const tmp(OUStringToOString(rPassword, RTL_TEXTENCODING_UTF8));
+    ::std::vector<unsigned char> const hash(::comphelper::Hash::calculateHash(
+        reinterpret_cast<unsigned char const*>(tmp.getStr()), tmp.getLength(),
+        ::comphelper::HashType::SHA1));
+    rPassHash.realloc(hash.size());
+    ::std::copy(hash.begin(), hash.end(), rPassHash.begin());
+}
+
 void SvPasswordHelper::GetHashPassword(uno::Sequence<sal_Int8>& rPassHash, 
const sal_Char* pPass, sal_uInt32 nLen)
 {
     rPassHash.realloc(RTL_DIGEST_LENGTH_SHA1);
@@ -74,14 +95,31 @@ bool SvPasswordHelper::CompareHashPassword(const 
uno::Sequence<sal_Int8>& rOldPa
 {
     bool bResult = false;
 
-    uno::Sequence<sal_Int8> aNewPass(RTL_DIGEST_LENGTH_SHA1);
-    GetHashPasswordLittleEndian(aNewPass, sNewPass);
-    if (aNewPass == rOldPassHash)
-        bResult = true;
-    else
+    if (rOldPassHash.getLength() == RTL_DIGEST_LENGTH_SHA1)
+    {
+        uno::Sequence<sal_Int8> aNewPass(RTL_DIGEST_LENGTH_SHA1);
+        GetHashPasswordSHA1UTF8(aNewPass, sNewPass);
+        if (aNewPass == rOldPassHash)
+        {
+            bResult = true;
+        }
+        else
+        {
+            GetHashPasswordLittleEndian(aNewPass, sNewPass);
+            if (aNewPass == rOldPassHash)
+                bResult = true;
+            else
+            {
+                GetHashPasswordBigEndian(aNewPass, sNewPass);
+                bResult = (aNewPass == rOldPassHash);
+            }
+        }
+    }
+    else if (rOldPassHash.getLength() == 32)
     {
-        GetHashPasswordBigEndian(aNewPass, sNewPass);
-        bResult = (aNewPass == rOldPassHash);
+        uno::Sequence<sal_Int8> aNewPass;
+        GetHashPasswordSHA256(aNewPass, sNewPass);
+        bResult = aNewPass == rOldPassHash;
     }
 
     return bResult;
diff --git a/sw/CppunitTest_sw_odfexport.mk b/sw/CppunitTest_sw_odfexport.mk
index e8c43ad931c9..343ab0a58066 100644
--- a/sw/CppunitTest_sw_odfexport.mk
+++ b/sw/CppunitTest_sw_odfexport.mk
@@ -21,6 +21,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_odfexport, \
     cppuhelper \
     sal \
        sfx \
+       svl \
        sw \
     test \
     tl \
diff --git a/sw/qa/extras/odfexport/data/protection-key.fodt 
b/sw/qa/extras/odfexport/data/protection-key.fodt
new file mode 100644
index 000000000000..cd4cde9623a4
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/protection-key.fodt
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:config="urn:oas
 is:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:officeooo="http://openoffice.org/2009/office"; 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:formx="urn:openoffice:names:
 experimental:ooxml-odf-interop:xmlns:form:1.0" 
xmlns:css3t="http://www.w3.org/TR/css3-text/"; office:version="1.2" 
office:mimetype="application/vnd.oasis.opendocument.text">
+
+ <office:styles>
+
+  <style:style style:name="Standard" style:family="paragraph" 
style:class="text"/>
+
+ </office:styles>
+ <office:automatic-styles>
+
+  <style:style style:name="Sect" style:family="section">
+   <style:section-properties style:editable="false">
+    <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+   </style:section-properties>
+  </style:style>
+
+ </office:automatic-styles>
+ <office:body>
+  <office:text>
+
+   <!-- UTF-16 LE, bad SHA1 -->
+   <text:section text:style-name="Sect" text:name="Section0" 
text:protected="true" text:protection-key="vbnhxyBKtPHCA1wB21zG1Oha8ZA=">
+    <text:p text:style-name="Standard"/>
+   </text:section>
+
+   <!-- echo -n $(echo -n 1012345678901234567890123456789012345678901234567890 
| sha1sum | cut -f 1 -d ' ') | xxd -r -p | base64 -->
+   <!-- UTF-8, good SHA1 -->
+   <text:section text:style-name="Sect" text:name="Section1" 
text:protected="true" text:protection-key="nLHas0RIwepGDaH4c2hpyIUvIS8=">
+    <text:p text:style-name="Standard"/>
+   </text:section>
+
+   <!-- echo -n $(echo -n 1012345678901234567890123456789012345678901234567890 
| sha256sum | cut -f 1 -d ' ') | xxd -r -p | base64 -->
+   <!-- UTF-8, SHA256, ODF 1.2 URI -->
+   <text:section text:style-name="Sect" text:name="Section2" 
text:protected="true" 
text:protection-key="1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=" 
text:protection-key-digest-algorithm="http://www.w3.org/2000/09/xmldsig#sha256";>
+    <text:p text:style-name="Standard"/>
+   </text:section>
+
+   <!-- UTF-8, SHA256, W3C URI -->
+   <text:section text:style-name="Sect" text:name="Section3" 
text:protected="true" 
text:protection-key="1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=" 
text:protection-key-digest-algorithm="http://www.w3.org/2001/04/xmlenc#sha256";>
+    <text:p text:style-name="Standard"/>
+   </text:section>
+
+   <text:p text:style-name="Standard"/>
+  </office:text>
+ </office:body>
+</office:document>
+
diff --git a/sw/qa/extras/odfexport/odfexport.cxx 
b/sw/qa/extras/odfexport/odfexport.cxx
index 1e7b1badbe06..27762d0bf60b 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -36,6 +36,7 @@
 #include <comphelper/fileformat.h>
 #include <comphelper/propertysequence.hxx>
 #include <unotools/streamwrap.hxx>
+#include <svl/PasswordHelper.hxx>
 
 class Test : public SwModelTestBase
 {
@@ -748,6 +749,37 @@ DECLARE_ODFEXPORT_TEST(testCharacterBorder, 
"charborder.odt")
     }
 }
 
+DECLARE_ODFEXPORT_TEST(testProtectionKey, "protection-key.fodt")
+{
+    OUString const 
password("1012345678901234567890123456789012345678901234567890");
+
+    // check 1 invalid OOo legacy password and 3 valid ODF 1.2 passwords
+    uno::Reference<text::XTextSectionsSupplier> 
xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> 
xSections(xTextSectionsSupplier->getTextSections(), uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xSect0(xSections->getByIndex(0), 
uno::UNO_QUERY);
+    uno::Sequence<sal_Int8> const 
key0(getProperty<uno::Sequence<sal_Int8>>(xSect0, "ProtectionKey"));
+    CPPUNIT_ASSERT(SvPasswordHelper::CompareHashPassword(key0, password));
+    uno::Reference<beans::XPropertySet> xSect1(xSections->getByIndex(1), 
uno::UNO_QUERY);
+    uno::Sequence<sal_Int8> const 
key1(getProperty<uno::Sequence<sal_Int8>>(xSect1, "ProtectionKey"));
+    CPPUNIT_ASSERT(SvPasswordHelper::CompareHashPassword(key1, password));
+    uno::Reference<beans::XPropertySet> xSect2(xSections->getByIndex(2), 
uno::UNO_QUERY);
+    uno::Sequence<sal_Int8> const 
key2(getProperty<uno::Sequence<sal_Int8>>(xSect1, "ProtectionKey"));
+    CPPUNIT_ASSERT(SvPasswordHelper::CompareHashPassword(key2, password));
+    uno::Reference<beans::XPropertySet> xSect3(xSections->getByIndex(3), 
uno::UNO_QUERY);
+    uno::Sequence<sal_Int8> const 
key3(getProperty<uno::Sequence<sal_Int8>>(xSect1, "ProtectionKey"));
+    CPPUNIT_ASSERT(SvPasswordHelper::CompareHashPassword(key3, password));
+
+    // we can't assume that the user entered the password; check that we
+    // round-trip the password as-is
+    if (xmlDocPtr pXmlDoc = parseExport("content.xml"))
+    {
+        assertXPath(pXmlDoc, "//text:section[@text:name='Section0' and 
@text:protected='true' and 
@text:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=']");
+        assertXPath(pXmlDoc, "//text:section[@text:name='Section1' and 
@text:protected='true' and 
@text:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=']");
+        assertXPath(pXmlDoc, "//text:section[@text:name='Section2' and 
@text:protected='true' and 
@text:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256'
 and @text:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=']");
+        assertXPath(pXmlDoc, "//text:section[@text:name='Section3' and 
@text:protected='true' and 
@text:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256'
 and @text:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=']");
+    }
+}
+
 DECLARE_ODFEXPORT_TEST(testFdo43807, "fdo43807.odt")
 {
     uno::Reference<beans::XPropertySet> xSet(getParagraph(1), uno::UNO_QUERY);
diff --git a/xmloff/source/text/XMLSectionExport.cxx 
b/xmloff/source/text/XMLSectionExport.cxx
index 899cb51bc068..1413d2d791a5 100644
--- a/xmloff/source/text/XMLSectionExport.cxx
+++ b/xmloff/source/text/XMLSectionExport.cxx
@@ -398,8 +398,16 @@ void XMLSectionExport::ExportRegularSectionStart(
     {
         OUStringBuffer aBuffer;
         ::sax::Converter::encodeBase64(aBuffer, aPassword);
+        // in ODF 1.0/1.1 the algorithm was left unspecified so we can write 
anything
         GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTION_KEY,
                                  aBuffer.makeStringAndClear());
+        if (aPassword.getLength() == 32 && GetExport().getDefaultVersion() >= 
SvtSaveOptions::ODFVER_012)
+        {
+            // attribute exists in ODF 1.2 or later; default is SHA1 so no 
need to write that
+            GetExport().AddAttribute(XML_NAMESPACE_TEXT, 
XML_PROTECTION_KEY_DIGEST_ALGORITHM,
+                    // write the URL from ODF 1.2, not the W3C one
+                    "http://www.w3.org/2000/09/xmldsig#sha256";);
+        }
     }
 
     // export element
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to