/*1* Constant-time equality testing of memory regions.2*3* Authors:4*5* James Yonan <[email protected]>6* Daniel Borkmann <[email protected]>7*8* This file is provided under a dual BSD/GPLv2 license. When using or9* redistributing this file, you may do so under either license.10*11* GPL LICENSE SUMMARY12*13* Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.14*15* This program is free software; you can redistribute it and/or modify16* it under the terms of version 2 of the GNU General Public License as17* published by the Free Software Foundation.18*19* This program is distributed in the hope that it will be useful, but20* WITHOUT ANY WARRANTY; without even the implied warranty of21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU22* General Public License for more details.23*24* You should have received a copy of the GNU General Public License25* along with this program; if not, write to the Free Software26* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.27* The full GNU General Public License is included in this distribution28* in the file called LICENSE.GPL.29*30* BSD LICENSE31*32* Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.33*34* Redistribution and use in source and binary forms, with or without35* modification, are permitted provided that the following conditions36* are met:37*38* * Redistributions of source code must retain the above copyright39* notice, this list of conditions and the following disclaimer.40* * Redistributions in binary form must reproduce the above copyright41* notice, this list of conditions and the following disclaimer in42* the documentation and/or other materials provided with the43* distribution.44* * Neither the name of OpenVPN Technologies nor the names of its45* contributors may be used to endorse or promote products derived46* from this software without specific prior written permission.47*48* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS49* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT50* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR51* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT52* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,53* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT54* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,55* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY56* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT57* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE58* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.59*/6061#include <crypto/algapi.h>62#include <linux/export.h>63#include <linux/module.h>64#include <linux/unaligned.h>6566/* Generic path for arbitrary size */67static inline unsigned long68__crypto_memneq_generic(const void *a, const void *b, size_t size)69{70unsigned long neq = 0;7172#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)73while (size >= sizeof(unsigned long)) {74neq |= get_unaligned((unsigned long *)a) ^75get_unaligned((unsigned long *)b);76OPTIMIZER_HIDE_VAR(neq);77a += sizeof(unsigned long);78b += sizeof(unsigned long);79size -= sizeof(unsigned long);80}81#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */82while (size > 0) {83neq |= *(unsigned char *)a ^ *(unsigned char *)b;84OPTIMIZER_HIDE_VAR(neq);85a += 1;86b += 1;87size -= 1;88}89return neq;90}9192/* Loop-free fast-path for frequently used 16-byte size */93static inline unsigned long __crypto_memneq_16(const void *a, const void *b)94{95unsigned long neq = 0;9697#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS98if (sizeof(unsigned long) == 8) {99neq |= get_unaligned((unsigned long *)a) ^100get_unaligned((unsigned long *)b);101OPTIMIZER_HIDE_VAR(neq);102neq |= get_unaligned((unsigned long *)(a + 8)) ^103get_unaligned((unsigned long *)(b + 8));104OPTIMIZER_HIDE_VAR(neq);105} else if (sizeof(unsigned int) == 4) {106neq |= get_unaligned((unsigned int *)a) ^107get_unaligned((unsigned int *)b);108OPTIMIZER_HIDE_VAR(neq);109neq |= get_unaligned((unsigned int *)(a + 4)) ^110get_unaligned((unsigned int *)(b + 4));111OPTIMIZER_HIDE_VAR(neq);112neq |= get_unaligned((unsigned int *)(a + 8)) ^113get_unaligned((unsigned int *)(b + 8));114OPTIMIZER_HIDE_VAR(neq);115neq |= get_unaligned((unsigned int *)(a + 12)) ^116get_unaligned((unsigned int *)(b + 12));117OPTIMIZER_HIDE_VAR(neq);118} else119#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */120{121neq |= *(unsigned char *)(a) ^ *(unsigned char *)(b);122OPTIMIZER_HIDE_VAR(neq);123neq |= *(unsigned char *)(a+1) ^ *(unsigned char *)(b+1);124OPTIMIZER_HIDE_VAR(neq);125neq |= *(unsigned char *)(a+2) ^ *(unsigned char *)(b+2);126OPTIMIZER_HIDE_VAR(neq);127neq |= *(unsigned char *)(a+3) ^ *(unsigned char *)(b+3);128OPTIMIZER_HIDE_VAR(neq);129neq |= *(unsigned char *)(a+4) ^ *(unsigned char *)(b+4);130OPTIMIZER_HIDE_VAR(neq);131neq |= *(unsigned char *)(a+5) ^ *(unsigned char *)(b+5);132OPTIMIZER_HIDE_VAR(neq);133neq |= *(unsigned char *)(a+6) ^ *(unsigned char *)(b+6);134OPTIMIZER_HIDE_VAR(neq);135neq |= *(unsigned char *)(a+7) ^ *(unsigned char *)(b+7);136OPTIMIZER_HIDE_VAR(neq);137neq |= *(unsigned char *)(a+8) ^ *(unsigned char *)(b+8);138OPTIMIZER_HIDE_VAR(neq);139neq |= *(unsigned char *)(a+9) ^ *(unsigned char *)(b+9);140OPTIMIZER_HIDE_VAR(neq);141neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10);142OPTIMIZER_HIDE_VAR(neq);143neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11);144OPTIMIZER_HIDE_VAR(neq);145neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12);146OPTIMIZER_HIDE_VAR(neq);147neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13);148OPTIMIZER_HIDE_VAR(neq);149neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14);150OPTIMIZER_HIDE_VAR(neq);151neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15);152OPTIMIZER_HIDE_VAR(neq);153}154155return neq;156}157158/* Compare two areas of memory without leaking timing information,159* and with special optimizations for common sizes. Users should160* not call this function directly, but should instead use161* crypto_memneq defined in crypto/algapi.h.162*/163noinline unsigned long __crypto_memneq(const void *a, const void *b,164size_t size)165{166switch (size) {167case 16:168return __crypto_memneq_16(a, b);169default:170return __crypto_memneq_generic(a, b, size);171}172}173EXPORT_SYMBOL(__crypto_memneq);174175176