diff options
Diffstat (limited to 'providers/common/ciphers/block.c')
-rw-r--r-- | providers/common/ciphers/block.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/providers/common/ciphers/block.c b/providers/common/ciphers/block.c new file mode 100644 index 0000000000..fc15c5e55a --- /dev/null +++ b/providers/common/ciphers/block.c @@ -0,0 +1,113 @@ +/* + * 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 <string.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include "ciphers_locl.h" +#include <assert.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) + 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) + 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) { + EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT); + return 0; + } + for (i = 0; i < pad; i++) { + if (buf[--len] != pad) { + EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_BAD_DECRYPT); + return 0; + } + } + *buflen = len; + return 1; +} |