Back to home page

OSCL-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 #include <asm/unaligned.h>
0064 
0065 #ifndef __HAVE_ARCH_CRYPTO_MEMNEQ
0066 
0067 /* Generic path for arbitrary size */
0068 static inline unsigned long
0069 __crypto_memneq_generic(const void *a, const void *b, size_t size)
0070 {
0071     unsigned long neq = 0;
0072 
0073 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
0074     while (size >= sizeof(unsigned long)) {
0075         neq |= get_unaligned((unsigned long *)a) ^
0076                get_unaligned((unsigned long *)b);
0077         OPTIMIZER_HIDE_VAR(neq);
0078         a += sizeof(unsigned long);
0079         b += sizeof(unsigned long);
0080         size -= sizeof(unsigned long);
0081     }
0082 #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
0083     while (size > 0) {
0084         neq |= *(unsigned char *)a ^ *(unsigned char *)b;
0085         OPTIMIZER_HIDE_VAR(neq);
0086         a += 1;
0087         b += 1;
0088         size -= 1;
0089     }
0090     return neq;
0091 }
0092 
0093 /* Loop-free fast-path for frequently used 16-byte size */
0094 static inline unsigned long __crypto_memneq_16(const void *a, const void *b)
0095 {
0096     unsigned long neq = 0;
0097 
0098 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
0099     if (sizeof(unsigned long) == 8) {
0100         neq |= get_unaligned((unsigned long *)a) ^
0101                get_unaligned((unsigned long *)b);
0102         OPTIMIZER_HIDE_VAR(neq);
0103         neq |= get_unaligned((unsigned long *)(a + 8)) ^
0104                get_unaligned((unsigned long *)(b + 8));
0105         OPTIMIZER_HIDE_VAR(neq);
0106     } else if (sizeof(unsigned int) == 4) {
0107         neq |= get_unaligned((unsigned int *)a) ^
0108                get_unaligned((unsigned int *)b);
0109         OPTIMIZER_HIDE_VAR(neq);
0110         neq |= get_unaligned((unsigned int *)(a + 4)) ^
0111                get_unaligned((unsigned int *)(b + 4));
0112         OPTIMIZER_HIDE_VAR(neq);
0113         neq |= get_unaligned((unsigned int *)(a + 8)) ^
0114                get_unaligned((unsigned int *)(b + 8));
0115         OPTIMIZER_HIDE_VAR(neq);
0116         neq |= get_unaligned((unsigned int *)(a + 12)) ^
0117                get_unaligned((unsigned int *)(b + 12));
0118         OPTIMIZER_HIDE_VAR(neq);
0119     } else
0120 #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
0121     {
0122         neq |= *(unsigned char *)(a)    ^ *(unsigned char *)(b);
0123         OPTIMIZER_HIDE_VAR(neq);
0124         neq |= *(unsigned char *)(a+1)  ^ *(unsigned char *)(b+1);
0125         OPTIMIZER_HIDE_VAR(neq);
0126         neq |= *(unsigned char *)(a+2)  ^ *(unsigned char *)(b+2);
0127         OPTIMIZER_HIDE_VAR(neq);
0128         neq |= *(unsigned char *)(a+3)  ^ *(unsigned char *)(b+3);
0129         OPTIMIZER_HIDE_VAR(neq);
0130         neq |= *(unsigned char *)(a+4)  ^ *(unsigned char *)(b+4);
0131         OPTIMIZER_HIDE_VAR(neq);
0132         neq |= *(unsigned char *)(a+5)  ^ *(unsigned char *)(b+5);
0133         OPTIMIZER_HIDE_VAR(neq);
0134         neq |= *(unsigned char *)(a+6)  ^ *(unsigned char *)(b+6);
0135         OPTIMIZER_HIDE_VAR(neq);
0136         neq |= *(unsigned char *)(a+7)  ^ *(unsigned char *)(b+7);
0137         OPTIMIZER_HIDE_VAR(neq);
0138         neq |= *(unsigned char *)(a+8)  ^ *(unsigned char *)(b+8);
0139         OPTIMIZER_HIDE_VAR(neq);
0140         neq |= *(unsigned char *)(a+9)  ^ *(unsigned char *)(b+9);
0141         OPTIMIZER_HIDE_VAR(neq);
0142         neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10);
0143         OPTIMIZER_HIDE_VAR(neq);
0144         neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11);
0145         OPTIMIZER_HIDE_VAR(neq);
0146         neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12);
0147         OPTIMIZER_HIDE_VAR(neq);
0148         neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13);
0149         OPTIMIZER_HIDE_VAR(neq);
0150         neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14);
0151         OPTIMIZER_HIDE_VAR(neq);
0152         neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15);
0153         OPTIMIZER_HIDE_VAR(neq);
0154     }
0155 
0156     return neq;
0157 }
0158 
0159 /* Compare two areas of memory without leaking timing information,
0160  * and with special optimizations for common sizes.  Users should
0161  * not call this function directly, but should instead use
0162  * crypto_memneq defined in crypto/algapi.h.
0163  */
0164 noinline unsigned long __crypto_memneq(const void *a, const void *b,
0165                        size_t size)
0166 {
0167     switch (size) {
0168     case 16:
0169         return __crypto_memneq_16(a, b);
0170     default:
0171         return __crypto_memneq_generic(a, b, size);
0172     }
0173 }
0174 EXPORT_SYMBOL(__crypto_memneq);
0175 
0176 #endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */