xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/krb5/crypto-evp.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
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
_krb5_evp_schedule(krb5_context context,struct _krb5_key_type * kt,struct _krb5_key_data * kd)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
_krb5_evp_cleanup(krb5_context context,struct _krb5_key_data * kd)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
_krb5_evp_encrypt(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,krb5_boolean encryptp,int usage,void * ivec)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
_krb5_evp_encrypt_cts(krb5_context context,struct _krb5_key_data * key,void * data,size_t len,krb5_boolean encryptp,int usage,void * ivec)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