VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/cipher-openssl.cpp@ 84204

Last change on this file since 84204 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1/* $Id: cipher-openssl.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - Symmetric Cipher using OpenSSL.
4 */
5
6/*
7 * Copyright (C) 2018-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#ifdef IPRT_WITH_OPENSSL
32# include "internal/iprt.h"
33# include <iprt/crypto/cipher.h>
34
35# include <iprt/asm.h>
36# include <iprt/assert.h>
37# include <iprt/err.h>
38# include <iprt/mem.h>
39# include <iprt/string.h>
40
41# include "internal/iprt-openssl.h"
42# include "openssl/evp.h"
43
44# include "internal/magics.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * OpenSSL cipher instance data.
52 */
53typedef struct RTCRCIPHERINT
54{
55 /** Magic value (RTCRCIPHERINT_MAGIC). */
56 uint32_t u32Magic;
57 /** Reference count. */
58 uint32_t volatile cRefs;
59 /** The cihper. */
60 const EVP_CIPHER *pCipher;
61 /** The IPRT cipher type, if we know it. */
62 RTCRCIPHERTYPE enmType;
63} RTCRCIPHERINT;
64
65
66RTDECL(int) RTCrCipherOpenByType(PRTCRCIPHER phCipher, RTCRCIPHERTYPE enmType, uint32_t fFlags)
67{
68 AssertPtrReturn(phCipher, VERR_INVALID_POINTER);
69 *phCipher = NIL_RTCRCIPHER;
70 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
71
72 /*
73 * Translate the IPRT cipher type to EVP cipher.
74 */
75 const EVP_CIPHER *pCipher = NULL;
76 switch (enmType)
77 {
78 case RTCRCIPHERTYPE_XTS_AES_128:
79 pCipher = EVP_aes_128_xts();
80 break;
81 case RTCRCIPHERTYPE_XTS_AES_256:
82 pCipher = EVP_aes_256_xts();
83 break;
84
85 /* no default! */
86 case RTCRCIPHERTYPE_INVALID:
87 case RTCRCIPHERTYPE_END:
88 case RTCRCIPHERTYPE_32BIT_HACK:
89 AssertFailedReturn(VERR_INVALID_PARAMETER);
90 }
91 AssertReturn(pCipher, VERR_CR_CIPHER_NOT_SUPPORTED);
92
93 /*
94 * Create the instance.
95 */
96 RTCRCIPHERINT *pThis = (RTCRCIPHERINT *)RTMemAllocZ(sizeof(*pThis));
97 if (pThis)
98 {
99 pThis->u32Magic = RTCRCIPHERINT_MAGIC;
100 pThis->cRefs = 1;
101 pThis->pCipher = pCipher;
102 pThis->enmType = enmType;
103 *phCipher = pThis;
104 return VINF_SUCCESS;
105 }
106 return VERR_NO_MEMORY;
107}
108
109
110RTDECL(uint32_t) RTCrCipherRetain(RTCRCIPHER hCipher)
111{
112 RTCRCIPHERINT *pThis = hCipher;
113 AssertPtrReturn(pThis, UINT32_MAX);
114 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, UINT32_MAX);
115
116 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
117 Assert(cRefs > 1 && cRefs < 1024);
118 return cRefs;
119}
120
121
122/**
123 * Destroys the cipher instance.
124 */
125static uint32_t rtCrCipherDestroy(RTCRCIPHER pThis)
126{
127 pThis->u32Magic= ~RTCRCIPHERINT_MAGIC;
128 pThis->pCipher = NULL;
129 RTMemFree(pThis);
130 return 0;
131}
132
133
134RTDECL(uint32_t) RTCrCipherRelease(RTCRCIPHER hCipher)
135{
136 RTCRCIPHERINT *pThis = hCipher;
137 if (pThis == NIL_RTCRCIPHER)
138 return 0;
139 AssertPtrReturn(pThis, UINT32_MAX);
140 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, UINT32_MAX);
141
142 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
143 Assert(cRefs < 1024);
144 if (cRefs == 0)
145 return rtCrCipherDestroy(pThis);
146 return cRefs;
147}
148
149
150RTDECL(uint32_t) RTCrCipherGetKeyLength(RTCRCIPHER hCipher)
151{
152 RTCRCIPHERINT *pThis = hCipher;
153 AssertPtrReturn(pThis, 0);
154 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, 0);
155
156 return EVP_CIPHER_key_length(pThis->pCipher);
157}
158
159
160RTDECL(uint32_t) RTCrCipherGetInitializationVectorLength(RTCRCIPHER hCipher)
161{
162 RTCRCIPHERINT *pThis = hCipher;
163 AssertPtrReturn(pThis, 0);
164 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, 0);
165
166 return EVP_CIPHER_iv_length(pThis->pCipher);
167}
168
169
170RTDECL(uint32_t) RTCrCipherGetBlockSize(RTCRCIPHER hCipher)
171{
172 RTCRCIPHERINT *pThis = hCipher;
173 AssertPtrReturn(pThis, 0);
174 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, 0);
175
176 return EVP_CIPHER_block_size(pThis->pCipher);
177}
178
179
180RTDECL(int) RTCrCipherEncrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey,
181 void const *pvInitVector, size_t cbInitVector,
182 void const *pvPlainText, size_t cbPlainText,
183 void *pvEncrypted, size_t cbEncrypted, size_t *pcbEncrypted)
184{
185 /*
186 * Validate input.
187 */
188 RTCRCIPHERINT *pThis = hCipher;
189 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
190 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, VERR_INVALID_HANDLE);
191 AssertMsgReturn((ssize_t)cbKey == EVP_CIPHER_key_length(pThis->pCipher),
192 ("%zu, expected %d\n", cbKey, EVP_CIPHER_key_length(pThis->pCipher)),
193 VERR_CR_CIPHER_INVALID_KEY_LENGTH);
194 AssertMsgReturn((ssize_t)cbInitVector == EVP_CIPHER_iv_length(pThis->pCipher),
195 ("%zu, expected %d\n", cbInitVector, EVP_CIPHER_iv_length(pThis->pCipher)),
196 VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH);
197 AssertReturn(cbPlainText > 0, VERR_NO_DATA);
198
199 Assert(EVP_CIPHER_block_size(pThis->pCipher) <= 1); /** @todo more complicated ciphers later */
200 size_t const cbNeeded = cbPlainText;
201 if (pcbEncrypted)
202 {
203 *pcbEncrypted = cbNeeded;
204 AssertReturn(cbEncrypted >= cbNeeded, VERR_BUFFER_OVERFLOW);
205 }
206 else
207 AssertReturn(cbEncrypted == cbNeeded, VERR_INVALID_PARAMETER);
208 AssertReturn((size_t)(int)cbPlainText == cbPlainText && (int)cbPlainText > 0, VERR_OUT_OF_RANGE);
209
210 /*
211 * Allocate and initialize the cipher context.
212 */
213 int rc = VERR_NO_MEMORY;
214# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
215 EVP_CIPHER_CTX *pCipherCtx = EVP_CIPHER_CTX_new();
216 if (pCipherCtx)
217# else
218 EVP_CIPHER_CTX CipherCtx;
219 EVP_CIPHER_CTX *pCipherCtx = &CipherCtx;
220 RT_ZERO(CipherCtx);
221# endif
222 {
223 int rcOssl = EVP_EncryptInit(pCipherCtx, pThis->pCipher, (unsigned char const *)pvKey,
224 (unsigned char const *)pvInitVector);
225 if (rcOssl > 0)
226 {
227 /*
228 * Do the encryption.
229 */
230 int cbEncrypted1 = 0;
231 rcOssl = EVP_EncryptUpdate(pCipherCtx, (unsigned char *)pvEncrypted, &cbEncrypted1,
232 (unsigned char const *)pvPlainText, (int)cbPlainText);
233 if (rcOssl > 0)
234 {
235 Assert(cbEncrypted1 <= (ssize_t)cbNeeded);
236 int cbEncrypted2 = 0;
237 rcOssl = EVP_EncryptFinal(pCipherCtx, (unsigned char *)pvEncrypted + cbEncrypted1, &cbEncrypted2);
238 if (rcOssl > 0)
239 {
240 Assert(cbEncrypted1 + cbEncrypted2 == (ssize_t)cbNeeded);
241 if (pcbEncrypted)
242 *pcbEncrypted = cbEncrypted1 + cbEncrypted2;
243 rc = VINF_SUCCESS;
244 }
245 else
246 rc = VERR_CR_CIPHER_OSSL_ENCRYPT_FINAL_FAILED;
247 }
248 else
249 rc = VERR_CR_CIPHER_OSSL_ENCRYPT_UPDATE_FAILED;
250 }
251 else
252 rc = VERR_CR_CIPHER_OSSL_ENCRYPT_INIT_FAILED;
253
254# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
255 EVP_CIPHER_CTX_free(pCipherCtx);
256# else
257 EVP_CIPHER_CTX_cleanup(&CipherCtx);
258# endif
259 }
260 return rc;
261}
262
263
264RTDECL(int) RTCrCipherDecrypt(RTCRCIPHER hCipher, void const *pvKey, size_t cbKey,
265 void const *pvInitVector, size_t cbInitVector,
266 void const *pvEncrypted, size_t cbEncrypted,
267 void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText)
268{
269 /*
270 * Validate input.
271 */
272 RTCRCIPHERINT *pThis = hCipher;
273 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
274 AssertReturn(pThis->u32Magic == RTCRCIPHERINT_MAGIC, VERR_INVALID_HANDLE);
275 AssertMsgReturn((ssize_t)cbKey == EVP_CIPHER_key_length(pThis->pCipher),
276 ("%zu, expected %d\n", cbKey, EVP_CIPHER_key_length(pThis->pCipher)),
277 VERR_CR_CIPHER_INVALID_KEY_LENGTH);
278 AssertMsgReturn((ssize_t)cbInitVector == EVP_CIPHER_iv_length(pThis->pCipher),
279 ("%zu, expected %d\n", cbInitVector, EVP_CIPHER_iv_length(pThis->pCipher)),
280 VERR_CR_CIPHER_INVALID_INITIALIZATION_VECTOR_LENGTH);
281 AssertReturn(cbPlainText > 0, VERR_NO_DATA);
282
283 Assert(EVP_CIPHER_block_size(pThis->pCipher) <= 1); /** @todo more complicated ciphers later */
284 size_t const cbNeeded = cbEncrypted;
285 if (pcbPlainText)
286 {
287 *pcbPlainText = cbNeeded;
288 AssertReturn(cbPlainText >= cbNeeded, VERR_BUFFER_OVERFLOW);
289 }
290 else
291 AssertReturn(cbPlainText == cbNeeded, VERR_INVALID_PARAMETER);
292 AssertReturn((size_t)(int)cbEncrypted == cbEncrypted && (int)cbEncrypted > 0, VERR_OUT_OF_RANGE);
293
294 /*
295 * Allocate and initialize the cipher context.
296 */
297 int rc = VERR_NO_MEMORY;
298# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
299 EVP_CIPHER_CTX *pCipherCtx = EVP_CIPHER_CTX_new();
300 if (pCipherCtx)
301# else
302 EVP_CIPHER_CTX CipherCtx;
303 EVP_CIPHER_CTX *pCipherCtx = &CipherCtx;
304 RT_ZERO(CipherCtx);
305# endif
306 {
307 int rcOssl = EVP_DecryptInit(pCipherCtx, pThis->pCipher, (unsigned char const *)pvKey,
308 (unsigned char const *)pvInitVector);
309 if (rcOssl > 0)
310 {
311 /*
312 * Do the decryption.
313 */
314 int cbDecrypted1 = 0;
315 rcOssl = EVP_DecryptUpdate(pCipherCtx, (unsigned char *)pvPlainText, &cbDecrypted1,
316 (unsigned char const *)pvEncrypted, (int)cbEncrypted);
317 if (rcOssl > 0)
318 {
319 Assert(cbDecrypted1 <= (ssize_t)cbNeeded);
320 int cbDecrypted2 = 0;
321 rcOssl = EVP_DecryptFinal(pCipherCtx, (unsigned char *)pvPlainText + cbDecrypted1, &cbDecrypted2);
322 if (rcOssl > 0)
323 {
324 Assert(cbDecrypted1 + cbDecrypted2 == (ssize_t)cbNeeded);
325 if (pcbPlainText)
326 *pcbPlainText = cbDecrypted1 + cbDecrypted2;
327 rc = VINF_SUCCESS;
328 }
329 else
330 rc = VERR_CR_CIPHER_OSSL_DECRYPT_FINAL_FAILED;
331 }
332 else
333 rc = VERR_CR_CIPHER_OSSL_DECRYPT_UPDATE_FAILED;
334 }
335 else
336 rc = VERR_CR_CIPHER_OSSL_DECRYPT_INIT_FAILED;
337
338# if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
339 EVP_CIPHER_CTX_free(pCipherCtx);
340# else
341 EVP_CIPHER_CTX_cleanup(&CipherCtx);
342# endif
343 }
344 return rc;
345}
346
347#endif /* IPRT_WITH_OPENSSL */
348
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette