9

I'm building an automated process to produce extensions. Is there a code example of calculating the extension-ID directly and entirely bypassing interaction with the browser?

(I'm answering my own question, below.)

4

3 回答 3

11

我只能找到一篇带有 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,但使用 [ap](称为“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<username>\AppData\Local\Google\Chrome\User Data\Default\Extensions<extension ID>
  3. 从“key”下的 manifest.json 文件中获取公钥。由于密钥已经准备好进行 base64 解码,您可以跳过该过程的步骤 (1)。

示例中的公钥来自“Chrome Reader”扩展。它的扩展 ID 是“lojpenhmoajbciapkjkiekmobleogjc”。

也可以看看:

  1. Google Chrome - 用于识别扩展的字母数字哈希
  2. http://blog.roomanna.com/12-14-2010/getting-an-extensions-id
于 2013-06-07T21:48:20.490 回答
7

从 Chrome 64 开始,Chrome 将扩展的包格式更改为CRX₃ 文件格式,该格式支持多个签名并明确声明其 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 解析器框架。)

于 2018-09-10T17:56:24.713 回答
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
于 2014-02-11T20:10:25.897 回答