文章目录

  • 1.签名流程
    • 1.1 镜像的签名
    • 1.2 镜像的内容
  • 2.验证镜像的hash和signature签名
    • 2.1 计算hash
    • 2.2 验证签名

1.签名流程

我们以一下空的dtbo.img镜像为例,进行说明

1.1 镜像的签名

调用external/avb/avbtool.py脚本的add_hash_footer 函数
@build/core/Makefile

# dtbo image
INSTALLED_DTBOIMAGE_TARGET := $(PRODUCT_OUT)/dtbo.img
$(INSTALLED_DTBOIMAGE_TARGET): $(BOARD_PREBUILT_DTBOIMAGE) $(AVBTOOL) $(BOARD_AVB_DTBO_KEY_PATH)cp $(BOARD_PREBUILT_DTBOIMAGE) $@$(AVBTOOL) add_hash_footer \--image $@ \--partition_size $(BOARD_DTBOIMG_PARTITION_SIZE) \--partition_name dtbo $(INTERNAL_AVB_DTBO_SIGNING_ARGS) \$(BOARD_AVB_DTBO_ADD_HASH_FOOTER_ARGS)

下面是avbtoo.py脚本的add_hash_footer的函数部分内容:

  def add_hash_footer(self, image_filename, partition_size, partition_name...)#镜像大小original_image_size = image.image_sizedigest_size = len(hashlib.new(name=hash_algorithm).digest())#salt 加盐值是随机数,不是真随机数 软件生成的salt = open('/dev/urandom').read(hash_size)#实例化hasherhasher = hashlib.new(name=hash_algorithm, string=salt)image.seek(0)#可以看到digest是根据镜像的大小来生成的摘要hasher.update(image.read(image.image_size))#生成digest值digest = hasher.digest()#生成descriptor描述信息数据h_desc = AvbHashDescriptor()h_desc.image_size = image.image_sizeh_desc.hash_algorithm = hash_algorithmh_desc.partition_name = partition_nameh_desc.salt = salth_desc.flags = 0#生成blob数据并写入blob数据vbmeta_blob = self._generate_vbmeta_blob(...)output_vbmeta_image.write(vbmeta_blob)vbmeta_offset = image.image_size#padding填充,padding的方式有好几种,主要目的是提高RSA的安全性。涉及到RSA的补位算法 有兴趣的自己查查看padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -len(vbmeta_blob))vbmeta_blob_with_padding = vbmeta_blob + '\0' * padding_neededimage.append_raw(vbmeta_blob_with_padding)vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)image.append_dont_care(partition_size - vbmeta_end_offset -1*image.block_size)

重点看一下_generate_vbmeta_blob函数,注释中也解释了各个步骤


def _generate_vbmeta_blob(self, algorithm_name, key_path...)
“”“This blob contains the header (struct AvbVBMetaHeader), theauthentication data block (which contains the hash and signaturefor the header and auxiliary block), and the auxiliary block(which contains descriptors, the public key used, and other data).
”“”# Add descriptors from other images.if include_descriptors_from_image:descriptors_dict = dict()for image in include_descriptors_from_image:image_handler = ImageHandler(image.name)(_, image_vbmeta_header, image_descriptors, _) = self._parse_image(image_handler)# Bump the required libavb version to support all included descriptors.h.bump_required_libavb_version_minor(image_vbmeta_header.required_libavb_version_minor)for desc in image_descriptors:if hasattr(desc, 'partition_name'):key = type(desc).__name__ + '_' + desc.partition_namedescriptors_dict[key] = desc.encode()else:encoded_descriptors.extend(desc.encode())for key in sorted(descriptors_dict):encoded_descriptors.extend(descriptors_dict[key])# Load public key metadata blob, if requested.pkmd_blob = []if public_key_metadata_path:with open(public_key_metadata_path) as f:pkmd_blob = f.read()key = Noneencoded_key = bytearray()if alg.public_key_num_bytes > 0:if not key_path:raise AvbError('Key is required for algorithm {}'.format(algorithm_name))encoded_key = encode_rsa_key(key_path)if len(encoded_key) != alg.public_key_num_bytes:raise AvbError('Key is wrong size for algorithm {}'.format(algorithm_name))# For the Auxiliary data block, descriptors are stored at offset 0,# followed by the public key, followed by the public key metadata blob.h.auxiliary_data_block_size = round_to_multiple(len(encoded_descriptors) + len(encoded_key) + len(pkmd_blob), 64)h.descriptors_offset = 0h.descriptors_size = len(encoded_descriptors)h.public_key_offset = h.descriptors_sizeh.public_key_size = len(encoded_key)h.public_key_metadata_offset = h.public_key_offset + h.public_key_sizeh.public_key_metadata_size = len(pkmd_blob)# For the Authentication data block, the hash is first and then# the signature.h.authentication_data_block_size = round_to_multiple(alg.hash_num_bytes + alg.signature_num_bytes, 64)h.algorithm_type = alg.algorithm_typeh.hash_offset = 0h.hash_size = alg.hash_num_bytes# Signature offset and size - it's stored right after the hash# (in Authentication data block).h.signature_offset = alg.hash_num_bytesh.signature_size = alg.signature_num_bytes# Generate Auxiliary data block.aux_data_blob = bytearray()aux_data_blob.extend(encoded_descriptors)aux_data_blob.extend(encoded_key)aux_data_blob.extend(pkmd_blob)padding_bytes = h.auxiliary_data_block_size - len(aux_data_blob)aux_data_blob.extend('\0' * padding_bytes)# Calculate the hash.binary_hash = bytearray()binary_signature = bytearray()if algorithm_name != 'NONE':ha = hashlib.new(alg.hash_name)ha.update(header_data_blob)ha.update(aux_data_blob)binary_hash.extend(ha.digest())# Calculate the signature.padding_and_hash = str(bytearray(alg.padding)) + binary_hashbinary_signature.extend(raw_sign(signing_helper,signing_helper_with_files,algorithm_name,alg.signature_num_bytes, key_path,padding_and_hash))# Generate Authentication data block.auth_data_blob = bytearray()auth_data_blob.extend(binary_hash)auth_data_blob.extend(binary_signature)padding_bytes = h.authentication_data_block_size - len(auth_data_blob)auth_data_blob.extend('\0' * padding_bytes)

我补上一张图,不然难理解上面脚本的验证数据和辅助数据的区别,分类如下:

1.2 镜像的内容

下面是xxd打开dtbo.img的内容

00000ff0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001000: 4156 4230 0000 0001 0000 0000 0000 0000  AVB0............
00001010: 0000 0000 0000 0000 0000 0180 0000 0000  ................
00001020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001040: 0000 0000 0000 0160 0000 0000 0000 0000  .......`........
00001050: 0000 0000 0000 0160 0000 0000 0000 0000  .......`........
00001060: 0000 0000 0000 0000 0000 0000 0000 0160  ...............`
00001070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001080: 6176 6274 6f6f 6c20 312e 312e 3000 0000  avbtool 1.1.0...
00001090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000010a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000010b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000010c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000010d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000010e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000010f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001100: 0000 0000 0000 0002 0000 0000 0000 00b8  ................
00001110: 0000 0000 0000 0020 7368 6132 3536 0000  ....... sha256..
00001120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001130: 0000 0000 0000 0000 0000 0004 0000 0020  ...............
00001140: 0000 0020 0000 0000 0000 0000 0000 0000  ... ............
00001150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001180: 0000 0000 6474 626f d720 08a9 3668 fa34  ....dtbo. ..6h.4
00001190: 1fa1 9229 5be3 51fb a68d ad00 47e6 73bb  ...)[.Q.....G.s.
000011a0: 3b68 3f26 337d 2c5c d886 4242 361c 1dbd  ;h?&3},\..BB6...
000011b0: 60cb c00c da36 0da6 ecad 843a bc0a f79e  `....6.....:....

使用avbtool.py脚本dump一下vbmeta.img和dtbo.img,我这里编译的是一个空的dtbo.img,dump的结果如下,可以看到vbmeta和dtbo中的相关salt和digest是匹配的。

vbmeta.img内容


Minimum libavb version:   1.0
Header Block:             256 bytes
Authentication Block:     576 bytes
Auxiliary Block:          3456 bytes
Public key (sha1):        xx
Algorithm:                SHA256_RSA4096
Rollback Index:           0
Flags:                    0
Release String:           'avbtool 1.1.0'Hash descriptor:Image Size:            32 bytesHash Algorithm:        sha256Partition Name:        dtboSalt:                  d72008a93668fa341fa192295be351fba68dad0047e673bb3b683f26337d2c5cDigest:                d8864242361c1dbd60cbc00cda360da6ecad843abc0af79e1da42b09bbee8922Flags:                 0

dtbo.img内容


Footer version:           1.0
...
Release String:           'avbtool 1.1.0'
Descriptors:Hash descriptor:Image Size:            32 bytesHash Algorithm:        sha256Partition Name:        dtboSalt:                  d72008a93668fa341fa192295be351fba68dad0047e673bb3b683f26337d2c5cDigest:                d8864242361c1dbd60cbc00cda360da6ecad843abc0af79e1da42b09bbee8922Flags:                 0

2.验证镜像的hash和signature签名

不是所有的镜像中都有Authentication Block的,所以我们重点分析vbmeta镜像中的Authentication Block和Auxiliary Block的校验,我们衔接上篇博客“AVB2.0(四)libavb库介绍”最后尾部遗留的内容,分析一下验证签名和比对hash这两个部分。

代码在avb_slot_verify.c
avb_slot_verify -> load_and_verify_vbmeta -> avb_vbmeta_image_verify,接着这里开始分析,一共比较两个部分,先对比hash,如果hash不相等 返回AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH错误

接着验证签名,如果签名不匹配,返回AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH错误

  switch (h.algorithm_type) {/* Explicit fall-through: */case AVB_ALGORITHM_TYPE_SHA256_RSA2048:case AVB_ALGORITHM_TYPE_SHA256_RSA4096:case AVB_ALGORITHM_TYPE_SHA256_RSA8192:avb_sha256_init(&sha256_ctx);avb_sha256_update(&sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));avb_sha256_update(&sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);computed_hash = avb_sha256_final(&sha256_ctx);##使用sha256计算得到的hash,和vbmeta头中的hash比较是否相等##auxiliary_block中有public key公钥数据if (avb_safe_memcmp(authentication_block + h.hash_offset,computed_hash,h.hash_size) != 0) {avb_error("Hash does not match!\n");ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;goto out;}#验证一下签名文件是否合法verification_result =avb_rsa_verify(auxiliary_block + h.public_key_offset,h.public_key_size,authentication_block + h.signature_offset,h.signature_size,authentication_block + h.hash_offset,h.hash_size,algorithm->padding,algorithm->padding_len);if (verification_result == 0) {ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH;goto out;}

上面步骤中有两个动作,一个是计算hash,一个是验证签名。

2.1 计算hash

AvbSHA256Ctx结构体

/* Data structure used for SHA-256. */
typedef struct {uint32_t h[8];uint32_t tot_len;uint32_t len;uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */void *user_data;
} AvbSHA256Ctx;

avb_sha256_init函数,主要是给h成员赋值,为下面的avb_sha256_update和avb_sha256_final提供上下文环境

/* SHA-256 implementation */
void avb_sha256_init(AvbSHA256Ctx* ctx) {#ifndef UNROLL_LOOPSint i;for (i = 0; i < 8; i++) {ctx->h[i] = sha256_h0[i];}
#elsectx->h[0] = sha256_h0[0];ctx->h[1] = sha256_h0[1];ctx->h[2] = sha256_h0[2];ctx->h[3] = sha256_h0[3];ctx->h[4] = sha256_h0[4];ctx->h[5] = sha256_h0[5];ctx->h[6] = sha256_h0[6];ctx->h[7] = sha256_h0[7];
#endif /* !UNROLL_LOOPS */ctx->len = 0;ctx->tot_len = 0;
}static const uint32_t sha256_h0[8] = {0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19};

avb_sha256_update函数

void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len) {size_t block_nb;size_t new_len, rem_len, tmp_len;const uint8_t* shifted_data;tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;rem_len = len < tmp_len ? len : tmp_len;avb_memcpy(&ctx->block[ctx->len], data, rem_len);if (ctx->len + len < AVB_SHA256_BLOCK_SIZE) {ctx->len += len;return;}new_len = len - rem_len;block_nb = new_len / AVB_SHA256_BLOCK_SIZE;shifted_data = data + rem_len;SHA256_transform(ctx, ctx->block, 1);SHA256_transform(ctx, shifted_data, block_nb);rem_len = new_len % AVB_SHA256_BLOCK_SIZE;avb_memcpy(ctx->block, &shifted_data[block_nb << 6], rem_len);ctx->len = rem_len;ctx->tot_len += (block_nb + 1) << 6;
}static void SHA256_transform(AvbSHA256Ctx* ctx,const uint8_t* message,size_t block_nb) {uint32_t w[64];uint32_t wv[8];uint32_t t1, t2;const unsigned char* sub_block;size_t i;#ifndef UNROLL_LOOPSsize_t j;
#endiffor (i = 0; i < block_nb; i++) {sub_block = message + (i << 6);#ifndef UNROLL_LOOPSfor (j = 0; j < 16; j++) {PACK32(&sub_block[j << 2], &w[j]);}for (j = 16; j < 64; j++) {SHA256_SCR(j);}for (j = 0; j < 8; j++) {wv[j] = ctx->h[j];}for (j = 0; j < 64; j++) {t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] +w[j];t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);wv[7] = wv[6];wv[6] = wv[5];wv[5] = wv[4];wv[4] = wv[3] + t1;wv[3] = wv[2];wv[2] = wv[1];wv[1] = wv[0];wv[0] = t1 + t2;}for (j = 0; j < 8; j++) {ctx->h[j] += wv[j];}
#elsePACK32(&sub_block[0], &w[0]);PACK32(&sub_block[4], &w[1]);
...PACK32(&sub_block[60], &w[15]);SHA256_SCR(16);
...SHA256_SCR(62);SHA256_SCR(63);wv[0] = ctx->h[0];wv[1] = ctx->h[1];wv[2] = ctx->h[2];wv[3] = ctx->h[3];wv[4] = ctx->h[4];wv[5] = ctx->h[5];wv[6] = ctx->h[6];wv[7] = ctx->h[7];SHA256_EXP(0, 1, 2, 3, 4, 5, 6, 7, 0);SHA256_EXP(7, 0, 1, 2, 3, 4, 5, 6, 1);
...SHA256_EXP(2, 3, 4, 5, 6, 7, 0, 1, 62);SHA256_EXP(1, 2, 3, 4, 5, 6, 7, 0, 63);ctx->h[0] += wv[0];ctx->h[1] += wv[1];ctx->h[2] += wv[2];ctx->h[3] += wv[3];ctx->h[4] += wv[4];ctx->h[5] += wv[5];ctx->h[6] += wv[6];ctx->h[7] += wv[7];
#endif /* !UNROLL_LOOPS */}
}

avb_sha256_final函数

uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {size_t block_nb;size_t pm_len;uint64_t len_b;
#ifndef UNROLL_LOOPSsize_t i;
#endifblock_nb =(1 + ((AVB_SHA256_BLOCK_SIZE - 9) < (ctx->len % AVB_SHA256_BLOCK_SIZE)));len_b = (ctx->tot_len + ctx->len) << 3;pm_len = block_nb << 6;avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);ctx->block[ctx->len] = 0x80;UNPACK64(len_b, ctx->block + pm_len - 8);SHA256_transform(ctx, ctx->block, block_nb);#ifndef UNROLL_LOOPSfor (i = 0; i < 8; i++) {UNPACK32(ctx->h[i], &ctx->buf[i << 2]);}
#elseUNPACK32(ctx->h[0], &ctx->buf[0]);UNPACK32(ctx->h[1], &ctx->buf[4]);UNPACK32(ctx->h[2], &ctx->buf[8]);UNPACK32(ctx->h[3], &ctx->buf[12]);UNPACK32(ctx->h[4], &ctx->buf[16]);UNPACK32(ctx->h[5], &ctx->buf[20]);UNPACK32(ctx->h[6], &ctx->buf[24]);UNPACK32(ctx->h[7], &ctx->buf[28]);
#endif /* !UNROLL_LOOPS */return ctx->buf;
}

2.2 验证签名

接着分析avb_rsa_verify验证签名函数

/* Verify a RSA PKCS1.5 signature against an expected hash.* Returns false on failure, true on success.*/
bool avb_rsa_verify(const uint8_t* key,size_t key_num_bytes,const uint8_t* sig,size_t sig_num_bytes,const uint8_t* hash,size_t hash_num_bytes,const uint8_t* padding,size_t padding_num_bytes) {uint8_t* buf = NULL;Key* parsed_key = NULL;bool success = false;
...parsed_key = parse_key_data(key, key_num_bytes);...buf = (uint8_t*)avb_malloc(sig_num_bytes);
...avb_memcpy(buf, sig, sig_num_bytes);modpowF4(parsed_key, buf);/* Check padding bytes.** Even though there are probably no timing issues here, we use* avb_safe_memcmp() just to be on the safe side.*/if (avb_safe_memcmp(buf, padding, padding_num_bytes)) {avb_error("Padding check failed.\n");goto out;}/* Check hash. */if (avb_safe_memcmp(buf + padding_num_bytes, hash, hash_num_bytes)) {avb_error("Hash check failed.\n");goto out;}success = true;out:if (parsed_key != NULL) {free_parsed_key(parsed_key);}if (buf != NULL) {avb_free(buf);}return success;
}

AVB之镜像的签名及验证签名详解相关推荐

  1. iOS使用Security.framework进行RSA 加密解密签名和验证签名

    iOS 上 Security.framework为我们提供了安全方面相关的api: Security框架提供的RSA在iOS上使用的一些小结 支持的RSA keySize 大小有:512,768,10 ...

  2. Android签名与校验过程详解

    原文:https://blog.csdn.net/gulinxieying/article/details/78677487 目 录 一.签名与校验原理概要    2 1.数字签名简介    2 2. ...

  3. ASP.Net 2.0窗体身份验证机制详解(FormsAuthentication) (转载)

    ASP.Net 2.0窗体身份验证机制详解(FormsAuthentication) 收藏 转自:http://www.aspxclub.com/l12/c_3689.html 本篇文章介绍了在ASP ...

  4. jQuery Validate验证框架详解

    2019独角兽企业重金招聘Python工程师标准>>> 一.导入js库 <script type="text/javascript" src="& ...

  5. php微信小程序物流进度推送,微信小程序 消息推送php服务器验证实例详解

    微信小程序 消息推送php服务器验证实例详解 设置页面("设置">>"开发设置"): 1.设置服务器域名 注意http和https协议的不同. 2. ...

  6. atitit.jQuery Validate验证框架详解与ati Validate 设计新特性

    atitit.jQuery Validate验证框架详解与ati Validate 设计新特性 1. AtiValidate的目标1 2. 默的认校验规则1 2.1. 使用方式 1.metadata用 ...

  7. layui单选框verify_layui lay-verify form表单自定义验证规则详解

    虽然layui的官方文档已经是写的比较详细,但是初次使用的时候总会懵一下,这里纪录一下lay-verify自定义验证规则的时候到底放哪. html: 提交 js: form.verify({ //数组 ...

  8. jQuery Validate表单验证框架详解

    jQuery表单验证框架总结 jQuery Validate验证框架详解 jQuery校验官网地址:bassistance.de » jQuery plugin: Validation 一.导入js库 ...

  9. docker镜像的构建及Dockerfile的详解应用,镜像加速器,镜像优化

    docker镜像的构建及dockerfile的祥解应用 1.镜像的构建 1.1创建一个Dockerfile 1.2构建镜像 1.3查看镜像的分层结构 1.4镜像的缓存特性 2.Dockerfile详解 ...

  10. php字段验证规则,ThinkPHP 自动验证及验证规则详解

    ThinkPHP 自动验证及验证规则详解 ThinkPHP 自动验证 ThinkPHP 内置了数据对象的自动验证功能来完成模型的业务规则验证.自动验证是基于数据对象的,而大多情况下数据对象是基于 $_ ...

最新文章

  1. 西里尔字 - 俄罗斯
  2. Streaming Big Data: Storm, Spark and Samza--转载
  3. 应用程序文件Android安全分析挑战:运行时篡改Dalvik字节码
  4. 【机器学习】特征提取代码汇总
  5. AVC sequence header AAC sequence header
  6. javascript 点点滴滴01章 javascript的认知
  7. vue 一直登录错误_vue中路由拦截无限循环的情况
  8. 一句话让你明白伪元素和伪类的区别
  9. linux 线程异常退出_Linux 进程必知必会
  10. 使用YOLO V4通过社交距离和口罩检测来缓解COVID
  11. 传输层协议(10):滑动窗口(4)
  12. 妙盈科技:ESG数据提供商获融资
  13. VC6 Tips 002: WndTabs 插件
  14. jQuery文档加载完毕的几种写法
  15. 外卖侠使用教程【干货】
  16. Stata资源:一些不错的Stata-Blogs
  17. 如何官网下载 IEEE 论文 Latex 和 Word 模板
  18. Python数据分析--统计注册用户
  19. python 将列表中的英文或者拼音转换为中文
  20. CPGIS三十周年专访系列|陶闯主席

热门文章

  1. 虚拟服务器共享文件夹端口,如何查看共享文件夹端口
  2. DNS是如何进行域名解析的?
  3. HTML5情人节礼物2(女友3D相册)
  4. p6000 深度学习_英伟达推Quadro新显卡,支持VR、深度学习等技术
  5. OpenStack八大核心组件精讲之---swift
  6. String为什么要设计成final
  7. 移动智能与终端安全防护
  8. python中round函数的精度保留方法---四舍六入五成双
  9. 魅族x8详细打开usb调试模式的方法
  10. 文件内容读取相关操作