73e17e1a11cc486b56ae45058e869c7156fa8a40
[openssl.git] / providers / common / ciphers / block.c
1 /*
2  * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <assert.h>
11 #include "cipher_locl.h"
12
13 /*
14  * Fills a single block of buffered data from the input, and returns the amount
15  * of data remaining in the input that is a multiple of the blocksize. The buffer
16  * is only filled if it already has some data in it, isn't full already or we
17  * don't have at least one block in the input.
18  *
19  * buf: a buffer of blocksize bytes
20  * buflen: contains the amount of data already in buf on entry. Updated with the
21  *         amount of data in buf at the end. On entry *buflen must always be
22  *         less than the blocksize
23  * blocksize: size of a block. Must be greater than 0 and a power of 2
24  * in: pointer to a pointer containing the input data
25  * inlen: amount of input data available
26  *
27  * On return buf is filled with as much data as possible up to a full block,
28  * *buflen is updated containing the amount of data in buf. *in is updated to
29  * the new location where input data should be read from, *inlen is updated with
30  * the remaining amount of data in *in. Returns the largest value <= *inlen
31  * which is a multiple of the blocksize.
32  */
33 size_t fillblock(unsigned char *buf, size_t *buflen, size_t blocksize,
34                  const unsigned char **in, size_t *inlen)
35 {
36     size_t blockmask = ~(blocksize - 1);
37
38     assert(*buflen <= blocksize);
39     assert(blocksize > 0 && (blocksize & (blocksize - 1)) == 0);
40
41     if (*buflen != blocksize && (*buflen != 0 || *inlen < blocksize)) {
42         size_t bufremain = blocksize - *buflen;
43
44         if (*inlen < bufremain)
45             bufremain = *inlen;
46         memcpy(buf + *buflen, *in, bufremain);
47         *in += bufremain;
48         *inlen -= bufremain;
49         *buflen += bufremain;
50     }
51
52     return *inlen & blockmask;
53 }
54
55 /*
56  * Fills the buffer with trailing data from an encryption/decryption that didn't
57  * fit into a full block.
58  */
59 int trailingdata(unsigned char *buf, size_t *buflen, size_t blocksize,
60                  const unsigned char **in, size_t *inlen)
61 {
62     if (*inlen == 0)
63         return 1;
64
65     if (*buflen + *inlen > blocksize) {
66         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
67         return 0;
68     }
69
70     memcpy(buf + *buflen, *in, *inlen);
71     *buflen += *inlen;
72     *inlen = 0;
73
74     return 1;
75 }
76
77 /* Pad the final block for encryption */
78 void padblock(unsigned char *buf, size_t *buflen, size_t blocksize)
79 {
80     size_t i;
81     unsigned char pad = (unsigned char)(blocksize - *buflen);
82
83     for (i = *buflen; i < blocksize; i++)
84         buf[i] = pad;
85 }
86
87 int unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize)
88 {
89     size_t pad, i;
90     size_t len = *buflen;
91
92     if(len != blocksize) {
93         ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
94         return 0;
95     }
96
97     /*
98      * The following assumes that the ciphertext has been authenticated.
99      * Otherwise it provides a padding oracle.
100      */
101     pad = buf[blocksize - 1];
102     if (pad == 0 || pad > blocksize) {
103         ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
104         return 0;
105     }
106     for (i = 0; i < pad; i++) {
107         if (buf[--len] != pad) {
108             ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT);
109             return 0;
110         }
111     }
112     *buflen = len;
113     return 1;
114 }