linux/include/crypto/cbc.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 * CBC: Cipher Block Chaining mode
   4 *
   5 * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au>
   6 */
   7
   8#ifndef _CRYPTO_CBC_H
   9#define _CRYPTO_CBC_H
  10
  11#include <crypto/internal/skcipher.h>
  12#include <linux/string.h>
  13#include <linux/types.h>
  14
  15static inline int crypto_cbc_encrypt_segment(
  16        struct skcipher_walk *walk, struct crypto_skcipher *tfm,
  17        void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
  18{
  19        unsigned int bsize = crypto_skcipher_blocksize(tfm);
  20        unsigned int nbytes = walk->nbytes;
  21        u8 *src = walk->src.virt.addr;
  22        u8 *dst = walk->dst.virt.addr;
  23        u8 *iv = walk->iv;
  24
  25        do {
  26                crypto_xor(iv, src, bsize);
  27                fn(tfm, iv, dst);
  28                memcpy(iv, dst, bsize);
  29
  30                src += bsize;
  31                dst += bsize;
  32        } while ((nbytes -= bsize) >= bsize);
  33
  34        return nbytes;
  35}
  36
  37static inline int crypto_cbc_encrypt_inplace(
  38        struct skcipher_walk *walk, struct crypto_skcipher *tfm,
  39        void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
  40{
  41        unsigned int bsize = crypto_skcipher_blocksize(tfm);
  42        unsigned int nbytes = walk->nbytes;
  43        u8 *src = walk->src.virt.addr;
  44        u8 *iv = walk->iv;
  45
  46        do {
  47                crypto_xor(src, iv, bsize);
  48                fn(tfm, src, src);
  49                iv = src;
  50
  51                src += bsize;
  52        } while ((nbytes -= bsize) >= bsize);
  53
  54        memcpy(walk->iv, iv, bsize);
  55
  56        return nbytes;
  57}
  58
  59static inline int crypto_cbc_encrypt_walk(struct skcipher_request *req,
  60                                          void (*fn)(struct crypto_skcipher *,
  61                                                     const u8 *, u8 *))
  62{
  63        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  64        struct skcipher_walk walk;
  65        int err;
  66
  67        err = skcipher_walk_virt(&walk, req, false);
  68
  69        while (walk.nbytes) {
  70                if (walk.src.virt.addr == walk.dst.virt.addr)
  71                        err = crypto_cbc_encrypt_inplace(&walk, tfm, fn);
  72                else
  73                        err = crypto_cbc_encrypt_segment(&walk, tfm, fn);
  74                err = skcipher_walk_done(&walk, err);
  75        }
  76
  77        return err;
  78}
  79
  80static inline int crypto_cbc_decrypt_segment(
  81        struct skcipher_walk *walk, struct crypto_skcipher *tfm,
  82        void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
  83{
  84        unsigned int bsize = crypto_skcipher_blocksize(tfm);
  85        unsigned int nbytes = walk->nbytes;
  86        u8 *src = walk->src.virt.addr;
  87        u8 *dst = walk->dst.virt.addr;
  88        u8 *iv = walk->iv;
  89
  90        do {
  91                fn(tfm, src, dst);
  92                crypto_xor(dst, iv, bsize);
  93                iv = src;
  94
  95                src += bsize;
  96                dst += bsize;
  97        } while ((nbytes -= bsize) >= bsize);
  98
  99        memcpy(walk->iv, iv, bsize);
 100
 101        return nbytes;
 102}
 103
 104static inline int crypto_cbc_decrypt_inplace(
 105        struct skcipher_walk *walk, struct crypto_skcipher *tfm,
 106        void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
 107{
 108        unsigned int bsize = crypto_skcipher_blocksize(tfm);
 109        unsigned int nbytes = walk->nbytes;
 110        u8 *src = walk->src.virt.addr;
 111        u8 last_iv[MAX_CIPHER_BLOCKSIZE];
 112
 113        /* Start of the last block. */
 114        src += nbytes - (nbytes & (bsize - 1)) - bsize;
 115        memcpy(last_iv, src, bsize);
 116
 117        for (;;) {
 118                fn(tfm, src, src);
 119                if ((nbytes -= bsize) < bsize)
 120                        break;
 121                crypto_xor(src, src - bsize, bsize);
 122                src -= bsize;
 123        }
 124
 125        crypto_xor(src, walk->iv, bsize);
 126        memcpy(walk->iv, last_iv, bsize);
 127
 128        return nbytes;
 129}
 130
 131static inline int crypto_cbc_decrypt_blocks(
 132        struct skcipher_walk *walk, struct crypto_skcipher *tfm,
 133        void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
 134{
 135        if (walk->src.virt.addr == walk->dst.virt.addr)
 136                return crypto_cbc_decrypt_inplace(walk, tfm, fn);
 137        else
 138                return crypto_cbc_decrypt_segment(walk, tfm, fn);
 139}
 140
 141#endif  /* _CRYPTO_CBC_H */
 142