diff options
-rw-r--r-- | include/svl/PasswordHelper.hxx | 7 | ||||
-rw-r--r-- | sc/CppunitTest_sc_subsequent_export_test.mk | 2 | ||||
-rw-r--r-- | sc/inc/tabprotection.hxx | 2 | ||||
-rw-r--r-- | sc/qa/unit/data/fods/protection-key1.fods | 20 | ||||
-rw-r--r-- | sc/qa/unit/data/fods/protection-key2.fods | 20 | ||||
-rw-r--r-- | sc/qa/unit/data/fods/protection-key3.fods | 20 | ||||
-rw-r--r-- | sc/qa/unit/data/fods/protection-key4.fods | 20 | ||||
-rw-r--r-- | sc/qa/unit/data/fods/protection-key5.fods | 20 | ||||
-rw-r--r-- | sc/qa/unit/subsequent_export-test.cxx | 118 | ||||
-rw-r--r-- | sc/source/core/data/tabprotection.cxx | 27 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlexprt.cxx | 25 | ||||
-rw-r--r-- | sc/source/ui/docshell/docsh.cxx | 4 | ||||
-rw-r--r-- | svl/source/misc/PasswordHelper.cxx | 52 | ||||
-rw-r--r-- | sw/CppunitTest_sw_odfexport.mk | 1 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/data/protection-key.fodt | 48 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/odfexport.cxx | 32 | ||||
-rw-r--r-- | xmloff/source/text/XMLSectionExport.cxx | 8 |
17 files changed, 416 insertions, 10 deletions
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:script="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: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.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:script="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: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.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:script="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: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.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:script="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: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.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:script="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: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.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 6865897d0318..2bf2cb8d8fd0 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 e9c6a22916f4..9c09a1ee0eb0 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 607cf964cdf9..1e56605c1d78 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -1714,6 +1714,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 da931c3f3006..8fb2228d84a3 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: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: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 14bd0bc2bc0e..4051d31349d5 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> #include <docufld.hxx> // for SwHiddenTextField::ParseIfFieldDefinition() method call class Test : public SwModelTestBase @@ -856,6 +857,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 e6a6875244c2..46189a119ca7 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 |