/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: */ |