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 Högskolan 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