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