Path: blob/main/crypto/heimdal/lib/krb5/crypto-evp.c
34878 views
/*1* Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "krb5_locl.h"3435void36_krb5_evp_schedule(krb5_context context,37struct _krb5_key_type *kt,38struct _krb5_key_data *kd)39{40struct _krb5_evp_schedule *key = kd->schedule->data;41const EVP_CIPHER *c = (*kt->evp)();4243key->ectx = EVP_CIPHER_CTX_new();44key->dctx = EVP_CIPHER_CTX_new();45if (key->ectx == NULL || key->dctx == NULL)46krb5_abort(context, ENOMEM, "malloc failed");4748EVP_CipherInit_ex(key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1);49EVP_CipherInit_ex(key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0);50}5152void53_krb5_evp_cleanup(krb5_context context, struct _krb5_key_data *kd)54{55struct _krb5_evp_schedule *key = kd->schedule->data;56EVP_CIPHER_CTX_free(key->ectx);57EVP_CIPHER_CTX_free(key->dctx);58}5960krb5_error_code61_krb5_evp_encrypt(krb5_context context,62struct _krb5_key_data *key,63void *data,64size_t len,65krb5_boolean encryptp,66int usage,67void *ivec)68{69struct _krb5_evp_schedule *ctx = key->schedule->data;70EVP_CIPHER_CTX *c;71c = encryptp ? ctx->ectx : ctx->dctx;72if (ivec == NULL) {73/* alloca ? */74size_t len2 = EVP_CIPHER_CTX_iv_length(c);75void *loiv = malloc(len2);76if (loiv == NULL) {77krb5_clear_error_message(context);78return ENOMEM;79}80memset(loiv, 0, len2);81EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1);82free(loiv);83} else84EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);85EVP_Cipher(c, data, data, len);86return 0;87}8889static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 };9091krb5_error_code92_krb5_evp_encrypt_cts(krb5_context context,93struct _krb5_key_data *key,94void *data,95size_t len,96krb5_boolean encryptp,97int usage,98void *ivec)99{100size_t i, blocksize;101struct _krb5_evp_schedule *ctx = key->schedule->data;102unsigned char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];103EVP_CIPHER_CTX *c;104unsigned char *p;105106c = encryptp ? ctx->ectx : ctx->dctx;107108blocksize = EVP_CIPHER_CTX_block_size(c);109110if (len < blocksize) {111krb5_set_error_message(context, EINVAL,112"message block too short");113return EINVAL;114} else if (len == blocksize) {115EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);116EVP_Cipher(c, data, data, len);117return 0;118}119120if (ivec)121EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);122else123EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);124125if (encryptp) {126127p = data;128i = ((len - 1) / blocksize) * blocksize;129EVP_Cipher(c, p, p, i);130p += i - blocksize;131len -= i;132memcpy(ivec2, p, blocksize);133134for (i = 0; i < len; i++)135tmp[i] = p[i + blocksize] ^ ivec2[i];136for (; i < blocksize; i++)137tmp[i] = 0 ^ ivec2[i];138139EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);140EVP_Cipher(c, p, tmp, blocksize);141142memcpy(p + blocksize, ivec2, len);143if (ivec)144memcpy(ivec, p, blocksize);145} else {146unsigned char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH];147148p = data;149if (len > blocksize * 2) {150/* remove last two blocks and round up, decrypt this with cbc, then do cts dance */151i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize);152memcpy(ivec2, p + i - blocksize, blocksize);153EVP_Cipher(c, p, p, i);154p += i;155len -= i + blocksize;156} else {157if (ivec)158memcpy(ivec2, ivec, blocksize);159else160memcpy(ivec2, zero_ivec, blocksize);161len -= blocksize;162}163164memcpy(tmp, p, blocksize);165EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);166EVP_Cipher(c, tmp2, p, blocksize);167168memcpy(tmp3, p + blocksize, len);169memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */170171for (i = 0; i < len; i++)172p[i + blocksize] = tmp2[i] ^ tmp3[i];173174EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);175EVP_Cipher(c, p, tmp3, blocksize);176177for (i = 0; i < blocksize; i++)178p[i] ^= ivec2[i];179if (ivec)180memcpy(ivec, tmp, blocksize);181}182return 0;183}184185186