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

简介: Android源码学习(五):AVB2.0-libavb库介绍2


上一篇的末尾我们说好好分析一下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_size
  digest_size = len(hashlib.new(name=hash_algorithm).digest())
  #salt 加盐值是随机数,不是真随机数 软件生成的
  salt = open('/dev/urandom').read(hash_size)
  #实例化hasher
  hasher = 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_size
  h_desc.hash_algorithm = hash_algorithm
  h_desc.partition_name = partition_name
  h_desc.salt = salt
  h_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_needed
  image.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), the
    authentication data block (which contains the hash and signature
    for 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_name
            descriptors_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 = None
    encoded_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 = 0
    h.descriptors_size = len(encoded_descriptors)
    h.public_key_offset = h.descriptors_size
    h.public_key_size = len(encoded_key)
    h.public_key_metadata_offset = h.public_key_offset + h.public_key_size
    h.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_type
    h.hash_offset = 0
    h.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_bytes
    h.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_hash
      binary_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 bytes
      Hash Algorithm:        sha256
      Partition Name:        dtbo
      Salt:                  d72008a93668fa341fa192295be351fba68dad0047e673bb3b683f26337d2c5c
      Digest:                d8864242361c1dbd60cbc00cda360da6ecad843abc0af79e1da42b09bbee8922
      Flags:                 0

dtbo.img内容

Footer version:           1.0
...
Release String:           'avbtool 1.1.0'
Descriptors:
    Hash descriptor:
      Image Size:            32 bytes
      Hash Algorithm:        sha256
      Partition Name:        dtbo
      Salt:                  d72008a93668fa341fa192295be351fba68dad0047e673bb3b683f26337d2c5c
      Digest:                d8864242361c1dbd60cbc00cda360da6ecad843abc0af79e1da42b09bbee8922
      Flags:                 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_LOOPS
  int i;
  for (i = 0; i < 8; i++) {
    ctx->h[i] = sha256_h0[i];
  }
#else
  ctx->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_LOOPS
  size_t j;
#endif
  for (i = 0; i < block_nb; i++) {
    sub_block = message + (i << 6);
#ifndef UNROLL_LOOPS
    for (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];
    }
#else
    PACK32(&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_LOOPS
  size_t i;
#endif
  block_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_LOOPS
  for (i = 0; i < 8; i++) {
    UNPACK32(ctx->h[i], &ctx->buf[i << 2]);
  }
#else
  UNPACK32(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.10
  if ((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);


目录
相关文章
|
8月前
|
XML 搜索推荐 Android开发
Android改变进度条控件progressbar的样式(根据源码修改)
本文介绍了如何基于Android源码自定义ProgressBar样式。首先分析了系统源码中ProgressBar样式的定义,发现其依赖一张旋转图片实现动画效果。接着分两步指导开发者实现自定义:1) 模仿源码创建一个旋转动画XML文件(放置在drawable文件夹),修改图片为自定义样式;2) 在UI控件中通过`indeterminateDrawable`属性应用该动画。最终实现简单且个性化的ProgressBar效果,附带效果图展示。
570 2
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
1399 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
9月前
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
11月前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
530 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
Java Maven 开发工具
第一个安卓项目 | 中国象棋demo学习
本文是作者关于其第一个安卓项目——中国象棋demo的学习记录,展示了demo的运行结果、爬坑记录以及参考资料,包括解决Android Studio和maven相关问题的方法。
241 7
第一个安卓项目 | 中国象棋demo学习
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
351 1
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
561 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
Android开发
Android学习 —— 测试init.rc中的条件触发的处理顺序
Android学习 —— 测试init.rc中的条件触发的处理顺序
|
监控 Java API
Android经典实战之OkDownload:一个经典强大的文件下载开源库,支持断点续传
本文介绍的 OkDownload 是一个专为 Android 设计的开源下载框架,支持多线程下载、断点续传和任务队列管理等功能,具备可靠性、灵活性和高性能特点。它提供了多种配置选项和监听器,便于开发者集成和扩展。尽管已多年未更新,但依然适用于大多数文件下载需求。
1248 1

热门文章

最新文章