bump product version to 6.3.0.0.beta1
[LibreOffice.git] / oox / source / crypto / CryptTools.cxx
blob96290e0dc5fcb99f8606b4c489b0c9bd32514db0
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/.
9 */
11 #include <oox/crypto/CryptTools.hxx>
12 #include <filter/msfilter/mscodec.hxx>
13 #include <com/sun/star/uno/RuntimeException.hpp>
15 #if USE_TLS_OPENSSL
16 #include <openssl/evp.h>
17 #include <openssl/sha.h>
18 #include <openssl/hmac.h>
19 #endif // USE_TLS_OPENSSL
21 #if USE_TLS_NSS
22 #include <nss.h>
23 #include <pk11pub.h>
24 #include <sechash.h>
25 #endif // USE_TLS_NSS
27 namespace oox {
28 namespace core {
30 #if USE_TLS_OPENSSL
31 struct CryptoImpl
33 std::unique_ptr<EVP_CIPHER_CTX> mpContext;
34 std::unique_ptr<HMAC_CTX> mpHmacContext;
36 CryptoImpl() = default;
38 void setupEncryptContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto::CryptoType eType)
40 mpContext.reset(new EVP_CIPHER_CTX);
41 EVP_CIPHER_CTX_init(mpContext.get());
43 const EVP_CIPHER* cipher = getCipher(eType);
44 if (cipher == nullptr)
45 return;
47 if (iv.empty())
48 EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), 0);
49 else
50 EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), iv.data());
51 EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
54 void setupDecryptContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto::CryptoType eType)
56 mpContext.reset(new EVP_CIPHER_CTX);
57 EVP_CIPHER_CTX_init(mpContext.get());
59 const EVP_CIPHER* pCipher = getCipher(eType);
60 if (pCipher == nullptr)
61 return;
63 const size_t nMinKeySize = EVP_CIPHER_key_length(pCipher);
64 if (key.size() < nMinKeySize)
65 key.resize(nMinKeySize, 0);
67 if (iv.empty())
68 EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), 0);
69 else
71 const size_t nMinIVSize = EVP_CIPHER_iv_length(pCipher);
72 if (iv.size() < nMinIVSize)
73 iv.resize(nMinIVSize, 0);
75 EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), iv.data());
77 EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
80 void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType eType)
82 mpHmacContext.reset(new HMAC_CTX);
83 HMAC_CTX_init(mpHmacContext.get());
84 const EVP_MD* aEvpMd;
85 switch (eType)
87 case CryptoHashType::SHA1:
88 aEvpMd = EVP_sha1(); break;
89 case CryptoHashType::SHA256:
90 aEvpMd = EVP_sha256(); break;
91 case CryptoHashType::SHA512:
92 aEvpMd = EVP_sha512(); break;
94 HMAC_Init(mpHmacContext.get(), rKey.data(), rKey.size(), aEvpMd);
97 ~CryptoImpl()
99 if (mpContext)
100 EVP_CIPHER_CTX_cleanup(mpContext.get());
101 if (mpHmacContext)
102 HMAC_CTX_cleanup(mpHmacContext.get());
105 const EVP_CIPHER* getCipher(Crypto::CryptoType type)
107 switch(type)
109 case Crypto::CryptoType::AES_128_ECB:
110 return EVP_aes_128_ecb();
111 case Crypto::CryptoType::AES_128_CBC:
112 return EVP_aes_128_cbc();
113 case Crypto::CryptoType::AES_256_CBC:
114 return EVP_aes_256_cbc();
115 default:
116 break;
118 return nullptr;
122 #elif USE_TLS_NSS
124 #define MAX_WRAPPED_KEY_LEN 128
126 struct CryptoImpl
128 PK11SlotInfo* mSlot;
129 PK11Context* mContext;
130 SECItem* mSecParam;
131 PK11SymKey* mSymKey;
132 PK11Context* mWrapKeyContext;
133 PK11SymKey* mWrapKey;
135 CryptoImpl()
136 : mSlot(nullptr)
137 , mContext(nullptr)
138 , mSecParam(nullptr)
139 , mSymKey(nullptr)
140 , mWrapKeyContext(nullptr)
141 , mWrapKey(nullptr)
143 // Initialize NSS, database functions are not needed
144 NSS_NoDB_Init(nullptr);
147 ~CryptoImpl()
149 if (mContext)
150 PK11_DestroyContext(mContext, PR_TRUE);
151 if (mSecParam)
152 SECITEM_FreeItem(mSecParam, PR_TRUE);
153 if (mSymKey)
154 PK11_FreeSymKey(mSymKey);
155 if (mWrapKeyContext)
156 PK11_DestroyContext(mWrapKeyContext, PR_TRUE);
157 if (mWrapKey)
158 PK11_FreeSymKey(mWrapKey);
159 if (mSlot)
160 PK11_FreeSlot(mSlot);
163 PK11SymKey* ImportSymKey(CK_MECHANISM_TYPE mechanism, CK_ATTRIBUTE_TYPE operation, SECItem* key)
165 mSymKey = PK11_ImportSymKey(mSlot, mechanism, PK11_OriginUnwrap, operation, key, nullptr);
166 if (!mSymKey) //rhbz#1614419 maybe failed due to FIPS, use rhbz#1461450 style workaround
169 * Without FIPS it would be possible to just use
170 * mSymKey = PK11_ImportSymKey( mSlot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr );
171 * with FIPS NSS Level 2 certification has to be "workarounded" (so it becomes Level 1) by using
172 * following method:
173 * 1. Generate wrap key
174 * 2. Encrypt authkey with wrap key
175 * 3. Unwrap encrypted authkey using wrap key
179 * Generate wrapping key
181 CK_MECHANISM_TYPE wrap_mechanism = PK11_GetBestWrapMechanism(mSlot);
182 int wrap_key_len = PK11_GetBestKeyLength(mSlot, wrap_mechanism);
183 mWrapKey = PK11_KeyGen(mSlot, wrap_mechanism, nullptr, wrap_key_len, nullptr);
184 if (!mWrapKey)
185 throw css::uno::RuntimeException("PK11_KeyGen SymKey failure", css::uno::Reference<css::uno::XInterface>());
188 * Encrypt authkey with wrapping key
192 * Initialization of IV is not needed because PK11_GetBestWrapMechanism should return ECB mode
194 SECItem tmp_sec_item;
195 memset(&tmp_sec_item, 0, sizeof(tmp_sec_item));
196 mWrapKeyContext = PK11_CreateContextBySymKey(wrap_mechanism, CKA_ENCRYPT, mWrapKey, &tmp_sec_item);
197 if (!mWrapKeyContext)
198 throw css::uno::RuntimeException("PK11_CreateContextBySymKey failure", css::uno::Reference<css::uno::XInterface>());
200 unsigned char wrapped_key_data[MAX_WRAPPED_KEY_LEN];
201 int wrapped_key_len = sizeof(wrapped_key_data);
203 if (PK11_CipherOp(mWrapKeyContext, wrapped_key_data, &wrapped_key_len,
204 sizeof(wrapped_key_data), key->data, key->len) != SECSuccess)
206 throw css::uno::RuntimeException("PK11_CipherOp failure", css::uno::Reference<css::uno::XInterface>());
209 if (PK11_Finalize(mWrapKeyContext) != SECSuccess)
210 throw css::uno::RuntimeException("PK11_Finalize failure", css::uno::Reference<css::uno::XInterface>());
213 * Finally unwrap sym key
215 SECItem wrapped_key;
216 memset(&tmp_sec_item, 0, sizeof(tmp_sec_item));
217 wrapped_key.data = wrapped_key_data;
218 wrapped_key.len = wrapped_key_len;
220 mSymKey = PK11_UnwrapSymKey(mWrapKey, wrap_mechanism, &tmp_sec_item, &wrapped_key,
221 mechanism, operation, key->len);
223 return mSymKey;
226 void setupCryptoContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto::CryptoType type, CK_ATTRIBUTE_TYPE operation)
228 CK_MECHANISM_TYPE mechanism = static_cast<CK_ULONG>(-1);
230 SECItem ivItem;
231 ivItem.type = siBuffer;
232 if(iv.empty())
233 ivItem.data = nullptr;
234 else
235 ivItem.data = iv.data();
236 ivItem.len = iv.size();
238 SECItem* pIvItem = nullptr;
240 switch(type)
242 case Crypto::CryptoType::AES_128_ECB:
243 mechanism = CKM_AES_ECB;
244 break;
245 case Crypto::CryptoType::AES_128_CBC:
246 mechanism = CKM_AES_CBC;
247 pIvItem = &ivItem;
248 break;
249 case Crypto::CryptoType::AES_256_CBC:
250 mechanism = CKM_AES_CBC;
251 pIvItem = &ivItem;
252 break;
253 default:
254 break;
257 mSlot = PK11_GetBestSlot(mechanism, nullptr);
259 if (!mSlot)
260 throw css::uno::RuntimeException("NSS Slot failure", css::uno::Reference<css::uno::XInterface>());
262 SECItem keyItem;
263 keyItem.type = siBuffer;
264 keyItem.data = key.data();
265 keyItem.len = key.size();
267 mSymKey = ImportSymKey(mechanism, CKA_ENCRYPT, &keyItem);
268 if (!mSymKey)
269 throw css::uno::RuntimeException("NSS SymKey failure", css::uno::Reference<css::uno::XInterface>());
271 mSecParam = PK11_ParamFromIV(mechanism, pIvItem);
272 mContext = PK11_CreateContextBySymKey(mechanism, operation, mSymKey, mSecParam);
275 void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType eType)
277 CK_MECHANISM_TYPE aMechanism = static_cast<CK_ULONG>(-1);
279 switch(eType)
281 case CryptoHashType::SHA1:
282 aMechanism = CKM_SHA_1_HMAC;
283 break;
284 case CryptoHashType::SHA256:
285 aMechanism = CKM_SHA256_HMAC;
286 break;
287 case CryptoHashType::SHA512:
288 aMechanism = CKM_SHA512_HMAC;
289 break;
292 mSlot = PK11_GetBestSlot(aMechanism, nullptr);
294 if (!mSlot)
295 throw css::uno::RuntimeException("NSS Slot failure", css::uno::Reference<css::uno::XInterface>());
297 SECItem aKeyItem;
298 aKeyItem.data = rKey.data();
299 aKeyItem.len = rKey.size();
301 mSymKey = ImportSymKey(aMechanism, CKA_SIGN, &aKeyItem);
302 if (!mSymKey)
303 throw css::uno::RuntimeException("NSS SymKey failure", css::uno::Reference<css::uno::XInterface>());
305 SECItem param;
306 param.data = nullptr;
307 param.len = 0;
308 mContext = PK11_CreateContextBySymKey(aMechanism, CKA_SIGN, mSymKey, &param);
311 #else
312 struct CryptoImpl
314 #endif
316 Crypto::Crypto()
317 : mpImpl(std::make_unique<CryptoImpl>())
321 Crypto::~Crypto()
325 // DECRYPT
327 Decrypt::Decrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, CryptoType type)
328 : Crypto()
330 #if USE_TLS_OPENSSL + USE_TLS_NSS == 0
331 (void)key;
332 (void)iv;
333 (void)type;
334 #endif
336 #if USE_TLS_OPENSSL
337 mpImpl->setupDecryptContext(key, iv, type);
338 #endif
340 #if USE_TLS_NSS
341 mpImpl->setupCryptoContext(key, iv, type, CKA_DECRYPT);
342 #endif // USE_TLS_NSS
345 sal_uInt32 Decrypt::update(std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input, sal_uInt32 inputLength)
347 int outputLength = 0;
349 #if USE_TLS_OPENSSL + USE_TLS_NSS > 0
350 sal_uInt32 actualInputLength = inputLength == 0 || inputLength > input.size() ? input.size() : inputLength;
351 #else
352 (void)output;
353 (void)input;
354 (void)inputLength;
355 #endif
357 #if USE_TLS_OPENSSL
358 (void)EVP_DecryptUpdate(mpImpl->mpContext.get(), output.data(), &outputLength, input.data(), actualInputLength);
359 #endif // USE_TLS_OPENSSL
361 #if USE_TLS_NSS
362 if (!mpImpl->mContext)
363 return 0;
364 (void)PK11_CipherOp(mpImpl->mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength);
365 #endif // USE_TLS_NSS
367 return static_cast<sal_uInt32>(outputLength);
370 sal_uInt32 Decrypt::aes128ecb(std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input, std::vector<sal_uInt8>& key)
372 sal_uInt32 outputLength = 0;
373 std::vector<sal_uInt8> iv;
374 Decrypt crypto(key, iv, Crypto::AES_128_ECB);
375 outputLength = crypto.update(output, input);
376 return outputLength;
379 // ENCRYPT
381 Encrypt::Encrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, CryptoType type)
382 : Crypto()
384 #if USE_TLS_OPENSSL + USE_TLS_NSS == 0
385 (void)key;
386 (void)iv;
387 (void)type;
388 #endif
390 #if USE_TLS_OPENSSL
391 mpImpl->setupEncryptContext(key, iv, type);
392 #elif USE_TLS_NSS
393 mpImpl->setupCryptoContext(key, iv, type, CKA_ENCRYPT);
394 #endif // USE_TLS_NSS
397 sal_uInt32 Encrypt::update(std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input, sal_uInt32 inputLength)
399 int outputLength = 0;
401 #if USE_TLS_OPENSSL + USE_TLS_NSS > 0
402 sal_uInt32 actualInputLength = inputLength == 0 || inputLength > input.size() ? input.size() : inputLength;
403 #else
404 (void)output;
405 (void)input;
406 (void)inputLength;
407 #endif
409 #if USE_TLS_OPENSSL
410 (void)EVP_EncryptUpdate(mpImpl->mpContext.get(), output.data(), &outputLength, input.data(), actualInputLength);
411 #endif // USE_TLS_OPENSSL
413 #if USE_TLS_NSS
414 (void)PK11_CipherOp(mpImpl->mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength);
415 #endif // USE_TLS_NSS
417 return static_cast<sal_uInt32>(outputLength);
420 // CryptoHash - HMAC
422 namespace
425 sal_Int32 getSizeForHashType(CryptoHashType eType)
427 switch (eType)
429 case CryptoHashType::SHA1: return 20;
430 case CryptoHashType::SHA256: return 32;
431 case CryptoHashType::SHA512: return 64;
433 return 0;
436 } // end anonymous namespace
438 CryptoHash::CryptoHash(std::vector<sal_uInt8>& rKey, CryptoHashType eType)
439 : Crypto()
440 , mnHashSize(getSizeForHashType(eType))
442 #if USE_TLS_OPENSSL
443 mpImpl->setupCryptoHashContext(rKey, eType);
444 #elif USE_TLS_NSS
445 mpImpl->setupCryptoHashContext(rKey, eType);
446 PK11_DigestBegin(mpImpl->mContext);
447 #else
448 (void)rKey;
449 #endif
452 bool CryptoHash::update(std::vector<sal_uInt8>& rInput, sal_uInt32 nInputLength)
454 #if USE_TLS_OPENSSL + USE_TLS_NSS > 0
455 sal_uInt32 nActualInputLength = (nInputLength == 0 || nInputLength > rInput.size()) ? rInput.size() : nInputLength;
456 #else
457 (void)rInput;
458 (void)nInputLength;
459 #endif
461 #if USE_TLS_OPENSSL
462 return HMAC_Update(mpImpl->mpHmacContext.get(), rInput.data(), nActualInputLength) != 0;
463 #elif USE_TLS_NSS
464 return PK11_DigestOp(mpImpl->mContext, rInput.data(), nActualInputLength) == SECSuccess;
465 #else
466 return false; // ???
467 #endif
470 std::vector<sal_uInt8> CryptoHash::finalize()
472 std::vector<sal_uInt8> aHash(mnHashSize, 0);
473 unsigned int nSizeWritten;
474 #if USE_TLS_OPENSSL
475 (void) HMAC_Final(mpImpl->mpHmacContext.get(), aHash.data(), &nSizeWritten);
476 #elif USE_TLS_NSS
477 PK11_DigestFinal(mpImpl->mContext, aHash.data(), &nSizeWritten, aHash.size());
478 #endif
479 (void)nSizeWritten;
481 return aHash;
484 } // namespace core
485 } // namespace oox
487 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */