感谢前辈的blog,安全相关的资料可太少了,很详细很卓越
https://blog.csdn.net/jackone12347/article/details/116241676

上一篇的末尾我们说好好分析一下avb_vbmeta_image_verify函数,不过在这之前先让我们来了解一些AVB之镜像的签名及验证签名详解。

1、AVB之镜像的签名及验证签名详解

1.1、签名流程

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

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

2、avb_vbmeta_image_verify

现在基于上述知识,再回到avb_vbmeta_image_verify。

AvbVBMetaVerifyResult avb_vbmeta_image_verify(const uint8_t* data,size_t length,const uint8_t** out_public_key_data,size_t* out_public_key_length) {...//首先判断是不是以“AVB0”开头的,vim打开vbmeta.img就可以看到是以AVB0开头/* Ensure magic is correct. */if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {avb_error("Magic is incorrect.\n");goto out;}//把数据拷贝到到h AvbVBMetaImageHeader中avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,&h);//比较avbtool的版本号 avbtool 1.10if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) ||(h.required_libavb_version_minor > AVB_VERSION_MINOR)) {avb_error("Mismatch between image version and libavb version.\n");ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION;goto out;}
//判断authentication和auxiliary数据大小是不是64字节的整数倍if ((h.authentication_data_block_size & 0x3f) != 0 ||(h.auxiliary_data_block_size & 0x3f) != 0) {avb_error("Block size is not a multiple of 64.\n");goto out;}//判断hash和signature内容在vbmeta header中uint64_t hash_end;if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) ||hash_end > h.authentication_data_block_size) {avb_error("Hash is not entirely in its block.\n");goto out;}uint64_t signature_end;if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) ||signature_end > h.authentication_data_block_size) {avb_error("Signature is not entirely in its block.\n");goto out;}//判断public key和public key metadata内容在vbmeta header中/* Ensure public key is entirely in the Auxiliary data block. */uint64_t pubkey_end;if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) ||pubkey_end > h.auxiliary_data_block_size) {avb_error("Public key is not entirely in its block.\n");goto out;}/* Ensure public key metadata (if set) is entirely in the Auxiliary* data block. */if (h.public_key_metadata_size > 0) {uint64_t pubkey_md_end;if (!avb_safe_add(&pubkey_md_end,h.public_key_metadata_offset,h.public_key_metadata_size) ||pubkey_md_end > h.auxiliary_data_block_size) {avb_error("Public key metadata is not entirely in its block.\n");goto out;}}//判断RSA algorithm的type和长度是不是符合if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) {ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED;avb_error("pis algoth type none AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED!\n");goto out;}/* Ensure algorithm field is supported. */algorithm = avb_get_algorithm_data(h.algorithm_type);if (!algorithm) {avb_error("Invalid or unknown algorithm.\n");goto out;}/* Bail if the embedded hash size doesn't match the chosen algorithm. */if (h.hash_size != algorithm->hash_len) {avb_error("Embedded hash has wrong size.\n");goto out;}//到这里基本的检查项就完成了,接下来就是验证数据是不是匹配了header_block = data;authentication_block = header_block + sizeof(AvbVBMetaImageHeader);auxiliary_block = authentication_block + h.authentication_data_block_size;//我们编译vbmeta应该是使用的SHA256_RSA4096,所以走下面这段逻辑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);break;//验证hash是否相等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;}//验证signature签名是否匹配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);
}

hash比较

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

signature签名比较

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

Android源码学习(五):AVB2.0-libavb库介绍2相关推荐

  1. android源码学习-Toast实现原理讲解

    前言: 前些日志QQ群有朋友发了一个Toast的崩溃日志.Toast如此简单的用法怎么会崩溃呢?所以顺便就学习了一下Toast在源码中的实现,不算复杂,但内容挺多的,这里就来分享一下,方便读者. 一. ...

  2. Android源码学习之浅析SystemServer脉络

    在之前的博文中<Android源码学习之如何创建使用JNI>和<Android源码学习之如何使用eclipse+NDK>中,浅谈了如何创建使用JNI和如何利用NDK工具开发创建 ...

  3. 【Android 源码学习】 init启动

    目录 Android 源码学习 init启动 从main.cpp开始 init.cpp 部分逻辑 init启动zygote 属性服务 总结 Android 源码学习 init启动 Android 11 ...

  4. 【Android 源码学习】Zygote启动原理

    Android 源码学习 Zygote启动原理 望舒课堂 Zygote进程启动原理学习记录整理. Zygote简介 Zygote是进程在init进程启动时创建的,进程本身是app_process,来源 ...

  5. 【Android 源码学习】系统架构和启动流程

    Android 源码学习 系统架构和启动流程 望舒课堂 学习记录整理.以及以下参考文章的整理汇总.便于我个人的学习记录. 感谢IngresGe,Gityuan的精彩文章.为我们这些初探android系 ...

  6. 【Android 源码学习】SystemServer启动原理

    Android 源码学习 SystemServer启动原理 望舒课堂 SystemServer进程启动原理学习记录整理. 参考文章: Android系统启动流程(三)解析SyetemServer进程启 ...

  7. 【Android 源码学习】SharedPreferences 源码学习

    第一章:SharedPreferences 源码学习 文章目录 第一章:SharedPreferences 源码学习 Android SharedPreferences的缺陷 MMKV.Jetpack ...

  8. Android源码学习------SystemUI(二)

    SystemUI----AndroidManifest文件 AndroidManifest是Android应用程序中最重要的文件之一.它是Android程序的全局配置文件,是每个 android程序中 ...

  9. Android源码学习之工厂方法模式应用

    主要内容: 工厂方法模式定义 工厂方法模式优势 工厂方法模式在Android源码中的应用 一.工厂方法模式定义 工厂方法模式定义: Define an interface for creating a ...

最新文章

  1. 如何让PHP以root权限执行系统命令
  2. 简单电商购物过程(续1)
  3. C#如何在钉钉开发平台中创建部门
  4. OKWatchDog 打造一个安全的容器类
  5. 手机uc怎么放大页面_手机网站怎样做可以提高用户体验度?——竹晨网络
  6. 【经典重温】所有数据无需共享同一个卷积核!谷歌提出条件参数化卷积CondConv(附Pytorch复现代码)...
  7. 存储过程,是否有查看所有项目功能
  8. c++实现一个敏感词汇的程序_一个C++程序员生产力,大概相当20个C程序员,200个java程序员?...
  9. oracle for扫描行,请教索引范围扫描具体IO行为?
  10. Centos7.6搭建FTP服务器
  11. 珍珠项链(洛谷-P2768)(Dp矩阵加速)
  12. 50道C/C++编程练习题 复习必备(1-10)
  13. html5的class属性值,HTML class 属性 | 菜鸟教程
  14. Java实现对文件的增删改查操作
  15. linux ln -sv命令,linux ln 命令详解
  16. 并发编程五:java并发线程池底层原理详解和源码分析
  17. html怎么给图片加密,实现图片加密
  18. 医院信息化建设历程(1)概述
  19. 计算机工作无法更改,win10系统计算机工作组名称无法更改的操作方案
  20. 技术总监的校招之旅——分享校招全攻略指南(万字长文)

热门文章

  1. Python的特点有哪些?
  2. VS2019 + OpenVINO 初体验
  3. 安卓卡android不卡,安卓手机用久了卡顿,到底哪些东西是可以删掉的?
  4. VSCode 安装与配置
  5. 【微信小程序高频面试题——精选一】
  6. 5G科普——三大场景
  7. 软件版本alpha、Beta、RC、GA、DMR等含义
  8. ES(elasticsearch)中遇到elasticsearch.keystore的问题,已解决!!!
  9. QT设计师无法修改窗口大小,无法通过鼠标拖动窗口改变大小的解决方案
  10. 贝叶斯方法的思想基础