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