1c616fb0cSHerbert Xu /* SPDX-License-Identifier: GPL-2.0-or-later */
2c616fb0cSHerbert Xu /*
3c616fb0cSHerbert Xu * Cryptographic utilities
4c616fb0cSHerbert Xu *
5c616fb0cSHerbert Xu * Copyright (c) 2023 Herbert Xu <[email protected]>
6c616fb0cSHerbert Xu */
7c616fb0cSHerbert Xu #ifndef _CRYPTO_UTILS_H
8c616fb0cSHerbert Xu #define _CRYPTO_UTILS_H
9c616fb0cSHerbert Xu
10*5f60d5f6SAl Viro #include <linux/unaligned.h>
11c616fb0cSHerbert Xu #include <linux/compiler_attributes.h>
12c616fb0cSHerbert Xu #include <linux/types.h>
13c616fb0cSHerbert Xu
14c616fb0cSHerbert Xu void __crypto_xor(u8 *dst, const u8 *src1, const u8 *src2, unsigned int size);
15c616fb0cSHerbert Xu
crypto_xor(u8 * dst,const u8 * src,unsigned int size)16c616fb0cSHerbert Xu static inline void crypto_xor(u8 *dst, const u8 *src, unsigned int size)
17c616fb0cSHerbert Xu {
18c616fb0cSHerbert Xu if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
19c616fb0cSHerbert Xu __builtin_constant_p(size) &&
20c616fb0cSHerbert Xu (size % sizeof(unsigned long)) == 0) {
21c616fb0cSHerbert Xu unsigned long *d = (unsigned long *)dst;
22c616fb0cSHerbert Xu unsigned long *s = (unsigned long *)src;
23c616fb0cSHerbert Xu unsigned long l;
24c616fb0cSHerbert Xu
25c616fb0cSHerbert Xu while (size > 0) {
26c616fb0cSHerbert Xu l = get_unaligned(d) ^ get_unaligned(s++);
27c616fb0cSHerbert Xu put_unaligned(l, d++);
28c616fb0cSHerbert Xu size -= sizeof(unsigned long);
29c616fb0cSHerbert Xu }
30c616fb0cSHerbert Xu } else {
31c616fb0cSHerbert Xu __crypto_xor(dst, dst, src, size);
32c616fb0cSHerbert Xu }
33c616fb0cSHerbert Xu }
34c616fb0cSHerbert Xu
crypto_xor_cpy(u8 * dst,const u8 * src1,const u8 * src2,unsigned int size)35c616fb0cSHerbert Xu static inline void crypto_xor_cpy(u8 *dst, const u8 *src1, const u8 *src2,
36c616fb0cSHerbert Xu unsigned int size)
37c616fb0cSHerbert Xu {
38c616fb0cSHerbert Xu if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
39c616fb0cSHerbert Xu __builtin_constant_p(size) &&
40c616fb0cSHerbert Xu (size % sizeof(unsigned long)) == 0) {
41c616fb0cSHerbert Xu unsigned long *d = (unsigned long *)dst;
42c616fb0cSHerbert Xu unsigned long *s1 = (unsigned long *)src1;
43c616fb0cSHerbert Xu unsigned long *s2 = (unsigned long *)src2;
44c616fb0cSHerbert Xu unsigned long l;
45c616fb0cSHerbert Xu
46c616fb0cSHerbert Xu while (size > 0) {
47c616fb0cSHerbert Xu l = get_unaligned(s1++) ^ get_unaligned(s2++);
48c616fb0cSHerbert Xu put_unaligned(l, d++);
49c616fb0cSHerbert Xu size -= sizeof(unsigned long);
50c616fb0cSHerbert Xu }
51c616fb0cSHerbert Xu } else {
52c616fb0cSHerbert Xu __crypto_xor(dst, src1, src2, size);
53c616fb0cSHerbert Xu }
54c616fb0cSHerbert Xu }
55c616fb0cSHerbert Xu
56c616fb0cSHerbert Xu noinline unsigned long __crypto_memneq(const void *a, const void *b, size_t size);
57c616fb0cSHerbert Xu
58c616fb0cSHerbert Xu /**
59c616fb0cSHerbert Xu * crypto_memneq - Compare two areas of memory without leaking
60c616fb0cSHerbert Xu * timing information.
61c616fb0cSHerbert Xu *
62c616fb0cSHerbert Xu * @a: One area of memory
63c616fb0cSHerbert Xu * @b: Another area of memory
64c616fb0cSHerbert Xu * @size: The size of the area.
65c616fb0cSHerbert Xu *
66c616fb0cSHerbert Xu * Returns 0 when data is equal, 1 otherwise.
67c616fb0cSHerbert Xu */
crypto_memneq(const void * a,const void * b,size_t size)68c616fb0cSHerbert Xu static inline int crypto_memneq(const void *a, const void *b, size_t size)
69c616fb0cSHerbert Xu {
70c616fb0cSHerbert Xu return __crypto_memneq(a, b, size) != 0UL ? 1 : 0;
71c616fb0cSHerbert Xu }
72c616fb0cSHerbert Xu
73c616fb0cSHerbert Xu #endif /* _CRYPTO_UTILS_H */
74