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