尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

MTK安全启动分析14:Android的AVB校验的总结

MTK安全启动分析14:Android的AVB校验的总结
📅 发布时间:2026/7/28 2:03:27

Android的AVB校验的总结

从代码看,顺序是:

1. avb_vbmeta_image_verify() 做的事: - 从 vbmeta.img 自身提取 public_key_X ← 这个公钥是 vbmeta.img 自己带在里面的 - 从 vbmeta.img 自身提取 signature - 计算 hash = SHA256(header_block + auxiliary_block) - RSA_verify(public_key_X, signature, hash) - 返回 public_key_X ↑ 这一步只证明: "vbmeta.img 是用 public_key_X 对应的私钥签名的" 但还不知道 public_key_X 是否可信 2. avb_hal_verify_public_key(public_key_X) 做的事: - memcmp(g_avb_key, public_key_X, pubk_sz) - 如果相等 → key_is_trusted = TRUE ↑ 这一步才证明: "public_key_X 就是 OEM 的 AVB_ROOT_PUBK" → "vbmeta.img 是 OEM 签的" 3. 遍历 vbmeta.img 的 descriptors ├── 发现 CHAIN_PARTITION "vbmeta_system" │ 提取 chain_public_key (就是 AVB_SYSTEM_PUBK) │ └── load_and_verify_vbmeta("vbmeta_system", AVB_SYSTEM_PUBK) │ 1. avb_vbmeta_image_verify() ← 用自身 key 验自身签名 │ 2. memcmp(AVB_SYSTEM_PUBK, vbmeta_system 提取的 public_key) │ └── 相等 → 信任 │ ├── 发现 CHAIN_PARTITION "vbmeta_vendor" │ 提取 chain_public_key (就是 AVB_VENDOR_PUBK) │ └── load_and_verify_vbmeta("vbmeta_vendor", AVB_VENDOR_PUBK) │ 1. avb_vbmeta_image_verify() ← 用自身 key 验自身签名 │ 2. memcmp(AVB_VENDOR_PUBK, vbmeta_vendor 提取的 public_key) │ └── 相等 → 信任 │ └── 发现 HASH descriptor └── load_and_verify_hash_partition() ├── 读取整个 boot 分区数据 ├── SHA256(salt || boot_partition_data) └── memcmp(算出来的 hash, vbmeta 中存的 hash)

先用 vbmeta.img 自带的公钥验它自己的签名(证明数据完整)再判断这个公钥是否等于 LK 里的公钥(证明是谁签的)

vbmeta.public_key → RSA验证 → vbmeta.signature ← 先验签名 vbmeta.public_key → memcmp → g_avb_key ← 后比公钥

为什么? 因为 avb_vbmeta_image_verify() 是 Google libavb 的通用函数,它不依赖任何"信任的公钥"——它只是说"这个 vbmeta 的签名能用一个自带的公钥验证通过"。而判断这个公钥是否被信任,是平台 HAL 层(MTK)的责任,所以分成了两个独立的步骤。

对比公钥 avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) 与 avb_hal_verify_public_key 中的 if (0 == memcmp((void *)g_avb_key, (void *)pubk, pubk_sz)):

case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: { AvbSlotVerifyResult sub_ret; AvbChainPartitionDescriptor chain_desc; const uint8_t* chain_partition_name; const uint8_t* chain_public_key; /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */ if (!is_main_vbmeta) { avb_errorv(full_partition_name, ": Encountered chain descriptor not in main image.\n", NULL); ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; goto out; } if (!avb_chain_partition_descriptor_validate_and_byteswap( (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) { avb_errorv(full_partition_name, ": Chain partition descriptor is invalid.\n", NULL); ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; goto out; } if (chain_desc.rollback_index_location == 0) { avb_errorv(full_partition_name, ": Chain partition has invalid " "rollback_index_location field.\n", NULL); ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA; goto out; } chain_partition_name = ((const uint8_t*)descriptors[n]) + sizeof(AvbChainPartitionDescriptor); chain_public_key = chain_partition_name + chain_desc.partition_name_len; sub_ret = load_and_verify_vbmeta(ops, requested_partitions, ab_suffix, flags, allow_verification_error, toplevel_vbmeta_flags, chain_desc.rollback_index_location, (const char*)chain_partition_name, chain_desc.partition_name_len, chain_public_key, chain_desc.public_key_len, slot_data, NULL, /* out_algorithm_type */ NULL /* out_additional_cmdline_subst */); if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) { ret = sub_ret; if (!result_should_continue(ret)) { goto out; } } /* Check if key used to make signature matches what is expected. */ if (pk_data != NULL) { if (expected_public_key != NULL) { avb_assert(!is_main_vbmeta); if (expected_public_key_length != pk_len || avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) { avb_errorv(full_partition_name, ": Public key used to sign data does not match key in chain " "partition descriptor.\n", NULL); ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED; if (!allow_verification_error) { goto out; } } } else { bool key_is_trusted = false; const uint8_t* pk_metadata = NULL; size_t pk_metadata_len = 0; if (vbmeta_header.public_key_metadata_size > 0) { pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) + vbmeta_header.authentication_data_block_size + vbmeta_header.public_key_metadata_offset; pk_metadata_len = vbmeta_header.public_key_metadata_size; } // If we're not using a vbmeta partition, need to use another AvbOps... if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) { io_ret = ops->validate_public_key_for_partition( ops, full_partition_name, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted, &rollback_index_location_to_use); } else { avb_assert(is_main_vbmeta); io_ret = ops->validate_vbmeta_public_key(ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted); } AvbIOResult avb_hal_verify_public_key(AvbOps *ops, const uint8_t *public_key_data, size_t public_key_length, const uint8_t *public_key_metadata, size_t public_key_metadata_length, bool *out_is_trusted) { AvbRSAPublicKeyHeader *key_hdr; uint8_t *pubk; uint32_t i = 0; uint32_t pubk_sz = 0; AvbIOResult ret = AVB_IO_RESULT_OK; if (out_is_trusted == NULL || public_key_data == NULL) return AVB_IO_RESULT_ERROR_IO; key_hdr = (AvbRSAPublicKeyHeader *)public_key_data; pubk = (uint8_t *)(public_key_data + sizeof(AvbRSAPublicKeyHeader)); pubk_sz = avb_htobe32(key_hdr->key_num_bits) / 8; *out_is_trusted = FALSE; if (pubk_sz != AVB_PUBK_SZ) { pal_log_err("invalid pubk size\n"); goto end; } #ifdef MTK_SECURITY_SW_SUPPORT if (sec_set_pubk(pubk, pubk_sz) != STATUS_OK) { pal_log_err("[%s] fails to set public key\n", __func__); return AVB_IO_RESULT_ERROR_IO; } #endif if (0 == memcmp((void *)g_avb_key, (void *)pubk, pubk_sz)) *out_is_trusted = TRUE; else { #ifdef MTK_SECURITY_YELLOW_STATE_SUPPORT *out_is_trusted = TRUE; g_vb_custom_key_exist = 1; #else pal_log_err("oem_avb_key =\n"); for (i = 0; i < AVB_PUBK_SZ; i++) { pal_log_err("0x%x ", g_avb_key[i]); if (((i + 1) % 16) == 0) pal_log_err("\n"); } pal_log_err("vbmeta_avb_key =\n"); for (i = 0; i < AVB_PUBK_SZ; i++) { pal_log_err("0x%x ", pubk[i]); if (((i + 1) % 16) == 0) pal_log_err("\n"); } #endif } end: return ret; }

分区的描述与对应代码

描述

对应代码

vbmeta.img 的 chain descriptor 描述了子 vbmeta

AVB_DESCRIPTOR_TAG_CHAIN_PARTITION指定 partition_name + public_key

用 chain 中的公钥校验子 vbmeta 的签名

load_and_verify_vbmeta("vbmeta_system", chain_public_key, ...)

全量 SHA256 计算 boot 分区

load_and_verify_hash_partition()全量加载 + SHA256

对比 SHA256 值与 vbmeta 中的 digest

memcmp(computed_digest, expected_digest, digest_len)

先用 vbmeta.img 自带的公钥验它自己的签名,再比对这个公钥是否等于 LK 编译的 AVB_ROOT_PUBK。子 vbmeta 同理,用 chain descriptor 里指定的公钥去验。boot 分区不做 RSA 签名,而是全量 SHA256 哈希比对。

相关新闻

  • COBOL与AI工具兼容性危机解析及企业级解决方案
  • 如何优化LoveIwara视频播放体验:5个Anime4K高级画质设置技巧
  • 2026年水性漆供应厂家:环保水性漆、水性木器漆、水性防锈漆优质品牌参考 - 卓企推荐

最新新闻

  • 开发者必看:Invio架构设计与核心代码实现原理详解
  • EasyX跑酷游戏开发:重力系统与菜单实现
  • (2026最新)娄底本地人必选的靠谱漏水检测维修推荐:正规防水补漏防水-卫生间/厨房/屋顶/阳台/外墙渗漏水精准测漏,本地人的信赖之选 - 安佳防水
  • 计算机图书热销榜TOP1的运作机制与内容策略
  • 摄像头sc233hgs驱动 v4l2驱动层设置参数方法
  • AI智能体研发 | 什么是OpenAI API协议

日新闻

  • 力旷智能:伺服驱动系统在制药收瓶设备中的应用解析
  • 2026 网安入门避坑指南,零基础如何避开无效学习直接上手实战
  • 揭秘CFC项目:如何通过手机摄像头实现850kbps无网络文件传输

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号