/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2025 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see .
*/
#include
#include
#include
#include
#include "crypto_cipher_mode_vectors.h"
GRUB_MOD_LICENSE ("GPLv3+");
/* Perform cipher lookup, handle init, and key setting. */
static grub_crypto_cipher_handle_t
handle_init (struct vector vec, grub_crypto_cipher_handle_t handle)
{
gcry_err_code_t err;
const gcry_cipher_spec_t *cipher = grub_crypto_lookup_cipher_by_name (vec.cipher);
grub_test_assert (cipher != NULL, "\n%s: cipher lookup failed for %s", vec.mode, vec.cipher);
if (cipher == NULL)
return NULL;
handle = grub_crypto_cipher_open (cipher);
grub_test_assert (handle != NULL, "\n%s: handle init failed for %s", vec.mode, vec.cipher);
if (handle == NULL)
return NULL;
err = grub_crypto_cipher_set_key (handle, (grub_uint8_t *) vec.key, vec.keylen);
grub_test_assert (err == GPG_ERR_NO_ERROR, "\n%s: key set of size %d failed for %s with err = %d",
vec.mode, vec.keylen, vec.cipher, err);
if (err != GPG_ERR_NO_ERROR)
{
grub_crypto_cipher_close (handle);
return NULL;
}
return handle;
}
static void
ecb_test (struct vector vec)
{
gcry_err_code_t gcry_err;
grub_crypto_cipher_handle_t handle = NULL;
grub_uint8_t *plaintext = NULL, *ciphertext = NULL;
grub_int32_t rc;
handle = handle_init (vec, handle);
if (handle == NULL)
return;
/* Test encryption. */
ciphertext = grub_zalloc (vec.plen);
grub_test_assert (ciphertext != NULL, "\necb: ciphertext buffer allocation failed");
if (ciphertext == NULL)
goto out_handle;
gcry_err = grub_crypto_ecb_encrypt (handle, ciphertext, vec.ptext, vec.plen);
grub_test_assert (gcry_err == GPG_ERR_NO_ERROR, "\necb: encryption failed with err = %d",
gcry_err);
if (gcry_err != GPG_ERR_NO_ERROR)
goto out_ct;
rc = grub_memcmp (ciphertext, vec.ctext, vec.plen);
grub_test_assert (rc == 0, "\necb: ciphertext mismatch after encryption");
if (rc != 0)
goto out_ct;
/* Test decryption. */
plaintext = grub_zalloc (vec.plen);
grub_test_assert (plaintext != NULL, "\necb: plaintext buffer allocation failed");
if (plaintext == NULL)
goto out_ct;
gcry_err = grub_crypto_ecb_decrypt (handle, plaintext, ciphertext, vec.plen);
grub_test_assert (gcry_err == GPG_ERR_NO_ERROR, "\necb: decryption failed failed with err = %d",
gcry_err);
if (gcry_err != GPG_ERR_NO_ERROR)
goto out_pt;
rc = grub_memcmp (plaintext, vec.ptext, vec.plen);
grub_test_assert (rc == 0, "\necb: plaintext mismatch after decryption");
out_pt:
grub_free(plaintext);
out_ct:
grub_free(ciphertext);
out_handle:
grub_crypto_cipher_close(handle);
}
static void
cbc_test (struct vector vec)
{
gcry_err_code_t gcry_err;
grub_crypto_cipher_handle_t handle = NULL;
grub_uint8_t *plaintext = NULL, *ciphertext = NULL;
grub_uint32_t *iv = NULL;
grub_int32_t rc;
handle = handle_init (vec, handle);
if (handle == NULL)
return;
/* Test Encryption */
iv = grub_malloc(vec.ivlen);
grub_test_assert (iv != NULL, "\ncbc: IV buffer allocation failed");
if (iv == NULL)
goto out_handle;
grub_memcpy (iv, vec.iv_in, vec.ivlen);
ciphertext = grub_zalloc (vec.plen);
grub_test_assert (ciphertext != NULL, "\ncbc: ciphertext buffer allocation failed");
if (ciphertext == NULL)
goto out_iv;
gcry_err = grub_crypto_cbc_encrypt (handle, ciphertext, vec.ptext, vec.plen, iv);
grub_test_assert (gcry_err == GPG_ERR_NO_ERROR, "\ncbc: encryption failed with err = %d",
gcry_err);
if (gcry_err != GPG_ERR_NO_ERROR)
goto out_ct;
rc = grub_memcmp (ciphertext, vec.ctext, vec.plen);
grub_test_assert (rc == 0, "\ncbc: ciphertext mismatch after encryption");
if (rc != 0)
goto out_ct;
rc = grub_memcmp (iv, vec.iv_out, vec.ivlen);
grub_test_assert (rc == 0, "\ncbc: IV out mismatch after encryption");
if (rc != 0)
goto out_ct;
/* Test Decryption */
grub_memcpy (iv, vec.iv_in, vec.ivlen);
plaintext = grub_zalloc (vec.plen);
grub_test_assert (plaintext != NULL, "\ncbc: plaintext buffer allocation failed");
if (plaintext == NULL)
goto out_ct;
gcry_err = grub_crypto_cbc_decrypt (handle, plaintext, ciphertext, vec.plen, iv);
grub_test_assert (gcry_err == GPG_ERR_NO_ERROR, "\ncbc: decryption failed with err = %d",
gcry_err);
if (gcry_err != GPG_ERR_NO_ERROR)
goto out_pt;
rc = grub_memcmp (plaintext, vec.ptext, vec.plen);
grub_test_assert (rc == 0, "\ncbc: plaintext mismatch after decryption");
out_pt:
grub_free(plaintext);
out_ct:
grub_free(ciphertext);
out_iv:
grub_free(iv);
out_handle:
grub_crypto_cipher_close(handle);
}
static void
crypto_cipher_mode_test (void)
{
grub_size_t i;
for (i = 0; i < ARRAY_SIZE (vecs); i++)
{
if (grub_strcmp (vecs[i].mode, "ecb") == 0)
ecb_test(vecs[i]);
else if (grub_strcmp (vecs[i].mode, "cbc") == 0)
cbc_test(vecs[i]);
else
{
grub_test_assert(0, "\n%s mode unsupported for testing", vecs[i].mode);
return;
}
}
}
/* Register example_test method as a functional test. */
GRUB_FUNCTIONAL_TEST (crypto_cipher_mode_test, crypto_cipher_mode_test);