xref: /kernel/linux/linux-5.10/crypto/cipher.c (revision 8c2ecf20)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Cryptographic API.
4 *
5 * Single-block cipher operations.
6 *
7 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
8 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
9 */
10
11#include <crypto/algapi.h>
12#include <linux/kernel.h>
13#include <linux/crypto.h>
14#include <linux/errno.h>
15#include <linux/slab.h>
16#include <linux/string.h>
17#include "internal.h"
18
19static int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key,
20			    unsigned int keylen)
21{
22	struct cipher_alg *cia = crypto_cipher_alg(tfm);
23	unsigned long alignmask = crypto_cipher_alignmask(tfm);
24	int ret;
25	u8 *buffer, *alignbuffer;
26	unsigned long absize;
27
28	absize = keylen + alignmask;
29	buffer = kmalloc(absize, GFP_ATOMIC);
30	if (!buffer)
31		return -ENOMEM;
32
33	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
34	memcpy(alignbuffer, key, keylen);
35	ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen);
36	kfree_sensitive(buffer);
37	return ret;
38
39}
40
41int crypto_cipher_setkey(struct crypto_cipher *tfm,
42			 const u8 *key, unsigned int keylen)
43{
44	struct cipher_alg *cia = crypto_cipher_alg(tfm);
45	unsigned long alignmask = crypto_cipher_alignmask(tfm);
46
47	if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize)
48		return -EINVAL;
49
50	if ((unsigned long)key & alignmask)
51		return setkey_unaligned(tfm, key, keylen);
52
53	return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen);
54}
55EXPORT_SYMBOL_GPL(crypto_cipher_setkey);
56
57static inline void cipher_crypt_one(struct crypto_cipher *tfm,
58				    u8 *dst, const u8 *src, bool enc)
59{
60	unsigned long alignmask = crypto_cipher_alignmask(tfm);
61	struct cipher_alg *cia = crypto_cipher_alg(tfm);
62	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
63		enc ? cia->cia_encrypt : cia->cia_decrypt;
64
65	if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
66		unsigned int bs = crypto_cipher_blocksize(tfm);
67		u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
68		u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
69
70		memcpy(tmp, src, bs);
71		fn(crypto_cipher_tfm(tfm), tmp, tmp);
72		memcpy(dst, tmp, bs);
73	} else {
74		fn(crypto_cipher_tfm(tfm), dst, src);
75	}
76}
77
78void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
79			       u8 *dst, const u8 *src)
80{
81	cipher_crypt_one(tfm, dst, src, true);
82}
83EXPORT_SYMBOL_GPL(crypto_cipher_encrypt_one);
84
85void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
86			       u8 *dst, const u8 *src)
87{
88	cipher_crypt_one(tfm, dst, src, false);
89}
90EXPORT_SYMBOL_GPL(crypto_cipher_decrypt_one);
91