Line data Source code
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 <crypto/algapi.h> 63 : 64 : #ifndef __HAVE_ARCH_CRYPTO_MEMNEQ 65 : 66 : /* Generic path for arbitrary size */ 67 : static inline unsigned long 68 0 : __crypto_memneq_generic(const void *a, const void *b, size_t size) 69 : { 70 0 : unsigned long neq = 0; 71 : 72 : #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) 73 0 : while (size >= sizeof(unsigned long)) { 74 0 : neq |= *(unsigned long *)a ^ *(unsigned long *)b; 75 0 : OPTIMIZER_HIDE_VAR(neq); 76 0 : a += sizeof(unsigned long); 77 0 : b += sizeof(unsigned long); 78 0 : size -= sizeof(unsigned long); 79 : } 80 : #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ 81 0 : while (size > 0) { 82 0 : neq |= *(unsigned char *)a ^ *(unsigned char *)b; 83 0 : OPTIMIZER_HIDE_VAR(neq); 84 0 : a += 1; 85 0 : b += 1; 86 0 : size -= 1; 87 : } 88 0 : return neq; 89 : } 90 : 91 : /* Loop-free fast-path for frequently used 16-byte size */ 92 0 : static inline unsigned long __crypto_memneq_16(const void *a, const void *b) 93 : { 94 0 : unsigned long neq = 0; 95 : 96 : #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 97 0 : if (sizeof(unsigned long) == 8) { 98 0 : neq |= *(unsigned long *)(a) ^ *(unsigned long *)(b); 99 0 : OPTIMIZER_HIDE_VAR(neq); 100 0 : neq |= *(unsigned long *)(a+8) ^ *(unsigned long *)(b+8); 101 0 : OPTIMIZER_HIDE_VAR(neq); 102 : } else if (sizeof(unsigned int) == 4) { 103 : neq |= *(unsigned int *)(a) ^ *(unsigned int *)(b); 104 : OPTIMIZER_HIDE_VAR(neq); 105 : neq |= *(unsigned int *)(a+4) ^ *(unsigned int *)(b+4); 106 : OPTIMIZER_HIDE_VAR(neq); 107 : neq |= *(unsigned int *)(a+8) ^ *(unsigned int *)(b+8); 108 : OPTIMIZER_HIDE_VAR(neq); 109 : neq |= *(unsigned int *)(a+12) ^ *(unsigned int *)(b+12); 110 : OPTIMIZER_HIDE_VAR(neq); 111 : } else 112 : #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ 113 : { 114 : neq |= *(unsigned char *)(a) ^ *(unsigned char *)(b); 115 : OPTIMIZER_HIDE_VAR(neq); 116 : neq |= *(unsigned char *)(a+1) ^ *(unsigned char *)(b+1); 117 : OPTIMIZER_HIDE_VAR(neq); 118 : neq |= *(unsigned char *)(a+2) ^ *(unsigned char *)(b+2); 119 : OPTIMIZER_HIDE_VAR(neq); 120 : neq |= *(unsigned char *)(a+3) ^ *(unsigned char *)(b+3); 121 : OPTIMIZER_HIDE_VAR(neq); 122 : neq |= *(unsigned char *)(a+4) ^ *(unsigned char *)(b+4); 123 : OPTIMIZER_HIDE_VAR(neq); 124 : neq |= *(unsigned char *)(a+5) ^ *(unsigned char *)(b+5); 125 : OPTIMIZER_HIDE_VAR(neq); 126 : neq |= *(unsigned char *)(a+6) ^ *(unsigned char *)(b+6); 127 : OPTIMIZER_HIDE_VAR(neq); 128 : neq |= *(unsigned char *)(a+7) ^ *(unsigned char *)(b+7); 129 : OPTIMIZER_HIDE_VAR(neq); 130 : neq |= *(unsigned char *)(a+8) ^ *(unsigned char *)(b+8); 131 : OPTIMIZER_HIDE_VAR(neq); 132 : neq |= *(unsigned char *)(a+9) ^ *(unsigned char *)(b+9); 133 : OPTIMIZER_HIDE_VAR(neq); 134 : neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10); 135 : OPTIMIZER_HIDE_VAR(neq); 136 : neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11); 137 : OPTIMIZER_HIDE_VAR(neq); 138 : neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12); 139 : OPTIMIZER_HIDE_VAR(neq); 140 : neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13); 141 : OPTIMIZER_HIDE_VAR(neq); 142 : neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14); 143 : OPTIMIZER_HIDE_VAR(neq); 144 : neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15); 145 : OPTIMIZER_HIDE_VAR(neq); 146 : } 147 : 148 0 : return neq; 149 : } 150 : 151 : /* Compare two areas of memory without leaking timing information, 152 : * and with special optimizations for common sizes. Users should 153 : * not call this function directly, but should instead use 154 : * crypto_memneq defined in crypto/algapi.h. 155 : */ 156 0 : noinline unsigned long __crypto_memneq(const void *a, const void *b, 157 : size_t size) 158 : { 159 0 : switch (size) { 160 : case 16: 161 0 : return __crypto_memneq_16(a, b); 162 0 : default: 163 0 : return __crypto_memneq_generic(a, b, size); 164 : } 165 : } 166 : EXPORT_SYMBOL(__crypto_memneq); 167 : 168 : #endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */