avb签名流程

背景

  avb签名涉及到安卓系统启动的安全部分,作为系统开发或者系统架构师,需要理解avb的签名逻辑。
本篇意图为承接上篇的流程安卓构建自定义镜像
 介绍avb之前,先了解一下什么是数字签名。因为avb签名就是典型的数字签名

什么是数字签名

 数字签名(Digital Signature)也叫作数字指纹(Digital Fingerprint),它是消息摘要算法和非对称加密算法的结合体,能够验证数据的完整性,并且认证数据的来源。
数字签名算法的模型分为两个主要阶段:
1、签名: 先计算数据的 [摘要],再使用私钥对 [摘要] 进行加密生成 [签名],将 [数据 + 签名] 一并发送给接收方;
2、验证: 先使用相同的摘要算法计算接收数据的 [摘要],再使用预先得到的公钥解密 [签名],对比 [解密的签名] 和 [计算的摘要] 是否一致。若一致,则说明数据没有被篡改。

在这里插入图片描述

Image的签名验证示意图

在这里插入图片描述

avb是什么

  avb(android verified boot)是启动时验证,目前已经来到AVB2.0。

为什么使用avb

一句话概括,为了在安卓系统启动的时候验证各个分区的安全性和完整性

如何使用avb

 avb除了集成在build system中对image进行签名外,还提供了好用的工具avbtool。在目录external/avb/avbtool
 查看image签名信息:avbtool info_image --image xxxx.img
 关于如何解读工具查到的签名信息,待补充哦。TODO

avb签名流程

 签名流程开始于build_image.py中verity_image_builder.Build(out_file)。这里我们关注AVB2.0,verity_image_builder代表VerifiedBootVersion2VerityImageBuilder类

 签名流程概述

  1. 调用avbtool签名
  2. 计算摘要digest的大小
  3. 计算max_image_size,作为后续动态调整image大小的阈值
  4. 检查partition_size是否是Image的block_size的倍数
  5. 调整image size,以确保image size是block_size倍数。
  6. 创建salt
  7. 创建root_digest、hash_tree
  8. 创建AvbHashtreeDescriptor
  9. 将hash_tree加入目标image
  10. 创建VBMeta_blob数据
  11. VBMeta _blob加入到目标image
  12. 创建AvbFooter,加入到目标image

 签名流程详述

  1. 调用avbtool

调用avbtool的add_hash_footer()或add_hashtree_footer(),这里跟踪add_hashtree_footer()

# VerifiedBootVersion2VerityImageBuilder类
  def Build(self, out_file):
    add_footer = ("add_hash_footer" if self.footer_type == self.AVB_HASH_FOOTER else "add_hashtree_footer")
    cmd = [self.avbtool, add_footer, "--partition_size", str(self.partition_size),"--partition_name",self.partition_name,"--image", out_file]
    if self.key_path and self.algorithm:
      cmd.extend(["--key", self.key_path, "--algorithm", self.algorithm])
    if self.salt:
      cmd.extend(["--salt", self.salt])
    cmd.extend(shlex.split(self.signing_args))
    proc = common.Run(cmd)
# 最终执行cmd命令(举例)['out/host/linux-x86/bin/avbtool', 'add_hashtree_footer', '--partition_size', 'xxx', '--partition_name', 'xxx', '--image', 'xxx.img', '--key', 'xxx.pem', '--algorithm', 'SHA256_RSA4096', '--salt','xxx]
  1. 计算摘要digest的大小
def add_hashtree_footer(self, ........):
	digest_size = len(create_avb_hashtree_hasher(hash_algorithm, b'').digest())
  1. 计算max_image_size,作为后续动态调整image大小的阈值
    总的来说,Image的最大阈值,不能超过partition大小减去metadata大小。metadata大小由fec大小、hashtree大小、vbmeta大小、footer大小组成。前面计算的digest_size用于计算hashtree大小了。
	  MAX_VBMETA_SIZE = 64 * 1024
  	  MAX_FOOTER_SIZE = 4096
	  ..............
      if not no_hashtree:
        (_, max_tree_size) = calc_hash_level_offsets(partition_size, block_size, digest_size + digest_padding)
      ..............
      max_metadata_size = (max_fec_size + max_tree_size + self.MAX_VBMETA_SIZE + self.MAX_FOOTER_SIZE)
      max_image_size = partition_size - max_metadata_size
  1. 检查partition_size是否是Image的block_size的倍数
      if partition_size % image.block_size != 0:
        raise AvbError('Partition size of {} is not a multiple of the image ''block size {}.'.format(partition_size,image.block_size))
  1. 调整image size,以确保image size是block_size倍数。
	  # Ensure image is multiple of block_size.
      rounded_image_size = round_to_multiple(image.image_size, block_size)
  1. 创建salt
    如果salt参数传了,将二进制转换成十六进制。否则使用/dev/urandom设备生成伪随机数,作为salt
      if salt:
        salt = binascii.unhexlify(salt)
      elif salt is None and not use_persistent_root_digest:
        hash_size = digest_size
        with open('/dev/urandom', 'rb') as f:
          salt = f.read(hash_size)
      ..................
  1. 创建root_digest、hash_tree
    这里是重点,注意创建入参用到了image相关、hash算法、盐。说白了就是使用hash算法、盐等计算摘要、hash_tree。经典的数字签名流程之一。
root_digest, hash_tree = generate_hash_tree(image, image.image_size,block_size,hash_algorithm, salt,digest_padding,hash_level_offsets,tree_size)
  1. 创建AvbHashtreeDescriptor
    描述符包含dm_verity_version、hash_algorithm、salt、root_digest等关键信息。这些信息avbtool info_image命令可以查看
	  ht_desc = AvbHashtreeDescriptor()
      ht_desc.dm_verity_version = 1
      ...............
      ht_desc.hash_algorithm = hash_algorithm
      ht_desc.partition_name = partition_name
      ht_desc.salt = salt
      ...............
      if not use_persistent_root_digest:
        ht_desc.root_digest = root_digest
  1. 将hash_tree加入目标image
     hash_tree_with_padding = hash_tree + b'\0' * padding_needed
     image.append_raw(hash_tree_with_padding)
  1. 创建VBMeta_blob数据
    创建会用到算法名称、私钥、[AvbHashtreeDescriptor]数组等关键参数
vbmeta_blob = self._generate_vbmeta_blob(algorithm_name, key_path, public_key_metadata_path, [h_desc],
          chain_partitions, rollback_index, flags, rollback_index_location,props, props_from_file,
          kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,include_descriptors_from_image, 					  signing_helper,signing_helper_with_files, release_string,append_to_release_string, required_libavb_version_minor)

vbmeta_blob由header_data_blob、auth_data_blob、aux_data_blob 3个部分组成
header_data_blob,如其名存放头信息,比如descriptors偏移量、大小。公钥的偏移量、大小等等。
auth_data_blob,存放摘要、签名
aux_data_blob ,存放描述符、公钥

def _generate_vbmeta_blob(...):
	h = AvbVBMetaHeader()
	.........
    # 添加chained partition descriptors
    if chain_partitions:
      for cp in chain_partitions:
        .............
        desc = AvbChainPartitionDescriptor()
        desc.partition_name = partition_name
        .............
        with open(file_path, 'rb') as f:
          desc.public_key = f.read()
        descriptors.append(desc)
	# 将之前的入参[AvbHashtreeDescriptor]和ChainPartitionDescriptor加密存放起来。这信息后期可通过avbtool查看的
    encoded_descriptors = bytearray()
    for desc in descriptors:
      encoded_descriptors.extend(desc.encode())
    # 添加prop
    if props:
      for prop in props:
        .................
        desc = AvbPropertyDescriptor()
        .....................
        encoded_descriptors.extend(desc.encode())
    ..................
    if alg.public_key_num_bytes > 0:
      .................
      # 重点,公钥是从私钥那里取得的
      encoded_key = RSAPublicKey(key_path).encode()
      .................
    h.descriptors_size = len(encoded_descriptors)
    h.public_key_offset = h.descriptors_size
    h.public_key_size = len(encoded_key)
	......................
    header_data_blob = h.encode()
    # aux_data_blob存放vbmeta相关的描述符、公钥
	aux_data_blob = bytearray()
    aux_data_blob.extend(encoded_descriptors)
    aux_data_blob.extend(encoded_key)
    aux_data_blob.extend(pkmd_blob)
	.......................
	# auth_data_blob存放认证信息,摘要、签名
	binary_hash = b''
    binary_signature = b''
    if algorithm_name != 'NONE':
      ha = hashlib.new(alg.hash_name)
      ................
      binary_hash = ha.digest()
	  ................
      binary_signature = rsa_key.sign(algorithm_name, data_to_sign,signing_helper, signing_helper_with_files)
    auth_data_blob = bytearray()
    auth_data_blob.extend(binary_hash)
    auth_data_blob.extend(binary_signature)
	return header_data_blob + bytes(auth_data_blob) + bytes(aux_data_blob)
  1. VBMeta _blob加入到目标image
	  vbmeta_blob_with_padding = vbmeta_blob + b'\0' * padding_needed
	  # 添加vbmeta信息
      if not do_not_append_vbmeta_image:
        image.append_raw(vbmeta_blob_with_padding)
  1. 创建AvbFooter,加入到目标image
		....................
        footer = AvbFooter()
        footer.original_image_size = original_image_size
        footer.vbmeta_offset = vbmeta_offset
        footer.vbmeta_size = len(vbmeta_blob)
        footer_blob = footer.encode()
        footer_blob_with_padding = (b'\0' * (image.block_size - AvbFooter.SIZE) + footer_blob)
        # 添加footer
        image.append_raw(footer_blob_with_padding)

参考资料

avb/README.mk
加密、摘要、签名、证书,一次说明白!
android AVB2.0(一)工作原理及编译配置

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值