| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright (c) 2019, Softathome |
| */ |
| |
| #ifdef USE_HOSTCC |
| #include "mkimage.h" |
| #include <time.h> |
| #else |
| #include <malloc.h> |
| #include <asm/global_data.h> |
| DECLARE_GLOBAL_DATA_PTR; |
| #endif /* !USE_HOSdTCC*/ |
| #include <image.h> |
| #include <uboot_aes.h> |
| #include <u-boot/aes.h> |
| |
| struct cipher_algo cipher_algos[] = { |
| { |
| .name = "aes128", |
| .key_len = AES128_KEY_LENGTH, |
| .iv_len = AES_BLOCK_LENGTH, |
| #if IMAGE_ENABLE_ENCRYPT |
| .calculate_type = EVP_aes_128_cbc, |
| #endif |
| .encrypt = image_aes_encrypt, |
| .decrypt = image_aes_decrypt, |
| .add_cipher_data = image_aes_add_cipher_data |
| }, |
| { |
| .name = "aes192", |
| .key_len = AES192_KEY_LENGTH, |
| .iv_len = AES_BLOCK_LENGTH, |
| #if IMAGE_ENABLE_ENCRYPT |
| .calculate_type = EVP_aes_192_cbc, |
| #endif |
| .encrypt = image_aes_encrypt, |
| .decrypt = image_aes_decrypt, |
| .add_cipher_data = image_aes_add_cipher_data |
| }, |
| { |
| .name = "aes256", |
| .key_len = AES256_KEY_LENGTH, |
| .iv_len = AES_BLOCK_LENGTH, |
| #if IMAGE_ENABLE_ENCRYPT |
| .calculate_type = EVP_aes_256_cbc, |
| #endif |
| .encrypt = image_aes_encrypt, |
| .decrypt = image_aes_decrypt, |
| .add_cipher_data = image_aes_add_cipher_data |
| } |
| }; |
| |
| struct cipher_algo *image_get_cipher_algo(const char *full_name) |
| { |
| int i; |
| const char *name; |
| |
| for (i = 0; i < ARRAY_SIZE(cipher_algos); i++) { |
| name = cipher_algos[i].name; |
| if (!strncmp(name, full_name, strlen(name))) |
| return &cipher_algos[i]; |
| } |
| |
| return NULL; |
| } |
| |
| static int fit_image_setup_decrypt(struct image_cipher_info *info, |
| const void *fit, int image_noffset, |
| int cipher_noffset) |
| { |
| const void *fdt = gd_fdt_blob(); |
| const char *node_name; |
| char node_path[128]; |
| int noffset; |
| char *algo_name; |
| int ret; |
| |
| node_name = fit_get_name(fit, image_noffset, NULL); |
| if (!node_name) { |
| printf("Can't get node name\n"); |
| return -1; |
| } |
| |
| if (fit_image_cipher_get_algo(fit, cipher_noffset, &algo_name)) { |
| printf("Can't get algo name for cipher '%s' in image '%s'\n", |
| node_name, node_name); |
| return -1; |
| } |
| |
| info->keyname = fdt_getprop(fit, cipher_noffset, FIT_KEY_HINT, NULL); |
| if (!info->keyname) { |
| printf("Can't get key name\n"); |
| return -1; |
| } |
| |
| info->iv = fdt_getprop(fit, cipher_noffset, "iv", NULL); |
| info->ivname = fdt_getprop(fit, cipher_noffset, "iv-name-hint", NULL); |
| |
| if (!info->iv && !info->ivname) { |
| printf("Can't get IV or IV name\n"); |
| return -1; |
| } |
| |
| info->fit = fit; |
| info->node_noffset = image_noffset; |
| info->name = algo_name; |
| info->cipher = image_get_cipher_algo(algo_name); |
| if (!info->cipher) { |
| printf("Can't get cipher\n"); |
| return -1; |
| } |
| |
| ret = fit_image_get_data_size_unciphered(fit, image_noffset, |
| &info->size_unciphered); |
| if (ret) { |
| printf("Can't get size of unciphered data\n"); |
| return -1; |
| } |
| |
| /* |
| * Search the cipher node in the u-boot fdt |
| * the path should be: /cipher/key-<algo>-<key>-<iv> |
| */ |
| if (info->ivname) |
| snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s-%s", |
| FIT_CIPHER_NODENAME, algo_name, info->keyname, info->ivname); |
| else |
| snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s", |
| FIT_CIPHER_NODENAME, algo_name, info->keyname); |
| |
| noffset = fdt_path_offset(fdt, node_path); |
| if (noffset < 0) { |
| printf("Can't found cipher node offset\n"); |
| return -1; |
| } |
| |
| /* read key */ |
| info->key = fdt_getprop(fdt, noffset, "key", NULL); |
| if (!info->key) { |
| printf("Can't get key in cipher node '%s'\n", node_path); |
| return -1; |
| } |
| |
| /* read iv */ |
| if (!info->iv) { |
| info->iv = fdt_getprop(fdt, noffset, "iv", NULL); |
| if (!info->iv) { |
| printf("Can't get IV in cipher node '%s'\n", node_path); |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int fit_image_decrypt_data(const void *fit, |
| int image_noffset, int cipher_noffset, |
| const void *data_ciphered, size_t size_ciphered, |
| void **data_unciphered, size_t *size_unciphered) |
| { |
| struct image_cipher_info info; |
| int ret; |
| |
| ret = fit_image_setup_decrypt(&info, fit, image_noffset, |
| cipher_noffset); |
| if (ret < 0) |
| goto out; |
| |
| ret = info.cipher->decrypt(&info, data_ciphered, size_ciphered, |
| data_unciphered, size_unciphered); |
| |
| out: |
| return ret; |
| } |