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