Update ooo320-m1
[ooovba.git] / sc / source / core / data / tabprotection.cxx
blob5fe808bc23e71ebb54155a8ae50ea11092328510
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tabprotection.cxx,v $
10 * $Revision: 1.1.4.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include "tabprotection.hxx"
37 #include "tools/debug.hxx"
38 #include "svtools/PasswordHelper.hxx"
39 #include "document.hxx"
41 #include <vector>
43 #define DEBUG_TAB_PROTECTION 0
45 #define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
46 #define URI_XLS_LEGACY "http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
48 using namespace ::com::sun::star;
49 using ::com::sun::star::uno::Sequence;
50 using ::rtl::OUString;
51 using ::rtl::OUStringBuffer;
52 using ::std::vector;
54 // ============================================================================
56 bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2)
58 if (rDoc.IsDocProtected())
60 const ScDocProtection* p = rDoc.GetDocProtection();
61 if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
62 return true;
65 SCTAB nTabCount = rDoc.GetTableCount();
66 for (SCTAB i = 0; i < nTabCount; ++i)
68 const ScTableProtection* p = rDoc.GetTabProtection(i);
69 if (!p || !p->isProtected())
70 // Sheet not protected. Skip it.
71 continue;
73 if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
74 return true;
77 return false;
80 OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
82 switch (eHash)
84 case PASSHASH_SHA1:
85 return OUString::createFromAscii(URI_SHA1);
86 case PASSHASH_XL:
87 return OUString::createFromAscii(URI_XLS_LEGACY);
88 case PASSHASH_UNSPECIFIED:
89 default:
92 return OUString();
95 ScPasswordHash ScPassHashHelper::getHashTypeFromURI(const OUString& rURI)
97 if (rURI.equalsAscii(URI_SHA1))
98 return PASSHASH_SHA1;
99 else if (rURI.equalsAscii(URI_XLS_LEGACY))
100 return PASSHASH_XL;
101 return PASSHASH_UNSPECIFIED;
104 // ============================================================================
106 ScPassHashProtectable::~ScPassHashProtectable()
110 // ============================================================================
112 static sal_uInt16 lcl_getXLHashFromChar(const sal_Char* szPassword)
114 sal_uInt16 cchPassword = static_cast< sal_uInt16 >( strlen(szPassword) );
115 sal_uInt16 wPasswordHash = 0;
116 if (!cchPassword)
117 return wPasswordHash;
119 const char* pch = &szPassword[cchPassword];
120 while (pch-- != szPassword)
122 wPasswordHash = ((wPasswordHash >> 14) & 0x01) |
123 ((wPasswordHash << 1) & 0x7fff);
124 wPasswordHash ^= *pch;
127 wPasswordHash = ((wPasswordHash >> 14) & 0x01) |
128 ((wPasswordHash << 1) & 0x7fff);
130 wPasswordHash ^= (0x8000 | ('N' << 8) | 'K');
131 wPasswordHash ^= cchPassword;
133 return wPasswordHash;
136 static Sequence<sal_Int8> lcl_getXLHash(const String& aPassText)
138 const sal_Char* szBuf = OUStringToOString(OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr();
139 sal_uInt16 nHash = lcl_getXLHashFromChar(szBuf);
140 Sequence<sal_Int8> aHash(2);
141 aHash[0] = (nHash >> 8) & 0xFF;
142 aHash[1] = nHash & 0xFF;
143 return aHash;
146 class ScTableProtectionImpl
148 public:
149 static Sequence<sal_Int8> hashPassword(const String& aPassText, ScPasswordHash eHash = PASSHASH_SHA1);
150 static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash = PASSHASH_SHA1);
152 explicit ScTableProtectionImpl(SCSIZE nOptSize);
153 explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
155 bool isProtected() const;
156 bool isProtectedWithPass() const;
157 void setProtected(bool bProtected);
159 bool isPasswordEmpty() const;
160 bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
161 void setPassword(const String& aPassText);
162 ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
163 ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
164 void setPasswordHash(
165 const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
166 ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
167 bool verifyPassword(const String& aPassText) const;
169 bool isOptionEnabled(SCSIZE nOptId) const;
170 void setOption(SCSIZE nOptId, bool bEnabled);
172 private:
173 String maPassText;
174 ::com::sun::star::uno::Sequence<sal_Int8> maPassHash;
175 ::std::vector<bool> maOptions;
176 bool mbEmptyPass;
177 bool mbProtected;
178 ScPasswordHash meHash1;
179 ScPasswordHash meHash2;
182 Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const String& aPassText, ScPasswordHash eHash)
184 Sequence<sal_Int8> aHash;
185 switch (eHash)
187 case PASSHASH_XL:
188 aHash = lcl_getXLHash(aPassText);
189 break;
190 case PASSHASH_SHA1:
191 SvPasswordHelper::GetHashPassword(aHash, aPassText);
192 break;
193 default:
196 return aHash;
199 Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(
200 const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash)
202 if (!rPassHash.getLength() || eHash == PASSHASH_UNSPECIFIED)
203 return rPassHash;
205 // TODO: Right now, we only support double-hash by SHA1.
206 if (eHash == PASSHASH_SHA1)
208 vector<sal_Char> aChars;
209 sal_Int32 n = rPassHash.getLength();
210 aChars.reserve(n);
211 for (sal_Int32 i = 0; i < n; ++i)
212 aChars.push_back(static_cast<sal_Char>(rPassHash[i]));
214 Sequence<sal_Int8> aNewHash;
215 SvPasswordHelper::GetHashPassword(aNewHash, &aChars[0], aChars.size());
216 return aNewHash;
219 return rPassHash;
222 ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
223 maOptions(nOptSize),
224 mbEmptyPass(true),
225 mbProtected(false),
226 meHash1(PASSHASH_SHA1),
227 meHash2(PASSHASH_UNSPECIFIED)
231 ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
232 maPassText(r.maPassText),
233 maPassHash(r.maPassHash),
234 maOptions(r.maOptions),
235 mbEmptyPass(r.mbEmptyPass),
236 mbProtected(r.mbProtected),
237 meHash1(r.meHash1),
238 meHash2(r.meHash2)
242 bool ScTableProtectionImpl::isProtected() const
244 return mbProtected;
247 bool ScTableProtectionImpl::isProtectedWithPass() const
249 if (!mbProtected)
250 return false;
252 return maPassText.Len() || maPassHash.getLength();
255 void ScTableProtectionImpl::setProtected(bool bProtected)
257 mbProtected = bProtected;
258 // We need to keep the old password even when the protection is off. So,
259 // don't erase the password data here.
262 void ScTableProtectionImpl::setPassword(const String& aPassText)
264 // We can't hash it here because we don't know whether this document will
265 // get saved to Excel or ODF, depending on which we will need to use a
266 // different hashing algorithm. One alternative is to hash it using all
267 // hash algorithms that we support, and store them all.
269 maPassText = aPassText;
270 mbEmptyPass = aPassText.Len() == 0;
271 if (mbEmptyPass)
273 maPassHash = Sequence<sal_Int8>();
277 bool ScTableProtectionImpl::isPasswordEmpty() const
279 return mbEmptyPass;
282 bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
284 if (mbEmptyPass)
285 return true;
287 if (maPassText.Len())
288 return true;
290 if (meHash1 == eHash)
292 if (meHash2 == PASSHASH_UNSPECIFIED)
293 // single hash.
294 return true;
296 return meHash2 == eHash2;
299 return false;
302 Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(
303 ScPasswordHash eHash, ScPasswordHash eHash2) const
305 Sequence<sal_Int8> aPassHash;
307 if (mbEmptyPass)
308 // Flaged as empty.
309 return aPassHash;
311 if (maPassText.Len())
313 // Cleartext password exists. Hash it.
314 aPassHash = hashPassword(maPassText, eHash);
315 if (eHash2 != PASSHASH_UNSPECIFIED)
316 // Double-hash it.
317 aPassHash = hashPassword(aPassHash, eHash2);
319 return aPassHash;
321 else
323 // No clear text password. Check if we have a hash value of the right hash type.
324 if (meHash1 == eHash)
326 aPassHash = maPassHash;
328 if (meHash2 == eHash2)
329 // Matching double-hash requested.
330 return aPassHash;
331 else if (meHash2 == PASSHASH_UNSPECIFIED)
332 // primary hashing type match. Double hash it by the requested
333 // double-hash type.
334 return hashPassword(aPassHash, eHash2);
338 // failed.
339 return Sequence<sal_Int8>();
342 void ScTableProtectionImpl::setPasswordHash(
343 const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
345 sal_Int32 nLen = aPassword.getLength();
346 mbEmptyPass = nLen <= 0 ? true : false;
347 meHash1 = eHash;
348 meHash2 = eHash2;
349 maPassHash = aPassword;
351 #if DEBUG_TAB_PROTECTION
352 for (sal_Int32 i = 0; i < nLen; ++i)
353 printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
354 printf("\n");
355 #endif
358 bool ScTableProtectionImpl::verifyPassword(const String& aPassText) const
360 #if DEBUG_TAB_PROTECTION
361 fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
362 OUStringToOString(rtl::OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
363 #endif
365 if (mbEmptyPass)
366 return aPassText.Len() == 0;
368 if (maPassText.Len())
369 // Clear text password exists, and this one takes precedence.
370 return aPassText.Equals(maPassText);
372 Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash1);
373 aHash = hashPassword(aHash, meHash2);
375 #if DEBUG_TAB_PROTECTION
376 fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
377 for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
378 printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
379 printf("\n");
380 #endif
382 return aHash == maPassHash;
385 bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
387 if ( maOptions.size() <= static_cast<size_t>(nOptId) )
389 DBG_ERROR("ScTableProtectionImpl::isOptionEnabled: wrong size");
390 return false;
393 return maOptions[nOptId];
396 void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
398 if ( maOptions.size() <= static_cast<size_t>(nOptId) )
400 DBG_ERROR("ScTableProtectionImpl::setOption: wrong size");
401 return;
404 maOptions[nOptId] = bEnabled;
407 // ============================================================================
409 ScDocProtection::ScDocProtection() :
410 mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
414 ScDocProtection::ScDocProtection(const ScDocProtection& r) :
415 ScPassHashProtectable(),
416 mpImpl(new ScTableProtectionImpl(*r.mpImpl))
420 ScDocProtection::~ScDocProtection()
424 bool ScDocProtection::isProtected() const
426 return mpImpl->isProtected();
429 bool ScDocProtection::isProtectedWithPass() const
431 return mpImpl->isProtectedWithPass();
434 void ScDocProtection::setProtected(bool bProtected)
436 mpImpl->setProtected(bProtected);
438 // Currently Calc doesn't support document protection options. So, let's
439 // assume that when the document is protected, its structure is protected.
440 // We need to do this for Excel export.
441 mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
444 bool ScDocProtection::isPasswordEmpty() const
446 return mpImpl->isPasswordEmpty();
449 bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
451 return mpImpl->hasPasswordHash(eHash, eHash2);
454 void ScDocProtection::setPassword(const String& aPassText)
456 mpImpl->setPassword(aPassText);
459 uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
461 return mpImpl->getPasswordHash(eHash, eHash2);
464 void ScDocProtection::setPasswordHash(
465 const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
467 mpImpl->setPasswordHash(aPassword, eHash, eHash2);
470 bool ScDocProtection::verifyPassword(const String& aPassText) const
472 return mpImpl->verifyPassword(aPassText);
475 bool ScDocProtection::isOptionEnabled(Option eOption) const
477 return mpImpl->isOptionEnabled(eOption);
480 void ScDocProtection::setOption(Option eOption, bool bEnabled)
482 mpImpl->setOption(eOption, bEnabled);
485 // ============================================================================
487 ScTableProtection::ScTableProtection() :
488 mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
490 // Set default values for the options.
491 mpImpl->setOption(SELECT_LOCKED_CELLS, true);
492 mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
495 ScTableProtection::ScTableProtection(const ScTableProtection& r) :
496 ScPassHashProtectable(),
497 mpImpl(new ScTableProtectionImpl(*r.mpImpl))
501 ScTableProtection::~ScTableProtection()
505 bool ScTableProtection::isProtected() const
507 return mpImpl->isProtected();
510 bool ScTableProtection::isProtectedWithPass() const
512 return mpImpl->isProtectedWithPass();
515 void ScTableProtection::setProtected(bool bProtected)
517 mpImpl->setProtected(bProtected);
520 bool ScTableProtection::isPasswordEmpty() const
522 return mpImpl->isPasswordEmpty();
525 bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
527 return mpImpl->hasPasswordHash(eHash, eHash2);
530 void ScTableProtection::setPassword(const String& aPassText)
532 mpImpl->setPassword(aPassText);
535 Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
537 return mpImpl->getPasswordHash(eHash, eHash2);
540 void ScTableProtection::setPasswordHash(
541 const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
543 mpImpl->setPasswordHash(aPassword, eHash, eHash2);
546 bool ScTableProtection::verifyPassword(const String& aPassText) const
548 return mpImpl->verifyPassword(aPassText);
551 bool ScTableProtection::isOptionEnabled(Option eOption) const
553 return mpImpl->isOptionEnabled(eOption);
556 void ScTableProtection::setOption(Option eOption, bool bEnabled)
558 mpImpl->setOption(eOption, bEnabled);