/* * Copyright (c) 2011-12 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 2006 - 2008 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. */ #include "ossl-config.h" #include #include #include #include #include #include "ossl-evp.h" #include "ossl-objects.h" #include "ossl-evp-cc.h" #include "ossl-ui.h" #ifdef HAVE_COMMONCRYPTO_COMMONRANDOMSPI_H #include #endif #include "krb5-types.h" #ifndef OSSL_DEF_PROVIDER #define OSSL_DEF_PROVIDER cc #endif #define OSSL_CONCAT4(x, y, z, aa) x ## y ## z ## aa #define EVP_DEF_OP(_prov, _op) OSSL_CONCAT4(EVP_, _prov, _, _op) () /** * @page page_evp EVP - generic crypto interface * * @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(). */ /** * Return the output size of the message digest function. * * @param md the evp message * * @return size output size of the message digest function. */ 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 */ 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. */ 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. */ void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(*ctx)); } /** * Free a messsage digest context object. * * @param ctx context to free. */ 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. */ int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) { if (ctx->md && ctx->md->cleanup) { (ctx->md->cleanup)(ctx); } else if (ctx->md) { memset(ctx->ptr, 0, ctx->md->ctx_size); } ctx->md = NULL; ctx->engine = NULL; free(ctx->ptr); memset(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. */ 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. */ 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 */ size_t EVP_MD_CTX_block_size(EVP_MD_CTX *ctx) { return (EVP_MD_block_size(ctx->md)); } int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) { if ((NULL == in) || (NULL == in->md)) { /* EVPerr */ return (0); } EVP_MD_CTX_cleanup(out); memcpy(out, in, sizeof(*out)); if (out->md->ctx_size) { out->ptr = malloc(in->md->ctx_size); if (!out->ptr) { /* EVPerr */ return (0); } memcpy(out->ptr, in->ptr, out->md->ctx_size); } if (out->engine) { ENGINE_up_ref(out->engine); } /* * if (out->md->copy) * return out->md->copy(out, in); */ return (1); } /** * 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. */ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, ENGINE *engine) { if (NULL == ctx) return (0); if ((ctx->md != md) || (ctx->engine != engine)) { EVP_MD_CTX_cleanup(ctx); ctx->md = md; ctx->engine = engine; ctx->ptr = calloc(1, md->ctx_size); if (ctx->ptr == NULL) { return (0); } } (ctx->md->init)(ctx->ptr); return (1); } int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *md) { if (ctx) { EVP_MD_CTX_init(ctx); } return (EVP_DigestInit_ex(ctx, md, NULL)); } /** * 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. */ 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. */ 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); } int EVP_DigestFinal(EVP_MD_CTX *ctx, void *hash, unsigned int *size) { int rv = EVP_DigestFinal_ex(ctx, hash, size); EVP_MD_CTX_cleanup(ctx); return (rv); } /** * 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. */ 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; EVP_MD_CTX_init(&ctx); ret = EVP_DigestInit_ex(&ctx, md, engine) && EVP_DigestUpdate(&ctx, data, dsize) && EVP_DigestFinal_ex(&ctx, hash, hsize); EVP_MD_CTX_cleanup(&ctx); return (ret); } /** * The message digest rmd128 * * @return the message digest type. */ const EVP_MD * EVP_rmd128(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rmd128)); } const EVP_MD * EVP_ripemd128(void) { return (EVP_rmd128()); } /** * The message digest rmd160 * * @return the message digest type. */ const EVP_MD * EVP_rmd160(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rmd160)); } const EVP_MD * EVP_ripemd160(void) { return (EVP_rmd160()); } /** * The message digest rmd256 * * @return the message digest type. */ const EVP_MD * EVP_rmd256(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rmd256)); } const EVP_MD * EVP_ripemd256(void) { return (EVP_rmd256()); } /** * The message digest rmd320 * * @return the message digest type. */ const EVP_MD * EVP_rmd320(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rmd320)); } const EVP_MD * EVP_ripemd320(void) { return (EVP_rmd320()); } /** * The message digest sha224 * * @return the message digest type. */ const EVP_MD * EVP_sha224(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, sha224)); } /** * The message digest SHA256 * * @return the message digest type. */ const EVP_MD * EVP_sha256(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, sha256)); } /** * The message digest SHA384 * * @return the message digest type. */ const EVP_MD * EVP_sha384(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, sha384)); } /** * The message digest SHA512 * * @return the message digest type. */ const EVP_MD * EVP_sha512(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, sha512)); } /** * The message digest SHA1 * * @return the message digest type. */ const EVP_MD * EVP_sha1(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, sha1)); } /** * The message digest SHA1 * * @return the message digest type. */ const EVP_MD * EVP_sha(void) { return (EVP_sha1()); } /** * The message digest MD5 * * @return the message digest type. */ const EVP_MD * EVP_md5(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, md5)); } /** * The message digest MD4 * * @return the message digest type. */ const EVP_MD * EVP_md4(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, md4)); } /** * The message digest MD2 * * @return the message digest type. */ const EVP_MD * EVP_md2(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, md2)); } /* * Null MD */ static void null_Init(void *m) { } static void null_Update(void *m, const void *data, size_t size) { } static void null_Final(void *res, void *m) { } /** * The null message digest * * @return the message digest type. * * @ingroup hcrypto_evp */ const EVP_MD * EVP_md_null(void) { static const struct ossl_evp_md null = { .hash_size = 0, .block_size = 0, .ctx_size = 0, .init = (ossl_evp_md_init)null_Init, .update = (ossl_evp_md_update)null_Update, .final = (ossl_evp_md_final)null_Final, .cleanup = NULL }; return (&null); } const EVP_MD * EVP_get_digestbynid(int nid) { switch (nid) { case NID_md2: return (EVP_md2()); case NID_md4: return (EVP_md4()); case NID_md5: return (EVP_md5()); case NID_sha1: return (EVP_sha1()); case NID_sha256: return (EVP_sha256()); case NID_sha384: return (EVP_sha384()); case NID_sha512: return (EVP_sha512()); default: return (NULL); } } int EVP_CIPHER_nid(const EVP_CIPHER *c) { return (c->nid); } /** * Return the block size of the cipher. * * @param c cipher to get the block size from. * * @return the block size of the cipher. */ 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. */ 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. */ 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. */ 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. */ int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) { if (c->cipher) { if (c->cipher->cleanup) { c->cipher->cleanup(c); } if (c->cipher_data) { memset(c->cipher_data, 0, c->cipher->ctx_size); free(c->cipher_data); c->cipher_data = NULL; } EVP_CIPHER_CTX_init(c); } 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. */ 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. */ 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. */ 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. */ size_t EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) { /* return EVP_CIPHER_key_length(ctx->cipher); */ return (ctx->key_len); } /** * 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ 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; } 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_ECB_MODE: case EVP_CIPH_STREAM_CIPHER: 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)) { ctx->cipher->init(ctx, key, iv, encp); } return (1); } int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *c, const void *key, const void *iv, int encp) { return (EVP_CipherInit_ex(ctx, c, NULL, key, iv, encp)); } /** * 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. */ 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 spare bytes in the left from last Update and the * input length is on the block boundery, the EVP_CipherUpdate() * function can take a shortcut (and preformance gain) and * directly encrypt the data, otherwise we hav to fix it up and * store extra it the EVP_CIPHER_CTX. */ if ((ctx->buf_len == 0) && ((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 total buffer is smaller then input, store locally */ if (inlen < left) { memcpy(ctx->buf + ctx->buf_len, in, inlen); ctx->buf_len += inlen; return (1); } /* fill in local buffer and encrypt */ memcpy(ctx->buf + ctx->buf_len, in, left); ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); memset(ctx->buf, 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; ret = (*ctx->cipher->do_cipher)(ctx, out, in, inlen); if (ret != 1) { return (ret); } *outlen += inlen; 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. */ int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, void *out, int *outlen) { *outlen = 0; // Love say to always output a block even if we have ctx->buf_len is 0... that is a whole block of pad bytes. int ret, left, blocksize; blocksize = EVP_CIPHER_CTX_block_size(ctx); if (blocksize == 1) { *outlen = 0; return (1); } left = blocksize - ctx->buf_len; assert(left > 0); /* zero fill local buffer */ // use PKCS11 padding with pad value of number of pad byes. memset(ctx->buf + ctx->buf_len, left, left); ret = (*ctx->cipher->do_cipher)(ctx, out, ctx->buf, blocksize); memset(ctx->buf, 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. */ 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 = { .nid = 0, .block_size = 0, .key_len = 0, .iv_len = 0, .flags = EVP_CIPH_CBC_MODE, .init = enc_null_init, .do_cipher = enc_null_do_cipher, .cleanup = enc_null_cleanup, .ctx_size = 0, .set_asn1_parameters = NULL, .get_asn1_parameters = NULL, .ctrl = NULL, .app_data = NULL }; return (&enc_null); } /** * The RC2 cipher type * * @return the RC2 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_rc2_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rc2_cbc)); } /** * The RC2 cipher type * * @return the RC2 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_rc2_40_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rc2_40_cbc)); } /** * The RC2 cipher type * * @return the RC2 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_rc2_64_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rc2_64_cbc)); } /** * The RC4 cipher type * * @return the RC4 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_rc4(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rc4)); } /** * The RC4-40 cipher type * * @return the RC4-40 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_rc4_40(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, rc4_40)); } /** * The DES cipher type * * @return the DES-ECB EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_des_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, des_ecb)); } /** * The DES cipher type * * @return the DES-CBC EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_des_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, des_cbc)); } /** * The tripple DES cipher type * * @return the DES-EDE3-CBC EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_des_ede3_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, des_ede3_cbc)); } /** * The tripple DES cipher type * * @return the DES-EDE3-ECB EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_des_ede3_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, des_ede3_ecb)); } /** * The AES-128 cipher type * * @return the AES-128 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_128_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_128_cbc)); } /** * The AES-128 cipher type * * @return the AES-128 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_128_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_128_ecb)); } /** * The AES-192 cipher type * * @return the AES-192 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_192_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_192_cbc)); } /** * The AES-192 cipher type * * @return the AES-192 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_192_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_192_ecb)); } /** * The AES-256 cipher type * * @return the AES-256 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_256_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_256_cbc)); } /** * The AES-256 cipher type * * @return the AES-256 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_256_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_256_ecb)); } /** * The AES-128 CFB8 cipher type * * @return the AES-128 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_aes_128_cfb8(void) { #ifndef __APPLE_TARGET_EMBEDDED__ return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_128_cfb8)); #else return (NULL); #endif } /** * The AES-192 CFB8 cipher type * * @return the AES-192 EVP_CIPHER pointer. * * @ingroup hcrypto_evp */ const EVP_CIPHER * EVP_aes_192_cfb8(void) { #ifndef __APPLE_TARGET_EMBEDDED__ return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_192_cfb8)); #else return (NULL); #endif } /** * The AES-256 CFB8 cipher type * * @return the AES-256 EVP_CIPHER pointer. * * @ingroup hcrypto_evp */ const EVP_CIPHER * EVP_aes_256_cfb8(void) { #ifndef __APPLE_TARGET_EMBEDDED__ return (EVP_DEF_OP(OSSL_DEF_PROVIDER, aes_256_cfb8)); #else return (NULL); #endif } /** * The Camellia-128 cipher type * * @return the Camellia-128 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_camellia_128_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, camellia_128_cbc)); } /** * The Camellia-198 cipher type * * @return the Camellia-198 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_camellia_192_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, camellia_192_cbc)); } /** * The Camellia-256 cipher type * * @return the Camellia-256 EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_camellia_256_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, camellia_256_cbc)); } /** * The blowfish ecb cipher type * * @return the bf_ecb EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_bf_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, bf_ecb)); } /** * The blowfish cbc cipher type * * @return the bf_ecb EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_bf_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, bf_cbc)); } /** * The cast5 ecb cipher type * * @return the bf_ecb EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_cast5_ecb(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, cast5_ecb)); } /** * The cast5 cbc cipher type * * @return the bf_ecb EVP_CIPHER pointer. */ const EVP_CIPHER * EVP_cast5_cbc(void) { return (EVP_DEF_OP(OSSL_DEF_PROVIDER, cast5_cbc)); } /* * */ static const struct cipher_name { const char * name; const EVP_CIPHER * (*func)(void); } cipher_name[] = { { "des-ecb", EVP_des_ecb }, { "des-cbc", EVP_des_cbc }, { "des-ede3-ecb", EVP_des_ede3_ecb }, { "des-ede3-cbc", EVP_des_ede3_cbc }, { "aes-128-ecb", EVP_aes_128_ecb }, { "aes-192-ecb", EVP_aes_192_ecb }, { "aes-256-ecb", EVP_aes_256_ecb }, { "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 }, { "bf-ecb", EVP_bf_ecb }, { "bf-cbc", EVP_bf_cbc }, { "cast5-ecb", EVP_cast5_ecb }, { "cast5-cbc", EVP_cast5_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. */ 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)); } static char prompt_string[80]; void EVP_set_pw_prompt(const char *prompt) { if (prompt == NULL) { prompt_string[0] = '\0'; } else { strncpy(prompt_string, prompt, 79); prompt_string[79] = '\0'; } } char * EVP_get_pw_prompt(void) { if (prompt_string[0] == '\0') { return (NULL); } else{ return (prompt_string); } } int EVP_read_pw_string(char *buf, int len, const char *prompt, int verify) { if ((prompt == NULL) && (prompt_string[0] != '\0')) { prompt = prompt_string; } return (UI_UTIL_read_pw_string(buf, len, prompt, verify)); } /** * 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. */ 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 (CCRandomCopyBytes(kCCRandomDefault, key, ctx->key_len) != 0) { 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. */ 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)); } static void ossl_EVP_PKEY_free_it(EVP_PKEY *x); #define EVP_PKEY_assign_RSA(pkey, rsa) EVP_PKEY_assign((pkey), EVP_PKEY_RSA, (char *)(rsa)) #define EVP_PKEY_assign_DSA(pkey, dsa) EVP_PKEY_assign((pkey), EVP_PKEY_DSA, (char *)(dsa)) #define EVP_PKEY_assign_DH(pkey, dh) EVP_PKEY_assign((pkey), EVP_PKEY_DH, (char *)(dh)) int EVP_PKEY_assign(EVP_PKEY *pkey, int type, char *key) { if (pkey == NULL) { return (0); } if (pkey->pkey.ptr != NULL) { ossl_EVP_PKEY_free_it(pkey); } pkey->type = EVP_PKEY_type(type); pkey->save_type = type; pkey->pkey.ptr = key; return (key != NULL); } RSA * EVP_PKEY_get1_RSA(EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_RSA) { return (NULL); } RSA_up_ref(pkey->pkey.rsa); return (pkey->pkey.rsa); } int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) { int ret = EVP_PKEY_assign_RSA(pkey, key); if (ret) { RSA_up_ref(key); } return (ret); } DSA * EVP_PKEY_get1_DSA(EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_DSA) { return (NULL); } DSA_up_ref(pkey->pkey.dsa); return (pkey->pkey.dsa); } int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) { int ret = EVP_PKEY_assign_DSA(pkey, key); if (ret) { DSA_up_ref(key); } return (ret); } int EVP_PKEY_type(int type) { switch (type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: return (EVP_PKEY_RSA); case EVP_PKEY_DSA: case EVP_PKEY_DSA1: case EVP_PKEY_DSA2: case EVP_PKEY_DSA3: case EVP_PKEY_DSA4: return (EVP_PKEY_DSA); case EVP_PKEY_DH: return (EVP_PKEY_DH); default: return (NID_undef); } } EVP_PKEY * EVP_PKEY_new(void) { EVP_PKEY *ret = (EVP_PKEY *)malloc(sizeof(EVP_PKEY)); if (ret == NULL) { /* EVPerr(EVP_F_EVP_PKEY_NEW,ERR_R_MALLOC_FAILURE); */ return (NULL); } ret->type = EVP_PKEY_NONE; ret->references = 1; ret->pkey.ptr = NULL; #if 0 ret->attributes = NULL; #endif ret->save_parameters = 1; return (ret); } static void ossl_EVP_PKEY_free_it(EVP_PKEY *x) { switch (x->type) { case EVP_PKEY_RSA: case EVP_PKEY_RSA2: if (x->pkey.rsa) { RSA_free(x->pkey.rsa); } break; case EVP_PKEY_DSA: case EVP_PKEY_DSA2: case EVP_PKEY_DSA3: case EVP_PKEY_DSA4: if (x->pkey.dsa) { DSA_free(x->pkey.dsa); } break; case EVP_PKEY_DH: if (x->pkey.dh) { DH_free(x->pkey.dh); } break; } } void EVP_PKEY_free(EVP_PKEY *x) { int i; if (x == NULL) { return; } /* XXX not thread safe. */ x->references--; if (i > 0) { return; } ossl_EVP_PKEY_free_it(x); #if 0 if (x->attributes) { sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free); } #endif free(x); } /* * */ #define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f]) #define conv_ascii2bin(a) (data_ascii2bin[(a) & 0x7f]) /* 64 char lines * pad input with 0 * left over chars are set to = * 1 byte => xx== * 2 bytes => xxx= * 3 bytes => xxxx */ #define BIN_PER_LINE (64 / 4 * 3) #define CHUNKS_PER_LINE (64 / 4) #define CHAR_PER_LINE (64 + 1) static unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ abcdefghijklmnopqrstuvwxyz0123456789+/"; /* 0xF0 is a EOLN * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). * 0xF2 is EOF * 0xE0 is ignore at start of line. * 0xFF is error */ #define B64_EOLN 0xF0 #define B64_CR 0xF1 #define B64_EOF 0xF2 #define B64_WS 0xE0 #define B64_ERROR 0xFF #define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3) static unsigned char data_ascii2bin[128] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) { ctx->length = 48; ctx->num = 0; ctx->line_num = 0; } void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) { int i, j; unsigned int total = 0; *outl = 0; if (inl == 0) { return; } /* assert(ctx->length <= (int)sizeof(ctx->enc_data)); */ if ((ctx->num+inl) < ctx->length) { memcpy(&(ctx->enc_data[ctx->num]), in, inl); ctx->num += inl; return; } if (ctx->num != 0) { i = ctx->length-ctx->num; memcpy(&(ctx->enc_data[ctx->num]), in, i); in += i; inl -= i; j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); ctx->num = 0; out += j; *(out++) = '\n'; *out = '\0'; total = j + 1; } while (inl >= ctx->length) { j = EVP_EncodeBlock(out, in, ctx->length); in += ctx->length; inl -= ctx->length; out += j; *(out++) = '\n'; *out = '\0'; total += j + 1; } if (inl != 0) { memcpy(&(ctx->enc_data[0]), in, inl); } ctx->num = inl; *outl = total; } void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) { unsigned int ret = 0; if (ctx->num != 0) { ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); out[ret++] = '\n'; out[ret] = '\0'; ctx->num = 0; } *outl = ret; } int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen) { int i, ret = 0; unsigned long l; for (i = dlen; i > 0; i -= 3) { if (i >= 3) { l = (((unsigned long)f[0])<<16L) | (((unsigned long)f[1])<< 8L)|f[2]; *(t++) = conv_bin2ascii(l>>18L); *(t++) = conv_bin2ascii(l>>12L); *(t++) = conv_bin2ascii(l>> 6L); *(t++) = conv_bin2ascii(l); } else { l = ((unsigned long)f[0])<<16L; if (i == 2) { l |= ((unsigned long)f[1] << 8L); } *(t++) = conv_bin2ascii(l>>18L); *(t++) = conv_bin2ascii(l>>12L); *(t++) = (i == 1) ? '=' : conv_bin2ascii(l>>6L); *(t++) = '='; } ret += 4; f += 3; } *t = '\0'; return (ret); } void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) { ctx->length = 30; ctx->num = 0; ctx->line_num = 0; ctx->expect_nl = 0; } /* -1 for error * 0 for last line * 1 for full line */ int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) { int seof = -1, eof = 0, rv = -1, ret = 0, i, v, tmp, n, ln, exp_nl; unsigned char *d; n = ctx->num; d = ctx->enc_data; ln = ctx->line_num; exp_nl = ctx->expect_nl; /* last line of input. */ if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) { rv = 0; goto end; } /* We parse the input data */ for (i = 0; i < inl; i++) { /* If the current line is > 80 characters, scream alot */ if (ln >= 80) { rv = -1; goto end; } /* Get char and put it into the buffer */ tmp = *(in++); v = conv_ascii2bin(tmp); /* only save the good data :-) */ if (!B64_NOT_BASE64(v)) { /* assert(n < (int)sizeof(ctx->enc_data)); */ d[n++] = tmp; ln++; } else if (v == B64_ERROR) { rv = -1; goto end; } /* have we seen a '=' which is 'definitly' the last * input line. seof will point to the character that * holds it. and eof will hold how many characters to * chop off. */ if (tmp == '=') { if (seof == -1) { seof = n; } eof++; } if (v == B64_CR) { ln = 0; if (exp_nl) { continue; } } /* eoln */ if (v == B64_EOLN) { ln = 0; if (exp_nl) { exp_nl = 0; continue; } } exp_nl = 0; /* If we are at the end of input and it looks like a * line, process it. */ if (((i+1) == inl) && (((n&3) == 0) || eof)) { v = B64_EOF; /* In case things were given us in really small * records (so two '=' were given in separate * updates), eof may contain the incorrect number * of ending bytes to skip, so let's redo the count */ eof = 0; if (d[n-1] == '=') { eof++; } if (d[n-2] == '=') { eof++; } /* There will never be more than two '=' */ } if (((v == B64_EOF) && ((n&3) == 0)) || (n >= 64)) { /* This is needed to work correctly on 64 byte input * lines. We process the line and then need to * accept the '\n' */ if ((v != B64_EOF) && (n >= 64)) { exp_nl = 1; } if (n > 0) { v = EVP_DecodeBlock(out, d, n); n = 0; if (v < 0) { rv = 0; goto end; } ret += (v-eof); } else { eof = 1; v = 0; } /* This is the case where we have had a short * but valid input line */ if ((v < ctx->length) && eof) { rv = 0; goto end; } else{ ctx->length = v; } if (seof >= 0) { rv = 0; goto end; } out += v; } } rv = 1; end: *outl = ret; ctx->num = n; ctx->line_num = ln; ctx->expect_nl = exp_nl; return (rv); } int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n) { int i, ret = 0, a, b, c, d; unsigned long l; /* trim white space from the start of the line. */ while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) { f++; n--; } /* strip off stuff at the end of the line * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */ while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n-1])))) { n--; } if (n % 4 != 0) { return (-1); } for (i = 0; i < n; i += 4) { a = conv_ascii2bin(*(f++)); b = conv_ascii2bin(*(f++)); c = conv_ascii2bin(*(f++)); d = conv_ascii2bin(*(f++)); if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) { return (-1); } l = ((((unsigned long)a) << 18L) | (((unsigned long)b) << 12L) | (((unsigned long)c) << 6L) | (((unsigned long)d))); *(t++) = (unsigned char)(l >> 16L) & 0xff; *(t++) = (unsigned char)(l >> 8L) & 0xff; *(t++) = (unsigned char)(l) & 0xff; ret += 3; } return (ret); } int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) { int i; *outl = 0; if (ctx->num != 0) { i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num); if (i < 0) { return (-1); } ctx->num = 0; *outl = i; return (1); } else{ return (1); } }