LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - crypto-evp.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 234 311 75.2 %
Date: 2024-06-13 04:01:37 Functions: 15 17 88.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "krb5_locl.h"
      35             : 
      36             : void
      37     4317791 : _krb5_evp_schedule(krb5_context context,
      38             :                    struct _krb5_key_type *kt,
      39             :                    struct _krb5_key_data *kd)
      40             : {
      41     4317791 :     struct _krb5_evp_schedule *key = kd->schedule->data;
      42     4317791 :     const EVP_CIPHER *c = (*kt->evp)();
      43             : 
      44     4317791 :     EVP_CIPHER_CTX_init(&key->ectx);
      45     4317791 :     EVP_CIPHER_CTX_init(&key->dctx);
      46             : 
      47     4317791 :     EVP_CipherInit_ex(&key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1);
      48     4317791 :     EVP_CipherInit_ex(&key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0);
      49     4317791 : }
      50             : 
      51             : void
      52     4317791 : _krb5_evp_cleanup(krb5_context context, struct _krb5_key_data *kd)
      53             : {
      54     4317791 :     struct _krb5_evp_schedule *key = kd->schedule->data;
      55     4317791 :     EVP_CIPHER_CTX_cleanup(&key->ectx);
      56     4317791 :     EVP_CIPHER_CTX_cleanup(&key->dctx);
      57     4317791 : }
      58             : 
      59             : int
      60     2437596 : _krb5_evp_digest_iov(krb5_crypto crypto,
      61             :                      const struct krb5_crypto_iov *iov,
      62             :                      int niov,
      63             :                      void *hash,
      64             :                      unsigned int *hsize,
      65             :                      const EVP_MD *md,
      66             :                      ENGINE *engine)
      67             : {
      68             :     EVP_MD_CTX *ctx;
      69             :     int ret, i;
      70     2437596 :     krb5_data current = {0,0};
      71             : 
      72     2437596 :     if (crypto != NULL) {
      73     1102143 :         if (crypto->mdctx == NULL)
      74      271622 :             crypto->mdctx = EVP_MD_CTX_create();
      75     1102143 :         if (crypto->mdctx == NULL)
      76           0 :             return 0;
      77     1102143 :         ctx = crypto->mdctx;
      78             :     } else
      79     1335453 :         ctx = EVP_MD_CTX_create();
      80             : 
      81     2437596 :     ret = EVP_DigestInit_ex(ctx, md, engine);
      82     2437596 :     if (ret != 1)
      83           0 :         goto out;
      84             : 
      85     5834186 :     for (i = 0; i < niov; i++) {
      86     3396590 :         if (_krb5_crypto_iov_should_sign(&iov[i])) {
      87     3396590 :             if ((char *)current.data + current.length == iov[i].data.data) {
      88          32 :                 current.length += iov[i].data.length;
      89             :             } else {
      90     3396558 :                 if (current.data) {
      91      958994 :                     ret = EVP_DigestUpdate(ctx, current.data, current.length);
      92      958994 :                     if (ret != 1)
      93           0 :                         goto out;
      94             :                 }
      95     3396558 :                 current = iov[i].data;
      96             :             }
      97             :         }
      98             :     }
      99             : 
     100     2437596 :     if (current.data) {
     101     2437564 :         ret = EVP_DigestUpdate(ctx, current.data, current.length);
     102     2437564 :         if (ret != 1)
     103           0 :             goto out;
     104             :     }
     105             : 
     106     2437596 :     ret = EVP_DigestFinal_ex(ctx, hash, hsize);
     107             : 
     108     2437596 : out:
     109     2437596 :     if (crypto == NULL)
     110     1335453 :         EVP_MD_CTX_destroy(ctx);
     111             : 
     112     2437596 :     return ret;
     113             : }
     114             : 
     115             : krb5_error_code
     116     3874642 : _krb5_evp_hmac_iov(krb5_context context,
     117             :                    krb5_crypto crypto,
     118             :                    struct _krb5_key_data *key,
     119             :                    const struct krb5_crypto_iov *iov,
     120             :                    int niov,
     121             :                    void *hmac,
     122             :                    unsigned int *hmaclen,
     123             :                    const EVP_MD *md,
     124             :                    ENGINE *engine)
     125             : {
     126             :     HMAC_CTX *ctx;
     127     3874642 :     krb5_data current = {0, 0};
     128             :     int i;
     129             : 
     130     3874642 :     if (crypto != NULL) {
     131     3874642 :         if (crypto->hmacctx == NULL)
     132      874579 :             crypto->hmacctx = HMAC_CTX_new();
     133     3874642 :         ctx = crypto->hmacctx;
     134             :     } else {
     135           0 :         ctx = HMAC_CTX_new();
     136             :     }
     137     3874642 :     if (ctx == NULL)
     138           0 :         return krb5_enomem(context);
     139             : 
     140     3874642 :     if (HMAC_Init_ex(ctx, key->key->keyvalue.data, key->key->keyvalue.length,
     141             :                      md, engine) == 0) {
     142           0 :         HMAC_CTX_free(ctx);
     143           0 :         return krb5_enomem(context);
     144             :     }
     145             : 
     146    16120142 :     for (i = 0; i < niov; i++) {
     147    12245500 :         if (_krb5_crypto_iov_should_sign(&iov[i])) {
     148     9408358 :             if ((char *)current.data + current.length == iov[i].data.data) {
     149     2743531 :                 current.length += iov[i].data.length;
     150             :             } else {
     151     6664827 :                 if (current.data)
     152     2790286 :                     HMAC_Update(ctx, current.data, current.length);
     153     6664827 :                 current = iov[i].data;
     154             :             }
     155             :         }
     156             :     }
     157             : 
     158     3874642 :     if (current.data)
     159     3874541 :         HMAC_Update(ctx, current.data, current.length);
     160             : 
     161     3874642 :     HMAC_Final(ctx, hmac, hmaclen);
     162             : 
     163     3874642 :     if (crypto == NULL)
     164           0 :         HMAC_CTX_free(ctx);
     165             : 
     166     3874642 :     return 0;
     167             : }
     168             : 
     169             : krb5_error_code
     170           0 : _krb5_evp_encrypt(krb5_context context,
     171             :                 struct _krb5_key_data *key,
     172             :                 void *data,
     173             :                 size_t len,
     174             :                 krb5_boolean encryptp,
     175             :                 int usage,
     176             :                 void *ivec)
     177             : {
     178           0 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     179             :     EVP_CIPHER_CTX *c;
     180           0 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     181           0 :     if (ivec == NULL) {
     182             :         /* alloca ? */
     183           0 :         size_t len2 = EVP_CIPHER_CTX_iv_length(c);
     184           0 :         void *loiv = malloc(len2);
     185           0 :         if (loiv == NULL)
     186           0 :             return krb5_enomem(context);
     187           0 :         memset(loiv, 0, len2);
     188           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1);
     189           0 :         free(loiv);
     190             :     } else
     191           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     192           0 :     EVP_Cipher(c, data, data, len);
     193           0 :     return 0;
     194             : }
     195             : 
     196             : struct _krb5_evp_iov_cursor
     197             : {
     198             :     struct krb5_crypto_iov *iov;
     199             :     int niov;
     200             :     krb5_data current;
     201             :     int nextidx;
     202             : };
     203             : 
     204             : static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 };
     205             : 
     206             : static inline int
     207    26123025 : _krb5_evp_iov_should_encrypt(struct krb5_crypto_iov *iov)
     208             : {
     209    26123025 :     return (iov->flags == KRB5_CRYPTO_TYPE_DATA
     210    20205584 :             || iov->flags == KRB5_CRYPTO_TYPE_HEADER
     211    43538323 :             || iov->flags == KRB5_CRYPTO_TYPE_PADDING);
     212             : }
     213             : /*
     214             :  * If we have a group of iovecs which have been split up from
     215             :  * a single common buffer, expand the 'current' iovec out to
     216             :  * be as large as possible.
     217             :  */
     218             : 
     219             : static inline void
     220     4522106 : _krb5_evp_iov_cursor_expand(struct _krb5_evp_iov_cursor *cursor)
     221             : {
     222     4522106 :     if (cursor->nextidx == cursor->niov)
     223           0 :        return;
     224             : 
     225     9044212 :     while (_krb5_evp_iov_should_encrypt(&cursor->iov[cursor->nextidx])) {
     226           0 :         if (cursor->iov[cursor->nextidx].data.length != 0 &&
     227           0 :             ((char *)cursor->current.data + cursor->current.length
     228           0 :              != cursor->iov[cursor->nextidx].data.data)) {
     229           0 :             return;
     230             :         }
     231           0 :         cursor->current.length += cursor->iov[cursor->nextidx].data.length;
     232           0 :         cursor->nextidx++;
     233             :     }
     234             : 
     235     4522106 :     return;
     236             : }
     237             : 
     238             : /* Move the cursor along to the start of the next block to be
     239             :  * encrypted */
     240             : static inline void
     241     7312392 : _krb5_evp_iov_cursor_nextcrypt(struct _krb5_evp_iov_cursor *cursor)
     242             : {
     243    14625204 :     for (; cursor->nextidx < cursor->niov; cursor->nextidx++) {
     244    11834918 :         if (_krb5_evp_iov_should_encrypt(&cursor->iov[cursor->nextidx])
     245     4522298 :             && cursor->iov[cursor->nextidx].data.length != 0) {
     246     4522106 :             cursor->current = cursor->iov[cursor->nextidx].data;
     247     4522106 :             cursor->nextidx++;
     248     4522106 :             _krb5_evp_iov_cursor_expand(cursor);
     249     4522106 :             return;
     250             :         }
     251             :     }
     252             : 
     253     2790286 :     cursor->current.length = 0; /* No matches, so we're done here */
     254             : }
     255             : 
     256             : static inline void
     257     1395143 : _krb5_evp_iov_cursor_init(struct _krb5_evp_iov_cursor *cursor,
     258             :                           struct krb5_crypto_iov *iov, int niov)
     259             : {
     260     1395143 :     memset(cursor, 0, sizeof(struct _krb5_evp_iov_cursor));
     261             : 
     262     1395143 :     cursor->iov = iov;
     263     1395143 :     cursor->niov = niov;
     264     1395143 :     cursor->nextidx = 0;
     265             : 
     266             :     /* Move along to the first block we're going to be encrypting */
     267     1395143 :     _krb5_evp_iov_cursor_nextcrypt(cursor);
     268     1395143 : }
     269             : 
     270             : static inline void
     271     6630203 : _krb5_evp_iov_cursor_advance(struct _krb5_evp_iov_cursor *cursor,
     272             :                              size_t amount)
     273             : {
     274    15713703 :     while (amount > 0) {
     275     5571893 :         if (cursor->current.length > amount) {
     276     3118596 :             cursor->current.data = (char *)cursor->current.data + amount;
     277     3118596 :             cursor->current.length -= amount;
     278     3118596 :             return;
     279             :         }
     280     2453297 :         amount -= cursor->current.length;
     281     2453297 :         _krb5_evp_iov_cursor_nextcrypt(cursor);
     282             :     }
     283             : }
     284             : 
     285             : static inline int
     286     5195928 : _krb5_evp_iov_cursor_done(struct _krb5_evp_iov_cursor *cursor)
     287             : {
     288     5195928 :     return (cursor->nextidx == cursor->niov && cursor->current.length == 0);
     289             : }
     290             : 
     291             : /* Fill a memory buffer with data from one or more iovecs. Doesn't
     292             :  * advance the passed in cursor - use outcursor for the position
     293             :  * at the end
     294             :  */
     295             : static inline void
     296     2068809 : _krb5_evp_iov_cursor_fillbuf(struct _krb5_evp_iov_cursor *cursor,
     297             :                              unsigned char *buf, size_t length,
     298             :                              struct _krb5_evp_iov_cursor *outcursor)
     299             : {
     300             :     struct _krb5_evp_iov_cursor cursorint;
     301             : 
     302     2068809 :     cursorint = *cursor;
     303             : 
     304     6206427 :     while (length > 0 && !_krb5_evp_iov_cursor_done(&cursorint)) {
     305     2068809 :         if (cursorint.current.length > length) {
     306      336833 :             memcpy(buf, cursorint.current.data, length);
     307      336833 :             _krb5_evp_iov_cursor_advance(&cursorint, length);
     308      336833 :             length = 0;
     309             :         } else {
     310     1731976 :             memcpy(buf, cursorint.current.data, cursorint.current.length);
     311     1731976 :             length -= cursorint.current.length;
     312     1731976 :             buf += cursorint.current.length;
     313     1731976 :             _krb5_evp_iov_cursor_nextcrypt(&cursorint);
     314             :         }
     315             :     }
     316             : 
     317     2068809 :     if (outcursor != NULL)
     318      336833 :         *outcursor = cursorint;
     319     2068809 : }
     320             : 
     321             : /* Fill an iovec from a memory buffer. Always advances the cursor to
     322             :  * the end of the filled region
     323             :  */
     324             : static inline void
     325     3127119 : _krb5_evp_iov_cursor_fillvec(struct _krb5_evp_iov_cursor *cursor,
     326             :                              unsigned char *buf, size_t length)
     327             : {
     328     9381357 :     while (length > 0 && !_krb5_evp_iov_cursor_done(cursor)) {
     329     3127119 :         if (cursor->current.length > length) {
     330     1395143 :             memcpy(cursor->current.data, buf, length);
     331     1395143 :             _krb5_evp_iov_cursor_advance(cursor, length);
     332     1395143 :             length = 0;
     333             :         } else {
     334     1731976 :             memcpy(cursor->current.data, buf, cursor->current.length);
     335     1731976 :             length -= cursor->current.length;
     336     1731976 :             buf += cursor->current.length;
     337     1731976 :             _krb5_evp_iov_cursor_nextcrypt(cursor);
     338             :         }
     339             :     }
     340     3127119 : }
     341             : 
     342             : static size_t
     343     1395143 : _krb5_evp_iov_cryptlength(struct krb5_crypto_iov *iov, int niov)
     344             : {
     345             :     int i;
     346     1395143 :     size_t length = 0;
     347             : 
     348    11161144 :     for (i = 0; i < niov; i++) {
     349     9766001 :         if (_krb5_evp_iov_should_encrypt(&iov[i]))
     350     4185429 :             length += iov[i].data.length;
     351             :     }
     352             : 
     353     1395143 :     return length;
     354             : }
     355             : 
     356             : int
     357           0 : _krb5_evp_encrypt_iov(krb5_context context,
     358             :                       struct _krb5_key_data *key,
     359             :                       struct krb5_crypto_iov *iov,
     360             :                       int niov,
     361             :                       krb5_boolean encryptp,
     362             :                       int usage,
     363             :                       void *ivec)
     364             : {
     365             :     size_t blocksize, blockmask, wholeblocks;
     366           0 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     367             :     unsigned char tmp[EVP_MAX_BLOCK_LENGTH];
     368             :     EVP_CIPHER_CTX *c;
     369             :     struct _krb5_evp_iov_cursor cursor;
     370             : 
     371           0 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     372             : 
     373           0 :     blocksize = EVP_CIPHER_CTX_block_size(c);
     374             : 
     375           0 :     blockmask = ~(blocksize - 1);
     376             : 
     377           0 :     if (ivec)
     378           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     379             :     else
     380           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     381             : 
     382           0 :     _krb5_evp_iov_cursor_init(&cursor, iov, niov);
     383             : 
     384           0 :     while (!_krb5_evp_iov_cursor_done(&cursor)) {
     385             : 
     386             :         /* Number of bytes of data in this iovec that are in whole blocks */
     387           0 :         wholeblocks = cursor.current.length & ~blockmask;
     388             : 
     389           0 :         if (wholeblocks != 0) {
     390           0 :             EVP_Cipher(c, cursor.current.data,
     391           0 :                        cursor.current.data, wholeblocks);
     392           0 :             _krb5_evp_iov_cursor_advance(&cursor, wholeblocks);
     393             :         }
     394             : 
     395             :         /* If there's a partial block of data remaining in the current
     396             :          * iovec, steal enough from subsequent iovecs to form a whole block */
     397           0 :         if (cursor.current.length > 0 && cursor.current.length < blocksize) {
     398             :             /* Build up a block's worth of data in tmp, leaving the cursor
     399             :              * pointing at where we started */
     400           0 :             _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, blocksize, NULL);
     401             : 
     402           0 :             EVP_Cipher(c, tmp, tmp, blocksize);
     403             : 
     404             :             /* Copy the data in tmp back into the iovecs that it came from,
     405             :              * advancing the cursor */
     406           0 :             _krb5_evp_iov_cursor_fillvec(&cursor, tmp, blocksize);
     407             :         }
     408             :     }
     409             : 
     410           0 :     return 0;
     411             : }
     412             : 
     413             : int
     414     1395143 : _krb5_evp_encrypt_iov_cts(krb5_context context,
     415             :                           struct _krb5_key_data *key,
     416             :                           struct krb5_crypto_iov *iov,
     417             :                           int niov,
     418             :                           krb5_boolean encryptp,
     419             :                           int usage,
     420             :                           void *ivec)
     421             : {
     422             :     size_t blocksize, blockmask, wholeblocks, length;
     423             :     size_t remaining, partiallen;
     424             :     struct _krb5_evp_iov_cursor cursor, lastpos;
     425     1395143 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     426             :     unsigned char tmp[EVP_MAX_BLOCK_LENGTH], tmp2[EVP_MAX_BLOCK_LENGTH];
     427             :     unsigned char tmp3[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];
     428             :     EVP_CIPHER_CTX *c;
     429             :     int i;
     430             : 
     431     1395143 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     432             : 
     433     1395143 :     blocksize = EVP_CIPHER_CTX_block_size(c);
     434     1395143 :     blockmask = ~(blocksize - 1);
     435             : 
     436     1395143 :     length = _krb5_evp_iov_cryptlength(iov, niov);
     437             : 
     438     1395143 :     if (length < blocksize) {
     439           0 :         krb5_set_error_message(context, EINVAL,
     440             :                                "message block too short");
     441           0 :         return EINVAL;
     442             :     }
     443             : 
     444     1395143 :     if (length == blocksize)
     445           0 :         return _krb5_evp_encrypt_iov(context, key, iov, niov,
     446             :                                      encryptp, usage, ivec);
     447             : 
     448     1395143 :     if (ivec)
     449           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     450             :     else
     451     1395143 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     452             : 
     453     1395143 :     if (encryptp) {
     454             :         /* On our first pass, we want to process everything but the
     455             :          * final partial block */
     456     1058310 :         remaining = ((length - 1) & blockmask);
     457     1058310 :         partiallen = length - remaining;
     458             : 
     459     1058310 :         memset(&lastpos, 0, sizeof(lastpos)); /* Keep the compiler happy */
     460             :     } else {
     461             :         /* Decryption needs to leave 2 whole blocks and a partial for
     462             :          * further processing */
     463      336833 :         if (length > 2 * blocksize) {
     464      336833 :             remaining = (((length - 1) / blocksize) * blocksize) - (blocksize*2);
     465      336833 :             partiallen = length - remaining - (blocksize * 2);
     466             :         } else {
     467           0 :             remaining = 0;
     468           0 :             partiallen = length - blocksize;
     469             :         }
     470             :     }
     471             : 
     472     1395143 :     _krb5_evp_iov_cursor_init(&cursor, iov, niov);
     473     6630203 :     while (remaining > 0) {
     474             :         /* If the iovec has more data than we need, just use it */
     475     3839917 :         if (cursor.current.length >= remaining) {
     476     1395107 :             EVP_Cipher(c, cursor.current.data, cursor.current.data, remaining);
     477             : 
     478     1395107 :             if (encryptp) {
     479             :                 /* We've just encrypted the last block of data. Make a copy
     480             :                  * of it (and its location) for the CTS dance, below */
     481     1058310 :                 lastpos = cursor;
     482     1058310 :                 _krb5_evp_iov_cursor_advance(&lastpos, remaining - blocksize);
     483     1058310 :                 memcpy(ivec2, lastpos.current.data, blocksize);
     484             :             }
     485             : 
     486     1395107 :             _krb5_evp_iov_cursor_advance(&cursor, remaining);
     487     1395107 :             remaining = 0;
     488             :         } else {
     489             :             /* Use as much as we can, firstly all of the whole blocks */
     490     2444810 :             wholeblocks = cursor.current.length & blockmask;
     491             : 
     492     2444810 :             if (wholeblocks > 0) {
     493     2444810 :                 EVP_Cipher(c, cursor.current.data, cursor.current.data,
     494             :                            wholeblocks);
     495     2444810 :                 _krb5_evp_iov_cursor_advance(&cursor, wholeblocks);
     496     2444810 :                 remaining -= wholeblocks;
     497             :             }
     498             : 
     499             :             /* Then, if we have partial data left, steal enough from subsequent
     500             :              * iovecs to make a whole block */
     501     2444810 :             if (cursor.current.length > 0 && cursor.current.length < blocksize) {
     502           0 :                 if (encryptp && remaining == blocksize)
     503           0 :                     lastpos = cursor;
     504             : 
     505           0 :                 _krb5_evp_iov_cursor_fillbuf(&cursor, ivec2, blocksize, NULL);
     506           0 :                 EVP_Cipher(c, ivec2, ivec2, blocksize);
     507           0 :                 _krb5_evp_iov_cursor_fillvec(&cursor, ivec2, blocksize);
     508             : 
     509           0 :                 remaining -= blocksize;
     510             :             }
     511             :         }
     512             :     }
     513             : 
     514             :     /* Encryption */
     515     1395143 :     if (encryptp) {
     516             :         /* Copy the partial block into tmp */
     517     1058310 :         _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, partiallen, NULL);
     518             : 
     519             :         /* XOR the final partial block with ivec2 */
     520    17991270 :         for (i = 0; i < partiallen; i++)
     521    16932960 :             tmp[i] = tmp[i] ^ ivec2[i];
     522     1058310 :         for (; i < blocksize; i++)
     523           0 :             tmp[i] = 0 ^ ivec2[i]; /* XOR 0s if partial block exhausted */
     524             : 
     525     1058310 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     526     1058310 :         EVP_Cipher(c, tmp, tmp, blocksize);
     527             : 
     528     1058310 :         _krb5_evp_iov_cursor_fillvec(&lastpos, tmp, blocksize);
     529     1058310 :         _krb5_evp_iov_cursor_fillvec(&cursor, ivec2, partiallen);
     530             : 
     531     1058310 :         if (ivec)
     532           0 :             memcpy(ivec, tmp, blocksize);
     533             : 
     534     1058310 :         return 0;
     535             :     }
     536             : 
     537             :     /* Decryption */
     538             : 
     539             :     /* Make a copy of the 2nd last full ciphertext block in ivec2 before
     540             :      * decrypting it. If no such block exists, use ivec or zero_ivec */
     541      336833 :     if (length <= blocksize * 2) {
     542           0 :         if (ivec)
     543           0 :            memcpy(ivec2, ivec, blocksize);
     544             :         else
     545           0 :            memcpy(ivec2, zero_ivec, blocksize);
     546             :     } else {
     547      336833 :         _krb5_evp_iov_cursor_fillbuf(&cursor, ivec2, blocksize, NULL);
     548      336833 :         EVP_Cipher(c, tmp, ivec2, blocksize);
     549      336833 :         _krb5_evp_iov_cursor_fillvec(&cursor, tmp, blocksize);
     550             :     }
     551             : 
     552      336833 :     lastpos = cursor; /* Remember where the last block is */
     553      336833 :     _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, blocksize, &cursor);
     554      336833 :     EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     555      336833 :     EVP_Cipher(c, tmp2, tmp, blocksize); /* tmp eventually becomes output ivec */
     556             : 
     557      336833 :     _krb5_evp_iov_cursor_fillbuf(&cursor, tmp3, partiallen, NULL);
     558             : 
     559      336833 :     memcpy(tmp3 + partiallen, tmp2 + partiallen, blocksize - partiallen); /* xor 0 */
     560     5726161 :     for (i = 0; i < partiallen; i++)
     561     5389328 :         tmp2[i] = tmp2[i] ^ tmp3[i];
     562             : 
     563      336833 :     _krb5_evp_iov_cursor_fillvec(&cursor, tmp2, partiallen);
     564             : 
     565      336833 :     EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     566      336833 :     EVP_Cipher(c, tmp3, tmp3, blocksize);
     567             : 
     568     5726161 :     for (i = 0; i < blocksize; i++)
     569     5389328 :         tmp3[i] ^= ivec2[i];
     570             : 
     571      336833 :     _krb5_evp_iov_cursor_fillvec(&lastpos, tmp3, blocksize);
     572             : 
     573      336833 :     if (ivec)
     574           0 :         memcpy(ivec, tmp, blocksize);
     575             : 
     576      336833 :     return 0;
     577             : }
     578             : 
     579             : krb5_error_code
     580     6454517 : _krb5_evp_encrypt_cts(krb5_context context,
     581             :                       struct _krb5_key_data *key,
     582             :                       void *data,
     583             :                       size_t len,
     584             :                       krb5_boolean encryptp,
     585             :                       int usage,
     586             :                       void *ivec)
     587             : {
     588             :     size_t i, blocksize;
     589     6454517 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     590             :     unsigned char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];
     591             :     EVP_CIPHER_CTX *c;
     592             :     unsigned char *p;
     593             : 
     594     6454517 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     595             : 
     596     6454517 :     blocksize = EVP_CIPHER_CTX_block_size(c);
     597             : 
     598     6454517 :     if (len < blocksize) {
     599           0 :         krb5_set_error_message(context, EINVAL,
     600             :                                "message block too short");
     601           0 :         return EINVAL;
     602     6454517 :     } else if (len == blocksize) {
     603     4733111 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     604     4733111 :         EVP_Cipher(c, data, data, len);
     605     4733111 :         return 0;
     606             :     }
     607             : 
     608     1721406 :     if (ivec)
     609           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     610             :     else
     611     1721406 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     612             : 
     613     1721406 :     if (encryptp) {
     614             : 
     615      836902 :         p = data;
     616      836902 :         i = ((len - 1) / blocksize) * blocksize;
     617      836902 :         EVP_Cipher(c, p, p, i);
     618      836902 :         p += i - blocksize;
     619      836902 :         len -= i;
     620      836902 :         memcpy(ivec2, p, blocksize);
     621             : 
     622     8303259 :         for (i = 0; i < len; i++)
     623     7466357 :             tmp[i] = p[i + blocksize] ^ ivec2[i];
     624     6760977 :         for (; i < blocksize; i++)
     625     5924075 :             tmp[i] = 0 ^ ivec2[i];
     626             : 
     627      836902 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     628      836902 :         EVP_Cipher(c, p, tmp, blocksize);
     629             : 
     630      836902 :         memcpy(p + blocksize, ivec2, len);
     631      836902 :         if (ivec)
     632           0 :             memcpy(ivec, p, blocksize);
     633             :     } else {
     634             :         unsigned char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH];
     635             : 
     636      884504 :         p = data;
     637      884504 :         if (len > blocksize * 2) {
     638             :             /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */
     639      884504 :             i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize);
     640      884504 :             memcpy(ivec2, p + i - blocksize, blocksize);
     641      884504 :             EVP_Cipher(c, p, p, i);
     642      884504 :             p += i;
     643      884504 :             len -= i + blocksize;
     644             :         } else {
     645           0 :             if (ivec)
     646           0 :                 memcpy(ivec2, ivec, blocksize);
     647             :             else
     648           0 :                 memcpy(ivec2, zero_ivec, blocksize);
     649           0 :             len -= blocksize;
     650             :         }
     651             : 
     652      884504 :         memcpy(tmp, p, blocksize);
     653      884504 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     654      884504 :         EVP_Cipher(c, tmp2, p, blocksize);
     655             : 
     656      884504 :         memcpy(tmp3, p + blocksize, len);
     657      884504 :         memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */
     658             : 
     659     8707863 :         for (i = 0; i < len; i++)
     660     7823359 :             p[i + blocksize] = tmp2[i] ^ tmp3[i];
     661             : 
     662      884504 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     663      884504 :         EVP_Cipher(c, p, tmp3, blocksize);
     664             : 
     665    15036568 :         for (i = 0; i < blocksize; i++)
     666    14152064 :             p[i] ^= ivec2[i];
     667      884504 :         if (ivec)
     668           0 :             memcpy(ivec, tmp, blocksize);
     669             :     }
     670     1721406 :     return 0;
     671             : }

Generated by: LCOV version 1.13