blob: 53c8c36b22ea4954c4a8841adc1483e479c0fb03 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/crypto/impl/aes_gcm/aes_gcm.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/tests/crypto/aes_gcm_testutils.h"
#include "sw/device/tests/crypto/aes_gcm_testvectors.h"
/**
* Checks that decryption takes the same number of cycles regardless of tag.
*
* This test ensures that the AES-GCM tag check takes the exact same amount of
* time for all *incorrect* tags; if it didn't, for instance exiting early at
* the first incorrect byte, then an attacker could guess one byte at a time
* and observe the timing to see if the byte was correct.
*
* It's OK if decryption takes a different amount of time with a correct tag
* than with an incorrect one.
*
* @param test Test vector to use
*/
static void test_decrypt_timing(aes_gcm_test_t test) {
// Call AES-GCM decrypt with an incorrect tag (first word wrong).
test.tag[0]++;
uint32_t cycles_invalid1 = call_aes_gcm_decrypt(test, /*tag_valid=*/false);
test.tag[0]--;
// Call AES-GCM decrypt with an incorrect tag (middle word wrong).
test.tag[kAesGcmTagNumWords / 2]++;
uint32_t cycles_invalid2 = call_aes_gcm_decrypt(test, /*tag_valid=*/false);
test.tag[kAesGcmTagNumWords / 2]--;
// Call AES-GCM decrypt with an incorrect tag (last word wrong).
test.tag[kAesGcmTagNumWords - 1]++;
uint32_t cycles_invalid3 = call_aes_gcm_decrypt(test, /*tag_valid=*/false);
test.tag[kAesGcmTagNumWords - 1]--;
// Check that the cycle counts for the invalid tags match.
CHECK(cycles_invalid1 == cycles_invalid2,
"AES-GCM decryption was not constant-time for different invalid tags");
CHECK(cycles_invalid2 == cycles_invalid3,
"AES-GCM decryption was not constant-time for different invalid tags");
}
OTTF_DEFINE_TEST_CONFIG();
bool test_main(void) {
for (size_t i = 0; i < ARRAYSIZE(kAesGcmTestvectors); i++) {
LOG_INFO("Starting AES-GCM timing test %d of %d...", i + 1,
ARRAYSIZE(kAesGcmTestvectors));
test_decrypt_timing(kAesGcmTestvectors[i]);
LOG_INFO("Finished AES-GCM timing test %d.", i + 1);
}
return true;
}