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 master 2f515e9b Lines: 257 336 76.5 %
Date: 2024-04-21 15:09:00 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     5815328 : _krb5_evp_schedule(krb5_context context,
      38             :                    struct _krb5_key_type *kt,
      39             :                    struct _krb5_key_data *kd)
      40             : {
      41     5815328 :     struct _krb5_evp_schedule *key = kd->schedule->data;
      42     5815328 :     const EVP_CIPHER *c = (*kt->evp)();
      43             : 
      44     5815328 :     EVP_CIPHER_CTX_init(&key->ectx);
      45     5815328 :     EVP_CIPHER_CTX_init(&key->dctx);
      46             : 
      47     5815328 :     EVP_CipherInit_ex(&key->ectx, c, NULL, kd->key->keyvalue.data, NULL, 1);
      48     5815328 :     EVP_CipherInit_ex(&key->dctx, c, NULL, kd->key->keyvalue.data, NULL, 0);
      49     5815328 : }
      50             : 
      51             : void
      52     5815328 : _krb5_evp_cleanup(krb5_context context, struct _krb5_key_data *kd)
      53             : {
      54     5815328 :     struct _krb5_evp_schedule *key = kd->schedule->data;
      55     5815328 :     EVP_CIPHER_CTX_cleanup(&key->ectx);
      56     5815328 :     EVP_CIPHER_CTX_cleanup(&key->dctx);
      57     5815328 : }
      58             : 
      59             : int
      60     2975456 : _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       26920 :     EVP_MD_CTX *ctx;
      69       26920 :     int ret, i;
      70     2975456 :     krb5_data current = {0,0};
      71             : 
      72     2975456 :     if (crypto != NULL) {
      73     1407183 :         if (crypto->mdctx == NULL)
      74      369232 :             crypto->mdctx = EVP_MD_CTX_create();
      75     1407183 :         if (crypto->mdctx == NULL)
      76           0 :             return 0;
      77     1380479 :         ctx = crypto->mdctx;
      78             :     } else
      79     1568273 :         ctx = EVP_MD_CTX_create();
      80             : 
      81     2975456 :     ret = EVP_DigestInit_ex(ctx, md, engine);
      82     2975456 :     if (ret != 1)
      83           0 :         goto out;
      84             : 
      85             :     /* Minimize EVP calls by coalescing contiguous iovec elements */
      86     7081031 :     for (i = 0; i < niov; i++) {
      87     4105575 :         if (_krb5_crypto_iov_should_sign(&iov[i])) {
      88     4105575 :             if (current.data &&
      89     1130119 :                 (char *)current.data + current.length == iov[i].data.data) {
      90           0 :                 current.length += iov[i].data.length;
      91             :             } else {
      92     4105575 :                 if (current.data) {
      93     1130119 :                     ret = EVP_DigestUpdate(ctx, current.data, current.length);
      94     1130119 :                     if (ret != 1)
      95           0 :                         goto out;
      96             :                 }
      97     4105575 :                 current = iov[i].data;
      98             :             }
      99             :         }
     100             :     }
     101             : 
     102     2975456 :     if (current.data) {
     103     2975424 :         ret = EVP_DigestUpdate(ctx, current.data, current.length);
     104     2975424 :         if (ret != 1)
     105           0 :             goto out;
     106             :     }
     107             : 
     108     2975456 :     ret = EVP_DigestFinal_ex(ctx, hash, hsize);
     109             : 
     110     2975456 : out:
     111     2975456 :     if (crypto == NULL)
     112     1568273 :         EVP_MD_CTX_destroy(ctx);
     113             : 
     114     2948536 :     return ret;
     115             : }
     116             : 
     117             : krb5_error_code
     118     4824286 : _krb5_evp_hmac_iov(krb5_context context,
     119             :                    krb5_crypto crypto,
     120             :                    struct _krb5_key_data *key,
     121             :                    const struct krb5_crypto_iov *iov,
     122             :                    int niov,
     123             :                    void *hmac,
     124             :                    unsigned int *hmaclen,
     125             :                    const EVP_MD *md,
     126             :                    ENGINE *engine)
     127             : {
     128       52223 :     HMAC_CTX *ctx;
     129     4824286 :     krb5_data current = {0, NULL};
     130       52223 :     int i;
     131             : 
     132     4824286 :     if (crypto != NULL) {
     133     4824286 :         if (crypto->hmacctx == NULL)
     134     1193564 :             crypto->hmacctx = HMAC_CTX_new();
     135     4824286 :         ctx = crypto->hmacctx;
     136             :     } else {
     137           0 :         ctx = HMAC_CTX_new();
     138             :     }
     139     4824286 :     if (ctx == NULL)
     140           0 :         return krb5_enomem(context);
     141             : 
     142     4824286 :     if (HMAC_Init_ex(ctx, key->key->keyvalue.data, key->key->keyvalue.length,
     143             :                      md, engine) == 0) {
     144           0 :         HMAC_CTX_free(ctx);
     145           0 :         return krb5_enomem(context);
     146             :     }
     147             : 
     148    19056014 :     for (i = 0; i < niov; i++) {
     149    14231728 :         if (_krb5_crypto_iov_should_sign(&iov[i])) {
     150    11045406 :             if (current.data &&
     151     6221120 :                 (char *)current.data + current.length == iov[i].data.data) {
     152     3085306 :                 current.length += iov[i].data.length;
     153             :             } else {
     154     7960100 :                 if (current.data)
     155     3135814 :                     HMAC_Update(ctx, current.data, current.length);
     156     7960100 :                 current = iov[i].data;
     157             :             }
     158             :         }
     159             :     }
     160             : 
     161     4824286 :     if (current.data)
     162     4824184 :         HMAC_Update(ctx, current.data, current.length);
     163             : 
     164     4824286 :     HMAC_Final(ctx, hmac, hmaclen);
     165             : 
     166     4824286 :     if (crypto == NULL)
     167           0 :         HMAC_CTX_free(ctx);
     168             : 
     169     4772063 :     return 0;
     170             : }
     171             : 
     172             : krb5_error_code
     173           0 : _krb5_evp_encrypt(krb5_context context,
     174             :                 struct _krb5_key_data *key,
     175             :                 void *data,
     176             :                 size_t len,
     177             :                 krb5_boolean encryptp,
     178             :                 int usage,
     179             :                 void *ivec)
     180             : {
     181           0 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     182           0 :     EVP_CIPHER_CTX *c;
     183           0 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     184           0 :     if (ivec == NULL) {
     185             :         /* alloca ? */
     186           0 :         size_t len2 = EVP_CIPHER_CTX_iv_length(c);
     187           0 :         void *loiv = malloc(len2);
     188           0 :         if (loiv == NULL)
     189           0 :             return krb5_enomem(context);
     190           0 :         memset(loiv, 0, len2);
     191           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1);
     192           0 :         free(loiv);
     193             :     } else
     194           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     195           0 :     EVP_Cipher(c, data, data, len);
     196           0 :     return 0;
     197             : }
     198             : 
     199             : struct _krb5_evp_iov_cursor
     200             : {
     201             :     struct krb5_crypto_iov *iov;
     202             :     int niov;
     203             :     krb5_data current;
     204             :     int nextidx;
     205             : };
     206             : 
     207             : static const unsigned char zero_ivec[EVP_MAX_BLOCK_LENGTH] = { 0 };
     208             : 
     209             : static inline int
     210    29499177 : _krb5_evp_iov_should_encrypt(struct krb5_crypto_iov *iov)
     211             : {
     212    29499177 :     return (iov->flags == KRB5_CRYPTO_TYPE_DATA
     213    22762460 :             || iov->flags == KRB5_CRYPTO_TYPE_HEADER
     214    52261637 :             || iov->flags == KRB5_CRYPTO_TYPE_PADDING);
     215             : }
     216             : /*
     217             :  * If we have a group of iovecs which have been split up from
     218             :  * a single common buffer, expand the 'current' iovec out to
     219             :  * be as large as possible.
     220             :  */
     221             : 
     222             : static inline void
     223     5129106 : _krb5_evp_iov_cursor_expand(struct _krb5_evp_iov_cursor *cursor)
     224             : {
     225     5129106 :     if (cursor->nextidx == cursor->niov)
     226           0 :        return;
     227             : 
     228     5129106 :     while (_krb5_evp_iov_should_encrypt(&cursor->iov[cursor->nextidx])) {
     229           0 :         if (cursor->iov[cursor->nextidx].data.length != 0 &&
     230           0 :             ((char *)cursor->current.data + cursor->current.length
     231           0 :              != cursor->iov[cursor->nextidx].data.data)) {
     232           0 :             return;
     233             :         }
     234           0 :         cursor->current.length += cursor->iov[cursor->nextidx].data.length;
     235           0 :         cursor->nextidx++;
     236             :     }
     237             : 
     238     5119919 :     return;
     239             : }
     240             : 
     241             : /* Move the cursor along to the start of the next block to be
     242             :  * encrypted */
     243             : static inline void
     244     8264920 : _krb5_evp_iov_cursor_nextcrypt(struct _krb5_evp_iov_cursor *cursor)
     245             : {
     246    16530536 :     for (; cursor->nextidx < cursor->niov; cursor->nextidx++) {
     247    13394722 :         if (_krb5_evp_iov_should_encrypt(&cursor->iov[cursor->nextidx])
     248     5129436 :             && cursor->iov[cursor->nextidx].data.length != 0) {
     249     5129106 :             cursor->current = cursor->iov[cursor->nextidx].data;
     250     5129106 :             cursor->nextidx++;
     251     5129106 :             _krb5_evp_iov_cursor_expand(cursor);
     252     5129106 :             return;
     253             :         }
     254             :     }
     255             : 
     256     3135814 :     cursor->current.length = 0; /* No matches, so we're done here */
     257             : }
     258             : 
     259             : static inline void
     260     1567907 : _krb5_evp_iov_cursor_init(struct _krb5_evp_iov_cursor *cursor,
     261             :                           struct krb5_crypto_iov *iov, int niov)
     262             : {
     263     1567907 :     memset(cursor, 0, sizeof(struct _krb5_evp_iov_cursor));
     264             : 
     265     1567907 :     cursor->iov = iov;
     266     1567907 :     cursor->niov = niov;
     267     1567907 :     cursor->nextidx = 0;
     268             : 
     269             :     /* Move along to the first block we're going to be encrypting */
     270     1567907 :     _krb5_evp_iov_cursor_nextcrypt(cursor);
     271     1567907 : }
     272             : 
     273             : static inline void
     274     7401039 : _krb5_evp_iov_cursor_advance(struct _krb5_evp_iov_cursor *cursor,
     275             :                              size_t amount)
     276             : {
     277    10110880 :     while (amount > 0) {
     278     6258811 :         if (cursor->current.length > amount) {
     279     3548970 :             cursor->current.data = (char *)cursor->current.data + amount;
     280     3548970 :             cursor->current.length -= amount;
     281     3548970 :             return;
     282             :         }
     283     2709841 :         amount -= cursor->current.length;
     284     2709841 :         _krb5_evp_iov_cursor_nextcrypt(cursor);
     285             :     }
     286             : }
     287             : 
     288             : static inline int
     289     5980758 : _krb5_evp_iov_cursor_done(struct _krb5_evp_iov_cursor *cursor)
     290             : {
     291     5980758 :     return (cursor->nextidx == cursor->niov && cursor->current.length == 0);
     292             : }
     293             : 
     294             : /* Fill a memory buffer with data from one or more iovecs. Doesn't
     295             :  * advance the passed in cursor - use outcursor for the position
     296             :  * at the end
     297             :  */
     298             : static inline void
     299     2419265 : _krb5_evp_iov_cursor_fillbuf(struct _krb5_evp_iov_cursor *cursor,
     300             :                              unsigned char *buf, size_t length,
     301             :                              struct _krb5_evp_iov_cursor *outcursor)
     302             : {
     303        5249 :     struct _krb5_evp_iov_cursor cursorint;
     304             : 
     305     2419265 :     cursorint = *cursor;
     306             : 
     307     4837218 :     while (length > 0 && !_krb5_evp_iov_cursor_done(&cursorint)) {
     308     2419265 :         if (cursorint.current.length > length) {
     309      425679 :             memcpy(buf, cursorint.current.data, length);
     310      425679 :             _krb5_evp_iov_cursor_advance(&cursorint, length);
     311      425679 :             length = 0;
     312             :         } else {
     313     1993586 :             memcpy(buf, cursorint.current.data, cursorint.current.length);
     314     1993586 :             length -= cursorint.current.length;
     315     1993586 :             buf += cursorint.current.length;
     316     1993586 :             _krb5_evp_iov_cursor_nextcrypt(&cursorint);
     317             :         }
     318             :     }
     319             : 
     320     2419265 :     if (outcursor != NULL)
     321      425679 :         *outcursor = cursorint;
     322     2419265 : }
     323             : 
     324             : /* Fill an iovec from a memory buffer. Always advances the cursor to
     325             :  * the end of the filled region
     326             :  */
     327             : static inline void
     328     3561493 : _krb5_evp_iov_cursor_fillvec(struct _krb5_evp_iov_cursor *cursor,
     329             :                              unsigned char *buf, size_t length)
     330             : {
     331     7120361 :     while (length > 0 && !_krb5_evp_iov_cursor_done(cursor)) {
     332     3561493 :         if (cursor->current.length > length) {
     333     1567907 :             memcpy(cursor->current.data, buf, length);
     334     1567907 :             _krb5_evp_iov_cursor_advance(cursor, length);
     335     1567907 :             length = 0;
     336             :         } else {
     337     1993586 :             memcpy(cursor->current.data, buf, cursor->current.length);
     338     1993586 :             length -= cursor->current.length;
     339     1993586 :             buf += cursor->current.length;
     340     1993586 :             _krb5_evp_iov_cursor_nextcrypt(cursor);
     341             :         }
     342             :     }
     343     3561493 : }
     344             : 
     345             : static size_t
     346     1567907 : _krb5_evp_iov_cryptlength(struct krb5_crypto_iov *iov, int niov)
     347             : {
     348        2625 :     int i;
     349     1567907 :     size_t length = 0;
     350             : 
     351    12543256 :     for (i = 0; i < niov; i++) {
     352    10975349 :         if (_krb5_evp_iov_should_encrypt(&iov[i]))
     353     4703721 :             length += iov[i].data.length;
     354             :     }
     355             : 
     356     1567907 :     return length;
     357             : }
     358             : 
     359             : int
     360           0 : _krb5_evp_encrypt_iov(krb5_context context,
     361             :                       struct _krb5_key_data *key,
     362             :                       struct krb5_crypto_iov *iov,
     363             :                       int niov,
     364             :                       krb5_boolean encryptp,
     365             :                       int usage,
     366             :                       void *ivec)
     367             : {
     368           0 :     size_t blocksize, blockmask, wholeblocks;
     369           0 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     370           0 :     unsigned char tmp[EVP_MAX_BLOCK_LENGTH];
     371           0 :     EVP_CIPHER_CTX *c;
     372           0 :     struct _krb5_evp_iov_cursor cursor;
     373             : 
     374           0 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     375             : 
     376           0 :     blocksize = EVP_CIPHER_CTX_block_size(c);
     377             : 
     378           0 :     blockmask = ~(blocksize - 1);
     379             : 
     380           0 :     if (ivec)
     381           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     382             :     else
     383           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     384             : 
     385           0 :     _krb5_evp_iov_cursor_init(&cursor, iov, niov);
     386             : 
     387           0 :     while (!_krb5_evp_iov_cursor_done(&cursor)) {
     388             : 
     389             :         /* Number of bytes of data in this iovec that are in whole blocks */
     390           0 :         wholeblocks = cursor.current.length & ~blockmask;
     391             : 
     392           0 :         if (wholeblocks != 0) {
     393           0 :             EVP_Cipher(c, cursor.current.data,
     394           0 :                        cursor.current.data, wholeblocks);
     395           0 :             _krb5_evp_iov_cursor_advance(&cursor, wholeblocks);
     396             :         }
     397             : 
     398             :         /* If there's a partial block of data remaining in the current
     399             :          * iovec, steal enough from subsequent iovecs to form a whole block */
     400           0 :         if (cursor.current.length > 0 && cursor.current.length < blocksize) {
     401             :             /* Build up a block's worth of data in tmp, leaving the cursor
     402             :              * pointing at where we started */
     403           0 :             _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, blocksize, NULL);
     404             : 
     405           0 :             EVP_Cipher(c, tmp, tmp, blocksize);
     406             : 
     407             :             /* Copy the data in tmp back into the iovecs that it came from,
     408             :              * advancing the cursor */
     409           0 :             _krb5_evp_iov_cursor_fillvec(&cursor, tmp, blocksize);
     410             :         }
     411             :     }
     412             : 
     413           0 :     return 0;
     414             : }
     415             : 
     416             : int
     417     1567907 : _krb5_evp_encrypt_iov_cts(krb5_context context,
     418             :                           struct _krb5_key_data *key,
     419             :                           struct krb5_crypto_iov *iov,
     420             :                           int niov,
     421             :                           krb5_boolean encryptp,
     422             :                           int usage,
     423             :                           void *ivec)
     424             : {
     425        2625 :     size_t blocksize, blockmask, wholeblocks, length;
     426        2625 :     size_t remaining, partiallen;
     427        2625 :     struct _krb5_evp_iov_cursor cursor, lastpos;
     428     1567907 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     429        2625 :     unsigned char tmp[EVP_MAX_BLOCK_LENGTH], tmp2[EVP_MAX_BLOCK_LENGTH];
     430        2625 :     unsigned char tmp3[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];
     431        2625 :     EVP_CIPHER_CTX *c;
     432        2625 :     int i;
     433             : 
     434     1567907 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     435             : 
     436     1567907 :     blocksize = EVP_CIPHER_CTX_block_size(c);
     437     1567907 :     blockmask = ~(blocksize - 1);
     438             : 
     439     1567907 :     length = _krb5_evp_iov_cryptlength(iov, niov);
     440             : 
     441     1567907 :     if (length < blocksize) {
     442           0 :         krb5_set_error_message(context, EINVAL,
     443             :                                "message block too short");
     444           0 :         return EINVAL;
     445             :     }
     446             : 
     447     1567907 :     if (length == blocksize)
     448           0 :         return _krb5_evp_encrypt_iov(context, key, iov, niov,
     449             :                                      encryptp, usage, ivec);
     450             : 
     451     1567907 :     if (ivec)
     452           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     453             :     else
     454     1567907 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     455             : 
     456     1567907 :     if (encryptp) {
     457             :         /* On our first pass, we want to process everything but the
     458             :          * final partial block */
     459     1142228 :         remaining = ((length - 1) & blockmask);
     460     1142228 :         partiallen = length - remaining;
     461             : 
     462     1142228 :         memset(&lastpos, 0, sizeof(lastpos)); /* Keep the compiler happy */
     463             :     } else {
     464             :         /* Decryption needs to leave 2 whole blocks and a partial for
     465             :          * further processing */
     466      425679 :         if (length > 2 * blocksize) {
     467      425679 :             remaining = (((length - 1) / blocksize) * blocksize) - (blocksize*2);
     468      425679 :             partiallen = length - remaining - (blocksize * 2);
     469             :         } else {
     470           0 :             remaining = 0;
     471           0 :             partiallen = length - blocksize;
     472             :         }
     473             :     }
     474             : 
     475     1567907 :     _krb5_evp_iov_cursor_init(&cursor, iov, niov);
     476     5830507 :     while (remaining > 0) {
     477             :         /* If the iovec has more data than we need, just use it */
     478     4265225 :         if (cursor.current.length >= remaining) {
     479     1567871 :             EVP_Cipher(c, cursor.current.data, cursor.current.data, remaining);
     480             : 
     481     1567871 :             if (encryptp) {
     482             :                 /* We've just encrypted the last block of data. Make a copy
     483             :                  * of it (and its location) for the CTS dance, below */
     484     1142228 :                 lastpos = cursor;
     485     1142228 :                 _krb5_evp_iov_cursor_advance(&lastpos, remaining - blocksize);
     486     1142228 :                 memcpy(ivec2, lastpos.current.data, blocksize);
     487             :             }
     488             : 
     489     1567871 :             _krb5_evp_iov_cursor_advance(&cursor, remaining);
     490     1567871 :             remaining = 0;
     491             :         } else {
     492             :             /* Use as much as we can, firstly all of the whole blocks */
     493     2697354 :             wholeblocks = cursor.current.length & blockmask;
     494             : 
     495     2697354 :             if (wholeblocks > 0) {
     496     2697354 :                 EVP_Cipher(c, cursor.current.data, cursor.current.data,
     497             :                            wholeblocks);
     498     2697354 :                 _krb5_evp_iov_cursor_advance(&cursor, wholeblocks);
     499     2697354 :                 remaining -= wholeblocks;
     500             :             }
     501             : 
     502             :             /* Then, if we have partial data left, steal enough from subsequent
     503             :              * iovecs to make a whole block */
     504     2697354 :             if (cursor.current.length > 0 && cursor.current.length < blocksize) {
     505           0 :                 if (encryptp && remaining == blocksize)
     506           0 :                     lastpos = cursor;
     507             : 
     508           0 :                 _krb5_evp_iov_cursor_fillbuf(&cursor, ivec2, blocksize, NULL);
     509           0 :                 EVP_Cipher(c, ivec2, ivec2, blocksize);
     510           0 :                 _krb5_evp_iov_cursor_fillvec(&cursor, ivec2, blocksize);
     511             : 
     512           0 :                 remaining -= blocksize;
     513             :             }
     514             :         }
     515             :     }
     516             : 
     517             :     /* Encryption */
     518     1567907 :     if (encryptp) {
     519             :         /* Copy the partial block into tmp */
     520     1142228 :         _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, partiallen, NULL);
     521             : 
     522             :         /* XOR the final partial block with ivec2 */
     523    19419189 :         for (i = 0; i < partiallen; i++)
     524    18275648 :             tmp[i] = tmp[i] ^ ivec2[i];
     525     1142228 :         for (; i < blocksize; i++)
     526           0 :             tmp[i] = 0 ^ ivec2[i]; /* XOR 0s if partial block exhausted */
     527             : 
     528     1142228 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     529     1142228 :         EVP_Cipher(c, tmp, tmp, blocksize);
     530             : 
     531     1142228 :         _krb5_evp_iov_cursor_fillvec(&lastpos, tmp, blocksize);
     532     1142228 :         _krb5_evp_iov_cursor_fillvec(&cursor, ivec2, partiallen);
     533             : 
     534     1142228 :         if (ivec)
     535           0 :             memcpy(ivec, tmp, blocksize);
     536             : 
     537     1142228 :         return 0;
     538             :     }
     539             : 
     540             :     /* Decryption */
     541             : 
     542             :     /* Make a copy of the 2nd last full ciphertext block in ivec2 before
     543             :      * decrypting it. If no such block exists, use ivec or zero_ivec */
     544      425679 :     if (length <= blocksize * 2) {
     545           0 :         if (ivec)
     546           0 :            memcpy(ivec2, ivec, blocksize);
     547             :         else
     548           0 :            memcpy(ivec2, zero_ivec, blocksize);
     549             :     } else {
     550      425679 :         _krb5_evp_iov_cursor_fillbuf(&cursor, ivec2, blocksize, NULL);
     551      425679 :         EVP_Cipher(c, tmp, ivec2, blocksize);
     552      425679 :         _krb5_evp_iov_cursor_fillvec(&cursor, tmp, blocksize);
     553             :     }
     554             : 
     555      425679 :     lastpos = cursor; /* Remember where the last block is */
     556      425679 :     _krb5_evp_iov_cursor_fillbuf(&cursor, tmp, blocksize, &cursor);
     557      425679 :     EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     558      425679 :     EVP_Cipher(c, tmp2, tmp, blocksize); /* tmp eventually becomes output ivec */
     559             : 
     560      425679 :     _krb5_evp_iov_cursor_fillbuf(&cursor, tmp3, partiallen, NULL);
     561             : 
     562      425679 :     memcpy(tmp3 + partiallen, tmp2 + partiallen, blocksize - partiallen); /* xor 0 */
     563     7236543 :     for (i = 0; i < partiallen; i++)
     564     6810864 :         tmp2[i] = tmp2[i] ^ tmp3[i];
     565             : 
     566      425679 :     _krb5_evp_iov_cursor_fillvec(&cursor, tmp2, partiallen);
     567             : 
     568      425679 :     EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     569      425679 :     EVP_Cipher(c, tmp3, tmp3, blocksize);
     570             : 
     571     7237855 :     for (i = 0; i < blocksize; i++)
     572     6810864 :         tmp3[i] ^= ivec2[i];
     573             : 
     574      425679 :     _krb5_evp_iov_cursor_fillvec(&lastpos, tmp3, blocksize);
     575             : 
     576      425679 :     if (ivec)
     577           0 :         memcpy(ivec, tmp, blocksize);
     578             : 
     579      424367 :     return 0;
     580             : }
     581             : 
     582             : krb5_error_code
     583     8599961 : _krb5_evp_encrypt_cts(krb5_context context,
     584             :                       struct _krb5_key_data *key,
     585             :                       void *data,
     586             :                       size_t len,
     587             :                       krb5_boolean encryptp,
     588             :                       int usage,
     589             :                       void *ivec)
     590             : {
     591      234305 :     size_t i, blocksize;
     592     8599961 :     struct _krb5_evp_schedule *ctx = key->schedule->data;
     593      234305 :     unsigned char tmp[EVP_MAX_BLOCK_LENGTH], ivec2[EVP_MAX_BLOCK_LENGTH];
     594      234305 :     EVP_CIPHER_CTX *c;
     595      234305 :     unsigned char *p;
     596             : 
     597     8599961 :     c = encryptp ? &ctx->ectx : &ctx->dctx;
     598             : 
     599     8599961 :     blocksize = EVP_CIPHER_CTX_block_size(c);
     600             : 
     601     8599961 :     if (len < blocksize) {
     602           0 :         krb5_set_error_message(context, EINVAL,
     603             :                                "message block too short");
     604           0 :         return EINVAL;
     605     8599961 :     } else if (len == blocksize) {
     606     6412162 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     607     6412162 :         EVP_Cipher(c, data, data, len);
     608     6412162 :         return 0;
     609             :     }
     610             : 
     611     2187799 :     if (ivec)
     612           0 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1);
     613             :     else
     614     2187799 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     615             : 
     616     2187799 :     if (encryptp) {
     617             : 
     618     1069009 :         p = data;
     619     1069009 :         i = ((len - 1) / blocksize) * blocksize;
     620     1069009 :         EVP_Cipher(c, p, p, i);
     621     1069009 :         p += i - blocksize;
     622     1069009 :         len -= i;
     623     1069009 :         memcpy(ivec2, p, blocksize);
     624             : 
     625    10617994 :         for (i = 0; i < len; i++)
     626     9548985 :             tmp[i] = p[i + blocksize] ^ ivec2[i];
     627     8624168 :         for (; i < blocksize; i++)
     628     7555159 :             tmp[i] = 0 ^ ivec2[i];
     629             : 
     630     1069009 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     631     1069009 :         EVP_Cipher(c, p, tmp, blocksize);
     632             : 
     633     1069009 :         memcpy(p + blocksize, ivec2, len);
     634     1069009 :         if (ivec)
     635           0 :             memcpy(ivec, p, blocksize);
     636             :     } else {
     637       13699 :         unsigned char tmp2[EVP_MAX_BLOCK_LENGTH], tmp3[EVP_MAX_BLOCK_LENGTH];
     638             : 
     639     1118790 :         p = data;
     640     1118790 :         if (len > blocksize * 2) {
     641             :             /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */
     642     1118789 :             i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize);
     643     1118789 :             memcpy(ivec2, p + i - blocksize, blocksize);
     644     1118789 :             EVP_Cipher(c, p, p, i);
     645     1118789 :             p += i;
     646     1118789 :             len -= i + blocksize;
     647             :         } else {
     648           1 :             if (ivec)
     649           0 :                 memcpy(ivec2, ivec, blocksize);
     650             :             else
     651           1 :                 memcpy(ivec2, zero_ivec, blocksize);
     652           1 :             len -= blocksize;
     653             :         }
     654             : 
     655     1118790 :         memcpy(tmp, p, blocksize);
     656     1118790 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     657     1118790 :         EVP_Cipher(c, tmp2, p, blocksize);
     658             : 
     659     1118790 :         memcpy(tmp3, p + blocksize, len);
     660     1118790 :         memcpy(tmp3 + len, tmp2 + len, blocksize - len); /* xor 0 */
     661             : 
     662    11056976 :         for (i = 0; i < len; i++)
     663     9938186 :             p[i + blocksize] = tmp2[i] ^ tmp3[i];
     664             : 
     665     1118790 :         EVP_CipherInit_ex(c, NULL, NULL, NULL, zero_ivec, -1);
     666     1118790 :         EVP_Cipher(c, p, tmp3, blocksize);
     667             : 
     668    19033129 :         for (i = 0; i < blocksize; i++)
     669    17900640 :             p[i] ^= ivec2[i];
     670     1118790 :         if (ivec)
     671       13699 :             memcpy(ivec, tmp, blocksize);
     672             :     }
     673     2159961 :     return 0;
     674             : }

Generated by: LCOV version 1.14