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 */ 67static 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 |= *(unsigned long *)a ^ *(unsigned long *)b; 75 OPTIMIZER_HIDE_VAR(neq); 76 a += sizeof(unsigned long); 77 b += sizeof(unsigned long); 78 size -= sizeof(unsigned long); 79 } 80#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ 81 while (size > 0) { 82 neq |= *(unsigned char *)a ^ *(unsigned char *)b; 83 OPTIMIZER_HIDE_VAR(neq); 84 a += 1; 85 b += 1; 86 size -= 1; 87 } 88 return neq; 89} 90 91/* Loop-free fast-path for frequently used 16-byte size */ 92static 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 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 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 */ 156noinline unsigned long __crypto_memneq(const void *a, const void *b, 157 size_t size) 158{ 159 switch (size) { 160 case 16: 161 return __crypto_memneq_16(a, b); 162 default: 163 return __crypto_memneq_generic(a, b, size); 164 } 165} 166EXPORT_SYMBOL(__crypto_memneq); 167 168#endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */ 169