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/Reference.hxx>
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 
27 namespace comphelper {
28 
29 struct HashImpl
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;
43  case HashType::SHA256:
44  return HASH_AlgSHA256;
45  case HashType::SHA512:
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();
62  case HashType::SHA256:
63  return EVP_sha256();
64  case HashType::SHA512:
65  return EVP_sha512();
66  }
67 
68  return nullptr;
69  }
70 #endif
71 
73 
75  meType(eType)
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(), NULL);
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 
110 void 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 
122 std::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 
137 size_t Hash::getLength() const
138 {
139  switch (mpImpl->meType)
140  {
141  case HashType::MD5:
142  return 16;
143  case HashType::SHA1:
144  return 20;
145  case HashType::SHA256:
146  return 32;
147  case HashType::SHA512:
148  return 64;
149  }
150 
151  return 0;
152 }
153 
154 std::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 
161 std::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 
226 std::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::unique_ptr< HashImpl > mpImpl
Definition: hash.hxx:37
ParserContextSharedPtr mpContext
Hash(HashType eType)
Definition: hash.cxx:101
return NULL
Iteration count prepended to hash iterations.
HashImpl(HashType eType)
Definition: hash.cxx:74
int i
Iteration count not added to hash iterations.
HashType const meType
Definition: hash.cxx:72
exports com.sun.star.chart2. data
unsigned char sal_uInt8
void update(const unsigned char *pInput, size_t length)
Definition: hash.cxx:110
void * p
static std::vector< unsigned char > calculateHash(const unsigned char *pInput, size_t length, HashType eType)
Definition: hash.cxx:154
size_t getLength() const
Definition: hash.cxx:137
std::vector< unsigned char > finalize()
Definition: hash.cxx:122
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo