text: /*
   * Copyright 2019 The Opentls Project Authors. All Rights Reserved.
   *
   * Licensed under the Apache License 2.0 (the "License").  You may not use
   * this file except in compliance with the License.  You can obtain a copy
   * in the file LICENSE in the source distribution or at
   * https://www.opentls.org/source/license.html
   */
  
  #include <assert.h>
  #include "ciphercommon_local.h"
  #include "prov/providercommonerr.h"
  
  /*
   * Fills a single block of buffered data from the input, and returns the amount
   * of data remaining in the input that is a multiple of the blocksize. The buffer
   * is only filled if it already has some data in it, isn't full already or we
   * don't have at least one block in the input.
   *
   * buf: a buffer of blocksize bytes
   * buflen: contains the amount of data already in buf on entry. Updated with the
   *         amount of data in buf at the end. On entry *buflen must always be
   *         less than the blocksize
   * blocksize: size of a block. Must be greater than 0 and a power of 2
   * in: pointer to a pointer containing the input data
   * inlen: amount of input data available
   *
   * On return buf is filled with as much data as possible up to a full block,
   * *buflen is updated containing the amount of data in buf. *in is updated to
   * the new location where input data should be read from, *inlen is updated with
   * the remaining amount of data in *in. Returns the largest value <= *inlen
   * which is a multiple of the blocksize.
   */
  size_t fillblock(unsigned char *buf, size_t *buflen, size_t blocksize,
                   const unsigned char **in, size_t *inlen)
  {
      size_t blockmask = ~(blocksize - 1);
  
      assert(*buflen <= blocksize);
      assert(blocksize > 0 && (blocksize & (blocksize - 1)) == 0);
  
      if (*buflen != blocksize && (*buflen != 0 || *inlen < blocksize)) {
          size_t bufremain = blocksize - *buflen;
  
          if (*inlen < bufremain)
              bufremain = *inlen;
          memcpy(buf + *buflen, *in, bufremain);
          *in += bufremain;
          *inlen -= bufremain;
          *buflen += bufremain;
      }
  
      return *inlen & blockmask;
  }
  
  /*
   * Fills the buffer with trailing data from an encryption/decryption that didn't
   * fit into a full block.
   */
  int trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize,
                   const unsigned char **in, size_t *inlen)
  {
      if (*inlen == 0)
          return 1;
  
      if (*buflen + *inlen > blocksize) {
          ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
          return 0;
      }
  
      memcpy(buf + *buflen, *in, *inlen);
      *buflen += *inlen;
      *inlen = 0;
  
      return 1;
  }
  
  /* Pad the final block for encryption */
  void padblock(unsigned char *buf, size_t *buflen, size_t blocksize)
  {
      size_t i;
      unsigned char pad = (unsigned char)(blocksize - *buflen);
  
      for (i = *buflen; i < blocksize; i++)
          buf[i] = pad;
  }
  
  int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize)
  {
      size_t pad, i;
      size_t len = *buflen;
  
      if(len != blocksize) {
          ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
          return 0;
      }
  
      /*
       * The following assumes that the ciphertext has been authenticated.
       * Otherwise it provides a padding oracle.
       */
      pad = buf[blocksize - 1];
      if (pad == 0 || pad > blocksize) {
          ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
          return 0;
      }
      for (i = 0; i < pad; i++) {
          if (buf[--len] != pad) {
              ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
              return 0;
          }
      }
      *buflen = len;
      return 1;
  }
  