如何以编程方式计算Chrome扩展ID?

时间:2013-06-07 21:48:20

标签: python google-chrome google-chrome-extension sha256

我正在构建一个自动化流程来生成扩展。是否有直接计算扩展ID的代码示例,并完全绕过与浏览器的交互?

(我正在回答我自己的问题,如下。)

3 个答案:

答案 0 :(得分:8)

我只能找到一篇带有Ruby片段的相关文章,它只在IA中提供:http://web.archive.org/web/20120606044635/http://supercollider.dk/2010/01/calculating-chrome-extension-id-from-your-private-key-233

重要的是要知道:

  1. 这取决于DER编码的公钥(原始二进制),而不是PEM编码的密钥(通过base64编码DER密钥生成的漂亮ASCII)。
  2. 扩展ID是base-16,但是使用[a-p](称为“mpdecimal”)编码,而不是[0-9a-f]。
  3. 使用PEM编码的公钥,请按照以下步骤操作:

    1. 如果您的PEM格式的公钥仍然具有页眉和页脚并被分成多行,请手动重新格式化,以便您有一个字符串排除页眉和页脚,并一起运行以便每个密钥的行包装到下一个。
    2. Base64-解码公钥以呈现DER格式的公钥。
    3. 生成DER格式密钥的SHA256十六进制摘要。
    4. 获取哈希的前32个字节。你不需要休息。
    5. 对于每个字符,将其转换为base-10,并添加“a”的ASCII代码。
    6. 以下是执行此操作的Python例程:

      import hashlib
      from base64 import b64decode
      
      def build_id(pub_key_pem):
          pub_key_der = b64decode(pub_key_pem)
          sha = hashlib.sha256(pub_key_der).hexdigest()
          prefix = sha[:32]
      
          reencoded = ""
          ord_a = ord('a')
          for old_char in prefix:
              code = int(old_char, 16)
              new_char = chr(ord_a + code)
      
              reencoded += new_char
      
          return reencoded
      
      def main():
          pub_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjvF5pjuK8gRaw/2LoRYi37QqRd48B/FeO9yFtT6ueY84z/u0NrJ/xbPFc9OCGBi8RKIblVvcbY0ySGqdmp0QsUr/oXN0b06GL4iB8rMhlO082HhMzrClV8OKRJ+eJNhNBl8viwmtJs3MN0x9ljA4HQLaAPBA9a14IUKLjP0pWuwIDAQAB'
      
          id_ = build_id(pub_key)
          print(id_)
      
      if __name__ == '__main__':
          main()
      

      非常欢迎您针对现有扩展及其ID进行测试。要检索其PEM格式的公钥:

      1. 进入Chrome中现有扩展程序列表。获取一个扩展名ID。
      2. 找到托管扩展程序的目录。在我的Windows 7框中,它是:C:\ Users \\ AppData \ Local \ Google \ Chrome \ User Data \ Default \ Extensions \
      3. 从“key”下的manifest.json文件中获取公钥。由于密钥已准备好进行base64解码,因此您可以跳过该过程的步骤(1)。
      4. 示例中的公钥来自“Chrome阅读器”扩展程序。其扩展ID为“lojpenhmoajbiciapkjkiekmobleogjc”。

        另见:

        1. Google Chrome - Alphanumeric hashes to identify extensions
        2. http://blog.roomanna.com/12-14-2010/getting-an-extensions-id

答案 1 :(得分:4)

从Chrome 64开始,Chrome更改了CRX₃ file format扩展名的软件包格式,该格式支持多个签名并显式声明其CRX ID。从CRX₃文件中提取CRX ID需要解析协议缓冲区。

这是一个小的python脚本,用于从CRX₃文件中提取ID。 此解决方案仅应与受信任的CRX₃文件一起使用,或在不涉及安全性的情况下使用:与CRX2不同,软件包格式不限制CRX₃文件声明的CRX ID。 (实际上,文件的使用者(例如Chrome)会对其进行限制,例如要求使用至少一个散列到声明的CRX ID的密钥对文件进行签名)。

import binascii
import string
import struct
import sys

def decode(proto, data):
    index = 0
    length = len(data)
    msg = dict()
    while index < length:
        item = 128
        key = 0
        left = 0
        while item & 128:
            item = data[index]
            index += 1
            value = (item & 127) << left
            key += value
            left += 7
        field = key >> 3
        wire = key & 7
        if wire == 0:
            item = 128
            num = 0
            left = 0
            while item & 128:
                item = data[index]
                index += 1
                value = (item & 127) << left
                num += value
                left += 7
            continue
        elif wire == 1:
            index += 8
            continue
        elif wire == 2:
            item = 128
            _length = 0
            left = 0
            while item & 128:
                item = data[index]
                index += 1
                value = (item & 127) << left
                _length += value
                left += 7
            last = index
            index += _length
            item = data[last:index]
            if field not in proto:
                continue
            msg[proto[field]] = item
            continue
        elif wire == 5:
            index += 4
            continue
        raise ValueError(
            'invalid wire type: {wire}'.format(wire=wire)
        )
    return msg

def get_extension_id(crx_file):
    with open(crx_file, 'rb') as f:
      f.read(8); # 'Cr24\0\0\0\3'
      data = f.read(struct.unpack('<I', f.read(4))[0])
    crx3 = decode(
        {10000: "signed_header_data"},
        [ord(d) for d in data])
    signed_header = decode(
        {1: "crx_id"},
        crx3['signed_header_data'])
    return string.translate(
        binascii.hexlify(bytearray(signed_header['crx_id'])),
        string.maketrans('0123456789abcdef', string.ascii_lowercase[:16]))

def main():
    if len(sys.argv) != 2:
      print 'usage: %s crx_file' % sys.argv[0]
    else:
      print get_extension_id(sys.argv[1])

if __name__ == "__main__":
    main()

(感谢https://github.com/thelinuxkid/python-protolite的protobuf解析器框架。)

答案 2 :(得分:3)

使用python从.crx文件获取公钥的一种简单方法,因为chrome只为您生成私有.pem密钥。公钥实际上存储在.crx文件中。

这是基于http://developer.chrome.com/extensions/crx.html

中找到的.crx文件的格式
import struct
import hashlib
import string

def get_pub_key_from_crx(crx_file):
    with open(crx_file, 'rb') as f:
        data = f.read()
    header = struct.unpack('<4sIII', data[:16])
    pubkey = struct.unpack('<%ds' % header[2], data[16:16+header[2]])[0]
    return pubkey

def get_extension_id(crx_file):
    pubkey = get_pub_key_from_crx(crx_file)
    digest = hashlib.sha256(pubkey).hexdigest()

    trans = string.maketrans('0123456789abcdef', string.ascii_lowercase[:16])
    return string.translate(digest[:32], trans)

if __name__ == '__main__':
    import sys
    if len(sys.argv) != 2:
        print 'usage: %s crx_file' % sys.argv[0]

    print get_extension_id(sys.argv[1])

虽然这不可能“绕过与浏览器的交互”,因为您仍然需要使用像

这样的命令生成.crx文件
chrome.exe --pack-extension=my_extension --pack-extension-key=my_extension.pem