xref: /openbmc/linux/lib/crypto/memneq.c (revision 7033b937)
1*7033b937SEric Biggers /*
2*7033b937SEric Biggers  * Constant-time equality testing of memory regions.
3*7033b937SEric Biggers  *
4*7033b937SEric Biggers  * Authors:
5*7033b937SEric Biggers  *
6*7033b937SEric Biggers  *   James Yonan <james@openvpn.net>
7*7033b937SEric Biggers  *   Daniel Borkmann <dborkman@redhat.com>
8*7033b937SEric Biggers  *
9*7033b937SEric Biggers  * This file is provided under a dual BSD/GPLv2 license.  When using or
10*7033b937SEric Biggers  * redistributing this file, you may do so under either license.
11*7033b937SEric Biggers  *
12*7033b937SEric Biggers  * GPL LICENSE SUMMARY
13*7033b937SEric Biggers  *
14*7033b937SEric Biggers  * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
15*7033b937SEric Biggers  *
16*7033b937SEric Biggers  * This program is free software; you can redistribute it and/or modify
17*7033b937SEric Biggers  * it under the terms of version 2 of the GNU General Public License as
18*7033b937SEric Biggers  * published by the Free Software Foundation.
19*7033b937SEric Biggers  *
20*7033b937SEric Biggers  * This program is distributed in the hope that it will be useful, but
21*7033b937SEric Biggers  * WITHOUT ANY WARRANTY; without even the implied warranty of
22*7033b937SEric Biggers  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23*7033b937SEric Biggers  * General Public License for more details.
24*7033b937SEric Biggers  *
25*7033b937SEric Biggers  * You should have received a copy of the GNU General Public License
26*7033b937SEric Biggers  * along with this program; if not, write to the Free Software
27*7033b937SEric Biggers  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
28*7033b937SEric Biggers  * The full GNU General Public License is included in this distribution
29*7033b937SEric Biggers  * in the file called LICENSE.GPL.
30*7033b937SEric Biggers  *
31*7033b937SEric Biggers  * BSD LICENSE
32*7033b937SEric Biggers  *
33*7033b937SEric Biggers  * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
34*7033b937SEric Biggers  *
35*7033b937SEric Biggers  * Redistribution and use in source and binary forms, with or without
36*7033b937SEric Biggers  * modification, are permitted provided that the following conditions
37*7033b937SEric Biggers  * are met:
38*7033b937SEric Biggers  *
39*7033b937SEric Biggers  *   * Redistributions of source code must retain the above copyright
40*7033b937SEric Biggers  *     notice, this list of conditions and the following disclaimer.
41*7033b937SEric Biggers  *   * Redistributions in binary form must reproduce the above copyright
42*7033b937SEric Biggers  *     notice, this list of conditions and the following disclaimer in
43*7033b937SEric Biggers  *     the documentation and/or other materials provided with the
44*7033b937SEric Biggers  *     distribution.
45*7033b937SEric Biggers  *   * Neither the name of OpenVPN Technologies nor the names of its
46*7033b937SEric Biggers  *     contributors may be used to endorse or promote products derived
47*7033b937SEric Biggers  *     from this software without specific prior written permission.
48*7033b937SEric Biggers  *
49*7033b937SEric Biggers  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50*7033b937SEric Biggers  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51*7033b937SEric Biggers  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52*7033b937SEric Biggers  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53*7033b937SEric Biggers  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54*7033b937SEric Biggers  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55*7033b937SEric Biggers  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56*7033b937SEric Biggers  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57*7033b937SEric Biggers  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58*7033b937SEric Biggers  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59*7033b937SEric Biggers  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60*7033b937SEric Biggers  */
61*7033b937SEric Biggers 
62*7033b937SEric Biggers #include <asm/unaligned.h>
63*7033b937SEric Biggers #include <crypto/algapi.h>
64*7033b937SEric Biggers #include <linux/module.h>
65*7033b937SEric Biggers 
66*7033b937SEric Biggers #ifndef __HAVE_ARCH_CRYPTO_MEMNEQ
67*7033b937SEric Biggers 
68*7033b937SEric Biggers /* Generic path for arbitrary size */
69*7033b937SEric Biggers static inline unsigned long
70*7033b937SEric Biggers __crypto_memneq_generic(const void *a, const void *b, size_t size)
71*7033b937SEric Biggers {
72*7033b937SEric Biggers 	unsigned long neq = 0;
73*7033b937SEric Biggers 
74*7033b937SEric Biggers #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
75*7033b937SEric Biggers 	while (size >= sizeof(unsigned long)) {
76*7033b937SEric Biggers 		neq |= get_unaligned((unsigned long *)a) ^
77*7033b937SEric Biggers 		       get_unaligned((unsigned long *)b);
78*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
79*7033b937SEric Biggers 		a += sizeof(unsigned long);
80*7033b937SEric Biggers 		b += sizeof(unsigned long);
81*7033b937SEric Biggers 		size -= sizeof(unsigned long);
82*7033b937SEric Biggers 	}
83*7033b937SEric Biggers #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
84*7033b937SEric Biggers 	while (size > 0) {
85*7033b937SEric Biggers 		neq |= *(unsigned char *)a ^ *(unsigned char *)b;
86*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
87*7033b937SEric Biggers 		a += 1;
88*7033b937SEric Biggers 		b += 1;
89*7033b937SEric Biggers 		size -= 1;
90*7033b937SEric Biggers 	}
91*7033b937SEric Biggers 	return neq;
92*7033b937SEric Biggers }
93*7033b937SEric Biggers 
94*7033b937SEric Biggers /* Loop-free fast-path for frequently used 16-byte size */
95*7033b937SEric Biggers static inline unsigned long __crypto_memneq_16(const void *a, const void *b)
96*7033b937SEric Biggers {
97*7033b937SEric Biggers 	unsigned long neq = 0;
98*7033b937SEric Biggers 
99*7033b937SEric Biggers #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
100*7033b937SEric Biggers 	if (sizeof(unsigned long) == 8) {
101*7033b937SEric Biggers 		neq |= get_unaligned((unsigned long *)a) ^
102*7033b937SEric Biggers 		       get_unaligned((unsigned long *)b);
103*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
104*7033b937SEric Biggers 		neq |= get_unaligned((unsigned long *)(a + 8)) ^
105*7033b937SEric Biggers 		       get_unaligned((unsigned long *)(b + 8));
106*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
107*7033b937SEric Biggers 	} else if (sizeof(unsigned int) == 4) {
108*7033b937SEric Biggers 		neq |= get_unaligned((unsigned int *)a) ^
109*7033b937SEric Biggers 		       get_unaligned((unsigned int *)b);
110*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
111*7033b937SEric Biggers 		neq |= get_unaligned((unsigned int *)(a + 4)) ^
112*7033b937SEric Biggers 		       get_unaligned((unsigned int *)(b + 4));
113*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
114*7033b937SEric Biggers 		neq |= get_unaligned((unsigned int *)(a + 8)) ^
115*7033b937SEric Biggers 		       get_unaligned((unsigned int *)(b + 8));
116*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
117*7033b937SEric Biggers 		neq |= get_unaligned((unsigned int *)(a + 12)) ^
118*7033b937SEric Biggers 		       get_unaligned((unsigned int *)(b + 12));
119*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
120*7033b937SEric Biggers 	} else
121*7033b937SEric Biggers #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
122*7033b937SEric Biggers 	{
123*7033b937SEric Biggers 		neq |= *(unsigned char *)(a)    ^ *(unsigned char *)(b);
124*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
125*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+1)  ^ *(unsigned char *)(b+1);
126*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
127*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+2)  ^ *(unsigned char *)(b+2);
128*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
129*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+3)  ^ *(unsigned char *)(b+3);
130*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
131*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+4)  ^ *(unsigned char *)(b+4);
132*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
133*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+5)  ^ *(unsigned char *)(b+5);
134*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
135*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+6)  ^ *(unsigned char *)(b+6);
136*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
137*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+7)  ^ *(unsigned char *)(b+7);
138*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
139*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+8)  ^ *(unsigned char *)(b+8);
140*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
141*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+9)  ^ *(unsigned char *)(b+9);
142*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
143*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10);
144*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
145*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11);
146*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
147*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12);
148*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
149*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13);
150*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
151*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14);
152*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
153*7033b937SEric Biggers 		neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15);
154*7033b937SEric Biggers 		OPTIMIZER_HIDE_VAR(neq);
155*7033b937SEric Biggers 	}
156*7033b937SEric Biggers 
157*7033b937SEric Biggers 	return neq;
158*7033b937SEric Biggers }
159*7033b937SEric Biggers 
160*7033b937SEric Biggers /* Compare two areas of memory without leaking timing information,
161*7033b937SEric Biggers  * and with special optimizations for common sizes.  Users should
162*7033b937SEric Biggers  * not call this function directly, but should instead use
163*7033b937SEric Biggers  * crypto_memneq defined in crypto/algapi.h.
164*7033b937SEric Biggers  */
165*7033b937SEric Biggers noinline unsigned long __crypto_memneq(const void *a, const void *b,
166*7033b937SEric Biggers 				       size_t size)
167*7033b937SEric Biggers {
168*7033b937SEric Biggers 	switch (size) {
169*7033b937SEric Biggers 	case 16:
170*7033b937SEric Biggers 		return __crypto_memneq_16(a, b);
171*7033b937SEric Biggers 	default:
172*7033b937SEric Biggers 		return __crypto_memneq_generic(a, b, size);
173*7033b937SEric Biggers 	}
174*7033b937SEric Biggers }
175*7033b937SEric Biggers EXPORT_SYMBOL(__crypto_memneq);
176*7033b937SEric Biggers 
177*7033b937SEric Biggers #endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */
178*7033b937SEric Biggers 
179*7033b937SEric Biggers MODULE_LICENSE("GPL");
180