"Fossies" - the Fresh Open Source Software Archive

Member "krb5-1.18/src/lib/crypto/krb/aead.c" (12 Feb 2020, 7193 Bytes) of package /linux/misc/krb5-1.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "aead.c" see the Fossies "Dox" file reference documentation.

    1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
    2 /* lib/crypto/krb/aead.c */
    3 /*
    4  * Copyright 2008 by the Massachusetts Institute of Technology.
    5  * All Rights Reserved.
    6  *
    7  * Export of this software from the United States of America may
    8  *   require a specific license from the United States Government.
    9  *   It is the responsibility of any person or organization contemplating
   10  *   export to obtain such a license before exporting.
   11  *
   12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
   13  * distribute this software and its documentation for any purpose and
   14  * without fee is hereby granted, provided that the above copyright
   15  * notice appear in all copies and that both that copyright notice and
   16  * this permission notice appear in supporting documentation, and that
   17  * the name of M.I.T. not be used in advertising or publicity pertaining
   18  * to distribution of the software without specific, written prior
   19  * permission.  Furthermore if you modify this software you must label
   20  * your software as modified software and not distribute it in such a
   21  * fashion that it might be confused with the original M.I.T. software.
   22  * M.I.T. makes no representations about the suitability of
   23  * this software for any purpose.  It is provided "as is" without express
   24  * or implied warranty.
   25  */
   26 
   27 #include "crypto_int.h"
   28 
   29 krb5_crypto_iov *
   30 krb5int_c_locate_iov(krb5_crypto_iov *data, size_t num_data,
   31                      krb5_cryptotype type)
   32 {
   33     size_t i;
   34     krb5_crypto_iov *iov = NULL;
   35 
   36     if (data == NULL)
   37         return NULL;
   38 
   39     for (i = 0; i < num_data; i++) {
   40         if (data[i].flags == type) {
   41             if (iov == NULL)
   42                 iov = &data[i];
   43             else
   44                 return NULL; /* can't appear twice */
   45         }
   46     }
   47 
   48     return iov;
   49 }
   50 
   51 krb5_error_code
   52 krb5int_c_iov_decrypt_stream(const struct krb5_keytypes *ktp, krb5_key key,
   53                              krb5_keyusage keyusage, const krb5_data *ivec,
   54                              krb5_crypto_iov *data, size_t num_data)
   55 {
   56     krb5_error_code ret;
   57     unsigned int header_len, trailer_len;
   58     krb5_crypto_iov *iov;
   59     krb5_crypto_iov *stream;
   60     size_t i, j;
   61     int got_data = 0;
   62 
   63     stream = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_STREAM);
   64     assert(stream != NULL);
   65 
   66     header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER);
   67     trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER);
   68 
   69     if (stream->data.length < header_len + trailer_len)
   70         return KRB5_BAD_MSIZE;
   71 
   72     iov = calloc(num_data + 2, sizeof(krb5_crypto_iov));
   73     if (iov == NULL)
   74         return ENOMEM;
   75 
   76     i = 0;
   77 
   78     iov[i].flags = KRB5_CRYPTO_TYPE_HEADER; /* takes place of STREAM */
   79     iov[i].data = make_data(stream->data.data, header_len);
   80     i++;
   81 
   82     for (j = 0; j < num_data; j++) {
   83         if (data[j].flags == KRB5_CRYPTO_TYPE_DATA) {
   84             if (got_data) {
   85                 free(iov);
   86                 return KRB5_BAD_MSIZE;
   87             }
   88 
   89             got_data++;
   90 
   91             data[j].data.data = stream->data.data + header_len;
   92             data[j].data.length = stream->data.length - header_len
   93                 - trailer_len;
   94         }
   95         if (data[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY ||
   96             data[j].flags == KRB5_CRYPTO_TYPE_DATA)
   97             iov[i++] = data[j];
   98     }
   99 
  100     /* Use empty padding since tokens don't indicate the padding length. */
  101     iov[i].flags = KRB5_CRYPTO_TYPE_PADDING;
  102     iov[i].data = empty_data();
  103     i++;
  104 
  105     iov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
  106     iov[i].data = make_data(stream->data.data + stream->data.length -
  107                             trailer_len, trailer_len);
  108     i++;
  109 
  110     assert(i <= num_data + 2);
  111 
  112     ret = ktp->decrypt(ktp, key, keyusage, ivec, iov, i);
  113     free(iov);
  114     return ret;
  115 }
  116 
  117 unsigned int
  118 krb5int_c_padding_length(const struct krb5_keytypes *ktp, size_t data_length)
  119 {
  120     unsigned int header, padding;
  121 
  122     /*
  123      * Add in the header length since the header is encrypted along with the
  124      * data.  (arcfour violates this assumption since not all of the header is
  125      * encrypted, but that's okay since it has no padding.  If there is ever an
  126      * enctype using a similar token format and a block cipher, we will have to
  127      * move this logic into an enctype-dependent function.)
  128      */
  129     header = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER);
  130     data_length += header;
  131 
  132     padding = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_PADDING);
  133     if (padding == 0 || (data_length % padding) == 0)
  134         return 0;
  135     else
  136         return padding - (data_length % padding);
  137 }
  138 
  139 /* Return the next iov (starting from ind) which cursor should process, or
  140  * cursor->iov_count if there are none remaining. */
  141 static size_t
  142 next_iov_to_process(struct iov_cursor *cursor, size_t ind)
  143 {
  144     const krb5_crypto_iov *iov;
  145 
  146     for (; ind < cursor->iov_count; ind++) {
  147         iov = &cursor->iov[ind];
  148         if (cursor->signing ? SIGN_IOV(iov) : ENCRYPT_IOV(iov))
  149             break;
  150     }
  151     return ind;
  152 }
  153 
  154 void
  155 k5_iov_cursor_init(struct iov_cursor *cursor, const krb5_crypto_iov *iov,
  156                    size_t count, size_t block_size, krb5_boolean signing)
  157 {
  158     cursor->iov = iov;
  159     cursor->iov_count = count;
  160     cursor->block_size = block_size;
  161     cursor->signing = signing;
  162     cursor->in_iov = next_iov_to_process(cursor, 0);
  163     cursor->out_iov = cursor->in_iov;
  164     cursor->in_pos = cursor->out_pos = 0;
  165 }
  166 
  167 /* Fetch one block from cursor's input position. */
  168 krb5_boolean
  169 k5_iov_cursor_get(struct iov_cursor *cursor, unsigned char *block)
  170 {
  171     size_t nbytes, bsz = cursor->block_size, remain = cursor->block_size;
  172     const krb5_crypto_iov *iov;
  173 
  174     remain = cursor->block_size;
  175     while (remain > 0 && cursor->in_iov < cursor->iov_count) {
  176         iov = &cursor->iov[cursor->in_iov];
  177 
  178         nbytes = iov->data.length - cursor->in_pos;
  179         if (nbytes > remain)
  180             nbytes = remain;
  181 
  182         memcpy(block + bsz - remain, iov->data.data + cursor->in_pos, nbytes);
  183         cursor->in_pos += nbytes;
  184         remain -= nbytes;
  185 
  186         if (cursor->in_pos == iov->data.length) {
  187             cursor->in_iov = next_iov_to_process(cursor, cursor->in_iov + 1);
  188             cursor->in_pos = 0;
  189         }
  190     }
  191 
  192     if (remain == bsz)
  193         return FALSE;
  194     if (remain > 0)
  195         memset(block + bsz - remain, 0, remain);
  196     return TRUE;
  197 }
  198 
  199 /* Write a block to a cursor's output position. */
  200 void
  201 k5_iov_cursor_put(struct iov_cursor *cursor, unsigned char *block)
  202 {
  203     size_t nbytes, bsz = cursor->block_size, remain = cursor->block_size;
  204     const krb5_crypto_iov *iov;
  205 
  206     remain = cursor->block_size;
  207     while (remain > 0 && cursor->out_iov < cursor->iov_count) {
  208         iov = &cursor->iov[cursor->out_iov];
  209 
  210         nbytes = iov->data.length - cursor->out_pos;
  211         if (nbytes > remain)
  212             nbytes = remain;
  213 
  214         memcpy(iov->data.data + cursor->out_pos, block + bsz - remain, nbytes);
  215         cursor->out_pos += nbytes;
  216         remain -= nbytes;
  217 
  218         if (cursor->out_pos == iov->data.length) {
  219             cursor->out_iov = next_iov_to_process(cursor, cursor->out_iov + 1);
  220             cursor->out_pos = 0;
  221         }
  222     }
  223 }