1226031Sstas/* 2226031Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4226031Sstas * All rights reserved. 5226031Sstas * 6226031Sstas * Redistribution and use in source and binary forms, with or without 7226031Sstas * modification, are permitted provided that the following conditions 8226031Sstas * are met: 9226031Sstas * 10226031Sstas * 1. Redistributions of source code must retain the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer. 12226031Sstas * 13226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 14226031Sstas * notice, this list of conditions and the following disclaimer in the 15226031Sstas * documentation and/or other materials provided with the distribution. 16226031Sstas * 17226031Sstas * 3. Neither the name of the Institute nor the names of its contributors 18226031Sstas * may be used to endorse or promote products derived from this software 19226031Sstas * without specific prior written permission. 20226031Sstas * 21226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31226031Sstas * SUCH DAMAGE. 32226031Sstas */ 33226031Sstas 34226031Sstas#include "krb5_locl.h" 35226031Sstas 36226031Sstasvoid 37226031Sstas_krb5_evp_schedule(krb5_context context, 38226031Sstas struct _krb5_key_type *kt, 39226031Sstas struct _krb5_key_data *kd) 40226031Sstas{ 41226031Sstas struct _krb5_evp_schedule *key = kd->schedule->data; 42226031Sstas const EVP_CIPHER *c = (*kt->evp)(); 43226031Sstas 44226031Sstas EVP_CIPHER_CTX_init(&key->ectx); 45226031Sstas EVP_CIPHER_CTX_init(&key->dctx); 46226031Sstas 47226031Sstas EVP_CipherInit_ex(&key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1); 48226031Sstas EVP_CipherInit_ex(&key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0); 49226031Sstas} 50226031Sstas 51226031Sstasvoid 52226031Sstas_krb5_evp_cleanup(krb5_context context, struct _krb5_key_data *kd) 53226031Sstas{ 54226031Sstas struct _krb5_evp_schedule *key = kd->schedule->data; 55226031Sstas EVP_CIPHER_CTX_cleanup(&key->ectx); 56226031Sstas EVP_CIPHER_CTX_cleanup(&key->dctx); 57226031Sstas} 58226031Sstas 59226031Sstaskrb5_error_code 60226031Sstas_krb5_evp_encrypt(krb5_context context, 61226031Sstas struct _krb5_key_data *key, 62226031Sstas void *data, 63226031Sstas size_t len, 64226031Sstas krb5_boolean encryptp, 65226031Sstas int usage, 66226031Sstas void *ivec) 67226031Sstas{ 68226031Sstas struct _krb5_evp_schedule *ctx = key->schedule->data; 69226031Sstas EVP_CIPHER_CTX *c; 70226031Sstas c = encryptp ? &ctx->ectx : &ctx->dctx; 71226031Sstas if (ivec == NULL) { 72226031Sstas /* alloca ? */ 73226031Sstas size_t len2 = EVP_CIPHER_CTX_iv_length(c); 74226031Sstas void *loiv = malloc(len2); 75226031Sstas if (loiv == NULL) { 76226031Sstas krb5_clear_error_message(context); 77226031Sstas return ENOMEM; 78226031Sstas } 79226031Sstas memset(loiv, 0, len2); 80226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1); 81226031Sstas free(loiv); 82226031Sstas } else 83226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1); 84226031Sstas EVP_Cipher(c, data, data, len); 85226031Sstas return 0; 86226031Sstas} 87226031Sstas 88226031Sstasstatic const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 }; 89226031Sstas 90226031Sstaskrb5_error_code 91226031Sstas_krb5_evp_encrypt_cts(krb5_context context, 92226031Sstas struct _krb5_key_data *key, 93226031Sstas void *data, 94226031Sstas size_t len, 95226031Sstas krb5_boolean encryptp, 96226031Sstas int usage, 97226031Sstas void *ivec) 98226031Sstas{ 99226031Sstas size_t i, blocksize; 100226031Sstas struct _krb5_evp_schedule *ctx = key->schedule->data; 101226031Sstas unsigned char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH]; 102226031Sstas EVP_CIPHER_CTX *c; 103226031Sstas unsigned char *p; 104226031Sstas 105226031Sstas c = encryptp ? &ctx->ectx : &ctx->dctx; 106226031Sstas 107226031Sstas blocksize = EVP_CIPHER_CTX_block_size(c); 108226031Sstas 109226031Sstas if (len < blocksize) { 110226031Sstas krb5_set_error_message(context, EINVAL, 111226031Sstas "message block too short"); 112226031Sstas return EINVAL; 113226031Sstas } else if (len == blocksize) { 114226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); 115226031Sstas EVP_Cipher(c, data, data, len); 116226031Sstas return 0; 117226031Sstas } 118226031Sstas 119226031Sstas if (ivec) 120226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1); 121226031Sstas else 122226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); 123226031Sstas 124226031Sstas if (encryptp) { 125226031Sstas 126226031Sstas p = data; 127226031Sstas i = ((len - 1) / blocksize) * blocksize; 128226031Sstas EVP_Cipher(c, p, p, i); 129226031Sstas p += i - blocksize; 130226031Sstas len -= i; 131226031Sstas memcpy(ivec2, p, blocksize); 132226031Sstas 133226031Sstas for (i = 0; i < len; i++) 134226031Sstas tmp[i] = p[i + blocksize] ^ ivec2[i]; 135226031Sstas for (; i < blocksize; i++) 136226031Sstas tmp[i] = 0 ^ ivec2[i]; 137226031Sstas 138226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); 139226031Sstas EVP_Cipher(c, p, tmp, blocksize); 140226031Sstas 141226031Sstas memcpy(p + blocksize, ivec2, len); 142226031Sstas if (ivec) 143226031Sstas memcpy(ivec, p, blocksize); 144226031Sstas } else { 145226031Sstas unsigned char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH]; 146226031Sstas 147226031Sstas p = data; 148226031Sstas if (len > blocksize * 2) { 149226031Sstas /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */ 150226031Sstas i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize); 151226031Sstas memcpy(ivec2, p + i - blocksize, blocksize); 152226031Sstas EVP_Cipher(c, p, p, i); 153226031Sstas p += i; 154226031Sstas len -= i + blocksize; 155226031Sstas } else { 156226031Sstas if (ivec) 157226031Sstas memcpy(ivec2, ivec, blocksize); 158226031Sstas else 159226031Sstas memcpy(ivec2, zero_ivec, blocksize); 160226031Sstas len -= blocksize; 161226031Sstas } 162226031Sstas 163226031Sstas memcpy(tmp, p, blocksize); 164226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); 165226031Sstas EVP_Cipher(c, tmp2, p, blocksize); 166226031Sstas 167226031Sstas memcpy(tmp3, p + blocksize, len); 168226031Sstas memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */ 169226031Sstas 170226031Sstas for (i = 0; i < len; i++) 171226031Sstas p[i + blocksize] = tmp2[i] ^ tmp3[i]; 172226031Sstas 173226031Sstas EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1); 174226031Sstas EVP_Cipher(c, p, tmp3, blocksize); 175226031Sstas 176226031Sstas for (i = 0; i < blocksize; i++) 177226031Sstas p[i] ^= ivec2[i]; 178226031Sstas if (ivec) 179226031Sstas memcpy(ivec, tmp, blocksize); 180226031Sstas } 181226031Sstas return 0; 182226031Sstas} 183