-# $OpenBSD: Makefile,v 1.159 2023/12/20 13:52:17 tb Exp $
+# $OpenBSD: Makefile,v 1.160 2023/12/29 05:57:24 tb Exp $
LIB= crypto
LIBREBUILD=y
SRCS+= bio_md.c
SRCS+= c_all.c
SRCS+= cipher_method_lib.c
-SRCS+= digest.c
SRCS+= e_aes.c
SRCS+= e_aes_cbc_hmac_sha1.c
SRCS+= e_bf.c
SRCS+= e_rc4_hmac_md5.c
SRCS+= e_sm4.c
SRCS+= e_xcbc_d.c
-SRCS+= encode.c
SRCS+= evp_aead.c
-SRCS+= evp_enc.c
+SRCS+= evp_cipher.c
+SRCS+= evp_digest.c
+SRCS+= evp_encode.c
SRCS+= evp_err.c
SRCS+= evp_key.c
SRCS+= evp_lib.c
+++ /dev/null
-/* $OpenBSD: digest.c,v 1.41 2023/12/24 22:17:05 tb Exp $ */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED 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 OpenSSL PROJECT OR
- * ITS 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.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <openssl/opensslconf.h>
-
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/objects.h>
-
-#include "evp_local.h"
-
-int
-EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
-{
- EVP_MD_CTX_init(ctx);
- return EVP_DigestInit_ex(ctx, type, NULL);
-}
-
-int
-EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
-{
- EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
-
- if (ctx->digest != type) {
- if (ctx->digest && ctx->digest->ctx_size && ctx->md_data &&
- !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
- freezero(ctx->md_data, ctx->digest->ctx_size);
- ctx->md_data = NULL;
- }
- ctx->digest = type;
- if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
- ctx->update = type->update;
- ctx->md_data = calloc(1, type->ctx_size);
- if (ctx->md_data == NULL) {
- EVP_PKEY_CTX_free(ctx->pctx);
- ctx->pctx = NULL;
- EVPerror(ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
- }
- if (ctx->pctx) {
- int r;
- r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
- EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
- if (r <= 0 && (r != -2))
- return 0;
- }
- if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT)
- return 1;
- return ctx->digest->init(ctx);
-}
-
-int
-EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
-{
- return ctx->update(ctx, data, count);
-}
-
-/* The caller can assume that this removes any secret data from the context */
-int
-EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
-{
- int ret;
-
- ret = EVP_DigestFinal_ex(ctx, md, size);
- EVP_MD_CTX_cleanup(ctx);
- return ret;
-}
-
-/* The caller can assume that this removes any secret data from the context */
-int
-EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
-{
- int ret;
-
- if ((size_t)ctx->digest->md_size > EVP_MAX_MD_SIZE) {
- EVPerror(EVP_R_TOO_LARGE);
- return 0;
- }
- ret = ctx->digest->final(ctx, md);
- if (size != NULL)
- *size = ctx->digest->md_size;
- if (ctx->digest->cleanup) {
- ctx->digest->cleanup(ctx);
- EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
- }
- memset(ctx->md_data, 0, ctx->digest->ctx_size);
- return ret;
-}
-
-int
-EVP_Digest(const void *data, size_t count,
- unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl)
-{
- EVP_MD_CTX ctx;
- int ret;
-
- EVP_MD_CTX_init(&ctx);
- EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_ONESHOT);
- ret = EVP_DigestInit_ex(&ctx, type, NULL) &&
- EVP_DigestUpdate(&ctx, data, count) &&
- EVP_DigestFinal_ex(&ctx, md, size);
- EVP_MD_CTX_cleanup(&ctx);
-
- return ret;
-}
-
-int
-EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in)
-{
- EVP_MD_CTX_init(out);
- return EVP_MD_CTX_copy_ex(out, in);
-}
-
-int
-EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
-{
- unsigned char *tmp_buf;
-
- if ((in == NULL) || (in->digest == NULL)) {
- EVPerror(EVP_R_INPUT_NOT_INITIALIZED);
- return 0;
- }
-
- if (out->digest == in->digest) {
- tmp_buf = out->md_data;
- EVP_MD_CTX_set_flags(out, EVP_MD_CTX_FLAG_REUSE);
- } else
- tmp_buf = NULL;
- EVP_MD_CTX_cleanup(out);
- memcpy(out, in, sizeof *out);
- out->md_data = NULL;
- out->pctx = NULL;
-
- /*
- * Because of the EVP_PKEY_CTX_dup() below, EVP_MD_CTX_cleanup() needs
- * to free out->pctx in all cases (even if this flag is set on in).
- */
- EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
-
- if (in->md_data && out->digest->ctx_size) {
- if (tmp_buf) {
- out->md_data = tmp_buf;
- } else {
- out->md_data = calloc(1, out->digest->ctx_size);
- if (out->md_data == NULL) {
- EVPerror(ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
- memcpy(out->md_data, in->md_data, out->digest->ctx_size);
- }
-
- out->update = in->update;
-
- if (in->pctx) {
- out->pctx = EVP_PKEY_CTX_dup(in->pctx);
- if (!out->pctx) {
- EVP_MD_CTX_cleanup(out);
- return 0;
- }
- }
-
- if (out->digest->copy)
- return out->digest->copy(out, in);
-
- return 1;
-}
-
-EVP_MD_CTX *
-EVP_MD_CTX_new(void)
-{
- return calloc(1, sizeof(EVP_MD_CTX));
-}
-
-void
-EVP_MD_CTX_free(EVP_MD_CTX *ctx)
-{
- if (ctx == NULL)
- return;
-
- EVP_MD_CTX_cleanup(ctx);
-
- free(ctx);
-}
-
-void
-EVP_MD_CTX_init(EVP_MD_CTX *ctx)
-{
- memset(ctx, 0, sizeof(*ctx));
-}
-
-int
-EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
-{
- return EVP_MD_CTX_cleanup(ctx);
-}
-
-EVP_MD_CTX *
-EVP_MD_CTX_create(void)
-{
- return EVP_MD_CTX_new();
-}
-
-void
-EVP_MD_CTX_destroy(EVP_MD_CTX *ctx)
-{
- EVP_MD_CTX_free(ctx);
-}
-
-/* This call frees resources associated with the context */
-int
-EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
-{
- /*
- * Don't assume ctx->md_data was cleaned in EVP_Digest_Final,
- * because sometimes only copies of the context are ever finalised.
- */
- if (ctx->digest && ctx->digest->cleanup &&
- !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
- ctx->digest->cleanup(ctx);
- if (ctx->digest && ctx->digest->ctx_size && ctx->md_data &&
- !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE))
- freezero(ctx->md_data, ctx->digest->ctx_size);
- /*
- * If EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set, EVP_MD_CTX_set_pkey() was
- * called and its strange API contract implies we don't own ctx->pctx.
- */
- if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
- EVP_PKEY_CTX_free(ctx->pctx);
- memset(ctx, 0, sizeof(*ctx));
-
- return 1;
-}
-
-int
-EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
-{
- int ret;
-
- if (!ctx->digest) {
- EVPerror(EVP_R_NO_CIPHER_SET);
- return 0;
- }
-
- if (!ctx->digest->md_ctrl) {
- EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED);
- return 0;
- }
-
- ret = ctx->digest->md_ctrl(ctx, type, arg, ptr);
- if (ret == -1) {
- EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
- return 0;
- }
- return ret;
-}
+++ /dev/null
-/* $OpenBSD: encode.c,v 1.32 2023/07/07 19:37:53 beck Exp $ */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <openssl/evp.h>
-
-#include "evp_local.h"
-
-static unsigned char conv_ascii2bin(unsigned char a);
-#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
-
-/* 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 const 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)
-#define B64_BASE64(a) !B64_NOT_BASE64(a)
-
-static const 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,
-};
-
-static unsigned char
-conv_ascii2bin(unsigned char a)
-{
- if (a & 0x80)
- return B64_ERROR;
- return data_ascii2bin[a];
-}
-
-EVP_ENCODE_CTX *
-EVP_ENCODE_CTX_new(void)
-{
- return calloc(1, sizeof(EVP_ENCODE_CTX));
-}
-
-void
-EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
-{
- free(ctx);
-}
-
-void
-EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
-{
- ctx->length = 48;
- ctx->num = 0;
- ctx->line_num = 0;
-}
-
-int
-EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
- const unsigned char *in, int inl)
-{
- int i, j;
- size_t total = 0;
-
- *outl = 0;
- if (inl <= 0)
- return 0;
- OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
- if (ctx->length - ctx->num > inl) {
- memcpy(&(ctx->enc_data[ctx->num]), in, inl);
- ctx->num += inl;
- return 1;
- }
- 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 && total <= INT_MAX) {
- j = EVP_EncodeBlock(out, in, ctx->length);
- in += ctx->length;
- inl -= ctx->length;
- out += j;
- *(out++) = '\n';
- *out = '\0';
- total += j + 1;
- }
- if (total > INT_MAX) {
- /* Too much output data! */
- *outl = 0;
- return 0;
- }
- if (inl != 0)
- memcpy(&(ctx->enc_data[0]), in, inl);
- ctx->num = inl;
- *outl = total;
-
- return 1;
-}
-
-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->num = 0;
- ctx->length = 0;
- ctx->line_num = 0;
- ctx->expect_nl = 0;
-}
-
-int
-EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
- const unsigned char *in, int inl)
-{
- int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
- unsigned char *d;
-
- n = ctx->num;
- d = ctx->enc_data;
-
- if (n > 0 && d[n - 1] == '=') {
- eof++;
- if (n > 1 && d[n - 2] == '=')
- eof++;
- }
-
- /* Legacy behaviour: an empty input chunk signals end of input. */
- if (inl == 0) {
- rv = 0;
- goto end;
- }
-
- for (i = 0; i < inl; i++) {
- tmp = *(in++);
- v = conv_ascii2bin(tmp);
- if (v == B64_ERROR) {
- rv = -1;
- goto end;
- }
-
- if (tmp == '=') {
- eof++;
- } else if (eof > 0 && B64_BASE64(v)) {
- /* More data after padding. */
- rv = -1;
- goto end;
- }
-
- if (eof > 2) {
- rv = -1;
- goto end;
- }
-
- if (v == B64_EOF) {
- seof = 1;
- goto tail;
- }
-
- /* Only save valid base64 characters. */
- if (B64_BASE64(v)) {
- if (n >= 64) {
- /*
- * We increment n once per loop, and empty the
- * buffer as soon as we reach 64 characters, so
- * this can only happen if someone's manually
- * messed with the ctx. Refuse to write any
- * more data.
- */
- rv = -1;
- goto end;
- }
- OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
- d[n++] = tmp;
- }
-
- if (n == 64) {
- decoded_len = EVP_DecodeBlock(out, d, n);
- n = 0;
- if (decoded_len < 0 || eof > decoded_len) {
- rv = -1;
- goto end;
- }
- ret += decoded_len - eof;
- out += decoded_len - eof;
- }
- }
-
- /*
- * Legacy behaviour: if the current line is a full base64-block (i.e.,
- * has 0 mod 4 base64 characters), it is processed immediately. We keep
- * this behaviour as applications may not be calling EVP_DecodeFinal
- * properly.
- */
- tail:
- if (n > 0) {
- if ((n & 3) == 0) {
- decoded_len = EVP_DecodeBlock(out, d, n);
- n = 0;
- if (decoded_len < 0 || eof > decoded_len) {
- rv = -1;
- goto end;
- }
- ret += (decoded_len - eof);
- } else if (seof) {
- /* EOF in the middle of a base64 block. */
- rv = -1;
- goto end;
- }
- }
-
- rv = seof || (n == 0 && eof) ? 0 : 1;
- end:
- /* Legacy behaviour. This should probably rather be zeroed on error. */
- *outl = ret;
- ctx->num = n;
- 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);
-}
--- /dev/null
+/* $OpenBSD: evp_cipher.c,v 1.1 2023/12/29 05:57:24 tb Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/opensslconf.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "evp_local.h"
+
+int
+EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ const unsigned char *key, const unsigned char *iv, int enc)
+{
+ return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
+}
+
+int
+EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine,
+ const unsigned char *key, const unsigned char *iv, int enc)
+{
+ if (enc == -1)
+ enc = ctx->encrypt;
+ if (enc != 0)
+ enc = 1;
+ ctx->encrypt = enc;
+
+ if (cipher == NULL && ctx->cipher == NULL) {
+ EVPerror(EVP_R_NO_CIPHER_SET);
+ return 0;
+ }
+
+ /*
+ * Set up cipher and context. Allocate cipher data and initialize ctx.
+ * On ctx reuse only retain encryption direction and key wrap flag.
+ */
+ if (cipher != NULL) {
+ unsigned long flags = ctx->flags;
+
+ EVP_CIPHER_CTX_cleanup(ctx);
+ ctx->encrypt = enc;
+ ctx->flags = flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
+
+ ctx->cipher = cipher;
+ ctx->key_len = cipher->key_len;
+
+ if (ctx->cipher->ctx_size != 0) {
+ ctx->cipher_data = calloc(1, ctx->cipher->ctx_size);
+ if (ctx->cipher_data == NULL) {
+ EVPerror(ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+
+ if ((ctx->cipher->flags & EVP_CIPH_CTRL_INIT) != 0) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
+ EVPerror(EVP_R_INITIALIZATION_ERROR);
+ return 0;
+ }
+ }
+ }
+
+ /* Block sizes must be a power of 2 due to the use of block_mask. */
+ if (ctx->cipher->block_size != 1 &&
+ ctx->cipher->block_size != 8 &&
+ ctx->cipher->block_size != 16) {
+ EVPerror(EVP_R_BAD_BLOCK_LENGTH);
+ return 0;
+ }
+
+ if ((ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) == 0 &&
+ EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_WRAP_MODE) {
+ EVPerror(EVP_R_WRAP_MODE_NOT_ALLOWED);
+ return 0;
+ }
+
+ if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV) == 0) {
+ int iv_len;
+
+ switch (EVP_CIPHER_CTX_mode(ctx)) {
+
+ case EVP_CIPH_STREAM_CIPHER:
+ case EVP_CIPH_ECB_MODE:
+ break;
+
+ case EVP_CIPH_CFB_MODE:
+ case EVP_CIPH_OFB_MODE:
+
+ ctx->num = 0;
+ /* fall-through */
+
+ case EVP_CIPH_CBC_MODE:
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+ if (iv_len < 0 || iv_len > sizeof(ctx->oiv)) {
+ EVPerror(EVP_R_IV_TOO_LARGE);
+ return 0;
+ }
+ if (iv != NULL)
+ memcpy(ctx->oiv, iv, iv_len);
+ memcpy(ctx->iv, ctx->oiv, iv_len);
+ break;
+
+ case EVP_CIPH_CTR_MODE:
+ ctx->num = 0;
+ iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+ if (iv_len < 0 || iv_len > sizeof(ctx->iv)) {
+ EVPerror(EVP_R_IV_TOO_LARGE);
+ return 0;
+ }
+ /* Don't reuse IV for CTR mode */
+ if (iv != NULL)
+ memcpy(ctx->iv, iv, iv_len);
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+ }
+
+ if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT) != 0) {
+ if (!ctx->cipher->init(ctx, key, iv, enc))
+ return 0;
+ }
+
+ ctx->partial_len = 0;
+ ctx->final_used = 0;
+
+ return 1;
+}
+
+int
+EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
+ const unsigned char *in, int in_len)
+{
+ if (ctx->encrypt)
+ return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
+
+ return EVP_DecryptUpdate(ctx, out, out_len, in, in_len);
+}
+
+int
+EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
+{
+ if (ctx->encrypt)
+ return EVP_EncryptFinal_ex(ctx, out, out_len);
+
+ return EVP_DecryptFinal_ex(ctx, out, out_len);
+}
+
+int
+EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
+{
+ if (ctx->encrypt)
+ return EVP_EncryptFinal_ex(ctx, out, out_len);
+
+ return EVP_DecryptFinal_ex(ctx, out, out_len);
+}
+
+int
+EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ const unsigned char *key, const unsigned char *iv)
+{
+ return EVP_CipherInit(ctx, cipher, key, iv, 1);
+}
+
+int
+EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine,
+ const unsigned char *key, const unsigned char *iv)
+{
+ return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1);
+}
+
+/*
+ * EVP_Cipher() is an implementation detail of EVP_Cipher{Update,Final}().
+ * Behavior depends on EVP_CIPH_FLAG_CUSTOM_CIPHER being set on ctx->cipher.
+ *
+ * If the flag is set, do_cipher() operates in update mode if in != NULL and
+ * in final mode if in == NULL. It returns the number of bytes written to out
+ * (which may be 0) or -1 on error.
+ *
+ * If the flag is not set, do_cipher() assumes properly aligned data and that
+ * padding is handled correctly by the caller. Most do_cipher() methods will
+ * silently produce garbage and succeed. Returns 1 on success, 0 on error.
+ */
+int
+EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in,
+ unsigned int in_len)
+{
+ return ctx->cipher->do_cipher(ctx, out, in, in_len);
+}
+
+static int
+evp_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
+ const unsigned char *in, int in_len)
+{
+ int len;
+
+ *out_len = 0;
+
+ if (in_len < 0)
+ return 0;
+
+ if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) {
+ if ((len = ctx->cipher->do_cipher(ctx, out, in, in_len)) < 0)
+ return 0;
+
+ *out_len = len;
+ return 1;
+ }
+
+ if (!ctx->cipher->do_cipher(ctx, out, in, in_len))
+ return 0;
+
+ *out_len = in_len;
+
+ return 1;
+}
+
+int
+EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
+ const unsigned char *in, int in_len)
+{
+ const int block_size = ctx->cipher->block_size;
+ const int block_mask = block_size - 1;
+ int partial_len = ctx->partial_len;
+ int len = 0, total_len = 0;
+
+ *out_len = 0;
+
+ if ((block_size & block_mask) != 0)
+ return 0;
+
+ if (in_len < 0)
+ return 0;
+
+ if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE)
+ return 1;
+
+ if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
+ return evp_cipher(ctx, out, out_len, in, in_len);
+
+ if (partial_len == 0 && (in_len & block_mask) == 0)
+ return evp_cipher(ctx, out, out_len, in, in_len);
+
+ if (partial_len < 0 || partial_len >= block_size ||
+ block_size > sizeof(ctx->buf)) {
+ EVPerror(EVP_R_BAD_BLOCK_LENGTH);
+ return 0;
+ }
+
+ if (partial_len > 0) {
+ int partial_needed;
+
+ if ((partial_needed = block_size - partial_len) > in_len) {
+ memcpy(&ctx->buf[partial_len], in, in_len);
+ ctx->partial_len += in_len;
+ return 1;
+ }
+
+ /*
+ * Once the first partial_needed bytes from in are processed,
+ * the number of multiples of block_size of data remaining is
+ * (in_len - partial_needed) & ~block_mask. Ensure that this
+ * plus the block processed from ctx->buf doesn't overflow.
+ */
+ if (((in_len - partial_needed) & ~block_mask) > INT_MAX - block_size) {
+ EVPerror(EVP_R_TOO_LARGE);
+ return 0;
+ }
+ memcpy(&ctx->buf[partial_len], in, partial_needed);
+
+ len = 0;
+ if (!evp_cipher(ctx, out, &len, ctx->buf, block_size))
+ return 0;
+ total_len = len;
+
+ in_len -= partial_needed;
+ in += partial_needed;
+ out += len;
+ }
+
+ partial_len = in_len & block_mask;
+ if ((in_len -= partial_len) > 0) {
+ if (INT_MAX - in_len < total_len)
+ return 0;
+ len = 0;
+ if (!evp_cipher(ctx, out, &len, in, in_len))
+ return 0;
+ if (INT_MAX - len < total_len)
+ return 0;
+ total_len += len;
+ }
+
+ if ((ctx->partial_len = partial_len) > 0)
+ memcpy(ctx->buf, &in[in_len], partial_len);
+
+ *out_len = total_len;
+
+ return 1;
+}
+
+int
+EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
+{
+ return EVP_EncryptFinal_ex(ctx, out, out_len);
+}
+
+int
+EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
+{
+ const int block_size = ctx->cipher->block_size;
+ int partial_len = ctx->partial_len;
+ int pad;
+
+ *out_len = 0;
+
+ if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
+ return evp_cipher(ctx, out, out_len, NULL, 0);
+
+ if (partial_len < 0 || partial_len >= block_size ||
+ block_size > sizeof(ctx->buf)) {
+ EVPerror(EVP_R_BAD_BLOCK_LENGTH);
+ return 0;
+ }
+ if (block_size == 1)
+ return 1;
+
+ if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) {
+ if (partial_len != 0) {
+ EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
+ return 0;
+ }
+ return 1;
+ }
+
+ pad = block_size - partial_len;
+ memset(&ctx->buf[partial_len], pad, pad);
+
+ return evp_cipher(ctx, out, out_len, ctx->buf, block_size);
+}
+
+int
+EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ const unsigned char *key, const unsigned char *iv)
+{
+ return EVP_CipherInit(ctx, cipher, key, iv, 0);
+}
+
+int
+EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine,
+ const unsigned char *key, const unsigned char *iv)
+{
+ return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0);
+}
+
+int
+EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
+ const unsigned char *in, int in_len)
+{
+ const int block_size = ctx->cipher->block_size;
+ const int block_mask = block_size - 1;
+ int len = 0, total_len = 0;
+
+ *out_len = 0;
+
+ if ((block_size & block_mask) != 0)
+ return 0;
+
+ if (in_len < 0)
+ return 0;
+
+ if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE)
+ return 1;
+
+ if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
+ return evp_cipher(ctx, out, out_len, in, in_len);
+
+ if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0)
+ return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
+
+ if (block_size > sizeof(ctx->final)) {
+ EVPerror(EVP_R_BAD_BLOCK_LENGTH);
+ return 0;
+ }
+
+ if (ctx->final_used) {
+ /*
+ * final_used is only set if partial_len is 0. Therefore the
+ * output from EVP_EncryptUpdate() is in_len & ~block_mask.
+ * Ensure (in_len & ~block_mask) + block_size doesn't overflow.
+ */
+ if ((in_len & ~block_mask) > INT_MAX - block_size) {
+ EVPerror(EVP_R_TOO_LARGE);
+ return 0;
+ }
+ memcpy(out, ctx->final, block_size);
+ out += block_size;
+ total_len = block_size;
+ }
+
+ ctx->final_used = 0;
+
+ len = 0;
+ if (!EVP_EncryptUpdate(ctx, out, &len, in, in_len))
+ return 0;
+
+ /* Keep copy of last block if a multiple of block_size was decrypted. */
+ if (block_size > 1 && ctx->partial_len == 0) {
+ if (len < block_size)
+ return 0;
+ len -= block_size;
+ memcpy(ctx->final, &out[len], block_size);
+ ctx->final_used = 1;
+ }
+
+ if (len > INT_MAX - total_len)
+ return 0;
+ total_len += len;
+
+ *out_len = total_len;
+
+ return 1;
+}
+
+int
+EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
+{
+ return EVP_DecryptFinal_ex(ctx, out, out_len);
+}
+
+int
+EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
+{
+ const int block_size = ctx->cipher->block_size;
+ int partial_len = ctx->partial_len;
+ int i, pad, plain_len;
+
+ *out_len = 0;
+
+ if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
+ return evp_cipher(ctx, out, out_len, NULL, 0);
+
+ if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) {
+ if (partial_len != 0) {
+ EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
+ return 0;
+ }
+ return 1;
+ }
+
+ if (block_size == 1)
+ return 1;
+
+ if (partial_len != 0 || !ctx->final_used) {
+ EVPerror(EVP_R_WRONG_FINAL_BLOCK_LENGTH);
+ return 0;
+ }
+
+ if (block_size > sizeof(ctx->final)) {
+ EVPerror(EVP_R_BAD_BLOCK_LENGTH);
+ return 0;
+ }
+
+ pad = ctx->final[block_size - 1];
+ if (pad <= 0 || pad > block_size) {
+ EVPerror(EVP_R_BAD_DECRYPT);
+ return 0;
+ }
+ plain_len = block_size - pad;
+ for (i = plain_len; i < block_size; i++) {
+ if (ctx->final[i] != pad) {
+ EVPerror(EVP_R_BAD_DECRYPT);
+ return 0;
+ }
+ }
+
+ memcpy(out, ctx->final, plain_len);
+ *out_len = plain_len;
+
+ return 1;
+}
+
+EVP_CIPHER_CTX *
+EVP_CIPHER_CTX_new(void)
+{
+ return calloc(1, sizeof(EVP_CIPHER_CTX));
+}
+
+void
+EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ EVP_CIPHER_CTX_cleanup(ctx);
+
+ free(ctx);
+}
+
+void
+EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
+{
+ memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
+}
+
+int
+EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *a)
+{
+ return EVP_CIPHER_CTX_cleanup(a);
+}
+
+int
+EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c)
+{
+ if (c->cipher != NULL) {
+ /* XXX - Avoid leaks, so ignore return value of cleanup()... */
+ if (c->cipher->cleanup != NULL)
+ c->cipher->cleanup(c);
+ if (c->cipher_data != NULL)
+ explicit_bzero(c->cipher_data, c->cipher->ctx_size);
+ }
+
+ /* XXX - store size of cipher_data so we can always freezero(). */
+ free(c->cipher_data);
+
+ explicit_bzero(c, sizeof(EVP_CIPHER_CTX));
+
+ return 1;
+}
+
+int
+EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen)
+{
+ if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH)
+ return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH,
+ keylen, NULL);
+ if (c->key_len == keylen)
+ return 1;
+ if (keylen > 0 && (c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) {
+ c->key_len = keylen;
+ return 1;
+ }
+ EVPerror(EVP_R_INVALID_KEY_LENGTH);
+ return 0;
+}
+
+int
+EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
+{
+ if (pad)
+ ctx->flags &= ~EVP_CIPH_NO_PADDING;
+ else
+ ctx->flags |= EVP_CIPH_NO_PADDING;
+ return 1;
+}
+
+int
+EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+{
+ int ret;
+
+ if (!ctx->cipher) {
+ EVPerror(EVP_R_NO_CIPHER_SET);
+ return 0;
+ }
+
+ if (!ctx->cipher->ctrl) {
+ EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED);
+ return 0;
+ }
+
+ ret = ctx->cipher->ctrl(ctx, type, arg, ptr);
+ if (ret == -1) {
+ EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
+ return 0;
+ }
+ return ret;
+}
+
+int
+EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
+{
+ if (ctx->cipher->flags & EVP_CIPH_RAND_KEY)
+ return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key);
+ arc4random_buf(key, ctx->key_len);
+ return 1;
+}
+
+int
+EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
+{
+ if (in == NULL || in->cipher == NULL) {
+ EVPerror(EVP_R_INPUT_NOT_INITIALIZED);
+ return 0;
+ }
+
+ EVP_CIPHER_CTX_cleanup(out);
+ memcpy(out, in, sizeof *out);
+
+ if (in->cipher_data && in->cipher->ctx_size) {
+ out->cipher_data = calloc(1, in->cipher->ctx_size);
+ if (out->cipher_data == NULL) {
+ EVPerror(ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
+ }
+
+ if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) {
+ if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY,
+ 0, out)) {
+ /*
+ * If the custom copy control failed, assume that there
+ * may still be pointers copied in the cipher_data that
+ * we do not own. This may result in a leak from a bad
+ * custom copy control, but that's preferable to a
+ * double free...
+ */
+ freezero(out->cipher_data, in->cipher->ctx_size);
+ out->cipher_data = NULL;
+ return 0;
+ }
+ }
+
+ return 1;
+}
--- /dev/null
+/* $OpenBSD: evp_digest.c,v 1.1 2023/12/29 05:57:24 tb Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/opensslconf.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+
+#include "evp_local.h"
+
+int
+EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
+{
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit_ex(ctx, type, NULL);
+}
+
+int
+EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
+{
+ EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
+
+ if (ctx->digest != type) {
+ if (ctx->digest && ctx->digest->ctx_size && ctx->md_data &&
+ !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
+ freezero(ctx->md_data, ctx->digest->ctx_size);
+ ctx->md_data = NULL;
+ }
+ ctx->digest = type;
+ if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
+ ctx->update = type->update;
+ ctx->md_data = calloc(1, type->ctx_size);
+ if (ctx->md_data == NULL) {
+ EVP_PKEY_CTX_free(ctx->pctx);
+ ctx->pctx = NULL;
+ EVPerror(ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ }
+ if (ctx->pctx) {
+ int r;
+ r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
+ EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
+ if (r <= 0 && (r != -2))
+ return 0;
+ }
+ if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT)
+ return 1;
+ return ctx->digest->init(ctx);
+}
+
+int
+EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
+{
+ return ctx->update(ctx, data, count);
+}
+
+/* The caller can assume that this removes any secret data from the context */
+int
+EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
+{
+ int ret;
+
+ ret = EVP_DigestFinal_ex(ctx, md, size);
+ EVP_MD_CTX_cleanup(ctx);
+ return ret;
+}
+
+/* The caller can assume that this removes any secret data from the context */
+int
+EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
+{
+ int ret;
+
+ if ((size_t)ctx->digest->md_size > EVP_MAX_MD_SIZE) {
+ EVPerror(EVP_R_TOO_LARGE);
+ return 0;
+ }
+ ret = ctx->digest->final(ctx, md);
+ if (size != NULL)
+ *size = ctx->digest->md_size;
+ if (ctx->digest->cleanup) {
+ ctx->digest->cleanup(ctx);
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
+ }
+ memset(ctx->md_data, 0, ctx->digest->ctx_size);
+ return ret;
+}
+
+int
+EVP_Digest(const void *data, size_t count,
+ unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl)
+{
+ EVP_MD_CTX ctx;
+ int ret;
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_ONESHOT);
+ ret = EVP_DigestInit_ex(&ctx, type, NULL) &&
+ EVP_DigestUpdate(&ctx, data, count) &&
+ EVP_DigestFinal_ex(&ctx, md, size);
+ EVP_MD_CTX_cleanup(&ctx);
+
+ return ret;
+}
+
+int
+EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in)
+{
+ EVP_MD_CTX_init(out);
+ return EVP_MD_CTX_copy_ex(out, in);
+}
+
+int
+EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
+{
+ unsigned char *tmp_buf;
+
+ if ((in == NULL) || (in->digest == NULL)) {
+ EVPerror(EVP_R_INPUT_NOT_INITIALIZED);
+ return 0;
+ }
+
+ if (out->digest == in->digest) {
+ tmp_buf = out->md_data;
+ EVP_MD_CTX_set_flags(out, EVP_MD_CTX_FLAG_REUSE);
+ } else
+ tmp_buf = NULL;
+ EVP_MD_CTX_cleanup(out);
+ memcpy(out, in, sizeof *out);
+ out->md_data = NULL;
+ out->pctx = NULL;
+
+ /*
+ * Because of the EVP_PKEY_CTX_dup() below, EVP_MD_CTX_cleanup() needs
+ * to free out->pctx in all cases (even if this flag is set on in).
+ */
+ EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+
+ if (in->md_data && out->digest->ctx_size) {
+ if (tmp_buf) {
+ out->md_data = tmp_buf;
+ } else {
+ out->md_data = calloc(1, out->digest->ctx_size);
+ if (out->md_data == NULL) {
+ EVPerror(ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ memcpy(out->md_data, in->md_data, out->digest->ctx_size);
+ }
+
+ out->update = in->update;
+
+ if (in->pctx) {
+ out->pctx = EVP_PKEY_CTX_dup(in->pctx);
+ if (!out->pctx) {
+ EVP_MD_CTX_cleanup(out);
+ return 0;
+ }
+ }
+
+ if (out->digest->copy)
+ return out->digest->copy(out, in);
+
+ return 1;
+}
+
+EVP_MD_CTX *
+EVP_MD_CTX_new(void)
+{
+ return calloc(1, sizeof(EVP_MD_CTX));
+}
+
+void
+EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ EVP_MD_CTX_cleanup(ctx);
+
+ free(ctx);
+}
+
+void
+EVP_MD_CTX_init(EVP_MD_CTX *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+int
+EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
+{
+ return EVP_MD_CTX_cleanup(ctx);
+}
+
+EVP_MD_CTX *
+EVP_MD_CTX_create(void)
+{
+ return EVP_MD_CTX_new();
+}
+
+void
+EVP_MD_CTX_destroy(EVP_MD_CTX *ctx)
+{
+ EVP_MD_CTX_free(ctx);
+}
+
+/* This call frees resources associated with the context */
+int
+EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
+{
+ /*
+ * Don't assume ctx->md_data was cleaned in EVP_Digest_Final,
+ * because sometimes only copies of the context are ever finalised.
+ */
+ if (ctx->digest && ctx->digest->cleanup &&
+ !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
+ ctx->digest->cleanup(ctx);
+ if (ctx->digest && ctx->digest->ctx_size && ctx->md_data &&
+ !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE))
+ freezero(ctx->md_data, ctx->digest->ctx_size);
+ /*
+ * If EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set, EVP_MD_CTX_set_pkey() was
+ * called and its strange API contract implies we don't own ctx->pctx.
+ */
+ if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
+ EVP_PKEY_CTX_free(ctx->pctx);
+ memset(ctx, 0, sizeof(*ctx));
+
+ return 1;
+}
+
+int
+EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr)
+{
+ int ret;
+
+ if (!ctx->digest) {
+ EVPerror(EVP_R_NO_CIPHER_SET);
+ return 0;
+ }
+
+ if (!ctx->digest->md_ctrl) {
+ EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED);
+ return 0;
+ }
+
+ ret = ctx->digest->md_ctrl(ctx, type, arg, ptr);
+ if (ret == -1) {
+ EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
+ return 0;
+ }
+ return ret;
+}
+++ /dev/null
-/* $OpenBSD: evp_enc.c,v 1.81 2023/12/26 09:04:30 tb Exp $ */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * 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 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <openssl/opensslconf.h>
-
-#include <openssl/err.h>
-#include <openssl/evp.h>
-
-#include "evp_local.h"
-
-int
-EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
- const unsigned char *key, const unsigned char *iv, int enc)
-{
- return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
-}
-
-int
-EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine,
- const unsigned char *key, const unsigned char *iv, int enc)
-{
- if (enc == -1)
- enc = ctx->encrypt;
- if (enc != 0)
- enc = 1;
- ctx->encrypt = enc;
-
- if (cipher == NULL && ctx->cipher == NULL) {
- EVPerror(EVP_R_NO_CIPHER_SET);
- return 0;
- }
-
- /*
- * Set up cipher and context. Allocate cipher data and initialize ctx.
- * On ctx reuse only retain encryption direction and key wrap flag.
- */
- if (cipher != NULL) {
- unsigned long flags = ctx->flags;
-
- EVP_CIPHER_CTX_cleanup(ctx);
- ctx->encrypt = enc;
- ctx->flags = flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
-
- ctx->cipher = cipher;
- ctx->key_len = cipher->key_len;
-
- if (ctx->cipher->ctx_size != 0) {
- ctx->cipher_data = calloc(1, ctx->cipher->ctx_size);
- if (ctx->cipher_data == NULL) {
- EVPerror(ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
-
- if ((ctx->cipher->flags & EVP_CIPH_CTRL_INIT) != 0) {
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
- EVPerror(EVP_R_INITIALIZATION_ERROR);
- return 0;
- }
- }
- }
-
- /* Block sizes must be a power of 2 due to the use of block_mask. */
- if (ctx->cipher->block_size != 1 &&
- ctx->cipher->block_size != 8 &&
- ctx->cipher->block_size != 16) {
- EVPerror(EVP_R_BAD_BLOCK_LENGTH);
- return 0;
- }
-
- if ((ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) == 0 &&
- EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_WRAP_MODE) {
- EVPerror(EVP_R_WRAP_MODE_NOT_ALLOWED);
- return 0;
- }
-
- if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV) == 0) {
- int iv_len;
-
- switch (EVP_CIPHER_CTX_mode(ctx)) {
-
- case EVP_CIPH_STREAM_CIPHER:
- case EVP_CIPH_ECB_MODE:
- break;
-
- case EVP_CIPH_CFB_MODE:
- case EVP_CIPH_OFB_MODE:
-
- ctx->num = 0;
- /* fall-through */
-
- case EVP_CIPH_CBC_MODE:
- iv_len = EVP_CIPHER_CTX_iv_length(ctx);
- if (iv_len < 0 || iv_len > sizeof(ctx->oiv)) {
- EVPerror(EVP_R_IV_TOO_LARGE);
- return 0;
- }
- if (iv != NULL)
- memcpy(ctx->oiv, iv, iv_len);
- memcpy(ctx->iv, ctx->oiv, iv_len);
- break;
-
- case EVP_CIPH_CTR_MODE:
- ctx->num = 0;
- iv_len = EVP_CIPHER_CTX_iv_length(ctx);
- if (iv_len < 0 || iv_len > sizeof(ctx->iv)) {
- EVPerror(EVP_R_IV_TOO_LARGE);
- return 0;
- }
- /* Don't reuse IV for CTR mode */
- if (iv != NULL)
- memcpy(ctx->iv, iv, iv_len);
- break;
-
- default:
- return 0;
- break;
- }
- }
-
- if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT) != 0) {
- if (!ctx->cipher->init(ctx, key, iv, enc))
- return 0;
- }
-
- ctx->partial_len = 0;
- ctx->final_used = 0;
-
- return 1;
-}
-
-int
-EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
- const unsigned char *in, int in_len)
-{
- if (ctx->encrypt)
- return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
-
- return EVP_DecryptUpdate(ctx, out, out_len, in, in_len);
-}
-
-int
-EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
-{
- if (ctx->encrypt)
- return EVP_EncryptFinal_ex(ctx, out, out_len);
-
- return EVP_DecryptFinal_ex(ctx, out, out_len);
-}
-
-int
-EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
-{
- if (ctx->encrypt)
- return EVP_EncryptFinal_ex(ctx, out, out_len);
-
- return EVP_DecryptFinal_ex(ctx, out, out_len);
-}
-
-int
-EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
- const unsigned char *key, const unsigned char *iv)
-{
- return EVP_CipherInit(ctx, cipher, key, iv, 1);
-}
-
-int
-EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine,
- const unsigned char *key, const unsigned char *iv)
-{
- return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1);
-}
-
-/*
- * EVP_Cipher() is an implementation detail of EVP_Cipher{Update,Final}().
- * Behavior depends on EVP_CIPH_FLAG_CUSTOM_CIPHER being set on ctx->cipher.
- *
- * If the flag is set, do_cipher() operates in update mode if in != NULL and
- * in final mode if in == NULL. It returns the number of bytes written to out
- * (which may be 0) or -1 on error.
- *
- * If the flag is not set, do_cipher() assumes properly aligned data and that
- * padding is handled correctly by the caller. Most do_cipher() methods will
- * silently produce garbage and succeed. Returns 1 on success, 0 on error.
- */
-int
-EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in,
- unsigned int in_len)
-{
- return ctx->cipher->do_cipher(ctx, out, in, in_len);
-}
-
-static int
-evp_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
- const unsigned char *in, int in_len)
-{
- int len;
-
- *out_len = 0;
-
- if (in_len < 0)
- return 0;
-
- if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) {
- if ((len = ctx->cipher->do_cipher(ctx, out, in, in_len)) < 0)
- return 0;
-
- *out_len = len;
- return 1;
- }
-
- if (!ctx->cipher->do_cipher(ctx, out, in, in_len))
- return 0;
-
- *out_len = in_len;
-
- return 1;
-}
-
-int
-EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
- const unsigned char *in, int in_len)
-{
- const int block_size = ctx->cipher->block_size;
- const int block_mask = block_size - 1;
- int partial_len = ctx->partial_len;
- int len = 0, total_len = 0;
-
- *out_len = 0;
-
- if ((block_size & block_mask) != 0)
- return 0;
-
- if (in_len < 0)
- return 0;
-
- if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE)
- return 1;
-
- if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
- return evp_cipher(ctx, out, out_len, in, in_len);
-
- if (partial_len == 0 && (in_len & block_mask) == 0)
- return evp_cipher(ctx, out, out_len, in, in_len);
-
- if (partial_len < 0 || partial_len >= block_size ||
- block_size > sizeof(ctx->buf)) {
- EVPerror(EVP_R_BAD_BLOCK_LENGTH);
- return 0;
- }
-
- if (partial_len > 0) {
- int partial_needed;
-
- if ((partial_needed = block_size - partial_len) > in_len) {
- memcpy(&ctx->buf[partial_len], in, in_len);
- ctx->partial_len += in_len;
- return 1;
- }
-
- /*
- * Once the first partial_needed bytes from in are processed,
- * the number of multiples of block_size of data remaining is
- * (in_len - partial_needed) & ~block_mask. Ensure that this
- * plus the block processed from ctx->buf doesn't overflow.
- */
- if (((in_len - partial_needed) & ~block_mask) > INT_MAX - block_size) {
- EVPerror(EVP_R_TOO_LARGE);
- return 0;
- }
- memcpy(&ctx->buf[partial_len], in, partial_needed);
-
- len = 0;
- if (!evp_cipher(ctx, out, &len, ctx->buf, block_size))
- return 0;
- total_len = len;
-
- in_len -= partial_needed;
- in += partial_needed;
- out += len;
- }
-
- partial_len = in_len & block_mask;
- if ((in_len -= partial_len) > 0) {
- if (INT_MAX - in_len < total_len)
- return 0;
- len = 0;
- if (!evp_cipher(ctx, out, &len, in, in_len))
- return 0;
- if (INT_MAX - len < total_len)
- return 0;
- total_len += len;
- }
-
- if ((ctx->partial_len = partial_len) > 0)
- memcpy(ctx->buf, &in[in_len], partial_len);
-
- *out_len = total_len;
-
- return 1;
-}
-
-int
-EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
-{
- return EVP_EncryptFinal_ex(ctx, out, out_len);
-}
-
-int
-EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
-{
- const int block_size = ctx->cipher->block_size;
- int partial_len = ctx->partial_len;
- int pad;
-
- *out_len = 0;
-
- if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
- return evp_cipher(ctx, out, out_len, NULL, 0);
-
- if (partial_len < 0 || partial_len >= block_size ||
- block_size > sizeof(ctx->buf)) {
- EVPerror(EVP_R_BAD_BLOCK_LENGTH);
- return 0;
- }
- if (block_size == 1)
- return 1;
-
- if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) {
- if (partial_len != 0) {
- EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
- return 0;
- }
- return 1;
- }
-
- pad = block_size - partial_len;
- memset(&ctx->buf[partial_len], pad, pad);
-
- return evp_cipher(ctx, out, out_len, ctx->buf, block_size);
-}
-
-int
-EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
- const unsigned char *key, const unsigned char *iv)
-{
- return EVP_CipherInit(ctx, cipher, key, iv, 0);
-}
-
-int
-EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine,
- const unsigned char *key, const unsigned char *iv)
-{
- return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0);
-}
-
-int
-EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len,
- const unsigned char *in, int in_len)
-{
- const int block_size = ctx->cipher->block_size;
- const int block_mask = block_size - 1;
- int len = 0, total_len = 0;
-
- *out_len = 0;
-
- if ((block_size & block_mask) != 0)
- return 0;
-
- if (in_len < 0)
- return 0;
-
- if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE)
- return 1;
-
- if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
- return evp_cipher(ctx, out, out_len, in, in_len);
-
- if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0)
- return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
-
- if (block_size > sizeof(ctx->final)) {
- EVPerror(EVP_R_BAD_BLOCK_LENGTH);
- return 0;
- }
-
- if (ctx->final_used) {
- /*
- * final_used is only set if partial_len is 0. Therefore the
- * output from EVP_EncryptUpdate() is in_len & ~block_mask.
- * Ensure (in_len & ~block_mask) + block_size doesn't overflow.
- */
- if ((in_len & ~block_mask) > INT_MAX - block_size) {
- EVPerror(EVP_R_TOO_LARGE);
- return 0;
- }
- memcpy(out, ctx->final, block_size);
- out += block_size;
- total_len = block_size;
- }
-
- ctx->final_used = 0;
-
- len = 0;
- if (!EVP_EncryptUpdate(ctx, out, &len, in, in_len))
- return 0;
-
- /* Keep copy of last block if a multiple of block_size was decrypted. */
- if (block_size > 1 && ctx->partial_len == 0) {
- if (len < block_size)
- return 0;
- len -= block_size;
- memcpy(ctx->final, &out[len], block_size);
- ctx->final_used = 1;
- }
-
- if (len > INT_MAX - total_len)
- return 0;
- total_len += len;
-
- *out_len = total_len;
-
- return 1;
-}
-
-int
-EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
-{
- return EVP_DecryptFinal_ex(ctx, out, out_len);
-}
-
-int
-EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len)
-{
- const int block_size = ctx->cipher->block_size;
- int partial_len = ctx->partial_len;
- int i, pad, plain_len;
-
- *out_len = 0;
-
- if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0)
- return evp_cipher(ctx, out, out_len, NULL, 0);
-
- if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) {
- if (partial_len != 0) {
- EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
- return 0;
- }
- return 1;
- }
-
- if (block_size == 1)
- return 1;
-
- if (partial_len != 0 || !ctx->final_used) {
- EVPerror(EVP_R_WRONG_FINAL_BLOCK_LENGTH);
- return 0;
- }
-
- if (block_size > sizeof(ctx->final)) {
- EVPerror(EVP_R_BAD_BLOCK_LENGTH);
- return 0;
- }
-
- pad = ctx->final[block_size - 1];
- if (pad <= 0 || pad > block_size) {
- EVPerror(EVP_R_BAD_DECRYPT);
- return 0;
- }
- plain_len = block_size - pad;
- for (i = plain_len; i < block_size; i++) {
- if (ctx->final[i] != pad) {
- EVPerror(EVP_R_BAD_DECRYPT);
- return 0;
- }
- }
-
- memcpy(out, ctx->final, plain_len);
- *out_len = plain_len;
-
- return 1;
-}
-
-EVP_CIPHER_CTX *
-EVP_CIPHER_CTX_new(void)
-{
- return calloc(1, sizeof(EVP_CIPHER_CTX));
-}
-
-void
-EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
-{
- if (ctx == NULL)
- return;
-
- EVP_CIPHER_CTX_cleanup(ctx);
-
- free(ctx);
-}
-
-void
-EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
-{
- memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
-}
-
-int
-EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *a)
-{
- return EVP_CIPHER_CTX_cleanup(a);
-}
-
-int
-EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c)
-{
- if (c->cipher != NULL) {
- /* XXX - Avoid leaks, so ignore return value of cleanup()... */
- if (c->cipher->cleanup != NULL)
- c->cipher->cleanup(c);
- if (c->cipher_data != NULL)
- explicit_bzero(c->cipher_data, c->cipher->ctx_size);
- }
-
- /* XXX - store size of cipher_data so we can always freezero(). */
- free(c->cipher_data);
-
- explicit_bzero(c, sizeof(EVP_CIPHER_CTX));
-
- return 1;
-}
-
-int
-EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen)
-{
- if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH)
- return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH,
- keylen, NULL);
- if (c->key_len == keylen)
- return 1;
- if (keylen > 0 && (c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) {
- c->key_len = keylen;
- return 1;
- }
- EVPerror(EVP_R_INVALID_KEY_LENGTH);
- return 0;
-}
-
-int
-EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
-{
- if (pad)
- ctx->flags &= ~EVP_CIPH_NO_PADDING;
- else
- ctx->flags |= EVP_CIPH_NO_PADDING;
- return 1;
-}
-
-int
-EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
-{
- int ret;
-
- if (!ctx->cipher) {
- EVPerror(EVP_R_NO_CIPHER_SET);
- return 0;
- }
-
- if (!ctx->cipher->ctrl) {
- EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED);
- return 0;
- }
-
- ret = ctx->cipher->ctrl(ctx, type, arg, ptr);
- if (ret == -1) {
- EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
- return 0;
- }
- return ret;
-}
-
-int
-EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
-{
- if (ctx->cipher->flags & EVP_CIPH_RAND_KEY)
- return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key);
- arc4random_buf(key, ctx->key_len);
- return 1;
-}
-
-int
-EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
-{
- if (in == NULL || in->cipher == NULL) {
- EVPerror(EVP_R_INPUT_NOT_INITIALIZED);
- return 0;
- }
-
- EVP_CIPHER_CTX_cleanup(out);
- memcpy(out, in, sizeof *out);
-
- if (in->cipher_data && in->cipher->ctx_size) {
- out->cipher_data = calloc(1, in->cipher->ctx_size);
- if (out->cipher_data == NULL) {
- EVPerror(ERR_R_MALLOC_FAILURE);
- return 0;
- }
- memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
- }
-
- if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) {
- if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY,
- 0, out)) {
- /*
- * If the custom copy control failed, assume that there
- * may still be pointers copied in the cipher_data that
- * we do not own. This may result in a leak from a bad
- * custom copy control, but that's preferable to a
- * double free...
- */
- freezero(out->cipher_data, in->cipher->ctx_size);
- out->cipher_data = NULL;
- return 0;
- }
- }
-
- return 1;
-}
--- /dev/null
+/* $OpenBSD: evp_encode.c,v 1.1 2023/12/29 05:57:24 tb Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include "evp_local.h"
+
+static unsigned char conv_ascii2bin(unsigned char a);
+#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f])
+
+/* 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 const 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)
+#define B64_BASE64(a) !B64_NOT_BASE64(a)
+
+static const 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,
+};
+
+static unsigned char
+conv_ascii2bin(unsigned char a)
+{
+ if (a & 0x80)
+ return B64_ERROR;
+ return data_ascii2bin[a];
+}
+
+EVP_ENCODE_CTX *
+EVP_ENCODE_CTX_new(void)
+{
+ return calloc(1, sizeof(EVP_ENCODE_CTX));
+}
+
+void
+EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
+{
+ free(ctx);
+}
+
+void
+EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
+{
+ ctx->length = 48;
+ ctx->num = 0;
+ ctx->line_num = 0;
+}
+
+int
+EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
+ const unsigned char *in, int inl)
+{
+ int i, j;
+ size_t total = 0;
+
+ *outl = 0;
+ if (inl <= 0)
+ return 0;
+ OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
+ if (ctx->length - ctx->num > inl) {
+ memcpy(&(ctx->enc_data[ctx->num]), in, inl);
+ ctx->num += inl;
+ return 1;
+ }
+ 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 && total <= INT_MAX) {
+ j = EVP_EncodeBlock(out, in, ctx->length);
+ in += ctx->length;
+ inl -= ctx->length;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total += j + 1;
+ }
+ if (total > INT_MAX) {
+ /* Too much output data! */
+ *outl = 0;
+ return 0;
+ }
+ if (inl != 0)
+ memcpy(&(ctx->enc_data[0]), in, inl);
+ ctx->num = inl;
+ *outl = total;
+
+ return 1;
+}
+
+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->num = 0;
+ ctx->length = 0;
+ ctx->line_num = 0;
+ ctx->expect_nl = 0;
+}
+
+int
+EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
+ const unsigned char *in, int inl)
+{
+ int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
+ unsigned char *d;
+
+ n = ctx->num;
+ d = ctx->enc_data;
+
+ if (n > 0 && d[n - 1] == '=') {
+ eof++;
+ if (n > 1 && d[n - 2] == '=')
+ eof++;
+ }
+
+ /* Legacy behaviour: an empty input chunk signals end of input. */
+ if (inl == 0) {
+ rv = 0;
+ goto end;
+ }
+
+ for (i = 0; i < inl; i++) {
+ tmp = *(in++);
+ v = conv_ascii2bin(tmp);
+ if (v == B64_ERROR) {
+ rv = -1;
+ goto end;
+ }
+
+ if (tmp == '=') {
+ eof++;
+ } else if (eof > 0 && B64_BASE64(v)) {
+ /* More data after padding. */
+ rv = -1;
+ goto end;
+ }
+
+ if (eof > 2) {
+ rv = -1;
+ goto end;
+ }
+
+ if (v == B64_EOF) {
+ seof = 1;
+ goto tail;
+ }
+
+ /* Only save valid base64 characters. */
+ if (B64_BASE64(v)) {
+ if (n >= 64) {
+ /*
+ * We increment n once per loop, and empty the
+ * buffer as soon as we reach 64 characters, so
+ * this can only happen if someone's manually
+ * messed with the ctx. Refuse to write any
+ * more data.
+ */
+ rv = -1;
+ goto end;
+ }
+ OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
+ d[n++] = tmp;
+ }
+
+ if (n == 64) {
+ decoded_len = EVP_DecodeBlock(out, d, n);
+ n = 0;
+ if (decoded_len < 0 || eof > decoded_len) {
+ rv = -1;
+ goto end;
+ }
+ ret += decoded_len - eof;
+ out += decoded_len - eof;
+ }
+ }
+
+ /*
+ * Legacy behaviour: if the current line is a full base64-block (i.e.,
+ * has 0 mod 4 base64 characters), it is processed immediately. We keep
+ * this behaviour as applications may not be calling EVP_DecodeFinal
+ * properly.
+ */
+ tail:
+ if (n > 0) {
+ if ((n & 3) == 0) {
+ decoded_len = EVP_DecodeBlock(out, d, n);
+ n = 0;
+ if (decoded_len < 0 || eof > decoded_len) {
+ rv = -1;
+ goto end;
+ }
+ ret += (decoded_len - eof);
+ } else if (seof) {
+ /* EOF in the middle of a base64 block. */
+ rv = -1;
+ goto end;
+ }
+ }
+
+ rv = seof || (n == 0 && eof) ? 0 : 1;
+ end:
+ /* Legacy behaviour. This should probably rather be zeroed on error. */
+ *outl = ret;
+ ctx->num = n;
+ 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);
+}