/* Copyright 2016 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "dcrypto.h" /** * CRYPTO_FAST_COMPARE = 1 will enable machine word reads if performance * is important, but will increase code size by ~100 bytes. */ #define CRYPTO_FAST_COMPARE 0 /* Constant time, hardened comparator. */ enum dcrypto_result __attribute__((optimize("-O1"))) DCRYPTO_equals( const void *a, const void *b, size_t len) { uintptr_t a_addr = (uintptr_t)a; uintptr_t b_addr = (uintptr_t)b; uintptr_t tail = a_addr + len; uintptr_t tail_copy = value_barrier(tail); uintptr_t diff = 0; #if CRYPTO_FAST_COMPARE /* Set 'body' to the last word boundary. */ uintptr_t body = tail & ~WORD_MASK; /* End of head is the tail if data is not aligned. */ uintptr_t head = tail; /* Compute starting address if src and dest can be aligned. */ if (((a_addr & WORD_MASK) == (b_addr & WORD_MASK)) && (len >= sizeof(uintptr_t))) /* Set 'head' to the first word boundary. */ head = ((a_addr + WORD_MASK) & ~WORD_MASK); /* Process misaligned head. */ while (a_addr < head) { diff |= *((volatile uint8_t *)a_addr) ^ *((volatile uint8_t *)b_addr); a_addr++; b_addr++; } /* Process aligned body (if any). */ while (a_addr < body) { diff |= *((volatile uintptr_t *)a_addr) ^ *((volatile uintptr_t *)b_addr); a_addr += sizeof(uintptr_t); b_addr += sizeof(uintptr_t); } #endif /* Process remaining part. Also serves as fault resistance. */ while (a_addr < tail) { diff |= *((volatile uint8_t *)a_addr) ^ *((volatile uint8_t *)b_addr); a_addr++; b_addr++; } /** * b_addr = src2 + len * tail, a_addr = src1 + len * (src2 + len) - (src1 + len) + src1 - src2 = 0 * Any other result of expression will result in wrong value. * Don't use 'src2_addr' as it is possible to make * b_addr == a_addr */ return dcrypto_ok_if_zero((value_barrier(b_addr) - tail_copy + (uintptr_t)a - (uintptr_t)b) | diff); }