Home | History | Annotate | Line # | Download | only in krb5
      1 /*	$NetBSD: crypto-evp.c,v 1.5 2023/06/19 21:41:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2008 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include "krb5_locl.h"
     37 
     38 void
     39 _krb5_evp_schedule(krb5_context context,
     40 		   struct _krb5_key_type *kt,
     41 		   struct _krb5_key_data *kd)
     42 {
     43     struct _krb5_evp_schedule *key = kd->schedule->data;
     44     const EVP_CIPHER *c = (*kt->evp)();
     45 
     46 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
     47     key->ectx = malloc(sizeof(*key->ectx));
     48     key->dctx = malloc(sizeof(*key->dctx));
     49     EVP_CIPHER_CTX_init(key->ectx);
     50     EVP_CIPHER_CTX_init(key->dctx);
     51 #else
     52     key->ectx = EVP_CIPHER_CTX_new();
     53     key->dctx = EVP_CIPHER_CTX_new();
     54 #endif
     55 
     56     if (!EVP_CipherInit_ex(key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1))
     57 	krb5_abortx(context, "can't initialize cipher");
     58     if (!EVP_CipherInit_ex(key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0))
     59 	krb5_abortx(context, "can't initialize cipher");
     60 }
     61 
     62 void
     63 _krb5_evp_cleanup(krb5_context context, struct _krb5_key_data *kd)
     64 {
     65     struct _krb5_evp_schedule *key = kd->schedule->data;
     66 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
     67     EVP_CIPHER_CTX_cleanup(key->ectx);
     68     EVP_CIPHER_CTX_cleanup(key->dctx);
     69     free(key->ectx);
     70     free(key->dctx);
     71 #else
     72     EVP_CIPHER_CTX_free(key->ectx);
     73     EVP_CIPHER_CTX_free(key->dctx);
     74 #endif
     75 }
     76 
     77 krb5_error_code
     78 _krb5_evp_encrypt(krb5_context context,
     79 		struct _krb5_key_data *key,
     80 		void *data,
     81 		size_t len,
     82 		krb5_boolean encryptp,
     83 		int usage,
     84 		void *ivec)
     85 {
     86     struct _krb5_evp_schedule *ctx = key->schedule->data;
     87     EVP_CIPHER_CTX *c;
     88     c = encryptp ? ctx->ectx : ctx->dctx;
     89     if (ivec == NULL) {
     90 	/* alloca ? */
     91 	size_t len2 = EVP_CIPHER_CTX_iv_length(c);
     92 	void *loiv = malloc(len2);
     93 	if (loiv == NULL)
     94 	    return krb5_enomem(context);
     95 	memset(loiv, 0, len2);
     96 	if (!EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1))
     97 	    krb5_abortx(context, "can't initialize cipher");
     98 	free(loiv);
     99     } else if (!EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1))
    100 	krb5_abortx(context, "can't initialize cipher");
    101 
    102     EVP_Cipher(c, data, data, len);
    103     return 0;
    104 }
    105 
    106 static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 };
    107 
    108 krb5_error_code
    109 _krb5_evp_encrypt_cts(krb5_context context,
    110 		      struct _krb5_key_data *key,
    111 		      void *data,
    112 		      size_t len,
    113 		      krb5_boolean encryptp,
    114 		      int usage,
    115 		      void *ivec)
    116 {
    117     size_t i, blocksize;
    118     int ret;
    119     struct _krb5_evp_schedule *ctx = key->schedule->data;
    120     unsigned char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];
    121     EVP_CIPHER_CTX *c;
    122     unsigned char *p;
    123 
    124     c = encryptp ? ctx->ectx : ctx->dctx;
    125 
    126     blocksize = EVP_CIPHER_CTX_block_size(c);
    127 
    128     if (len < blocksize) {
    129 	krb5_set_error_message(context, EINVAL,
    130 			       "message block too short");
    131 	return EINVAL;
    132     } else if (len == blocksize) {
    133 	if (!EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1))
    134 	    krb5_abortx(context, "can't initialize cipher");
    135 	EVP_Cipher(c, data, data, len);
    136 	return 0;
    137     }
    138 
    139     if (ivec)
    140 	ret = EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
    141     else
    142 	ret = EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
    143     if (!ret)
    144 	krb5_abortx(context, "can't initialize cipher");
    145 
    146     if (encryptp) {
    147 
    148 	p = data;
    149 	i = ((len - 1) / blocksize) * blocksize;
    150 	EVP_Cipher(c, p, p, i);
    151 	p += i - blocksize;
    152 	len -= i;
    153 	memcpy(ivec2, p, blocksize);
    154 
    155 	for (i = 0; i < len; i++)
    156 	    tmp[i] = p[i + blocksize] ^ ivec2[i];
    157 	for (; i < blocksize; i++)
    158 	    tmp[i] = 0 ^ ivec2[i];
    159 
    160 	if (!EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1))
    161 	    krb5_abortx(context, "can't initialize cipher");
    162 	EVP_Cipher(c, p, tmp, blocksize);
    163 
    164 	memcpy(p + blocksize, ivec2, len);
    165 	if (ivec)
    166 	    memcpy(ivec, p, blocksize);
    167     } else {
    168 	unsigned char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH];
    169 
    170 	p = data;
    171 	if (len > blocksize * 2) {
    172 	    /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */
    173 	    i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize);
    174 	    memcpy(ivec2, p + i - blocksize, blocksize);
    175 	    EVP_Cipher(c, p, p, i);
    176 	    p += i;
    177 	    len -= i + blocksize;
    178 	} else {
    179 	    if (ivec)
    180 		memcpy(ivec2, ivec, blocksize);
    181 	    else
    182 		memcpy(ivec2, zero_ivec, blocksize);
    183 	    len -= blocksize;
    184 	}
    185 
    186 	memcpy(tmp, p, blocksize);
    187 	if (!EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1))
    188 	    krb5_abortx(context, "can't initialize cipher");
    189 	EVP_Cipher(c, tmp2, p, blocksize);
    190 
    191 	memcpy(tmp3, p + blocksize, len);
    192 	memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */
    193 
    194 	for (i = 0; i < len; i++)
    195 	    p[i + blocksize] = tmp2[i] ^ tmp3[i];
    196 
    197 	if (!EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1))
    198 	    krb5_abortx(context, "can't initialize cipher");
    199 	EVP_Cipher(c, p, tmp3, blocksize);
    200 
    201 	for (i = 0; i < blocksize; i++)
    202 	    p[i] ^= ivec2[i];
    203 	if (ivec)
    204 	    memcpy(ivec, tmp, blocksize);
    205     }
    206     return 0;
    207 }
    208