LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

FIT(3):基于FIT对镜像进行加密和解密

mkimage根据its配置对镜像进行加密,uboot解析FIT对加密部分进行解密,完成镜像内容保护。

1 生成FIT加密镜像

通过openssl rand生成32字节二进制秘钥文件:

openssl rand -out aes-key.bin 32

修改kernel.its文件,增加cipher节点:

/ {
  images {
    kernel {
      cipher {
        algo = "aes256";--使用aes256作为加解密算法。
        key-name-hint = "aes-key";--会到-k <key dir>指定的目录中找名称为aes-key的秘钥文件作为输入秘钥。
      };
    };
  };
};

mkimage根据its配置生成fit镜像,对镜像文件进行加密:

mkimage -k <key dir> -f kernel.its kernel.itb -K pub-key.dtb -r

生成的kernel.itb文件如下:

  • data值是经过加密的数据。
  • 新增IV值。
  • algo指定解密算法。
  • key-name-hint指定秘钥名称,从uboot dtb中获取秘钥。
/ {
  images {
    kernel {
      data-size-unsiphered = <...>;
      data = <...>;       cipher {
        iv = <...>;         algo
= "aes256";         key-name-hint = "aes-key";       };     };   }; };

生成的pub-key.dtb中包含的aes-key秘钥:

/ {
  cipher {
    key-aes256-aes-key {--根据kernel.itb中cipher的algo和key-name-hint配置可以匹配到对应的秘钥。
      key-len = <0x20>;
      key = <...>;
    };
  };
};

将上述cipher节点拷贝到uboot dtb的根节点下,uboot启动时,从dtb中获取秘钥。

2 uboot支持FIT解密

2.1 配置uboot支持FIT中加解密功能

打开CONFIG_FIT_CIPHER支持加解密功能:

Boot options
  Boot images
    Enable ciphering data in a FIT uImages

由于解密会通过malloc()分配内存,可以修改CONFIG_SYS_MALLOC_LEN增加内存容量。

2.2 uboot对FIT解密流程

当内核支持CONFIG_FIT_CIPHER后,如果FIT中存在cipher节点则会启动解密流程:

fit_image_load
  fit_image_uncipher
    fdt_subnode_offset--找到FIT中cipher节点。
    fit_image_decrypt_data
      fit_image_setup_decrypt
        fit_get_name
        fit_image_cipher_get_algo--获取cipher节点中加解密算法algo的值。
        fdt_getprop--获取key-name-hint、iv、iv-name-hint的值。
        image_get_cipher_algo--根据算法名称获取对应的struct cipher_algo。
        fdt_getprop--根据keyname和ivname读取kery和iv的值。
      info.cipher->decrypt--比如aes256算法,对应的函数是image_aes_decrypt。

支持的加解密算法如下:

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
        }
};

image_aes_decrypt使用AES CBC(128/192/256)算法对数据进行解密,需要的参数包括:源加密数据地址、源加密数据大小、从FIT中获取的解密算法/秘钥/IV,获取的参数包括解密数据地址和解密数据大小。

image_aes_decrypt
  aes_expand_key
  DIV_ROUND_UP--根据cipher_len对齐到128 bit block。
  aes_cbc_decrypt_blocks--按照block为单位解密。

 

posted on 2025-05-10 23:59  ArnoldLu  阅读(211)  评论(0)    收藏  举报

导航