xref: /linux-6.15/lib/crypto/utils.c (revision 5f60d5f6)
16e78ad0bSEric Biggers // SPDX-License-Identifier: GPL-2.0-or-later
26e78ad0bSEric Biggers /*
36e78ad0bSEric Biggers  * Crypto library utility functions
46e78ad0bSEric Biggers  *
56e78ad0bSEric Biggers  * Copyright (c) 2006 Herbert Xu <[email protected]>
66e78ad0bSEric Biggers  */
76e78ad0bSEric Biggers 
8*5f60d5f6SAl Viro #include <linux/unaligned.h>
9c616fb0cSHerbert Xu #include <crypto/utils.h>
106e78ad0bSEric Biggers #include <linux/module.h>
116e78ad0bSEric Biggers 
126e78ad0bSEric Biggers /*
136e78ad0bSEric Biggers  * XOR @len bytes from @src1 and @src2 together, writing the result to @dst
146e78ad0bSEric Biggers  * (which may alias one of the sources).  Don't call this directly; call
156e78ad0bSEric Biggers  * crypto_xor() or crypto_xor_cpy() instead.
166e78ad0bSEric Biggers  */
__crypto_xor(u8 * dst,const u8 * src1,const u8 * src2,unsigned int len)176e78ad0bSEric Biggers void __crypto_xor(u8 *dst, const u8 *src1, const u8 *src2, unsigned int len)
186e78ad0bSEric Biggers {
196e78ad0bSEric Biggers 	int relalign = 0;
206e78ad0bSEric Biggers 
216e78ad0bSEric Biggers 	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
226e78ad0bSEric Biggers 		int size = sizeof(unsigned long);
236e78ad0bSEric Biggers 		int d = (((unsigned long)dst ^ (unsigned long)src1) |
246e78ad0bSEric Biggers 			 ((unsigned long)dst ^ (unsigned long)src2)) &
256e78ad0bSEric Biggers 			(size - 1);
266e78ad0bSEric Biggers 
276e78ad0bSEric Biggers 		relalign = d ? 1 << __ffs(d) : size;
286e78ad0bSEric Biggers 
296e78ad0bSEric Biggers 		/*
306e78ad0bSEric Biggers 		 * If we care about alignment, process as many bytes as
316e78ad0bSEric Biggers 		 * needed to advance dst and src to values whose alignments
326e78ad0bSEric Biggers 		 * equal their relative alignment. This will allow us to
336e78ad0bSEric Biggers 		 * process the remainder of the input using optimal strides.
346e78ad0bSEric Biggers 		 */
356e78ad0bSEric Biggers 		while (((unsigned long)dst & (relalign - 1)) && len > 0) {
366e78ad0bSEric Biggers 			*dst++ = *src1++ ^ *src2++;
376e78ad0bSEric Biggers 			len--;
386e78ad0bSEric Biggers 		}
396e78ad0bSEric Biggers 	}
406e78ad0bSEric Biggers 
416e78ad0bSEric Biggers 	while (IS_ENABLED(CONFIG_64BIT) && len >= 8 && !(relalign & 7)) {
426e78ad0bSEric Biggers 		if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
436e78ad0bSEric Biggers 			u64 l = get_unaligned((u64 *)src1) ^
446e78ad0bSEric Biggers 				get_unaligned((u64 *)src2);
456e78ad0bSEric Biggers 			put_unaligned(l, (u64 *)dst);
466e78ad0bSEric Biggers 		} else {
476e78ad0bSEric Biggers 			*(u64 *)dst = *(u64 *)src1 ^ *(u64 *)src2;
486e78ad0bSEric Biggers 		}
496e78ad0bSEric Biggers 		dst += 8;
506e78ad0bSEric Biggers 		src1 += 8;
516e78ad0bSEric Biggers 		src2 += 8;
526e78ad0bSEric Biggers 		len -= 8;
536e78ad0bSEric Biggers 	}
546e78ad0bSEric Biggers 
556e78ad0bSEric Biggers 	while (len >= 4 && !(relalign & 3)) {
566e78ad0bSEric Biggers 		if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
576e78ad0bSEric Biggers 			u32 l = get_unaligned((u32 *)src1) ^
586e78ad0bSEric Biggers 				get_unaligned((u32 *)src2);
596e78ad0bSEric Biggers 			put_unaligned(l, (u32 *)dst);
606e78ad0bSEric Biggers 		} else {
616e78ad0bSEric Biggers 			*(u32 *)dst = *(u32 *)src1 ^ *(u32 *)src2;
626e78ad0bSEric Biggers 		}
636e78ad0bSEric Biggers 		dst += 4;
646e78ad0bSEric Biggers 		src1 += 4;
656e78ad0bSEric Biggers 		src2 += 4;
666e78ad0bSEric Biggers 		len -= 4;
676e78ad0bSEric Biggers 	}
686e78ad0bSEric Biggers 
696e78ad0bSEric Biggers 	while (len >= 2 && !(relalign & 1)) {
706e78ad0bSEric Biggers 		if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
716e78ad0bSEric Biggers 			u16 l = get_unaligned((u16 *)src1) ^
726e78ad0bSEric Biggers 				get_unaligned((u16 *)src2);
736e78ad0bSEric Biggers 			put_unaligned(l, (u16 *)dst);
746e78ad0bSEric Biggers 		} else {
756e78ad0bSEric Biggers 			*(u16 *)dst = *(u16 *)src1 ^ *(u16 *)src2;
766e78ad0bSEric Biggers 		}
776e78ad0bSEric Biggers 		dst += 2;
786e78ad0bSEric Biggers 		src1 += 2;
796e78ad0bSEric Biggers 		src2 += 2;
806e78ad0bSEric Biggers 		len -= 2;
816e78ad0bSEric Biggers 	}
826e78ad0bSEric Biggers 
836e78ad0bSEric Biggers 	while (len--)
846e78ad0bSEric Biggers 		*dst++ = *src1++ ^ *src2++;
856e78ad0bSEric Biggers }
866e78ad0bSEric Biggers EXPORT_SYMBOL_GPL(__crypto_xor);
876e78ad0bSEric Biggers 
883cbe18b0SJeff Johnson MODULE_DESCRIPTION("Crypto library utility functions");
896e78ad0bSEric Biggers MODULE_LICENSE("GPL");
90