1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "tabprotection.hxx"
21 #include "svl/PasswordHelper.hxx"
22 #include <comphelper/docpasswordhelper.hxx>
23 #include "document.hxx"
27 #define DEBUG_TAB_PROTECTION 0
29 #define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
30 #define URI_XLS_LEGACY "http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
32 using namespace ::com::sun::star
;
33 using ::com::sun::star::uno::Sequence
;
36 // ============================================================================
38 bool ScPassHashHelper::needsPassHashRegen(const ScDocument
& rDoc
, ScPasswordHash eHash1
, ScPasswordHash eHash2
)
40 if (rDoc
.IsDocProtected())
42 const ScDocProtection
* p
= rDoc
.GetDocProtection();
43 if (!p
->isPasswordEmpty() && !p
->hasPasswordHash(eHash1
, eHash2
))
47 SCTAB nTabCount
= rDoc
.GetTableCount();
48 for (SCTAB i
= 0; i
< nTabCount
; ++i
)
50 const ScTableProtection
* p
= rDoc
.GetTabProtection(i
);
51 if (!p
|| !p
->isProtected())
52 // Sheet not protected. Skip it.
55 if (!p
->isPasswordEmpty() && !p
->hasPasswordHash(eHash1
, eHash2
))
62 OUString
ScPassHashHelper::getHashURI(ScPasswordHash eHash
)
67 return OUString(URI_SHA1
);
69 return OUString(URI_XLS_LEGACY
);
70 case PASSHASH_UNSPECIFIED
:
77 ScPasswordHash
ScPassHashHelper::getHashTypeFromURI(const OUString
& rURI
)
79 if ( rURI
== URI_SHA1
)
81 else if ( rURI
== URI_XLS_LEGACY
)
83 return PASSHASH_UNSPECIFIED
;
86 // ============================================================================
88 ScPassHashProtectable::~ScPassHashProtectable()
92 // ============================================================================
94 class ScTableProtectionImpl
97 static Sequence
<sal_Int8
> hashPassword(const OUString
& aPassText
, ScPasswordHash eHash
= PASSHASH_SHA1
);
98 static Sequence
<sal_Int8
> hashPassword(const Sequence
<sal_Int8
>& rPassHash
, ScPasswordHash eHash
= PASSHASH_SHA1
);
100 explicit ScTableProtectionImpl(SCSIZE nOptSize
);
101 explicit ScTableProtectionImpl(const ScTableProtectionImpl
& r
);
103 bool isProtected() const;
104 bool isProtectedWithPass() const;
105 void setProtected(bool bProtected
);
107 bool isPasswordEmpty() const;
108 bool hasPasswordHash(ScPasswordHash eHash
, ScPasswordHash eHash2
= PASSHASH_UNSPECIFIED
) const;
109 void setPassword(const OUString
& aPassText
);
110 ::com::sun::star::uno::Sequence
<sal_Int8
> getPasswordHash(
111 ScPasswordHash eHash
, ScPasswordHash eHash2
= PASSHASH_UNSPECIFIED
) const;
112 void setPasswordHash(
113 const ::com::sun::star::uno::Sequence
<sal_Int8
>& aPassword
,
114 ScPasswordHash eHash
= PASSHASH_SHA1
, ScPasswordHash eHash2
= PASSHASH_UNSPECIFIED
);
115 bool verifyPassword(const OUString
& aPassText
) const;
117 bool isOptionEnabled(SCSIZE nOptId
) const;
118 void setOption(SCSIZE nOptId
, bool bEnabled
);
122 ::com::sun::star::uno::Sequence
<sal_Int8
> maPassHash
;
123 ::std::vector
<bool> maOptions
;
126 ScPasswordHash meHash1
;
127 ScPasswordHash meHash2
;
130 Sequence
<sal_Int8
> ScTableProtectionImpl::hashPassword(const OUString
& aPassText
, ScPasswordHash eHash
)
132 Sequence
<sal_Int8
> aHash
;
136 aHash
= ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText
, RTL_TEXTENCODING_UTF8
);
139 SvPasswordHelper::GetHashPassword(aHash
, aPassText
);
147 Sequence
<sal_Int8
> ScTableProtectionImpl::hashPassword(
148 const Sequence
<sal_Int8
>& rPassHash
, ScPasswordHash eHash
)
150 if (!rPassHash
.getLength() || eHash
== PASSHASH_UNSPECIFIED
)
153 // TODO: Right now, we only support double-hash by SHA1.
154 if (eHash
== PASSHASH_SHA1
)
156 vector
<sal_Char
> aChars
;
157 sal_Int32 n
= rPassHash
.getLength();
159 for (sal_Int32 i
= 0; i
< n
; ++i
)
160 aChars
.push_back(static_cast<sal_Char
>(rPassHash
[i
]));
162 Sequence
<sal_Int8
> aNewHash
;
163 SvPasswordHelper::GetHashPassword(aNewHash
, &aChars
[0], aChars
.size());
170 ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize
) :
174 meHash1(PASSHASH_SHA1
),
175 meHash2(PASSHASH_UNSPECIFIED
)
179 ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl
& r
) :
180 maPassText(r
.maPassText
),
181 maPassHash(r
.maPassHash
),
182 maOptions(r
.maOptions
),
183 mbEmptyPass(r
.mbEmptyPass
),
184 mbProtected(r
.mbProtected
),
190 bool ScTableProtectionImpl::isProtected() const
195 bool ScTableProtectionImpl::isProtectedWithPass() const
200 return !maPassText
.isEmpty() || maPassHash
.getLength();
203 void ScTableProtectionImpl::setProtected(bool bProtected
)
205 mbProtected
= bProtected
;
206 // We need to keep the old password even when the protection is off. So,
207 // don't erase the password data here.
210 void ScTableProtectionImpl::setPassword(const OUString
& aPassText
)
212 // We can't hash it here because we don't know whether this document will
213 // get saved to Excel or ODF, depending on which we will need to use a
214 // different hashing algorithm. One alternative is to hash it using all
215 // hash algorithms that we support, and store them all.
217 maPassText
= aPassText
;
218 mbEmptyPass
= aPassText
.isEmpty();
221 maPassHash
= Sequence
<sal_Int8
>();
225 bool ScTableProtectionImpl::isPasswordEmpty() const
230 bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash
, ScPasswordHash eHash2
) const
235 if (!maPassText
.isEmpty())
238 if (meHash1
== eHash
)
240 if (meHash2
== PASSHASH_UNSPECIFIED
)
244 return meHash2
== eHash2
;
250 Sequence
<sal_Int8
> ScTableProtectionImpl::getPasswordHash(
251 ScPasswordHash eHash
, ScPasswordHash eHash2
) const
253 Sequence
<sal_Int8
> aPassHash
;
259 if (!maPassText
.isEmpty())
261 // Cleartext password exists. Hash it.
262 aPassHash
= hashPassword(maPassText
, eHash
);
263 if (eHash2
!= PASSHASH_UNSPECIFIED
)
265 aPassHash
= hashPassword(aPassHash
, eHash2
);
271 // No clear text password. Check if we have a hash value of the right hash type.
272 if (meHash1
== eHash
)
274 aPassHash
= maPassHash
;
276 if (meHash2
== eHash2
)
277 // Matching double-hash requested.
279 else if (meHash2
== PASSHASH_UNSPECIFIED
)
280 // primary hashing type match. Double hash it by the requested
282 return hashPassword(aPassHash
, eHash2
);
287 return Sequence
<sal_Int8
>();
290 void ScTableProtectionImpl::setPasswordHash(
291 const uno::Sequence
<sal_Int8
>& aPassword
, ScPasswordHash eHash
, ScPasswordHash eHash2
)
293 sal_Int32 nLen
= aPassword
.getLength();
294 mbEmptyPass
= nLen
<= 0 ? true : false;
297 maPassHash
= aPassword
;
299 #if DEBUG_TAB_PROTECTION
300 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
301 printf("%2.2X ", static_cast<sal_uInt8
>(aPassword
[i
]));
306 bool ScTableProtectionImpl::verifyPassword(const OUString
& aPassText
) const
308 #if DEBUG_TAB_PROTECTION
309 fprintf(stdout
, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
310 OUStringToOString(OUString(aPassText
), RTL_TEXTENCODING_UTF8
).getStr());
314 return aPassText
.isEmpty();
316 if (!maPassText
.isEmpty())
317 // Clear text password exists, and this one takes precedence.
318 return aPassText
== maPassText
;
320 Sequence
<sal_Int8
> aHash
= hashPassword(aPassText
, meHash1
);
321 aHash
= hashPassword(aHash
, meHash2
);
323 #if DEBUG_TAB_PROTECTION
324 fprintf(stdout
, "ScTableProtectionImpl::verifyPassword: hash = ");
325 for (sal_Int32 i
= 0; i
< aHash
.getLength(); ++i
)
326 printf("%2.2X ", static_cast<sal_uInt8
>(aHash
[i
]));
330 return aHash
== maPassHash
;
333 bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId
) const
335 if ( maOptions
.size() <= static_cast<size_t>(nOptId
) )
337 OSL_FAIL("ScTableProtectionImpl::isOptionEnabled: wrong size");
341 return maOptions
[nOptId
];
344 void ScTableProtectionImpl::setOption(SCSIZE nOptId
, bool bEnabled
)
346 if ( maOptions
.size() <= static_cast<size_t>(nOptId
) )
348 OSL_FAIL("ScTableProtectionImpl::setOption: wrong size");
352 maOptions
[nOptId
] = bEnabled
;
355 // ============================================================================
357 ScDocProtection::ScDocProtection() :
358 mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE
>(ScDocProtection::NONE
)))
362 ScDocProtection::ScDocProtection(const ScDocProtection
& r
) :
363 ScPassHashProtectable(),
364 mpImpl(new ScTableProtectionImpl(*r
.mpImpl
))
368 ScDocProtection::~ScDocProtection()
372 bool ScDocProtection::isProtected() const
374 return mpImpl
->isProtected();
377 bool ScDocProtection::isProtectedWithPass() const
379 return mpImpl
->isProtectedWithPass();
382 void ScDocProtection::setProtected(bool bProtected
)
384 mpImpl
->setProtected(bProtected
);
386 // Currently Calc doesn't support document protection options. So, let's
387 // assume that when the document is protected, its structure is protected.
388 // We need to do this for Excel export.
389 mpImpl
->setOption(ScDocProtection::STRUCTURE
, bProtected
);
392 bool ScDocProtection::isPasswordEmpty() const
394 return mpImpl
->isPasswordEmpty();
397 bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash
, ScPasswordHash eHash2
) const
399 return mpImpl
->hasPasswordHash(eHash
, eHash2
);
402 void ScDocProtection::setPassword(const OUString
& aPassText
)
404 mpImpl
->setPassword(aPassText
);
407 uno::Sequence
<sal_Int8
> ScDocProtection::getPasswordHash(ScPasswordHash eHash
, ScPasswordHash eHash2
) const
409 return mpImpl
->getPasswordHash(eHash
, eHash2
);
412 void ScDocProtection::setPasswordHash(
413 const uno::Sequence
<sal_Int8
>& aPassword
, ScPasswordHash eHash
, ScPasswordHash eHash2
)
415 mpImpl
->setPasswordHash(aPassword
, eHash
, eHash2
);
418 bool ScDocProtection::verifyPassword(const OUString
& aPassText
) const
420 return mpImpl
->verifyPassword(aPassText
);
423 bool ScDocProtection::isOptionEnabled(Option eOption
) const
425 return mpImpl
->isOptionEnabled(eOption
);
428 void ScDocProtection::setOption(Option eOption
, bool bEnabled
)
430 mpImpl
->setOption(eOption
, bEnabled
);
433 // ============================================================================
435 ScTableProtection::ScTableProtection() :
436 mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE
>(ScTableProtection::NONE
)))
438 // Set default values for the options.
439 mpImpl
->setOption(SELECT_LOCKED_CELLS
, true);
440 mpImpl
->setOption(SELECT_UNLOCKED_CELLS
, true);
443 ScTableProtection::ScTableProtection(const ScTableProtection
& r
) :
444 ScPassHashProtectable(),
445 mpImpl(new ScTableProtectionImpl(*r
.mpImpl
))
449 ScTableProtection::~ScTableProtection()
453 bool ScTableProtection::isProtected() const
455 return mpImpl
->isProtected();
458 bool ScTableProtection::isProtectedWithPass() const
460 return mpImpl
->isProtectedWithPass();
463 void ScTableProtection::setProtected(bool bProtected
)
465 mpImpl
->setProtected(bProtected
);
468 bool ScTableProtection::isPasswordEmpty() const
470 return mpImpl
->isPasswordEmpty();
473 bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash
, ScPasswordHash eHash2
) const
475 return mpImpl
->hasPasswordHash(eHash
, eHash2
);
478 void ScTableProtection::setPassword(const OUString
& aPassText
)
480 mpImpl
->setPassword(aPassText
);
483 Sequence
<sal_Int8
> ScTableProtection::getPasswordHash(ScPasswordHash eHash
, ScPasswordHash eHash2
) const
485 return mpImpl
->getPasswordHash(eHash
, eHash2
);
488 void ScTableProtection::setPasswordHash(
489 const uno::Sequence
<sal_Int8
>& aPassword
, ScPasswordHash eHash
, ScPasswordHash eHash2
)
491 mpImpl
->setPasswordHash(aPassword
, eHash
, eHash2
);
494 bool ScTableProtection::verifyPassword(const OUString
& aPassText
) const
496 return mpImpl
->verifyPassword(aPassText
);
499 bool ScTableProtection::isOptionEnabled(Option eOption
) const
501 return mpImpl
->isOptionEnabled(eOption
);
504 void ScTableProtection::setOption(Option eOption
, bool bEnabled
)
506 mpImpl
->setOption(eOption
, bEnabled
);
508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */