Linux Audio

Check our new training course

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