LCOV - code coverage report
Current view: top level - crypto - cts.c (source / functions) Hit Total Coverage
Test: Real Lines: 2 143 1.4 %
Date: 2020-10-17 15:46:16 Functions: 0 14 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * CTS: Cipher Text Stealing mode
       3                 :            :  *
       4                 :            :  * COPYRIGHT (c) 2008
       5                 :            :  * The Regents of the University of Michigan
       6                 :            :  * ALL RIGHTS RESERVED
       7                 :            :  *
       8                 :            :  * Permission is granted to use, copy, create derivative works
       9                 :            :  * and redistribute this software and such derivative works
      10                 :            :  * for any purpose, so long as the name of The University of
      11                 :            :  * Michigan is not used in any advertising or publicity
      12                 :            :  * pertaining to the use of distribution of this software
      13                 :            :  * without specific, written prior authorization.  If the
      14                 :            :  * above copyright notice or any other identification of the
      15                 :            :  * University of Michigan is included in any copy of any
      16                 :            :  * portion of this software, then the disclaimer below must
      17                 :            :  * also be included.
      18                 :            :  *
      19                 :            :  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
      20                 :            :  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
      21                 :            :  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
      22                 :            :  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
      23                 :            :  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
      24                 :            :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
      25                 :            :  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
      26                 :            :  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
      27                 :            :  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
      28                 :            :  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
      29                 :            :  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
      30                 :            :  * SUCH DAMAGES.
      31                 :            :  */
      32                 :            : 
      33                 :            : /* Derived from various:
      34                 :            :  *      Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
      35                 :            :  */
      36                 :            : 
      37                 :            : /*
      38                 :            :  * This is the Cipher Text Stealing mode as described by
      39                 :            :  * Section 8 of rfc2040 and referenced by rfc3962.
      40                 :            :  * rfc3962 includes errata information in its Appendix A.
      41                 :            :  */
      42                 :            : 
      43                 :            : #include <crypto/algapi.h>
      44                 :            : #include <crypto/internal/skcipher.h>
      45                 :            : #include <linux/err.h>
      46                 :            : #include <linux/init.h>
      47                 :            : #include <linux/kernel.h>
      48                 :            : #include <linux/log2.h>
      49                 :            : #include <linux/module.h>
      50                 :            : #include <linux/scatterlist.h>
      51                 :            : #include <crypto/scatterwalk.h>
      52                 :            : #include <linux/slab.h>
      53                 :            : #include <linux/compiler.h>
      54                 :            : 
      55                 :            : struct crypto_cts_ctx {
      56                 :            :         struct crypto_skcipher *child;
      57                 :            : };
      58                 :            : 
      59                 :            : struct crypto_cts_reqctx {
      60                 :            :         struct scatterlist sg[2];
      61                 :            :         unsigned offset;
      62                 :            :         struct skcipher_request subreq;
      63                 :            : };
      64                 :            : 
      65                 :            : static inline u8 *crypto_cts_reqctx_space(struct skcipher_request *req)
      66                 :            : {
      67                 :            :         struct crypto_cts_reqctx *rctx = skcipher_request_ctx(req);
      68                 :            :         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
      69                 :            :         struct crypto_cts_ctx *ctx = crypto_skcipher_ctx(tfm);
      70                 :          0 :         struct crypto_skcipher *child = ctx->child;
      71                 :            : 
      72                 :          0 :         return PTR_ALIGN((u8 *)(rctx + 1) + crypto_skcipher_reqsize(child),
      73                 :            :                          crypto_skcipher_alignmask(tfm) + 1);
      74                 :            : }
      75                 :            : 
      76                 :          0 : static int crypto_cts_setkey(struct crypto_skcipher *parent, const u8 *key,
      77                 :            :                              unsigned int keylen)
      78                 :            : {
      79                 :            :         struct crypto_cts_ctx *ctx = crypto_skcipher_ctx(parent);
      80                 :          0 :         struct crypto_skcipher *child = ctx->child;
      81                 :            :         int err;
      82                 :            : 
      83                 :            :         crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
      84                 :          0 :         crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) &
      85                 :            :                                          CRYPTO_TFM_REQ_MASK);
      86                 :            :         err = crypto_skcipher_setkey(child, key, keylen);
      87                 :          0 :         crypto_skcipher_set_flags(parent, crypto_skcipher_get_flags(child) &
      88                 :            :                                           CRYPTO_TFM_RES_MASK);
      89                 :          0 :         return err;
      90                 :            : }
      91                 :            : 
      92                 :          0 : static void cts_cbc_crypt_done(struct crypto_async_request *areq, int err)
      93                 :            : {
      94                 :          0 :         struct skcipher_request *req = areq->data;
      95                 :            : 
      96                 :          0 :         if (err == -EINPROGRESS)
      97                 :          0 :                 return;
      98                 :            : 
      99                 :            :         skcipher_request_complete(req, err);
     100                 :            : }
     101                 :            : 
     102                 :          0 : static int cts_cbc_encrypt(struct skcipher_request *req)
     103                 :            : {
     104                 :            :         struct crypto_cts_reqctx *rctx = skcipher_request_ctx(req);
     105                 :            :         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
     106                 :          0 :         struct skcipher_request *subreq = &rctx->subreq;
     107                 :          0 :         int bsize = crypto_skcipher_blocksize(tfm);
     108                 :            :         u8 d[MAX_CIPHER_BLOCKSIZE * 2] __aligned(__alignof__(u32));
     109                 :            :         struct scatterlist *sg;
     110                 :            :         unsigned int offset;
     111                 :            :         int lastn;
     112                 :            : 
     113                 :          0 :         offset = rctx->offset;
     114                 :          0 :         lastn = req->cryptlen - offset;
     115                 :            : 
     116                 :          0 :         sg = scatterwalk_ffwd(rctx->sg, req->dst, offset - bsize);
     117                 :          0 :         scatterwalk_map_and_copy(d + bsize, sg, 0, bsize, 0);
     118                 :            : 
     119                 :          0 :         memset(d, 0, bsize);
     120                 :          0 :         scatterwalk_map_and_copy(d, req->src, offset, lastn, 0);
     121                 :            : 
     122                 :          0 :         scatterwalk_map_and_copy(d, sg, 0, bsize + lastn, 1);
     123                 :            :         memzero_explicit(d, sizeof(d));
     124                 :            : 
     125                 :          0 :         skcipher_request_set_callback(subreq, req->base.flags &
     126                 :            :                                               CRYPTO_TFM_REQ_MAY_BACKLOG,
     127                 :            :                                       cts_cbc_crypt_done, req);
     128                 :          0 :         skcipher_request_set_crypt(subreq, sg, sg, bsize, req->iv);
     129                 :          0 :         return crypto_skcipher_encrypt(subreq);
     130                 :            : }
     131                 :            : 
     132                 :          0 : static void crypto_cts_encrypt_done(struct crypto_async_request *areq, int err)
     133                 :            : {
     134                 :          0 :         struct skcipher_request *req = areq->data;
     135                 :            : 
     136                 :          0 :         if (err)
     137                 :            :                 goto out;
     138                 :            : 
     139                 :          0 :         err = cts_cbc_encrypt(req);
     140                 :          0 :         if (err == -EINPROGRESS || err == -EBUSY)
     141                 :          0 :                 return;
     142                 :            : 
     143                 :            : out:
     144                 :            :         skcipher_request_complete(req, err);
     145                 :            : }
     146                 :            : 
     147                 :          0 : static int crypto_cts_encrypt(struct skcipher_request *req)
     148                 :            : {
     149                 :            :         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
     150                 :            :         struct crypto_cts_reqctx *rctx = skcipher_request_ctx(req);
     151                 :            :         struct crypto_cts_ctx *ctx = crypto_skcipher_ctx(tfm);
     152                 :          0 :         struct skcipher_request *subreq = &rctx->subreq;
     153                 :            :         int bsize = crypto_skcipher_blocksize(tfm);
     154                 :          0 :         unsigned int nbytes = req->cryptlen;
     155                 :            :         unsigned int offset;
     156                 :            : 
     157                 :          0 :         skcipher_request_set_tfm(subreq, ctx->child);
     158                 :            : 
     159                 :          0 :         if (nbytes < bsize)
     160                 :            :                 return -EINVAL;
     161                 :            : 
     162                 :          0 :         if (nbytes == bsize) {
     163                 :          0 :                 skcipher_request_set_callback(subreq, req->base.flags,
     164                 :            :                                               req->base.complete,
     165                 :            :                                               req->base.data);
     166                 :          0 :                 skcipher_request_set_crypt(subreq, req->src, req->dst, nbytes,
     167                 :          0 :                                            req->iv);
     168                 :          0 :                 return crypto_skcipher_encrypt(subreq);
     169                 :            :         }
     170                 :            : 
     171                 :          0 :         offset = rounddown(nbytes - 1, bsize);
     172                 :          0 :         rctx->offset = offset;
     173                 :            : 
     174                 :          0 :         skcipher_request_set_callback(subreq, req->base.flags,
     175                 :            :                                       crypto_cts_encrypt_done, req);
     176                 :          0 :         skcipher_request_set_crypt(subreq, req->src, req->dst,
     177                 :          0 :                                    offset, req->iv);
     178                 :            : 
     179                 :          0 :         return crypto_skcipher_encrypt(subreq) ?:
     180                 :            :                cts_cbc_encrypt(req);
     181                 :            : }
     182                 :            : 
     183                 :          0 : static int cts_cbc_decrypt(struct skcipher_request *req)
     184                 :            : {
     185                 :            :         struct crypto_cts_reqctx *rctx = skcipher_request_ctx(req);
     186                 :            :         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
     187                 :          0 :         struct skcipher_request *subreq = &rctx->subreq;
     188                 :          0 :         int bsize = crypto_skcipher_blocksize(tfm);
     189                 :            :         u8 d[MAX_CIPHER_BLOCKSIZE * 2] __aligned(__alignof__(u32));
     190                 :            :         struct scatterlist *sg;
     191                 :            :         unsigned int offset;
     192                 :            :         u8 *space;
     193                 :            :         int lastn;
     194                 :            : 
     195                 :          0 :         offset = rctx->offset;
     196                 :          0 :         lastn = req->cryptlen - offset;
     197                 :            : 
     198                 :          0 :         sg = scatterwalk_ffwd(rctx->sg, req->dst, offset - bsize);
     199                 :            : 
     200                 :            :         /* 1. Decrypt Cn-1 (s) to create Dn */
     201                 :          0 :         scatterwalk_map_and_copy(d + bsize, sg, 0, bsize, 0);
     202                 :            :         space = crypto_cts_reqctx_space(req);
     203                 :          0 :         crypto_xor(d + bsize, space, bsize);
     204                 :            :         /* 2. Pad Cn with zeros at the end to create C of length BB */
     205                 :          0 :         memset(d, 0, bsize);
     206                 :          0 :         scatterwalk_map_and_copy(d, req->src, offset, lastn, 0);
     207                 :            :         /* 3. Exclusive-or Dn with C to create Xn */
     208                 :            :         /* 4. Select the first Ln bytes of Xn to create Pn */
     209                 :          0 :         crypto_xor(d + bsize, d, lastn);
     210                 :            : 
     211                 :            :         /* 5. Append the tail (BB - Ln) bytes of Xn to Cn to create En */
     212                 :          0 :         memcpy(d + lastn, d + bsize + lastn, bsize - lastn);
     213                 :            :         /* 6. Decrypt En to create Pn-1 */
     214                 :            : 
     215                 :          0 :         scatterwalk_map_and_copy(d, sg, 0, bsize + lastn, 1);
     216                 :            :         memzero_explicit(d, sizeof(d));
     217                 :            : 
     218                 :          0 :         skcipher_request_set_callback(subreq, req->base.flags &
     219                 :            :                                               CRYPTO_TFM_REQ_MAY_BACKLOG,
     220                 :            :                                       cts_cbc_crypt_done, req);
     221                 :            : 
     222                 :            :         skcipher_request_set_crypt(subreq, sg, sg, bsize, space);
     223                 :          0 :         return crypto_skcipher_decrypt(subreq);
     224                 :            : }
     225                 :            : 
     226                 :          0 : static void crypto_cts_decrypt_done(struct crypto_async_request *areq, int err)
     227                 :            : {
     228                 :          0 :         struct skcipher_request *req = areq->data;
     229                 :            : 
     230                 :          0 :         if (err)
     231                 :            :                 goto out;
     232                 :            : 
     233                 :          0 :         err = cts_cbc_decrypt(req);
     234                 :          0 :         if (err == -EINPROGRESS || err == -EBUSY)
     235                 :          0 :                 return;
     236                 :            : 
     237                 :            : out:
     238                 :            :         skcipher_request_complete(req, err);
     239                 :            : }
     240                 :            : 
     241                 :          0 : static int crypto_cts_decrypt(struct skcipher_request *req)
     242                 :            : {
     243                 :            :         struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
     244                 :            :         struct crypto_cts_reqctx *rctx = skcipher_request_ctx(req);
     245                 :            :         struct crypto_cts_ctx *ctx = crypto_skcipher_ctx(tfm);
     246                 :          0 :         struct skcipher_request *subreq = &rctx->subreq;
     247                 :          0 :         int bsize = crypto_skcipher_blocksize(tfm);
     248                 :          0 :         unsigned int nbytes = req->cryptlen;
     249                 :            :         unsigned int offset;
     250                 :            :         u8 *space;
     251                 :            : 
     252                 :          0 :         skcipher_request_set_tfm(subreq, ctx->child);
     253                 :            : 
     254                 :          0 :         if (nbytes < bsize)
     255                 :            :                 return -EINVAL;
     256                 :            : 
     257                 :          0 :         if (nbytes == bsize) {
     258                 :          0 :                 skcipher_request_set_callback(subreq, req->base.flags,
     259                 :            :                                               req->base.complete,
     260                 :            :                                               req->base.data);
     261                 :          0 :                 skcipher_request_set_crypt(subreq, req->src, req->dst, nbytes,
     262                 :          0 :                                            req->iv);
     263                 :          0 :                 return crypto_skcipher_decrypt(subreq);
     264                 :            :         }
     265                 :            : 
     266                 :          0 :         skcipher_request_set_callback(subreq, req->base.flags,
     267                 :            :                                       crypto_cts_decrypt_done, req);
     268                 :            : 
     269                 :            :         space = crypto_cts_reqctx_space(req);
     270                 :            : 
     271                 :          0 :         offset = rounddown(nbytes - 1, bsize);
     272                 :          0 :         rctx->offset = offset;
     273                 :            : 
     274                 :          0 :         if (offset <= bsize)
     275                 :          0 :                 memcpy(space, req->iv, bsize);
     276                 :            :         else
     277                 :          0 :                 scatterwalk_map_and_copy(space, req->src, offset - 2 * bsize,
     278                 :            :                                          bsize, 0);
     279                 :            : 
     280                 :          0 :         skcipher_request_set_crypt(subreq, req->src, req->dst,
     281                 :          0 :                                    offset, req->iv);
     282                 :            : 
     283                 :          0 :         return crypto_skcipher_decrypt(subreq) ?:
     284                 :            :                cts_cbc_decrypt(req);
     285                 :            : }
     286                 :            : 
     287                 :          0 : static int crypto_cts_init_tfm(struct crypto_skcipher *tfm)
     288                 :            : {
     289                 :            :         struct skcipher_instance *inst = skcipher_alg_instance(tfm);
     290                 :            :         struct crypto_skcipher_spawn *spawn = skcipher_instance_ctx(inst);
     291                 :            :         struct crypto_cts_ctx *ctx = crypto_skcipher_ctx(tfm);
     292                 :            :         struct crypto_skcipher *cipher;
     293                 :            :         unsigned reqsize;
     294                 :            :         unsigned bsize;
     295                 :            :         unsigned align;
     296                 :            : 
     297                 :            :         cipher = crypto_spawn_skcipher(spawn);
     298                 :          0 :         if (IS_ERR(cipher))
     299                 :          0 :                 return PTR_ERR(cipher);
     300                 :            : 
     301                 :          0 :         ctx->child = cipher;
     302                 :            : 
     303                 :            :         align = crypto_skcipher_alignmask(tfm);
     304                 :            :         bsize = crypto_skcipher_blocksize(cipher);
     305                 :          0 :         reqsize = ALIGN(sizeof(struct crypto_cts_reqctx) +
     306                 :            :                         crypto_skcipher_reqsize(cipher),
     307                 :          0 :                         crypto_tfm_ctx_alignment()) +
     308                 :          0 :                   (align & ~(crypto_tfm_ctx_alignment() - 1)) + bsize;
     309                 :            : 
     310                 :            :         crypto_skcipher_set_reqsize(tfm, reqsize);
     311                 :            : 
     312                 :          0 :         return 0;
     313                 :            : }
     314                 :            : 
     315                 :          0 : static void crypto_cts_exit_tfm(struct crypto_skcipher *tfm)
     316                 :            : {
     317                 :            :         struct crypto_cts_ctx *ctx = crypto_skcipher_ctx(tfm);
     318                 :            : 
     319                 :          0 :         crypto_free_skcipher(ctx->child);
     320                 :          0 : }
     321                 :            : 
     322                 :          0 : static void crypto_cts_free(struct skcipher_instance *inst)
     323                 :            : {
     324                 :            :         crypto_drop_skcipher(skcipher_instance_ctx(inst));
     325                 :          0 :         kfree(inst);
     326                 :          0 : }
     327                 :            : 
     328                 :          0 : static int crypto_cts_create(struct crypto_template *tmpl, struct rtattr **tb)
     329                 :            : {
     330                 :            :         struct crypto_skcipher_spawn *spawn;
     331                 :            :         struct skcipher_instance *inst;
     332                 :            :         struct crypto_attr_type *algt;
     333                 :            :         struct skcipher_alg *alg;
     334                 :            :         const char *cipher_name;
     335                 :            :         int err;
     336                 :            : 
     337                 :          0 :         algt = crypto_get_attr_type(tb);
     338                 :          0 :         if (IS_ERR(algt))
     339                 :          0 :                 return PTR_ERR(algt);
     340                 :            : 
     341                 :          0 :         if ((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask)
     342                 :            :                 return -EINVAL;
     343                 :            : 
     344                 :          0 :         cipher_name = crypto_attr_alg_name(tb[1]);
     345                 :          0 :         if (IS_ERR(cipher_name))
     346                 :          0 :                 return PTR_ERR(cipher_name);
     347                 :            : 
     348                 :          0 :         inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
     349                 :          0 :         if (!inst)
     350                 :            :                 return -ENOMEM;
     351                 :            : 
     352                 :            :         spawn = skcipher_instance_ctx(inst);
     353                 :            : 
     354                 :            :         crypto_set_skcipher_spawn(spawn, skcipher_crypto_instance(inst));
     355                 :          0 :         err = crypto_grab_skcipher(spawn, cipher_name, 0,
     356                 :          0 :                                    crypto_requires_sync(algt->type,
     357                 :            :                                                         algt->mask));
     358                 :          0 :         if (err)
     359                 :            :                 goto err_free_inst;
     360                 :            : 
     361                 :            :         alg = crypto_spawn_skcipher_alg(spawn);
     362                 :            : 
     363                 :            :         err = -EINVAL;
     364                 :          0 :         if (crypto_skcipher_alg_ivsize(alg) != alg->base.cra_blocksize)
     365                 :            :                 goto err_drop_spawn;
     366                 :            : 
     367                 :          0 :         if (strncmp(alg->base.cra_name, "cbc(", 4))
     368                 :            :                 goto err_drop_spawn;
     369                 :            : 
     370                 :          0 :         err = crypto_inst_setname(skcipher_crypto_instance(inst), "cts",
     371                 :            :                                   &alg->base);
     372                 :          0 :         if (err)
     373                 :            :                 goto err_drop_spawn;
     374                 :            : 
     375                 :          0 :         inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
     376                 :          0 :         inst->alg.base.cra_priority = alg->base.cra_priority;
     377                 :          0 :         inst->alg.base.cra_blocksize = alg->base.cra_blocksize;
     378                 :          0 :         inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
     379                 :            : 
     380                 :          0 :         inst->alg.ivsize = alg->base.cra_blocksize;
     381                 :          0 :         inst->alg.chunksize = crypto_skcipher_alg_chunksize(alg);
     382                 :          0 :         inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(alg);
     383                 :          0 :         inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(alg);
     384                 :            : 
     385                 :          0 :         inst->alg.base.cra_ctxsize = sizeof(struct crypto_cts_ctx);
     386                 :            : 
     387                 :          0 :         inst->alg.init = crypto_cts_init_tfm;
     388                 :          0 :         inst->alg.exit = crypto_cts_exit_tfm;
     389                 :            : 
     390                 :          0 :         inst->alg.setkey = crypto_cts_setkey;
     391                 :          0 :         inst->alg.encrypt = crypto_cts_encrypt;
     392                 :          0 :         inst->alg.decrypt = crypto_cts_decrypt;
     393                 :            : 
     394                 :          0 :         inst->free = crypto_cts_free;
     395                 :            : 
     396                 :          0 :         err = skcipher_register_instance(tmpl, inst);
     397                 :          0 :         if (err)
     398                 :            :                 goto err_drop_spawn;
     399                 :            : 
     400                 :            : out:
     401                 :          0 :         return err;
     402                 :            : 
     403                 :            : err_drop_spawn:
     404                 :            :         crypto_drop_skcipher(spawn);
     405                 :            : err_free_inst:
     406                 :          0 :         kfree(inst);
     407                 :          0 :         goto out;
     408                 :            : }
     409                 :            : 
     410                 :            : static struct crypto_template crypto_cts_tmpl = {
     411                 :            :         .name = "cts",
     412                 :            :         .create = crypto_cts_create,
     413                 :            :         .module = THIS_MODULE,
     414                 :            : };
     415                 :            : 
     416                 :          3 : static int __init crypto_cts_module_init(void)
     417                 :            : {
     418                 :          3 :         return crypto_register_template(&crypto_cts_tmpl);
     419                 :            : }
     420                 :            : 
     421                 :          0 : static void __exit crypto_cts_module_exit(void)
     422                 :            : {
     423                 :          0 :         crypto_unregister_template(&crypto_cts_tmpl);
     424                 :          0 : }
     425                 :            : 
     426                 :            : subsys_initcall(crypto_cts_module_init);
     427                 :            : module_exit(crypto_cts_module_exit);
     428                 :            : 
     429                 :            : MODULE_LICENSE("Dual BSD/GPL");
     430                 :            : MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC");
     431                 :            : MODULE_ALIAS_CRYPTO("cts");
    

Generated by: LCOV version 1.14