docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / comphelper / source / misc / hash.cxx
blob96e125cac23d1f7545764a71117b6c54be0442bf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <com/sun/star/uno/RuntimeException.hpp>
13 #include <comphelper/hash.hxx>
14 #include <rtl/ustring.hxx>
15 #include <rtl/alloc.h>
16 #include <osl/endian.h>
17 #include <config_oox.h>
18 #include <sstream>
19 #include <iomanip>
21 #if USE_TLS_NSS
22 #include <nss.h>
23 #include <nspr.h>
24 #include <sechash.h>
25 #elif USE_TLS_OPENSSL
26 #include <openssl/evp.h>
27 #include <openssl/sha.h>
28 #endif // USE_TLS_OPENSSL
30 namespace comphelper {
32 std::string hashToString(const std::vector<unsigned char>& rHash)
34 std::stringstream aStringStream;
35 for (auto& i: rHash)
37 aStringStream << std::setw(2) << std::setfill('0') << std::hex << int(i);
40 return aStringStream.str();
43 struct HashImpl
46 #if USE_TLS_NSS
47 HASHContext* mpContext;
49 HASH_HashType getNSSType() const
51 switch (meType)
53 case HashType::MD5:
54 return HASH_AlgMD5;
55 case HashType::SHA1:
56 return HASH_AlgSHA1;
57 case HashType::SHA256:
58 return HASH_AlgSHA256;
59 case HashType::SHA384:
60 return HASH_AlgSHA384;
61 case HashType::SHA512:
62 return HASH_AlgSHA512;
65 return HASH_AlgNULL;
67 #elif USE_TLS_OPENSSL
68 EVP_MD_CTX* mpContext;
70 const EVP_MD* getOpenSSLType() const
72 switch (meType)
74 case HashType::MD5:
75 return EVP_md5();
76 case HashType::SHA1:
77 return EVP_sha1();
78 case HashType::SHA256:
79 return EVP_sha256();
80 case HashType::SHA384:
81 return EVP_sha384();
82 case HashType::SHA512:
83 return EVP_sha512();
86 return nullptr;
88 #endif
90 HashType const meType;
92 HashImpl(HashType eType):
93 meType(eType)
96 #if USE_TLS_NSS
97 if (!NSS_IsInitialized())
99 auto const e = NSS_NoDB_Init(nullptr);
100 if (e != SECSuccess)
102 PRErrorCode error = PR_GetError();
103 const char* errorText = PR_ErrorToName(error);
104 throw css::uno::RuntimeException("NSS_NoDB_Init failed with " + OUString(errorText, strlen(errorText), RTL_TEXTENCODING_UTF8) + " (" + OUString::number(static_cast<int>(error)) + ")");
107 mpContext = HASH_Create(getNSSType());
108 HASH_Begin(mpContext);
109 #elif USE_TLS_OPENSSL
110 mpContext = EVP_MD_CTX_create();
111 EVP_DigestInit_ex(mpContext, getOpenSSLType(), nullptr);
112 #endif
115 ~HashImpl()
117 #if USE_TLS_NSS
118 HASH_Destroy(mpContext);
119 #elif USE_TLS_OPENSSL
120 EVP_MD_CTX_destroy(mpContext);
121 #endif
125 Hash::Hash(HashType eType):
126 mpImpl(new HashImpl(eType))
130 Hash::~Hash()
134 void Hash::update(const unsigned char* pInput, size_t length)
136 #if USE_TLS_NSS
137 HASH_Update(mpImpl->mpContext, pInput, length);
138 #elif USE_TLS_OPENSSL
139 EVP_DigestUpdate(mpImpl->mpContext, pInput, length);
140 #else
141 (void)pInput;
142 (void)length;
143 #endif
146 std::vector<unsigned char> Hash::finalize()
148 std::vector<unsigned char> hash(getLength(), 0);
149 unsigned int digestWrittenLength;
150 #if USE_TLS_NSS
151 HASH_End(mpImpl->mpContext, hash.data(), &digestWrittenLength, getLength());
152 #elif USE_TLS_OPENSSL
153 EVP_DigestFinal_ex(mpImpl->mpContext, hash.data(), &digestWrittenLength);
154 #else
155 (void)digestWrittenLength;
156 #endif
158 return hash;
161 size_t Hash::getLength() const
163 switch (mpImpl->meType)
165 case HashType::MD5:
166 return MD5_HASH_LENGTH;
167 case HashType::SHA1:
168 return SHA1_HASH_LENGTH;
169 case HashType::SHA256:
170 return SHA256_HASH_LENGTH;
171 case HashType::SHA384:
172 return SHA384_HASH_LENGTH;
173 case HashType::SHA512:
174 return SHA512_HASH_LENGTH;
177 return 0;
180 std::vector<unsigned char> Hash::calculateHash(const unsigned char* pInput, size_t length, HashType eType)
182 Hash aHash(eType);
183 aHash.update(pInput, length);
184 return aHash.finalize();
187 std::vector<unsigned char> Hash::calculateHash(
188 const unsigned char* pInput, size_t nLength,
189 const unsigned char* pSalt, size_t nSaltLen,
190 sal_uInt32 nSpinCount,
191 IterCount eIterCount,
192 HashType eType)
194 if (!pSalt)
195 nSaltLen = 0;
197 if (!nSaltLen && !nSpinCount)
198 return calculateHash( pInput, nLength, eType);
200 Hash aHash(eType);
201 if (nSaltLen)
203 std::vector<unsigned char> initialData( nSaltLen + nLength);
204 std::copy( pSalt, pSalt + nSaltLen, initialData.begin());
205 std::copy( pInput, pInput + nLength, initialData.begin() + nSaltLen);
206 aHash.update( initialData.data(), initialData.size());
207 rtl_secureZeroMemory( initialData.data(), initialData.size());
209 else
211 aHash.update( pInput, nLength);
213 std::vector<unsigned char> hash( aHash.finalize());
215 if (nSpinCount)
217 // https://msdn.microsoft.com/en-us/library/dd920692
218 // says the iteration is concatenated after the hash.
219 // https://msdn.microsoft.com/en-us/library/dd924776 and
220 // https://msdn.microsoft.com/en-us/library/dd925430
221 // say the iteration is prepended to the hash.
222 const size_t nAddIter = (eIterCount == IterCount::NONE ? 0 : 4);
223 const size_t nIterPos = (eIterCount == IterCount::APPEND ? hash.size() : 0);
224 const size_t nHashPos = (eIterCount == IterCount::PREPEND ? nAddIter : 0);
225 std::vector<unsigned char> data( hash.size() + nAddIter, 0);
226 for (sal_uInt32 i = 0; i < nSpinCount; ++i)
228 std::copy( hash.begin(), hash.end(), data.begin() + nHashPos);
229 if (nAddIter)
231 #ifdef OSL_BIGENDIAN
232 sal_uInt32 be = i;
233 sal_uInt8* p = reinterpret_cast<sal_uInt8*>(&be);
234 std::swap( p[0], p[3] );
235 std::swap( p[1], p[2] );
236 memcpy( data.data() + nIterPos, &be, nAddIter);
237 #else
238 memcpy( data.data() + nIterPos, &i, nAddIter);
239 #endif
241 /* TODO: isn't there something better than
242 * creating/finalizing/destroying on each iteration? */
243 Hash aReHash(eType);
244 aReHash.update( data.data(), data.size());
245 hash = aReHash.finalize();
249 return hash;
252 std::vector<unsigned char> Hash::calculateHash(
253 const OUString& rPassword,
254 const std::vector<unsigned char>& rSaltValue,
255 sal_uInt32 nSpinCount,
256 IterCount eIterCount,
257 HashType eType)
259 const unsigned char* pPassBytes = reinterpret_cast<const unsigned char*>(rPassword.getStr());
260 const size_t nPassBytesLen = rPassword.getLength() * 2;
261 #ifdef OSL_BIGENDIAN
262 // Swap UTF16-BE to UTF16-LE
263 std::vector<unsigned char> vPass;
264 if (nPassBytesLen)
266 vPass.resize( nPassBytesLen);
267 std::copy( pPassBytes, pPassBytes + nPassBytesLen, vPass.begin());
268 unsigned char* p = vPass.data();
269 unsigned char const * const pEnd = p + nPassBytesLen;
270 for ( ; p < pEnd; p += 2 )
272 std::swap( p[0], p[1] );
274 pPassBytes = vPass.data();
276 #endif
277 return calculateHash( pPassBytes, nPassBytesLen, rSaltValue.data(), rSaltValue.size(), nSpinCount,
278 eIterCount, eType);
283 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */