Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/crypto/Crypto_OpenSSL.cxx
Line
Count
Source
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 <comphelper/crypto/Crypto.hxx>
11
#include <sal/types.h>
12
#include <config_oox.h>
13
14
#include <openssl/evp.h>
15
#include <openssl/sha.h>
16
#include <openssl/hmac.h>
17
18
namespace comphelper
19
{
20
namespace
21
{
22
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
23
24
static HMAC_CTX* HMAC_CTX_new(void)
25
{
26
    HMAC_CTX* pContext = new HMAC_CTX;
27
    HMAC_CTX_init(pContext);
28
    return pContext;
29
}
30
31
static void HMAC_CTX_free(HMAC_CTX* pContext)
32
{
33
    HMAC_CTX_cleanup(pContext);
34
    delete pContext;
35
}
36
#endif
37
38
namespace
39
{
40
struct cipher_delete
41
{
42
96
    void operator()(EVP_CIPHER_CTX* p) { EVP_CIPHER_CTX_free(p); }
43
};
44
45
struct hmac_delete
46
{
47
    SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_CTX_free' is deprecated
48
        void
49
        operator()(HMAC_CTX* p)
50
0
    {
51
0
        HMAC_CTX_free(p);
52
0
    }
53
    SAL_WNODEPRECATED_DECLARATIONS_POP
54
};
55
}
56
57
class CryptoImplementationOpenSSL : public ICryptoImplementation
58
{
59
    std::unique_ptr<EVP_CIPHER_CTX, cipher_delete> mpContext;
60
    std::unique_ptr<HMAC_CTX, hmac_delete> mpHmacContext;
61
62
public:
63
96
    CryptoImplementationOpenSSL() = default;
64
65
    virtual ~CryptoImplementationOpenSSL()
66
96
    {
67
96
        if (mpContext)
68
96
            EVP_CIPHER_CTX_cleanup(mpContext.get());
69
96
    }
70
71
    void setupEncryptContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv,
72
                             CryptoType eType) override
73
0
    {
74
0
        mpContext.reset(EVP_CIPHER_CTX_new());
75
0
        EVP_CIPHER_CTX_init(mpContext.get());
76
77
0
        const EVP_CIPHER* cipher = getCipher(eType);
78
0
        if (cipher == nullptr)
79
0
            return;
80
81
0
        if (iv.empty())
82
0
            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), nullptr);
83
0
        else
84
0
            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), iv.data());
85
0
        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
86
0
    }
87
88
    void setupDecryptContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv,
89
                             CryptoType eType) override
90
96
    {
91
96
        mpContext.reset(EVP_CIPHER_CTX_new());
92
96
        EVP_CIPHER_CTX_init(mpContext.get());
93
94
96
        const EVP_CIPHER* pCipher = getCipher(eType);
95
96
        if (pCipher == nullptr)
96
0
            return;
97
98
96
        const size_t nMinKeySize = EVP_CIPHER_key_length(pCipher);
99
96
        if (key.size() < nMinKeySize)
100
1
            key.resize(nMinKeySize, 0);
101
102
96
        if (iv.empty())
103
94
            EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), nullptr);
104
2
        else
105
2
        {
106
2
            const size_t nMinIVSize = EVP_CIPHER_iv_length(pCipher);
107
2
            if (iv.size() < nMinIVSize)
108
0
                iv.resize(nMinIVSize, 0);
109
110
2
            EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), iv.data());
111
2
        }
112
96
        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
113
96
    }
114
115
    void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType eType) override
116
0
    {
117
        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_CTX_new' is deprecated
118
0
            mpHmacContext.reset(HMAC_CTX_new());
119
0
        SAL_WNODEPRECATED_DECLARATIONS_POP
120
0
        const EVP_MD* aEvpMd = nullptr;
121
0
        switch (eType)
122
0
        {
123
0
            case CryptoHashType::SHA1:
124
0
                aEvpMd = EVP_sha1();
125
0
                break;
126
0
            case CryptoHashType::SHA256:
127
0
                aEvpMd = EVP_sha256();
128
0
                break;
129
0
            case CryptoHashType::SHA384:
130
0
                aEvpMd = EVP_sha384();
131
0
                break;
132
0
            case CryptoHashType::SHA512:
133
0
                aEvpMd = EVP_sha512();
134
0
                break;
135
0
        }
136
        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Init_ex' is deprecated
137
0
            HMAC_Init_ex(mpHmacContext.get(), rKey.data(), rKey.size(), aEvpMd, nullptr);
138
0
        SAL_WNODEPRECATED_DECLARATIONS_POP
139
0
    }
140
141
    static const EVP_CIPHER* getCipher(CryptoType type)
142
96
    {
143
96
        switch (type)
144
96
        {
145
94
            case CryptoType::AES_128_ECB:
146
94
                return EVP_aes_128_ecb();
147
0
            case CryptoType::AES_192_ECB:
148
0
                return EVP_aes_192_ecb();
149
0
            case CryptoType::AES_256_ECB:
150
0
                return EVP_aes_256_ecb();
151
2
            case CryptoType::AES_128_CBC:
152
2
                return EVP_aes_128_cbc();
153
0
            case CryptoType::AES_192_CBC:
154
0
                return EVP_aes_192_cbc();
155
0
            case CryptoType::AES_256_CBC:
156
0
                return EVP_aes_256_cbc();
157
0
            default:
158
0
                break;
159
96
        }
160
0
        return nullptr;
161
96
    }
162
163
    sal_uInt32 decryptUpdate(std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input,
164
                             sal_uInt32 inputLength) override
165
122
    {
166
122
        if (!mpContext)
167
0
            return 0;
168
122
        int outputLength = 0;
169
122
        (void)EVP_DecryptUpdate(mpContext.get(), output.data(), &outputLength, input.data(),
170
122
                                inputLength);
171
122
        return outputLength;
172
122
    }
173
174
    sal_uInt32 encryptUpdate(std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input,
175
                             sal_uInt32 inputLength) override
176
0
    {
177
0
        if (!mpContext)
178
0
            return 0;
179
0
        int outputLength = 0;
180
0
        (void)EVP_EncryptUpdate(mpContext.get(), output.data(), &outputLength, input.data(),
181
0
                                inputLength);
182
0
        return sal_uInt32(outputLength);
183
0
    }
184
185
    bool cryptoHashUpdate(std::vector<sal_uInt8>& rInput, sal_uInt32 nInputLength) override
186
0
    {
187
        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Update' is deprecated
188
0
            return HMAC_Update(mpHmacContext.get(), rInput.data(), nInputLength)
189
0
            != 0;
190
0
        SAL_WNODEPRECATED_DECLARATIONS_POP
191
0
    }
192
193
    bool cryptoHashFinalize(std::vector<sal_uInt8>& rHash) override
194
0
    {
195
0
        unsigned int nSizeWritten = 0;
196
        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Final' is deprecated
197
0
            (void) HMAC_Final(mpHmacContext.get(), rHash.data(), &nSizeWritten);
198
0
        SAL_WNODEPRECATED_DECLARATIONS_POP
199
0
        return nSizeWritten == rHash.size();
200
0
    }
201
};
202
203
} // anonymous namespace
204
205
std::shared_ptr<ICryptoImplementation> ICryptoImplementation::createInstance()
206
96
{
207
96
    return std::shared_ptr<ICryptoImplementation>(new CryptoImplementationOpenSSL);
208
96
}
209
210
} // namespace comphelper
211
212
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */