diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hkdf.c | 2 | ||||
-rw-r--r-- | src/nc-crypto.c | 8 | ||||
-rw-r--r-- | src/nc-util.h | 37 | ||||
-rw-r--r-- | src/noscrypt.c | 7 | ||||
-rw-r--r-- | src/noscryptutil.c | 58 | ||||
-rw-r--r-- | src/providers/bcrypt.c | 16 | ||||
-rw-r--r-- | src/providers/openssl.c | 230 |
7 files changed, 268 insertions, 90 deletions
@@ -95,7 +95,7 @@ cstatus_t hkdfExpandProcess( } /* tlen becomes the hash size or remaining okm size */ - tLen = HKDF_MIN(okm.size - okmOffset, SHA256_DIGEST_SIZE); + tLen = HKDF_MIN(ncSpanGetSize(okm) - okmOffset, SHA256_DIGEST_SIZE); DEBUG_ASSERT(tLen <= sizeof(t)); diff --git a/src/nc-crypto.c b/src/nc-crypto.c index 752c9b0..56bdf75 100644 --- a/src/nc-crypto.c +++ b/src/nc-crypto.c @@ -292,10 +292,10 @@ cstatus_t ncCryptoChacha20( uint32_t dataSize ) { - DEBUG_ASSERT2(key != NULL, "Expected key to be non-null") - DEBUG_ASSERT2(nonce != NULL, "Expected nonce to be non-null") - DEBUG_ASSERT2(input != NULL, "Expected input to be non-null") - DEBUG_ASSERT2(output != NULL, "Expected output to be non-null") + DEBUG_ASSERT2(key != NULL, "Expected key to be non-null"); + DEBUG_ASSERT2(nonce != NULL, "Expected nonce to be non-null"); + DEBUG_ASSERT2(input != NULL, "Expected input to be non-null"); + DEBUG_ASSERT2(output != NULL, "Expected output to be non-null"); #ifndef _IMPL_CHACHA20_CRYPT #error "No chacha20 implementation defined" diff --git a/src/nc-util.h b/src/nc-util.h index 2ddfd3f..a248578 100644 --- a/src/nc-util.h +++ b/src/nc-util.h @@ -90,6 +90,10 @@ #endif /* NC_EXTREME_COMPAT */ +#ifndef EMPTY_SPANS + #define EMPTY_SPANS 1 +#endif + typedef struct memory_span_struct { uint8_t* data; @@ -136,6 +140,20 @@ static _nc_fn_inline void ncSpanInit(span_t* span, uint8_t* data, uint32_t size) static _nc_fn_inline const uint8_t* ncSpanGetOffsetC(cspan_t span, uint32_t offset) { + +#if EMPTY_SPANS + + /* + * Allow passing null pointers for empty spans, if enabled, + * otherwise debug guards will catch empty spans + */ + if (span.size == 0 && offset == 0) + { + return NULL; + } + +#endif /* !EMPTY_SPANS */ + DEBUG_ASSERT2(ncSpanIsValidC(span), "Expected span to be non-null"); DEBUG_ASSERT2(offset < span.size, "Expected offset to be less than span size"); @@ -144,10 +162,23 @@ static _nc_fn_inline const uint8_t* ncSpanGetOffsetC(cspan_t span, uint32_t offs static _nc_fn_inline uint8_t* ncSpanGetOffset(span_t span, uint32_t offset) { - DEBUG_ASSERT2(ncSpanIsValid(span), "Expected span to be non-null"); - DEBUG_ASSERT2(offset < span.size, "Expected offset to be less than span size"); + cspan_t cspan; + ncSpanInitC(&cspan, span.data, span.size); + return (uint8_t*)ncSpanGetOffsetC(cspan, offset); +} - return span.data + offset; +static _nc_fn_inline uint32_t ncSpanGetSizeC(cspan_t span) +{ + return ncSpanIsValidC(span) + ? span.size + : 0; +} + +static _nc_fn_inline uint32_t ncSpanGetSize(span_t span) +{ + return ncSpanIsValid(span) + ? span.size + : 0; } static _nc_fn_inline void ncSpanWrite(span_t span, uint32_t offset, const uint8_t* data, uint32_t size) diff --git a/src/noscrypt.c b/src/noscrypt.c index 46b3d65..deadca6 100644 --- a/src/noscrypt.c +++ b/src/noscrypt.c @@ -816,7 +816,12 @@ NC_EXPORT NCResult NC_CC NCEncryptEx( return E_VERSION_NOT_SUPPORTED; case NC_ENC_VERSION_NIP44: - return _encryptNip44Ex(ctx, (struct conversation_key*)conversationKey, args->keyData, args); + return _encryptNip44Ex( + ctx, + (struct conversation_key*)conversationKey, + args->keyData, + args + ); default: return E_VERSION_NOT_SUPPORTED; diff --git a/src/noscryptutil.c b/src/noscryptutil.c index 56acb1b..c47da13 100644 --- a/src/noscryptutil.c +++ b/src/noscryptutil.c @@ -309,7 +309,13 @@ static _nc_fn_inline void _cipherPublishOutput(NCUtilCipherContext* buffer, uint { /* use slice for debug guards */ slice = ncSpanSlice(buffer->buffer.output, offset, size); - ncSpanInitC(&buffer->buffer.actualOutput, slice.data, slice.size); + + /* init readonly span from mutable */ + ncSpanInitC( + &buffer->buffer.actualOutput, + ncSpanGetOffset(slice, 0), + ncSpanGetSize(slice) + ); } } @@ -330,7 +336,7 @@ static NCResult _nip44EncryptCompleteCore( NCResult result; cspan_t plainText; - span_t macData, macOutput, payload; + span_t macData, macOutput, message; uint32_t outPos; uint8_t ptSize[NIP44_PT_LEN_SIZE]; uint8_t hmacKeyOut[NC_ENCRYPTION_MAC_SIZE]; @@ -338,16 +344,18 @@ static NCResult _nip44EncryptCompleteCore( outPos = 0; encArgs = state->encArgs; - payload = state->buffer.output; + message = state->buffer.output; plainText = state->buffer.input; DEBUG_ASSERT(encArgs.version == NC_ENC_VERSION_NIP44); + ZERO_FILL(hmacKeyOut, sizeof(hmacKeyOut)); + /* Start by appending the version number */ - ncSpanAppend(payload, &outPos, Nip44VersionValue, sizeof(Nip44VersionValue)); + ncSpanAppend(message, &outPos, Nip44VersionValue, sizeof(Nip44VersionValue)); /* next is nonce data */ - ncSpanAppend(payload, &outPos, encArgs.nonceData, NC_ENCRYPTION_NONCE_SIZE); + ncSpanAppend(message, &outPos, encArgs.nonceData, NC_ENCRYPTION_NONCE_SIZE); DEBUG_ASSERT(outPos == 1 + NC_ENCRYPTION_NONCE_SIZE); /* @@ -385,16 +393,16 @@ static NCResult _nip44EncryptCompleteCore( result = NCSetEncryptionData( &encArgs, - ncSpanGetOffset(payload, outPos), /* in place encryption */ - ncSpanGetOffset(payload, outPos), + ncSpanGetOffset(message, outPos), /* in place encryption */ + ncSpanGetOffset(message, outPos), NIP44_PT_LEN_SIZE + _calcNip44PtPadding(plainText.size) /* Plaintext + pt size must be encrypted */ ); DEBUG_ASSERT(result == NC_SUCCESS); /* big endian plaintext size */ - ptSize[0] = (uint8_t)(plainText.size >> 8); - ptSize[1] = (uint8_t)(plainText.size & 0xFF); + ptSize[0] = (uint8_t)(ncSpanGetSizeC(plainText) >> 8); + ptSize[1] = (uint8_t)(ncSpanGetSizeC(plainText) & 0xFF); /* * Written position must point to the end of the padded ciphertext @@ -405,13 +413,13 @@ static NCResult _nip44EncryptCompleteCore( * the plaintext data, followed by zero padding. */ - ncSpanWrite(payload, outPos, ptSize, sizeof(ptSize)); + ncSpanWrite(message, outPos, ptSize, sizeof(ptSize)); ncSpanWrite( - payload, + message, outPos + NIP44_PT_LEN_SIZE, /* write pt directly after length */ - plainText.data, - plainText.size + ncSpanGetOffsetC(plainText, 0), + ncSpanGetSizeC(plainText) ); /* Move position pointer directly after final padding bytes */ @@ -429,14 +437,14 @@ static NCResult _nip44EncryptCompleteCore( this helper captures that data segment into a span */ - macData = _nip44GetMacData(payload); - macOutput = _nip44GetMacOutput(payload); + macData = _nip44GetMacData(message); + macOutput = _nip44GetMacOutput(message); result = NCComputeMac( libContext, hmacKeyOut, ncSpanGetOffset(macData, 0), - macData.size, + ncSpanGetSize(macData), ncSpanGetOffset(macOutput, 0) ); @@ -447,9 +455,9 @@ static NCResult _nip44EncryptCompleteCore( outPos += NC_ENCRYPTION_MAC_SIZE; - DEBUG_ASSERT2(outPos == payload.size, "Buffer under/overflow detected"); + DEBUG_ASSERT2(outPos == message.size, "Buffer under/overflow detected"); - /* publish all payload bytes to output */ + /* publish all message bytes to output */ _cipherPublishOutput(state, 0, outPos); /* zero hmac key before returning */ @@ -475,7 +483,7 @@ static NCResult _nip44DecryptCompleteCore( DEBUG_ASSERT(libContext && recvKey && sendKey && state); DEBUG_ASSERT(state->encArgs.version == NC_ENC_VERSION_NIP44); - DEBUG_ASSERT(state->buffer.input.size >= NIP44_MIN_PAYLOAD_SIZE); + DEBUG_ASSERT(ncSpanGetSizeC(state->buffer.input) >= NIP44_MIN_PAYLOAD_SIZE); /* ensure decryption mode */ DEBUG_ASSERT(state->_flags & NC_UTIL_CIPHER_MODE_DECRYPT); @@ -503,16 +511,16 @@ static NCResult _nip44DecryptCompleteCore( /* Verify mac if the user allowed it */ if ((state->_flags & NC_UTIL_CIPHER_MAC_NO_VERIFY) == 0) { - DEBUG_ASSERT(macValue.size == NC_ENCRYPTION_MAC_SIZE); - DEBUG_ASSERT(macData.size > NC_ENCRYPTION_NONCE_SIZE + MIN_PADDING_SIZE); + DEBUG_ASSERT(ncSpanGetSizeC(macValue) == NC_ENCRYPTION_MAC_SIZE); + DEBUG_ASSERT(ncSpanGetSizeC(macData) > NC_ENCRYPTION_NONCE_SIZE + MIN_PADDING_SIZE); /* Assign the mac data to the mac verify args */ macArgs.mac32 = ncSpanGetOffsetC(macValue, 0); macArgs.nonce32 = ncSpanGetOffsetC(nonce, 0); - /* payload for verifying a mac in nip44 is the nonce+ciphertext */ + /* message for verifying a mac in nip44 is the nonce+ciphertext */ macArgs.payload = ncSpanGetOffsetC(macData, 0); - macArgs.payloadSize = macData.size; + macArgs.payloadSize = ncSpanGetSizeC(macData); /* Verify the mac */ result = NCVerifyMac(libContext, recvKey, sendKey, &macArgs); @@ -541,7 +549,7 @@ static NCResult _nip44DecryptCompleteCore( &encArgs, ncSpanGetOffsetC(cipherText, 0), ncSpanGetOffset(output, 0), /*decrypt ciphertext and write directly to the output buffer */ - cipherText.size + ncSpanGetSizeC(cipherText) ); DEBUG_ASSERT(result == NC_SUCCESS); @@ -582,7 +590,7 @@ static NCResult _nip44DecryptCompleteCore( */ _cipherPublishOutput(state, NIP44_PT_LEN_SIZE, ptSize); - DEBUG_ASSERT(state->buffer.actualOutput.size < cipherText.size); + DEBUG_ASSERT(ncSpanGetSizeC(state->buffer.actualOutput) < cipherText.size); return result; } diff --git a/src/providers/bcrypt.c b/src/providers/bcrypt.c index 10cf801..2b9ba52 100644 --- a/src/providers/bcrypt.c +++ b/src/providers/bcrypt.c @@ -79,8 +79,8 @@ _IMPLSTB NTSTATUS _bcCreateHmac(struct _bcrypt_ctx* ctx, cspan_t key) &ctx->hHash, NULL, 0, - (uint8_t*)key.data, - key.size, + (uint8_t*)ncSpanGetOffsetC(key, 0), + ncSpanGetSizeC(key), BCRYPT_HASH_REUSABLE_FLAG /* Enable reusable for expand function */ ); } @@ -102,7 +102,11 @@ _IMPLSTB NTSTATUS _bcHashDataRaw(const struct _bcrypt_ctx* ctx, const uint8_t* d _IMPLSTB NTSTATUS _bcHashData(const struct _bcrypt_ctx* ctx, cspan_t data) { - return _bcHashDataRaw(ctx, data.data, data.size); + return _bcHashDataRaw( + ctx, + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) + ); } _IMPLSTB NTSTATUS _bcFinishHash(const struct _bcrypt_ctx* ctx, sha256_t digestOut32) @@ -118,8 +122,8 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx) /* Close the algorithm provider */ if (ctx->hAlg) BCryptCloseAlgorithmProvider(ctx->hAlg, 0); - ctx->hAlg = NULL; ctx->hHash = NULL; + ctx->hAlg = NULL; } #ifndef _IMPL_SECURE_ZERO_MEMSET @@ -213,7 +217,7 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx) #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _bcrypt_fallback_hkdf_expand - cstatus_t _bcrypt_hkdf_update(void* ctx, cspan_t data) + static cstatus_t _bcrypt_hkdf_update(void* ctx, cspan_t data) { DEBUG_ASSERT(ctx != NULL) @@ -221,7 +225,7 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx) return CSTATUS_OK; } - cstatus_t _bcrypt_hkdf_finish(void* ctx, sha256_t hmacOut32) + static cstatus_t _bcrypt_hkdf_finish(void* ctx, sha256_t hmacOut32) { DEBUG_ASSERT(ctx != NULL); DEBUG_ASSERT(hmacOut32 != NULL); diff --git a/src/providers/openssl.c b/src/providers/openssl.c index 5bade3b..7f405ef 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -27,6 +27,8 @@ #define _OSSL_FAIL(x) if(!(x)) return CSTATUS_FAIL; #define ossl_md_sha256() EVP_MD_fetch(NULL, "SHA2-256", NULL) +#define ossl_evp_fetch_chacha20() EVP_CIPHER_fetch(NULL, "ChaCha20", NULL) +#define ossl_mac_fetch_hmac() EVP_MAC_fetch(NULL, "hmac", NULL) #ifndef _IMPL_SECURE_ZERO_MEMSET @@ -67,9 +69,18 @@ _IMPLSTB cstatus_t _ossl_sha256_digest(cspan_t data, sha256_t digestOut32) { - _overflow_check(data.size) + _overflow_check(data.size); - _OSSL_FAIL(SHA256(data.data, data.size, digestOut32)) + DEBUG_ASSERT(digestOut32 != NULL); + DEBUG_ASSERT(ncSpanIsValidC(data)); + + _OSSL_FAIL( + SHA256( + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data), + digestOut32 + ) + ); return CSTATUS_OK; } @@ -95,17 +106,17 @@ _OSSL_FAIL( HMAC( ossl_md_sha256(), - key.data, - key.size, - data.data, - data.size, + ncSpanGetOffsetC(key, 0), + ncSpanGetSizeC(key), + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data), hmacOut32, &hmacLen ) - ) + ); /* digest length should match the actual digest size */ - DEBUG_ASSERT(hmacLen == sizeof(sha256_t)) + DEBUG_ASSERT(hmacLen == sizeof(sha256_t)); return CSTATUS_OK; } @@ -118,54 +129,91 @@ #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _ossl_sha256_hkdf_expand - cstatus_t _ossl_hkdf_update(void* ctx, cspan_t data) + struct ossl_hmac_state { + EVP_MAC_CTX* libCtx; + OSSL_PARAM params[2]; + cspan_t prk; + }; + + static cstatus_t _ossl_hmac_init(const struct ossl_hmac_state* osslCtx) { - DEBUG_ASSERT(ctx != NULL) + DEBUG_ASSERT(ncSpanIsValidC(osslCtx->prk)); + DEBUG_ASSERT(osslCtx->params != NULL); - _overflow_check(data.size) + _OSSL_FAIL( + EVP_MAC_init( + osslCtx->libCtx, + ncSpanGetOffsetC(osslCtx->prk, 0), + ncSpanGetSizeC(osslCtx->prk), + osslCtx->params + ) + ); + + return CSTATUS_OK; + } + + static cstatus_t _ossl_hkdf_update(void* ctx, cspan_t data) + { + const struct ossl_hmac_state* osslCtx; + + DEBUG_ASSERT(ctx != NULL); + _overflow_check(data.size); + + osslCtx = (const struct ossl_hmac_state*)ctx; + + DEBUG_ASSERT(osslCtx->libCtx != NULL); _OSSL_FAIL( EVP_MAC_update( - (EVP_MAC_CTX*)ctx, - data.data, - data.size + osslCtx->libCtx, + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) ) - ) + ); return CSTATUS_OK; } - cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) + static cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) { + const struct ossl_hmac_state* osslCtx; size_t hmacSize; DEBUG_ASSERT(ctx != NULL); - DEBUG_ASSERT(hmacOut32 != NULL) + DEBUG_ASSERT(hmacOut32 != NULL); + osslCtx = (const struct ossl_hmac_state*)ctx; hmacSize = 0; + DEBUG_ASSERT(osslCtx->libCtx != NULL); + _OSSL_FAIL( EVP_MAC_final( - (EVP_MAC_CTX*)ctx, - hmacOut32, - &hmacSize, + osslCtx->libCtx, + hmacOut32, + &hmacSize, sizeof(sha256_t) ) - ) + ); /* When configured for sha256, should always be the same size in/out */ - DEBUG_ASSERT(hmacSize == sizeof(sha256_t)) - - return CSTATUS_OK; + DEBUG_ASSERT(hmacSize == sizeof(sha256_t)); + + /* + * Context must be re-initalized after finalize + * See lifecycle https://docs.openssl.org/3.0/man7/life_cycle-mac/#copyright + */ + + return _ossl_hmac_init(osslCtx); } + _IMPLSTB cstatus_t _ossl_sha256_hkdf_expand(cspan_t prk, cspan_t info, span_t okm) { EVP_MAC* mac; - EVP_MAC_CTX* ctx; cstatus_t result; - OSSL_PARAM params[2]; - struct nc_hkdf_fn_cb_struct handler; + struct ossl_hmac_state hkdfState; + struct nc_hkdf_fn_cb_struct handler; result = CSTATUS_FAIL; @@ -173,41 +221,47 @@ handler.finish = _ossl_hkdf_finish; _overflow_check(prk.size); + _overflow_check(info.size); + _overflow_check(okm.size); + + hkdfState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + hkdfState.params[1] = OSSL_PARAM_construct_end(); + + hkdfState.prk = prk; /* * Silly openssl stuff. Enable hmac with sha256 using the system default * security provider. The one-shot flag must also be disabled (0) because * we need to call update multiple times. - * - * "provider=default,digest=SHA256,digest-oneshot=0" */ - ctx = NULL; - mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + mac = ossl_mac_fetch_hmac(); if (mac == NULL) { goto Cleanup; } - if ((ctx = EVP_MAC_CTX_new(mac)) == NULL) + hkdfState.libCtx = EVP_MAC_CTX_new(mac); + + if (hkdfState.libCtx == NULL) { goto Cleanup; } - params[0] = OSSL_PARAM_construct_utf8_string("digest", "SHA2-256", 0); - params[1] = OSSL_PARAM_construct_end(); - - if (!EVP_MAC_init(ctx, prk.data, prk.size, params)) + if (_ossl_hmac_init(&hkdfState) != CSTATUS_OK) { goto Cleanup; } - result = hkdfExpandProcess(&handler, ctx, info, okm); + DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(hkdfState.libCtx) == sizeof(sha256_t)); + + /* Pass the library */ + result = hkdfExpandProcess(&handler, &hkdfState, info, okm); Cleanup: - if (ctx) EVP_MAC_CTX_free(ctx); + if (hkdfState.libCtx) EVP_MAC_CTX_free(hkdfState.libCtx); if (mac) EVP_MAC_free(mac); return result; @@ -221,39 +275,115 @@ #define _IMPL_CHACHA20_CRYPT _ossl_chacha20_crypt - _IMPLSTB cstatus_t _ossl_chacha20_crypt( - const uint8_t* key, - const uint8_t* nonce, - const uint8_t* input, - uint8_t* output, - uint32_t dataLen + _IMPLSTB cstatus_t _ossl_chacha20_cipher_core( + const EVP_CIPHER* cipher, + cspan_t key, + cspan_t iv, + cspan_t input, + span_t output ) { cstatus_t result; EVP_CIPHER_CTX* ctx; + int tempLen, osslResult; - result = CSTATUS_FAIL; + DEBUG_ASSERT2(ncSpanGetSize(output) <= ncSpanGetSizeC(input), "Output buffer must be equal or larger than the input buffer"); + DEBUG_ASSERT(cipher != NULL); + + result = CSTATUS_FAIL; - if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + ctx = EVP_CIPHER_CTX_new(); + + if (ctx == NULL) { - return CSTATUS_FAIL; + goto Cleanup; } - if (!EVP_EncryptInit_ex(ctx, EVP_chacha20(), NULL, key, nonce)) + osslResult = EVP_EncryptInit_ex2( + ctx, + cipher, + ncSpanGetOffsetC(key, 0), + ncSpanGetOffsetC(iv, 0), + NULL + ); + + if (!osslResult) { goto Cleanup; } - if (!EVP_EncryptUpdate(ctx, output, (int*)&dataLen, input, dataLen)) + osslResult = EVP_EncryptUpdate( + ctx, + ncSpanGetOffset(output, 0), + &tempLen, + ncSpanGetOffsetC(input, 0), + ncSpanGetSizeC(input) + ); + + if (!osslResult) { goto Cleanup; } + /* + * We can't get a pointer outside the range of the + * output buffer + */ + if (((uint32_t)tempLen) < ncSpanGetSize(output)) + { + if (!EVP_EncryptFinal_ex(ctx, ncSpanGetOffset(output, tempLen), &tempLen)) + { + goto Cleanup; + } + } + result = CSTATUS_OK; Cleanup: - EVP_CIPHER_CTX_free(ctx); + if (ctx) EVP_CIPHER_CTX_free(ctx); + + return result; + } + + _IMPLSTB cstatus_t _ossl_chacha20_crypt( + const uint8_t* key, + const uint8_t* nonce, + const uint8_t* input, + uint8_t* output, + uint32_t dataLen + ) + { + cstatus_t result; + EVP_CIPHER* cipher; + cspan_t keySpan, nonceSpan, inputSpan; + span_t outputSpan; + + result = CSTATUS_FAIL; + + ncSpanInitC(&keySpan, key, CHACHA_KEY_SIZE); + ncSpanInitC(&nonceSpan, nonce, CHACHA_NONCE_SIZE); + ncSpanInitC(&inputSpan, input, dataLen); + ncSpanInit(&outputSpan, output, dataLen); + + cipher = ossl_evp_fetch_chacha20(); + + if (cipher == NULL) + { + goto Cleanup; + } + + result = _ossl_chacha20_cipher_core( + cipher, + keySpan, + nonceSpan, + inputSpan, + outputSpan + ); + + Cleanup: + + if (cipher) EVP_CIPHER_free(cipher); return result; } |