summaryrefslogtreecommitdiffstats
path: root/providers/common/ciphers/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'providers/common/ciphers/block.c')
-rw-r--r--providers/common/ciphers/block.c113
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;
+}