/* * Copyright 2019 The OpenSSL 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.openssl.org/source/license.html */ #include #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; }