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