【问题标题】:How to programmatically calculate Chrome extension ID?如何以编程方式计算 Chrome 扩展 ID?
【发布时间】:2013-06-07 21:48:20
【问题描述】:

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

(下面是我自己的问题。)

【问题讨论】:

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


    【解决方案1】:

    我只能找到一篇带有 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 编码的密钥(通过对 DER 密钥进行 base64 编码生成的漂亮 ASCII)。
    2. 扩展 ID 为 base-16,但使用 [a-p](称为“mpdecimal”)而不是 [0-9a-f] 进行编码。

    使用 PEM 编码的公钥,执行以下步骤:

    1. 如果您的 PEM 格式的公钥仍然有页眉和页脚并且被拆分为多行,请手动重新格式化它,以便您有一个不包括页眉和页脚的字符串,并一起运行,这样每个键换行到下一行。
    2. 对公钥进行 Base64 解码以呈现 DER 格式的公钥。
    3. 生成 DER 格式密钥的 SHA256 十六进制摘要。
    4. 获取散列的前 32 个字节。其余的都不需要。
    5. 对于每个字符,将其转换为 base-10,并为“a”添加 ASCII 代码。

    以下是执行此操作的 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) 步。

    示例中的公钥来自“Chrome 阅读器”扩展程序。它的扩展 ID 是“lojpenhmoajbciapkjkiekmobleogjc”。

    另见:

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

    【讨论】:

    • 推导事实: Chrome 扩展程序 ID == 32-char, [a-z]
    • @adam 由于 chrome ID 以 Base 16 编码,因此正确的事实是:32-chars, [a-p]
    【解决方案2】:

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

    这是一个用于从 CRX₃ 文件中提取 ID 的小型 Python 脚本。 此解决方案应仅用于受信任的 CRX₃ 文件或在不考虑安全性的情况下:与 CRX₂ 不同,包格式不限制 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\3\0\0\0'
          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 解析器框架。)

    【讨论】:

    • 为什么不直接导入 PB 解析器并保持低风险?
    • @DustinOprea:您希望避免什么风险?
    • 可维护性。您能否提供一个我们可以用来生成可导入模块的 protobuf 定义?
    • 是的。您可以找到 CRX₃ 设计文档中定义的文件格式(包括协议缓冲区)(链接在答案的开头)。这个答案按原样设计为密封的,因为我想为 Brian 的答案提供一个替代品,不需要安装额外的依赖项。
    • 链接拒绝访问。
    【解决方案3】:

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

    这是基于在此处找到的 .crx 文件的格式 http://developer.chrome.com/extensions/crx.html

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-30
      • 2014-05-10
      • 2014-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-18
      • 1970-01-01
      相关资源
      最近更新 更多