diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /third_party/heimdal/lib/hcrypto/evp.c | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/hcrypto/evp.c')
-rw-r--r-- | third_party/heimdal/lib/hcrypto/evp.c | 1562 |
1 files changed, 1562 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/hcrypto/evp.c b/third_party/heimdal/lib/hcrypto/evp.c new file mode 100644 index 0000000..3874179 --- /dev/null +++ b/third_party/heimdal/lib/hcrypto/evp.c @@ -0,0 +1,1562 @@ +/* + * Copyright (c) 2006 - 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <roken.h> + +#define HC_DEPRECATED +#define HC_DEPRECATED_CRYPTO + +#include <assert.h> + +#include <evp.h> +#include <evp-hcrypto.h> +#include <evp-cc.h> +#if defined(_WIN32) +#include <evp-w32.h> +#endif +#include <evp-pkcs11.h> +#include <evp-openssl.h> + +#include <krb5-types.h> + +#ifndef HCRYPTO_DEF_PROVIDER +# ifdef __APPLE__ +# define HCRYPTO_DEF_PROVIDER cc +# elif __sun +# define HCRYPTO_DEF_PROVIDER pkcs11_hcrypto +# elif HAVE_HCRYPTO_W_OPENSSL +# define HCRYPTO_DEF_PROVIDER ossl +# define HCRYPTO_DEF_PROVIDER_IS_OPENSSL +# else +# define HCRYPTO_DEF_PROVIDER hcrypto +# endif +#endif + +#define HC_CONCAT4(x,y,z,aa) x ## y ## z ## aa + + +#define EVP_DEF_OP(_prov,_op) HC_CONCAT4(EVP_,_prov,_,_op)() + +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) +extern int _heim_openssl_fips_enabled(void); +#endif + + +/** + * @page page_evp EVP - generic crypto interface + * + * See the library functions here: @ref hcrypto_evp + * + * @section evp_cipher EVP Cipher + * + * The use of EVP_CipherInit_ex() and EVP_Cipher() is pretty easy to + * understand forward, then EVP_CipherUpdate() and + * EVP_CipherFinal_ex() really needs an example to explain @ref + * example_evp_cipher.c . + * + * @example example_evp_cipher.c + * + * This is an example how to use EVP_CipherInit_ex(), + * EVP_CipherUpdate() and EVP_CipherFinal_ex(). + */ + +struct hc_EVP_MD_CTX { + const EVP_MD *md; + ENGINE *engine; + void *ptr; +}; + + +/** + * Return the output size of the message digest function. + * + * @param md the evp message + * + * @return size output size of the message digest function. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_size(const EVP_MD *md) +{ + return md->hash_size; +} + +/** + * Return the blocksize of the message digest function. + * + * @param md the evp message + * + * @return size size of the message digest block size + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_block_size(const EVP_MD *md) +{ + return md->block_size; +} + +/** + * Allocate a messsage digest context object. Free with + * EVP_MD_CTX_destroy(). + * + * @return a newly allocated message digest context object. + * + * @ingroup hcrypto_evp + */ + +EVP_MD_CTX * +EVP_MD_CTX_create(void) +{ + return calloc(1, sizeof(EVP_MD_CTX)); +} + +/** + * Initiate a messsage digest context object. Deallocate with + * EVP_MD_CTX_cleanup(). Please use EVP_MD_CTX_create() instead. + * + * @param ctx variable to initiate. + * + * @ingroup hcrypto_evp + */ + +void +EVP_MD_CTX_init(EVP_MD_CTX *ctx) HC_DEPRECATED +{ + memset(ctx, 0, sizeof(*ctx)); +} + +/** + * Free a messsage digest context object. + * + * @param ctx context to free. + * + * @ingroup hcrypto_evp + */ + +void +EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + free(ctx); +} + +/** + * Free the resources used by the EVP_MD context. + * + * @param ctx the context to free the resources from. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) HC_DEPRECATED +{ + if (ctx->md && ctx->md->cleanup) { + int ret = (ctx->md->cleanup)(ctx->ptr); + if (!ret) + return ret; + } else if (ctx->md) { + memset_s(ctx->ptr, ctx->md->ctx_size, 0, ctx->md->ctx_size); + } + ctx->md = NULL; + ctx->engine = NULL; + free(ctx->ptr); + memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx)); + return 1; +} + +/** + * Get the EVP_MD use for a specified context. + * + * @param ctx the EVP_MD context to get the EVP_MD for. + * + * @return the EVP_MD used for the context. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_MD_CTX_md(EVP_MD_CTX *ctx) +{ + return ctx->md; +} + +/** + * Return the output size of the message digest function. + * + * @param ctx the evp message digest context + * + * @return size output size of the message digest function. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_CTX_size(EVP_MD_CTX *ctx) +{ + return EVP_MD_size(ctx->md); +} + +/** + * Return the blocksize of the message digest function. + * + * @param ctx the evp message digest context + * + * @return size size of the message digest block size + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_MD_CTX_block_size(EVP_MD_CTX *ctx) +{ + return EVP_MD_block_size(ctx->md); +} + +/** + * Init a EVP_MD_CTX for use a specific message digest and engine. + * + * @param ctx the message digest context to init. + * @param md the message digest to use. + * @param engine the engine to use, NULL to use the default engine. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, ENGINE *engine) +{ + if (ctx->md != md || ctx->engine != engine) { + EVP_MD_CTX_cleanup(ctx); + ctx->md = md; + ctx->engine = engine; + if (md == NULL) + return 0; + + ctx->ptr = calloc(1, md->ctx_size); + if (ctx->ptr == NULL) + return 0; + } + if (ctx->md == 0) + return 0; + return (ctx->md->init)(ctx->ptr); +} + +/** + * Update the digest with some data. + * + * @param ctx the context to update + * @param data the data to update the context with + * @param size length of data + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t size) +{ + (ctx->md->update)(ctx->ptr, data, size); + return 1; +} + +/** + * Complete the message digest. + * + * @param ctx the context to complete. + * @param hash the output of the message digest function. At least + * EVP_MD_size(). + * @param size the output size of hash. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_DigestFinal_ex(EVP_MD_CTX *ctx, void *hash, unsigned int *size) +{ + (ctx->md->final)(hash, ctx->ptr); + if (size) + *size = ctx->md->hash_size; + return 1; +} + +/** + * Do the whole EVP_MD_CTX_create(), EVP_DigestInit_ex(), + * EVP_DigestUpdate(), EVP_DigestFinal_ex(), EVP_MD_CTX_destroy() + * dance in one call. + * + * @param data the data to update the context with + * @param dsize length of data + * @param hash output data of at least EVP_MD_size() length. + * @param hsize output length of hash. + * @param md message digest to use + * @param engine engine to use, NULL for default engine. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_Digest(const void *data, size_t dsize, void *hash, unsigned int *hsize, + const EVP_MD *md, ENGINE *engine) +{ + EVP_MD_CTX *ctx; + int ret; + + ctx = EVP_MD_CTX_create(); + if (ctx == NULL) + return 0; + ret = EVP_DigestInit_ex(ctx, md, engine); + if (ret != 1) { + EVP_MD_CTX_destroy(ctx); + return ret; + } + ret = EVP_DigestUpdate(ctx, data, dsize); + if (ret != 1) { + EVP_MD_CTX_destroy(ctx); + return ret; + } + ret = EVP_DigestFinal_ex(ctx, hash, hsize); + EVP_MD_CTX_destroy(ctx); + return ret; +} + +/** + * The message digest SHA256 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha256(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha256); +} + +/** + * The message digest SHA384 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha384(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha384); +} + +/** + * The message digest SHA512 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha512(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha512); +} + +/** + * The message digest SHA1 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha1(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, sha1); +} + +/** + * The message digest SHA1 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_sha(void) HC_DEPRECATED + +{ + hcrypto_validate(); + return EVP_sha1(); +} + +/** + * The message digest MD5 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_md5(void) HC_DEPRECATED_CRYPTO +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, md5); +} + +/** + * The message digest MD4 + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_md4(void) HC_DEPRECATED_CRYPTO +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, md4); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, md4); +} + +/* + * + */ + +static int +null_Init (void *m) +{ + return 1; +} +static int +null_Update (void *m, const void * data, size_t size) +{ + return 1; +} +static int +null_Final(void *res, void *m) +{ + return 1; +} + +/** + * The null message digest + * + * @return the message digest type. + * + * @ingroup hcrypto_evp + */ + +const EVP_MD * +EVP_md_null(void) +{ + static const struct hc_evp_md null = { + 0, + 0, + 0, + (hc_evp_md_init)null_Init, + (hc_evp_md_update)null_Update, + (hc_evp_md_final)null_Final, + NULL + }; + return &null; +} + +/** + * Return the block size of the cipher. + * + * @param c cipher to get the block size from. + * + * @return the block size of the cipher. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_block_size(const EVP_CIPHER *c) +{ + return c->block_size; +} + +/** + * Return the key size of the cipher. + * + * @param c cipher to get the key size from. + * + * @return the key size of the cipher. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_key_length(const EVP_CIPHER *c) +{ + return c->key_len; +} + +/** + * Return the IV size of the cipher. + * + * @param c cipher to get the IV size from. + * + * @return the IV size of the cipher. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_iv_length(const EVP_CIPHER *c) +{ + return c->iv_len; +} + +/** + * Initiate a EVP_CIPHER_CTX context. Clean up with + * EVP_CIPHER_CTX_cleanup(). + * + * @param c the cipher initiate. + * + * @ingroup hcrypto_evp + */ + +void +EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *c) +{ + memset(c, 0, sizeof(*c)); +} + +/** + * Clean up the EVP_CIPHER_CTX context. + * + * @param c the cipher to clean up. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) +{ + if (c->cipher && c->cipher->cleanup) { + int ret = c->cipher->cleanup(c); + if (!ret) + return ret; + } + if (c->cipher_data) { + if (c->cipher) + memset_s(c->cipher_data, c->cipher->ctx_size, 0, c->cipher->ctx_size); + free(c->cipher_data); + c->cipher_data = NULL; + } + return 1; +} + +/** + * If the cipher type supports it, change the key length + * + * @param c the cipher context to change the key length for + * @param length new key length + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int length) +{ + if ((c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH) && length > 0) { + c->key_len = length; + return 1; + } + return 0; +} + +#if 0 +int +EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad) +{ + return 0; +} +#endif + +/** + * Return the EVP_CIPHER for a EVP_CIPHER_CTX context. + * + * @param ctx the context to get the cipher type from. + * + * @return the EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_CIPHER_CTX_cipher(EVP_CIPHER_CTX *ctx) +{ + return ctx->cipher; +} + +/** + * Return the block size of the cipher context. + * + * @param ctx cipher context to get the block size from. + * + * @return the block size of the cipher context. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_block_size(ctx->cipher); +} + +/** + * Return the key size of the cipher context. + * + * @param ctx cipher context to get the key size from. + * + * @return the key size of the cipher context. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_key_length(ctx->cipher); +} + +/** + * Return the IV size of the cipher context. + * + * @param ctx cipher context to get the IV size from. + * + * @return the IV size of the cipher context. + * + * @ingroup hcrypto_evp + */ + +size_t +EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_iv_length(ctx->cipher); +} + +/** + * Get the flags for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to get the flags from + * + * @return the flags for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +unsigned long +EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx) +{ + return ctx->cipher->flags; +} + +/** + * Get the mode for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to get the mode from + * + * @return the mode for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_MODE; +} + +/** + * Get the app data for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to get the app data from + * + * @return the app data for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +void * +EVP_CIPHER_CTX_get_app_data(EVP_CIPHER_CTX *ctx) +{ + return ctx->app_data; +} + +/** + * Set the app data for an EVP_CIPHER_CTX context. + * + * @param ctx the EVP_CIPHER_CTX to set the app data for + * @param data the app data to set for an EVP_CIPHER_CTX. + * + * @ingroup hcrypto_evp + */ + +void +EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data) +{ + ctx->app_data = data; +} + +/** + * Initiate the EVP_CIPHER_CTX context to encrypt or decrypt data. + * Clean up with EVP_CIPHER_CTX_cleanup(). + * + * @param ctx context to initiate + * @param c cipher to use. + * @param engine crypto engine to use, NULL to select default. + * @param key the crypto key to use, NULL will use the previous value. + * @param iv the IV to use, NULL will use the previous value. + * @param encp non zero will encrypt, -1 use the previous value. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *c, ENGINE *engine, + const void *key, const void *iv, int encp) +{ + ctx->buf_len = 0; + + if (encp == -1) + encp = ctx->encrypt; + else + ctx->encrypt = (encp ? 1 : 0); + + if (c && (c != ctx->cipher)) { + EVP_CIPHER_CTX_cleanup(ctx); + ctx->cipher = c; + ctx->key_len = c->key_len; + + ctx->cipher_data = calloc(1, c->ctx_size); + if (ctx->cipher_data == NULL && c->ctx_size != 0) + return 0; + + /* assume block size is a multiple of 2 */ + ctx->block_mask = EVP_CIPHER_block_size(c) - 1; + + if ((ctx->cipher->flags & EVP_CIPH_CTRL_INIT) && + !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) + return 0; + + } else if (ctx->cipher == NULL) { + /* reuse of cipher, but not any cipher ever set! */ + return 0; + } + + switch (EVP_CIPHER_CTX_mode(ctx)) { + case EVP_CIPH_CBC_MODE: + + assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv)); + + if (iv) + memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); + break; + + case EVP_CIPH_STREAM_CIPHER: + break; + case EVP_CIPH_CFB8_MODE: + if (iv) + memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + break; + + default: + return 0; + } + + if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) + return ctx->cipher->init(ctx, key, iv, encp); + + return 1; +} + +/** + * Encipher/decipher partial data + * + * @param ctx the cipher context. + * @param out output data from the operation. + * @param outlen output length + * @param in input data to the operation. + * @param inlen length of data. + * + * The output buffer length should at least be EVP_CIPHER_block_size() + * byte longer then the input length. + * + * See @ref evp_cipher for an example how to use this function. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, void *out, int *outlen, + void *in, size_t inlen) +{ + int ret, left, blocksize; + + *outlen = 0; + + /* + * If there in no bytes left over from the last Update and the + * input length is on a block boundary, then we can take a + * shortcut (and preformance gain) and directly encrypt the + * data. + */ + if (ctx->buf_len == 0 && inlen && (inlen & ctx->block_mask) == 0) { + ret = (*ctx->cipher->do_cipher)(ctx, out, in, inlen); + if (ret == 1) + *outlen = inlen; + else + *outlen = 0; + return ret; + } + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + left = blocksize - ctx->buf_len; + assert(left > 0); + + if (ctx->buf_len) { + /* If we can't fill one block in the buffer, save the input there */ + if (inlen < left) { + memcpy(ctx->buf + ctx->buf_len, in, inlen); + ctx->buf_len += inlen; + return 1; + } + + /* Fill the buffer and encrypt */ + memcpy(ctx->buf + ctx->buf_len, in, left); + ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); + memset_s(ctx->buf, blocksize, 0, blocksize); + if (ret != 1) + return ret; + + *outlen += blocksize; + inlen -= left; + in = ((unsigned char *)in) + left; + out = ((unsigned char *)out) + blocksize; + ctx->buf_len = 0; + } + + if (inlen) { + ctx->buf_len = (inlen & ctx->block_mask); + inlen &= ~ctx->block_mask; + + if (inlen) { + /* Encrypt all the whole blocks of input that we have */ + ret = (*ctx->cipher->do_cipher)(ctx, out, in, inlen); + if (ret != 1) + return ret; + } + + *outlen += inlen; + + /* Save the tail of the input, if any */ + in = ((unsigned char *)in) + inlen; + memcpy(ctx->buf, in, ctx->buf_len); + } + + return 1; +} + +/** + * Encipher/decipher final data + * + * @param ctx the cipher context. + * @param out output data from the operation. + * @param outlen output length + * + * The input length needs to be at least EVP_CIPHER_block_size() bytes + * long. + * + * See @ref evp_cipher for an example how to use this function. + * + * @return 1 on success. + * + * @ingroup hcrypto_evp + */ + +int +EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, void *out, int *outlen) +{ + *outlen = 0; + + if (ctx->buf_len) { + int ret, left, blocksize; + + blocksize = EVP_CIPHER_CTX_block_size(ctx); + + left = blocksize - ctx->buf_len; + assert(left > 0); + + /* zero fill local buffer */ + memset(ctx->buf + ctx->buf_len, 0, left); + ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); + memset_s(ctx->buf, blocksize, 0, blocksize); + if (ret != 1) + return ret; + + *outlen += blocksize; + } + + return 1; +} + +/** + * Encipher/decipher data + * + * @param ctx the cipher context. + * @param out out data from the operation. + * @param in in data to the operation. + * @param size length of data. + * + * @return bytes encrypted on success, zero on failure. + */ + +int +EVP_Cipher(EVP_CIPHER_CTX *ctx, void *out, const void *in,size_t size) +{ + return ctx->cipher->do_cipher(ctx, out, in, size); +} + +/* + * + */ + +static int +enc_null_init(EVP_CIPHER_CTX *ctx, + const unsigned char * key, + const unsigned char * iv, + int encp) +{ + return 1; +} + +static int +enc_null_do_cipher(EVP_CIPHER_CTX *ctx, + unsigned char *out, + const unsigned char *in, + unsigned int size) +{ + memmove(out, in, size); + return 1; +} + +static int +enc_null_cleanup(EVP_CIPHER_CTX *ctx) +{ + return 1; +} + +/** + * The NULL cipher type, does no encryption/decryption. + * + * @return the null EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_enc_null(void) +{ + static const EVP_CIPHER enc_null = { + 0, + 0, + 0, + 0, + EVP_CIPH_CBC_MODE, + enc_null_init, + enc_null_do_cipher, + enc_null_cleanup, + 0, + NULL, + NULL, + NULL, + NULL + }; + return &enc_null; +} + +/** + * The RC2 cipher type + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc2_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc2_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc2_cbc); +} + +/** + * The RC2 cipher type + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc2_40_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc2_40_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc2_40_cbc); +} + +/** + * The RC2 cipher type + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc2_64_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc2_64_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc2_64_cbc); +} + +/** + * The RC4 cipher type + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc4(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc4); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc4); +} + +/** + * The RC4-40 cipher type + * + * @return the RC4-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_rc4_40(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, rc4_40); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, rc4_40); +} + +/** + * The DES cipher type + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_des_cbc(void) +{ + hcrypto_validate(); +#if defined(HCRYPTO_DEF_PROVIDER_IS_OPENSSL) && defined(HAVE_OPENSSL_30) +#if defined(HAVE_OPENSSL_FIPS_H) || defined(HAVE_OPENSSL_FIPS_MODE_SET_API) + if (_heim_openssl_fips_enabled()) + return NULL; +#endif + return EVP_DEF_OP(hcrypto, des_cbc); +#endif + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, des_cbc); +} + +/** + * The triple DES cipher type + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_des_ede3_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, des_ede3_cbc); +} + +/** + * The AES-128 cipher type + * + * @return the AES-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_128_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_128_cbc); +} + +/** + * The AES-192 cipher type + * + * @return the AES-192 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_192_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_192_cbc); +} + +/** + * The AES-256 cipher type + * + * @return the AES-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_256_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_256_cbc); +} + +/** + * The AES-128 cipher type + * + * @return the AES-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_128_cfb8(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_128_cfb8); +} + +/** + * The AES-192 cipher type + * + * @return the AES-192 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_192_cfb8(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_192_cfb8); +} + +/** + * The AES-256 cipher type + * + * @return the AES-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_aes_256_cfb8(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, aes_256_cfb8); +} + +/** + * The Camellia-128 cipher type + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_camellia_128_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, camellia_128_cbc); +} + +/** + * The Camellia-198 cipher type + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_camellia_192_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, camellia_192_cbc); +} + +/** + * The Camellia-256 cipher type + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_camellia_256_cbc(void) +{ + hcrypto_validate(); + return EVP_DEF_OP(HCRYPTO_DEF_PROVIDER, camellia_256_cbc); +} + +/* + * + */ + +static const struct cipher_name { + const char *name; + const EVP_CIPHER *(*func)(void); +} cipher_name[] = { + { "des-ede3-cbc", EVP_des_ede3_cbc }, + { "aes-128-cbc", EVP_aes_128_cbc }, + { "aes-192-cbc", EVP_aes_192_cbc }, + { "aes-256-cbc", EVP_aes_256_cbc }, + { "aes-128-cfb8", EVP_aes_128_cfb8 }, + { "aes-192-cfb8", EVP_aes_192_cfb8 }, + { "aes-256-cfb8", EVP_aes_256_cfb8 }, + { "camellia-128-cbc", EVP_camellia_128_cbc }, + { "camellia-192-cbc", EVP_camellia_192_cbc }, + { "camellia-256-cbc", EVP_camellia_256_cbc } +}; + +/** + * Get the cipher type using their name. + * + * @param name the name of the cipher. + * + * @return the selected EVP_CIPHER pointer or NULL if not found. + * + * @ingroup hcrypto_evp + */ + +const EVP_CIPHER * +EVP_get_cipherbyname(const char *name) +{ + int i; + for (i = 0; i < sizeof(cipher_name)/sizeof(cipher_name[0]); i++) { + if (strcasecmp(cipher_name[i].name, name) == 0) + return (*cipher_name[i].func)(); + } + return NULL; +} + + +/* + * + */ + +#ifndef min +#define min(a,b) (((a)>(b))?(b):(a)) +#endif + +/** + * Provides a legancy string to key function, used in PEM files. + * + * New protocols should use new string to key functions like NIST + * SP56-800A or PKCS#5 v2.0 (see PKCS5_PBKDF2_HMAC_SHA1()). + * + * @param type type of cipher to use + * @param md message digest to use + * @param salt salt salt string, should be an binary 8 byte buffer. + * @param data the password/input key string. + * @param datalen length of data parameter. + * @param count iteration counter. + * @param keydata output keydata, needs to of the size EVP_CIPHER_key_length(). + * @param ivdata output ivdata, needs to of the size EVP_CIPHER_block_size(). + * + * @return the size of derived key. + * + * @ingroup hcrypto_evp + */ + +int +EVP_BytesToKey(const EVP_CIPHER *type, + const EVP_MD *md, + const void *salt, + const void *data, size_t datalen, + unsigned int count, + void *keydata, + void *ivdata) +{ + unsigned int ivlen, keylen; + int first = 0; + unsigned int mds = 0, i; + unsigned char *key = keydata; + unsigned char *iv = ivdata; + unsigned char *buf; + EVP_MD_CTX c; + + keylen = EVP_CIPHER_key_length(type); + ivlen = EVP_CIPHER_iv_length(type); + + if (data == NULL) + return keylen; + + buf = malloc(EVP_MD_size(md)); + if (buf == NULL) + return -1; + + EVP_MD_CTX_init(&c); + + first = 1; + while (1) { + EVP_DigestInit_ex(&c, md, NULL); + if (!first) + EVP_DigestUpdate(&c, buf, mds); + first = 0; + EVP_DigestUpdate(&c,data,datalen); + +#define PKCS5_SALT_LEN 8 + + if (salt) + EVP_DigestUpdate(&c, salt, PKCS5_SALT_LEN); + + EVP_DigestFinal_ex(&c, buf, &mds); + assert(mds == EVP_MD_size(md)); + + for (i = 1; i < count; i++) { + EVP_DigestInit_ex(&c, md, NULL); + EVP_DigestUpdate(&c, buf, mds); + EVP_DigestFinal_ex(&c, buf, &mds); + assert(mds == EVP_MD_size(md)); + } + + i = 0; + if (keylen) { + size_t sz = min(keylen, mds); + if (key) { + memcpy(key, buf, sz); + key += sz; + } + keylen -= sz; + i += sz; + } + if (ivlen && mds > i) { + size_t sz = min(ivlen, (mds - i)); + if (iv) { + memcpy(iv, &buf[i], sz); + iv += sz; + } + ivlen -= sz; + } + if (keylen == 0 && ivlen == 0) + break; + } + + EVP_MD_CTX_cleanup(&c); + free(buf); + + return EVP_CIPHER_key_length(type); +} + +/** + * Generate a random key for the specificed EVP_CIPHER. + * + * @param ctx EVP_CIPHER_CTX type to build the key for. + * @param key return key, must be at least EVP_CIPHER_key_length() byte long. + * + * @return 1 for success, 0 for failure. + * + * @ingroup hcrypto_core + */ + +int +EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, void *key) +{ + if (ctx->cipher->flags & EVP_CIPH_RAND_KEY) + return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key); + if (RAND_bytes(key, ctx->key_len) != 1) + return 0; + return 1; +} + +/** + * Perform a operation on a ctx + * + * @param ctx context to perform operation on. + * @param type type of operation. + * @param arg argument to operation. + * @param data addition data to operation. + + * @return 1 for success, 0 for failure. + * + * @ingroup hcrypto_core + */ + +int +EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *data) +{ + if (ctx->cipher == NULL || ctx->cipher->ctrl == NULL) + return 0; + return (*ctx->cipher->ctrl)(ctx, type, arg, data); +} + +/** + * Add all algorithms to the crypto core. + * + * @ingroup hcrypto_core + */ + +void +OpenSSL_add_all_algorithms(void) +{ + return; +} + +/** + * Add all algorithms to the crypto core using configuration file. + * + * @ingroup hcrypto_core + */ + +void +OpenSSL_add_all_algorithms_conf(void) +{ + return; +} + +/** + * Add all algorithms to the crypto core, but don't use the + * configuration file. + * + * @ingroup hcrypto_core + */ + +void +OpenSSL_add_all_algorithms_noconf(void) +{ + return; +} |