LibreOffice Module comphelper (master) 1
hash.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#include <sal/config.h>
11
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
19#if USE_TLS_NSS
20#include <nss.h>
21#include <nspr.h>
22#include <sechash.h>
23#elif USE_TLS_OPENSSL
24#include <openssl/evp.h>
25#include <openssl/sha.h>
26#endif // USE_TLS_OPENSSL
27
28namespace comphelper {
29
31{
32
33#if USE_TLS_NSS
34 HASHContext* mpContext;
35
36 HASH_HashType getNSSType() const
37 {
38 switch (meType)
39 {
40 case HashType::MD5:
41 return HASH_AlgMD5;
42 case HashType::SHA1:
43 return HASH_AlgSHA1;
45 return HASH_AlgSHA256;
47 return HASH_AlgSHA512;
48 }
49
50 return HASH_AlgNULL;
51 }
52#elif USE_TLS_OPENSSL
53 EVP_MD_CTX* mpContext;
54
55 const EVP_MD* getOpenSSLType() const
56 {
57 switch (meType)
58 {
59 case HashType::MD5:
60 return EVP_md5();
61 case HashType::SHA1:
62 return EVP_sha1();
64 return EVP_sha256();
66 return EVP_sha512();
67 }
68
69 return nullptr;
70 }
71#endif
72
74
77 {
78
79#if USE_TLS_NSS
80 if (!NSS_IsInitialized())
81 {
82 auto const e = NSS_NoDB_Init(nullptr);
83 if (e != SECSuccess)
84 {
85 PRErrorCode error = PR_GetError();
86 const char* errorText = PR_ErrorToName(error);
87 throw css::uno::RuntimeException("NSS_NoDB_Init failed with " + OUString(errorText, strlen(errorText), RTL_TEXTENCODING_UTF8) + " (" + OUString::number(static_cast<int>(error)) + ")");
88 }
89 }
90 mpContext = HASH_Create(getNSSType());
91 HASH_Begin(mpContext);
92#elif USE_TLS_OPENSSL
93 mpContext = EVP_MD_CTX_create();
94 EVP_DigestInit_ex(mpContext, getOpenSSLType(), nullptr);
95#endif
96 }
97
99 {
100#if USE_TLS_NSS
101 HASH_Destroy(mpContext);
102#elif USE_TLS_OPENSSL
103 EVP_MD_CTX_destroy(mpContext);
104#endif
105 }
106};
107
109 mpImpl(new HashImpl(eType))
110{
111}
112
114{
115}
116
117void Hash::update(const unsigned char* pInput, size_t length)
118{
119#if USE_TLS_NSS
120 HASH_Update(mpImpl->mpContext, pInput, length);
121#elif USE_TLS_OPENSSL
122 EVP_DigestUpdate(mpImpl->mpContext, pInput, length);
123#else
124 (void)pInput;
125 (void)length;
126#endif
127}
128
129std::vector<unsigned char> Hash::finalize()
130{
131 std::vector<unsigned char> hash(getLength(), 0);
132 unsigned int digestWrittenLength;
133#if USE_TLS_NSS
134 HASH_End(mpImpl->mpContext, hash.data(), &digestWrittenLength, getLength());
135#elif USE_TLS_OPENSSL
136 EVP_DigestFinal_ex(mpImpl->mpContext, hash.data(), &digestWrittenLength);
137#else
138 (void)digestWrittenLength;
139#endif
140
141 return hash;
142}
143
144size_t Hash::getLength() const
145{
146 switch (mpImpl->meType)
147 {
148 case HashType::MD5:
149 return MD5_HASH_LENGTH;
150 case HashType::SHA1:
151 return SHA1_HASH_LENGTH;
152 case HashType::SHA256:
153 return SHA256_HASH_LENGTH;
154 case HashType::SHA512:
155 return SHA512_HASH_LENGTH;
156 }
157
158 return 0;
159}
160
161std::vector<unsigned char> Hash::calculateHash(const unsigned char* pInput, size_t length, HashType eType)
162{
163 Hash aHash(eType);
164 aHash.update(pInput, length);
165 return aHash.finalize();
166}
167
168std::vector<unsigned char> Hash::calculateHash(
169 const unsigned char* pInput, size_t nLength,
170 const unsigned char* pSalt, size_t nSaltLen,
171 sal_uInt32 nSpinCount,
172 IterCount eIterCount,
173 HashType eType)
174{
175 if (!pSalt)
176 nSaltLen = 0;
177
178 if (!nSaltLen && !nSpinCount)
179 return calculateHash( pInput, nLength, eType);
180
181 Hash aHash(eType);
182 if (nSaltLen)
183 {
184 std::vector<unsigned char> initialData( nSaltLen + nLength);
185 std::copy( pSalt, pSalt + nSaltLen, initialData.begin());
186 std::copy( pInput, pInput + nLength, initialData.begin() + nSaltLen);
187 aHash.update( initialData.data(), initialData.size());
188 rtl_secureZeroMemory( initialData.data(), initialData.size());
189 }
190 else
191 {
192 aHash.update( pInput, nLength);
193 }
194 std::vector<unsigned char> hash( aHash.finalize());
195
196 if (nSpinCount)
197 {
198 // https://msdn.microsoft.com/en-us/library/dd920692
199 // says the iteration is concatenated after the hash.
200 // https://msdn.microsoft.com/en-us/library/dd924776 and
201 // https://msdn.microsoft.com/en-us/library/dd925430
202 // say the iteration is prepended to the hash.
203 const size_t nAddIter = (eIterCount == IterCount::NONE ? 0 : 4);
204 const size_t nIterPos = (eIterCount == IterCount::APPEND ? hash.size() : 0);
205 const size_t nHashPos = (eIterCount == IterCount::PREPEND ? nAddIter : 0);
206 std::vector<unsigned char> data( hash.size() + nAddIter, 0);
207 for (sal_uInt32 i = 0; i < nSpinCount; ++i)
208 {
209 std::copy( hash.begin(), hash.end(), data.begin() + nHashPos);
210 if (nAddIter)
211 {
212#ifdef OSL_BIGENDIAN
213 sal_uInt32 be = i;
214 sal_uInt8* p = reinterpret_cast<sal_uInt8*>(&be);
215 std::swap( p[0], p[3] );
216 std::swap( p[1], p[2] );
217 memcpy( data.data() + nIterPos, &be, nAddIter);
218#else
219 memcpy( data.data() + nIterPos, &i, nAddIter);
220#endif
221 }
222 /* TODO: isn't there something better than
223 * creating/finalizing/destroying on each iteration? */
224 Hash aReHash(eType);
225 aReHash.update( data.data(), data.size());
226 hash = aReHash.finalize();
227 }
228 }
229
230 return hash;
231}
232
233std::vector<unsigned char> Hash::calculateHash(
234 const OUString& rPassword,
235 const std::vector<unsigned char>& rSaltValue,
236 sal_uInt32 nSpinCount,
237 IterCount eIterCount,
238 HashType eType)
239{
240 const unsigned char* pPassBytes = reinterpret_cast<const unsigned char*>(rPassword.getStr());
241 const size_t nPassBytesLen = rPassword.getLength() * 2;
242#ifdef OSL_BIGENDIAN
243 // Swap UTF16-BE to UTF16-LE
244 std::vector<unsigned char> vPass;
245 if (nPassBytesLen)
246 {
247 vPass.resize( nPassBytesLen);
248 std::copy( pPassBytes, pPassBytes + nPassBytesLen, vPass.begin());
249 unsigned char* p = vPass.data();
250 unsigned char const * const pEnd = p + nPassBytesLen;
251 for ( ; p < pEnd; p += 2 )
252 {
253 std::swap( p[0], p[1] );
254 }
255 pPassBytes = vPass.data();
256 }
257#endif
258 return calculateHash( pPassBytes, nPassBytesLen, rSaltValue.data(), rSaltValue.size(), nSpinCount,
259 eIterCount, eType);
260}
261
262}
263
264/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::vector< unsigned char > finalize()
Definition: hash.cxx:129
std::unique_ptr< HashImpl > mpImpl
Definition: hash.hxx:43
static std::vector< unsigned char > calculateHash(const unsigned char *pInput, size_t length, HashType eType)
Definition: hash.cxx:161
void update(const unsigned char *pInput, size_t length)
Definition: hash.cxx:117
size_t getLength() const
Definition: hash.cxx:144
@ APPEND
Iteration count prepended to hash iterations.
@ PREPEND
Iteration count not added to hash iterations.
Hash(HashType eType)
Definition: hash.cxx:108
DocumentType eType
void * p
const sal_uInt32 SHA256_HASH_LENGTH
Definition: hash.hxx:35
const sal_uInt32 SHA512_HASH_LENGTH
Definition: hash.hxx:36
const sal_uInt32 SHA1_HASH_LENGTH
Definition: hash.hxx:34
const sal_uInt32 MD5_HASH_LENGTH
Definition: hash.hxx:33
int i
ParserContextSharedPtr mpContext
HashType const meType
Definition: hash.cxx:73
HashImpl(HashType eType)
Definition: hash.cxx:75
unsigned char sal_uInt8
sal_Int32 nLength