Как программно вычислить идентификатор расширения Chrome?
Я создаю автоматизированный процесс для создания расширений. Есть ли пример кода вычисления идентификатора расширения напрямую и полностью в обход взаимодействия с браузером?
(Я отвечаю на свой собственный вопрос ниже.)
3 ответов
я смог найти только связанную статью с фрагментом Ruby, и она доступна только в IA: http://web.archive.org/web/20120606044635/http://supercollider.dk/2010/01/calculating-chrome-extension-id-from-your-private-key-233
важно знать:
- это зависит от открытого ключа с кодировкой DER (RAW binary), а не от ключа с кодировкой PEM (хороший ASCII, сгенерированный base64-кодировкой ключа DER).
- расширения-идентификаторы основание-16, но кодируются с использованием [a-p] (называется "mpdecimal"), а не [0-9a-f].
используя открытый ключ в PEM-кодировке, выполните следующие действия:
- если ваш открытый ключ в формате PEM все еще имеет верхний и Нижний колонтитулы и разделен на несколько строк, переформатируйте его вручную, чтобы у вас была одна строка символов, которая исключает верхний и Нижний колонтитулы, и работает вместе, так что каждая строка ключа обертывается к следующему.
- Base64-декодировать общественность ключ для отображения открытого ключа в формате DER.
- создайте шестнадцатеричный дайджест SHA256 ключа в формате DER.
- возьмите первые 32 байта хэша. Остальное вам не понадобится.
- для каждого символа преобразуйте его в base-10 и добавьте код ASCII для 'a'.
для этого используется следующая процедура 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-формат открытый ключ:
- перейдите в список существующих расширений в Chrome. Возьмите идентификатор расширения одного из них.
- найдите каталог, в котором размещается расширение. В моем окне Windows 7 это: C:\Users\\AppData\Local\Google\Chrome\User Data\Default\Extensions\
- Возьмите ключ из манифеста.файл json в разделе "ключ". Поскольку ключ уже готов к декодированию base64, вы можете пропустить Шаг (1) процесса.
открытый ключ в пример из расширения "Chrome Reader". Его идентификатор расширения - "lojpenhmoajbiciapkjkiekmobleogjc".
Читайте также:
хороший и простой способ получить открытый ключ из .crx-файл с использованием python, так как chrome генерирует только частный .PEM key для вас. Открытый ключ хранится в .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
начиная с Chrome 64, Chrome изменил формат пакета для расширений на CRX format формат файла, который поддерживает несколько подписей и явно объявляет свой идентификатор CRX. Извлекая идентификатор CRX из файла CRX₃ требуется парсинг буфера протокола.
вот небольшой скрипт python для извлечения идентификатора из файла CRX₃. Это решение должно использоваться только с доверенными файлами CRX₃ или в контекстах, где безопасность не является проблемой: в отличие от CRX₂, формат пакета не ограничивает того, что CRX и идентификатор файла CRX₃ заявляет. (На практике потребители файла (например, Chrome) будут накладывать на него ограничения, например, требовать, чтобы файл был подписан хотя бы одним ключом, который хэширует объявленный идентификатор CRX).
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'
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.)