Back to home page

LXR

 
 

    


0001 /*
0002  * Constant-time equality testing of memory regions.
0003  *
0004  * Authors:
0005  *
0006  *   James Yonan <james@openvpn.net>
0007  *   Daniel Borkmann <dborkman@redhat.com>
0008  *
0009  * This file is provided under a dual BSD/GPLv2 license.  When using or
0010  * redistributing this file, you may do so under either license.
0011  *
0012  * GPL LICENSE SUMMARY
0013  *
0014  * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
0015  *
0016  * This program is free software; you can redistribute it and/or modify
0017  * it under the terms of version 2 of the GNU General Public License as
0018  * published by the Free Software Foundation.
0019  *
0020  * This program is distributed in the hope that it will be useful, but
0021  * WITHOUT ANY WARRANTY; without even the implied warranty of
0022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0023  * General Public License for more details.
0024  *
0025  * You should have received a copy of the GNU General Public License
0026  * along with this program; if not, write to the Free Software
0027  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
0028  * The full GNU General Public License is included in this distribution
0029  * in the file called LICENSE.GPL.
0030  *
0031  * BSD LICENSE
0032  *
0033  * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
0034  *
0035  * Redistribution and use in source and binary forms, with or without
0036  * modification, are permitted provided that the following conditions
0037  * are met:
0038  *
0039  *   * Redistributions of source code must retain the above copyright
0040  *     notice, this list of conditions and the following disclaimer.
0041  *   * Redistributions in binary form must reproduce the above copyright
0042  *     notice, this list of conditions and the following disclaimer in
0043  *     the documentation and/or other materials provided with the
0044  *     distribution.
0045  *   * Neither the name of OpenVPN Technologies nor the names of its
0046  *     contributors may be used to endorse or promote products derived
0047  *     from this software without specific prior written permission.
0048  *
0049  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0050  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0051  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0052  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0053  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0054  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0055  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0056  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0057  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0058  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0059  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0060  */
0061 
0062 #include <crypto/algapi.h>
0063 
0064 #ifndef __HAVE_ARCH_CRYPTO_MEMNEQ
0065 
0066 /* Generic path for arbitrary size */
0067 static inline unsigned long
0068 __crypto_memneq_generic(const void *a, const void *b, size_t size)
0069 {
0070     unsigned long neq = 0;
0071 
0072 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
0073     while (size >= sizeof(unsigned long)) {
0074         neq |= *(unsigned long *)a ^ *(unsigned long *)b;
0075         OPTIMIZER_HIDE_VAR(neq);
0076         a += sizeof(unsigned long);
0077         b += sizeof(unsigned long);
0078         size -= sizeof(unsigned long);
0079     }
0080 #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
0081     while (size > 0) {
0082         neq |= *(unsigned char *)a ^ *(unsigned char *)b;
0083         OPTIMIZER_HIDE_VAR(neq);
0084         a += 1;
0085         b += 1;
0086         size -= 1;
0087     }
0088     return neq;
0089 }
0090 
0091 /* Loop-free fast-path for frequently used 16-byte size */
0092 static inline unsigned long __crypto_memneq_16(const void *a, const void *b)
0093 {
0094     unsigned long neq = 0;
0095 
0096 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
0097     if (sizeof(unsigned long) == 8) {
0098         neq |= *(unsigned long *)(a)   ^ *(unsigned long *)(b);
0099         OPTIMIZER_HIDE_VAR(neq);
0100         neq |= *(unsigned long *)(a+8) ^ *(unsigned long *)(b+8);
0101         OPTIMIZER_HIDE_VAR(neq);
0102     } else if (sizeof(unsigned int) == 4) {
0103         neq |= *(unsigned int *)(a)    ^ *(unsigned int *)(b);
0104         OPTIMIZER_HIDE_VAR(neq);
0105         neq |= *(unsigned int *)(a+4)  ^ *(unsigned int *)(b+4);
0106         OPTIMIZER_HIDE_VAR(neq);
0107         neq |= *(unsigned int *)(a+8)  ^ *(unsigned int *)(b+8);
0108         OPTIMIZER_HIDE_VAR(neq);
0109         neq |= *(unsigned int *)(a+12) ^ *(unsigned int *)(b+12);
0110         OPTIMIZER_HIDE_VAR(neq);
0111     } else
0112 #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
0113     {
0114         neq |= *(unsigned char *)(a)    ^ *(unsigned char *)(b);
0115         OPTIMIZER_HIDE_VAR(neq);
0116         neq |= *(unsigned char *)(a+1)  ^ *(unsigned char *)(b+1);
0117         OPTIMIZER_HIDE_VAR(neq);
0118         neq |= *(unsigned char *)(a+2)  ^ *(unsigned char *)(b+2);
0119         OPTIMIZER_HIDE_VAR(neq);
0120         neq |= *(unsigned char *)(a+3)  ^ *(unsigned char *)(b+3);
0121         OPTIMIZER_HIDE_VAR(neq);
0122         neq |= *(unsigned char *)(a+4)  ^ *(unsigned char *)(b+4);
0123         OPTIMIZER_HIDE_VAR(neq);
0124         neq |= *(unsigned char *)(a+5)  ^ *(unsigned char *)(b+5);
0125         OPTIMIZER_HIDE_VAR(neq);
0126         neq |= *(unsigned char *)(a+6)  ^ *(unsigned char *)(b+6);
0127         OPTIMIZER_HIDE_VAR(neq);
0128         neq |= *(unsigned char *)(a+7)  ^ *(unsigned char *)(b+7);
0129         OPTIMIZER_HIDE_VAR(neq);
0130         neq |= *(unsigned char *)(a+8)  ^ *(unsigned char *)(b+8);
0131         OPTIMIZER_HIDE_VAR(neq);
0132         neq |= *(unsigned char *)(a+9)  ^ *(unsigned char *)(b+9);
0133         OPTIMIZER_HIDE_VAR(neq);
0134         neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10);
0135         OPTIMIZER_HIDE_VAR(neq);
0136         neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11);
0137         OPTIMIZER_HIDE_VAR(neq);
0138         neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12);
0139         OPTIMIZER_HIDE_VAR(neq);
0140         neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13);
0141         OPTIMIZER_HIDE_VAR(neq);
0142         neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14);
0143         OPTIMIZER_HIDE_VAR(neq);
0144         neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15);
0145         OPTIMIZER_HIDE_VAR(neq);
0146     }
0147 
0148     return neq;
0149 }
0150 
0151 /* Compare two areas of memory without leaking timing information,
0152  * and with special optimizations for common sizes.  Users should
0153  * not call this function directly, but should instead use
0154  * crypto_memneq defined in crypto/algapi.h.
0155  */
0156 noinline unsigned long __crypto_memneq(const void *a, const void *b,
0157                        size_t size)
0158 {
0159     switch (size) {
0160     case 16:
0161         return __crypto_memneq_16(a, b);
0162     default:
0163         return __crypto_memneq_generic(a, b, size);
0164     }
0165 }
0166 EXPORT_SYMBOL(__crypto_memneq);
0167 
0168 #endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */