at v5.2 3.4 kB view raw
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 */