/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ #include "oox/crypto/CryptTools.hxx" #include #include namespace oox { namespace core { Crypto::Crypto() #if USE_TLS_NSS : mContext(nullptr) , mSecParam(nullptr) , mSymKey(nullptr) #endif { #if USE_TLS_NSS // Initialize NSS, database functions are not needed NSS_NoDB_Init(nullptr); #endif // USE_TLS_NSS } Crypto::~Crypto() { #if USE_TLS_OPENSSL EVP_CIPHER_CTX_cleanup( &mContext ); #endif #if USE_TLS_NSS PK11_DestroyContext( mContext, PR_TRUE ); PK11_FreeSymKey( mSymKey ); SECITEM_FreeItem( mSecParam, PR_TRUE ); #endif } #if USE_TLS_OPENSSL const EVP_CIPHER* Crypto::getCipher(CryptoType type) { switch(type) { case AES_128_ECB: return EVP_aes_128_ecb(); case AES_128_CBC: return EVP_aes_128_cbc(); case AES_256_CBC: return EVP_aes_256_cbc(); default: break; } return NULL; } #endif #if USE_TLS_NSS void Crypto::setupContext(std::vector& key, std::vector& iv, CryptoType type, CK_ATTRIBUTE_TYPE operation) { CK_MECHANISM_TYPE mechanism = static_cast(-1); SECItem ivItem; ivItem.type = siBuffer; if(iv.empty()) ivItem.data = nullptr; else ivItem.data = iv.data(); ivItem.len = iv.size(); SECItem* pIvItem = nullptr; switch(type) { case AES_128_ECB: mechanism = CKM_AES_ECB; break; case AES_128_CBC: mechanism = CKM_AES_CBC; pIvItem = &ivItem; break; case AES_256_CBC: mechanism = CKM_AES_CBC; pIvItem = &ivItem; break; default: break; } PK11SlotInfo* pSlot(PK11_GetBestSlot(mechanism, nullptr)); if (!pSlot) throw css::uno::RuntimeException("NSS Slot failure", css::uno::Reference()); SECItem keyItem; keyItem.type = siBuffer; keyItem.data = key.data(); keyItem.len = key.size(); mSymKey = PK11_ImportSymKey(pSlot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr); mSecParam = PK11_ParamFromIV(mechanism, pIvItem); mContext = PK11_CreateContextBySymKey(mechanism, operation, mSymKey, mSecParam); } #endif // USE_TLS_NSS // DECRYPT Decrypt::Decrypt(std::vector& key, std::vector& iv, CryptoType type) : Crypto() { #if USE_TLS_OPENSSL EVP_CIPHER_CTX_init(&mContext); const EVP_CIPHER* cipher = getCipher(type); if (iv.empty()) EVP_DecryptInit_ex(&mContext, cipher, nullptr, key.data(), 0); else EVP_DecryptInit_ex(&mContext, cipher, nullptr, key.data(), iv.data()); EVP_CIPHER_CTX_set_padding(&mContext, 0); #endif #if USE_TLS_NSS setupContext(key, iv, type, CKA_DECRYPT); #endif // USE_TLS_NSS } sal_uInt32 Decrypt::update(std::vector& output, std::vector& input, sal_uInt32 inputLength) { int outputLength = 0; sal_uInt32 actualInputLength = inputLength == 0 || inputLength > input.size() ? input.size() : inputLength; #if USE_TLS_OPENSSL (void)EVP_DecryptUpdate(&mContext, output.data(), &outputLength, input.data(), actualInputLength); #endif // USE_TLS_OPENSSL #if USE_TLS_NSS (void)PK11_CipherOp( mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength ); #endif // USE_TLS_NSS return static_cast(outputLength); } sal_uInt32 Decrypt::aes128ecb(std::vector& output, std::vector& input, std::vector& key) { sal_uInt32 outputLength = 0; std::vector iv; Decrypt crypto(key, iv, Crypto::AES_128_ECB); outputLength = crypto.update(output, input); return outputLength; } // ENCRYPT Encrypt::Encrypt(std::vector& key, std::vector& iv, CryptoType type) : Crypto() { #if USE_TLS_OPENSSL EVP_CIPHER_CTX_init(&mContext); const EVP_CIPHER* cipher = getCipher(type); if (iv.empty()) EVP_EncryptInit_ex(&mContext, cipher, nullptr, key.data(), 0); else EVP_EncryptInit_ex(&mContext, cipher, nullptr, key.data(), iv.data()); EVP_CIPHER_CTX_set_padding(&mContext, 0); #endif #if USE_TLS_NSS setupContext(key, iv, type, CKA_ENCRYPT); #endif // USE_TLS_NSS } sal_uInt32 Encrypt::update(std::vector& output, std::vector& input, sal_uInt32 inputLength) { int outputLength = 0; sal_uInt32 actualInputLength = inputLength == 0 || inputLength > input.size() ? input.size() : inputLength; #if USE_TLS_OPENSSL (void)EVP_EncryptUpdate(&mContext, output.data(), &outputLength, input.data(), actualInputLength); #endif // USE_TLS_OPENSSL #if USE_TLS_NSS (void)PK11_CipherOp(mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength); #endif // USE_TLS_NSS return static_cast(outputLength); } // Digest namespace { #if USE_TLS_OPENSSL const EVP_MD* lclOpenSSLgetEngine(Digest::DigestType eType) { switch(eType) { case Digest::SHA1: return EVP_sha1(); case Digest::SHA512: return EVP_sha512(); default: break; } return NULL; } #endif #if USE_TLS_NSS HASH_HashType lclNSSgetHashType(Digest::DigestType eType) { switch(eType) { case Digest::SHA1: return HASH_AlgSHA1; case Digest::SHA512: return HASH_AlgSHA512; default: break; } return HASH_AlgNULL; } #endif } Digest::Digest(DigestType eType) : meType(eType) { #if USE_TLS_OPENSSL mpContext = EVP_MD_CTX_create(); EVP_DigestInit_ex(mpContext, lclOpenSSLgetEngine(eType), NULL); #endif #if USE_TLS_NSS NSS_NoDB_Init(nullptr); mpContext = HASH_Create(lclNSSgetHashType(eType)); HASH_Begin(mpContext); #endif } Digest::~Digest() { #if USE_TLS_OPENSSL if(mpContext) EVP_MD_CTX_destroy(mpContext); #endif #if USE_TLS_NSS if(mpContext) HASH_Destroy(mpContext); #endif } sal_uInt32 Digest::getLength() { switch(meType) { case SHA1: return msfilter::SHA1_HASH_LENGTH; case SHA512: return msfilter::SHA512_HASH_LENGTH; default: break; } return 0; } void Digest::update(std::vector& input) { #if USE_TLS_OPENSSL EVP_DigestUpdate(mpContext, input.data(), input.size()); #endif #if USE_TLS_NSS HASH_Update(mpContext, input.data(), input.size()); #endif } void Digest::finalize(std::vector& digest) { digest.clear(); #if USE_TLS_OPENSSL unsigned int digestWrittenLength; digest.resize(getLength(), 0); EVP_DigestFinal_ex(mpContext, digest.data(), &digestWrittenLength); #endif #if USE_TLS_NSS unsigned int digestWrittenLength; unsigned int digestLength = static_cast(getLength()); digest.resize(digestLength, 0); HASH_End(mpContext, digest.data(), &digestWrittenLength, digestLength); #endif } bool Digest::sha1(std::vector& output, std::vector& input) { bool aResult = false; Digest aDigest(SHA1); aDigest.update(input); aDigest.finalize(output); aResult = true; return aResult; } bool Digest::sha512(std::vector& output, std::vector& input) { bool aResult = false; Digest aDigest(SHA512); aDigest.update(input); aDigest.finalize(output); aResult = true; return aResult; } } // namespace core } // namespace oox /* vim:set shiftwidth=4 softtabstop=4 expandtab: */