18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * CTR: Counter mode
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef _CRYPTO_CTR_H
98c2ecf20Sopenharmony_ci#define _CRYPTO_CTR_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
128c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define CTR_RFC3686_NONCE_SIZE 4
178c2ecf20Sopenharmony_ci#define CTR_RFC3686_IV_SIZE 8
188c2ecf20Sopenharmony_ci#define CTR_RFC3686_BLOCK_SIZE 16
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic inline int crypto_ctr_encrypt_walk(struct skcipher_request *req,
218c2ecf20Sopenharmony_ci					  void (*fn)(struct crypto_skcipher *,
228c2ecf20Sopenharmony_ci						     const u8 *, u8 *))
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
258c2ecf20Sopenharmony_ci	int blocksize = crypto_skcipher_chunksize(tfm);
268c2ecf20Sopenharmony_ci	u8 buf[MAX_CIPHER_BLOCKSIZE];
278c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
288c2ecf20Sopenharmony_ci	int err;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* avoid integer division due to variable blocksize parameter */
318c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!is_power_of_2(blocksize)))
328c2ecf20Sopenharmony_ci		return -EINVAL;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	while (walk.nbytes > 0) {
378c2ecf20Sopenharmony_ci		u8 *dst = walk.dst.virt.addr;
388c2ecf20Sopenharmony_ci		u8 *src = walk.src.virt.addr;
398c2ecf20Sopenharmony_ci		int nbytes = walk.nbytes;
408c2ecf20Sopenharmony_ci		int tail = 0;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci		if (nbytes < walk.total) {
438c2ecf20Sopenharmony_ci			tail = walk.nbytes & (blocksize - 1);
448c2ecf20Sopenharmony_ci			nbytes -= tail;
458c2ecf20Sopenharmony_ci		}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci		do {
488c2ecf20Sopenharmony_ci			int bsize = min(nbytes, blocksize);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci			fn(tfm, walk.iv, buf);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci			crypto_xor_cpy(dst, src, buf, bsize);
538c2ecf20Sopenharmony_ci			crypto_inc(walk.iv, blocksize);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci			dst += bsize;
568c2ecf20Sopenharmony_ci			src += bsize;
578c2ecf20Sopenharmony_ci			nbytes -= bsize;
588c2ecf20Sopenharmony_ci		} while (nbytes > 0);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, tail);
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	return err;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#endif  /* _CRYPTO_CTR_H */
66