Branch data 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 : 1616 : __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 [ + + ]: 9696 : while (size >= sizeof(unsigned long)) { 74 : 6464 : neq |= *(unsigned long *)a ^ *(unsigned long *)b; 75 : 6464 : OPTIMIZER_HIDE_VAR(neq); 76 : 6464 : a += sizeof(unsigned long); 77 : 6464 : b += sizeof(unsigned long); 78 : 6464 : size -= sizeof(unsigned long); 79 : : } 80 : : #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ 81 [ + + ]: 6464 : while (size > 0) { 82 : 4848 : neq |= *(unsigned char *)a ^ *(unsigned char *)b; 83 : 4848 : OPTIMIZER_HIDE_VAR(neq); 84 : 4848 : a += 1; 85 : 4848 : b += 1; 86 : 4848 : size -= 1; 87 : : } 88 : 1616 : return neq; 89 : : } 90 : : 91 : : /* Loop-free fast-path for frequently used 16-byte size */ 92 : : static inline unsigned long __crypto_memneq_16(const void *a, const void *b) 93 : : { 94 : : unsigned long neq = 0; 95 : : 96 : : #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 97 : : if (sizeof(unsigned long) == 8) { 98 : : neq |= *(unsigned long *)(a) ^ *(unsigned long *)(b); 99 : : OPTIMIZER_HIDE_VAR(neq); 100 : : neq |= *(unsigned long *)(a+8) ^ *(unsigned long *)(b+8); 101 : : OPTIMIZER_HIDE_VAR(neq); 102 : : } else if (sizeof(unsigned int) == 4) { 103 : 0 : neq |= *(unsigned int *)(a) ^ *(unsigned int *)(b); 104 : 0 : OPTIMIZER_HIDE_VAR(neq); 105 : 0 : neq |= *(unsigned int *)(a+4) ^ *(unsigned int *)(b+4); 106 : 0 : OPTIMIZER_HIDE_VAR(neq); 107 : 0 : neq |= *(unsigned int *)(a+8) ^ *(unsigned int *)(b+8); 108 : 0 : OPTIMIZER_HIDE_VAR(neq); 109 : 0 : neq |= *(unsigned int *)(a+12) ^ *(unsigned int *)(b+12); 110 : 0 : 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 : : 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 : 1616 : noinline unsigned long __crypto_memneq(const void *a, const void *b, 157 : : size_t size) 158 : : { 159 [ - + ]: 1616 : switch (size) { 160 : : case 16: 161 : 0 : return __crypto_memneq_16(a, b); 162 : : default: 163 : 1616 : return __crypto_memneq_generic(a, b, size); 164 : : } 165 : : } 166 : : EXPORT_SYMBOL(__crypto_memneq); 167 : : 168 : : #endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */