diff options
author | jvoung@google.com <jvoung@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-21 22:08:09 +0000 |
---|---|---|
committer | jvoung@google.com <jvoung@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-21 22:08:09 +0000 |
commit | 0d43d1e12a082b486cd1a8726313520c3ca6a907 (patch) | |
tree | 00814395fb61d97f269e4f33b093be68586dfe0b | |
parent | 2de2d62f73f4e58000055c0522a62af5d6da3cf5 (diff) | |
download | chromium_src-0d43d1e12a082b486cd1a8726313520c3ca6a907.zip chromium_src-0d43d1e12a082b486cd1a8726313520c3ca6a907.tar.gz chromium_src-0d43d1e12a082b486cd1a8726313520c3ca6a907.tar.bz2 |
Add a simple python script to extract the hash and AppID from a CRX.
BUG= none
TEST= tools/crx_id/crx_id_unittest.py
Review URL: http://codereview.chromium.org/8357028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106791 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | tools/crx_id/PRESUBMIT.py | 28 | ||||
-rw-r--r-- | tools/crx_id/__init__.py | 8 | ||||
-rwxr-xr-x | tools/crx_id/crx_id.py | 92 | ||||
-rwxr-xr-x | tools/crx_id/crx_id_unittest.py | 36 | ||||
-rw-r--r-- | tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx | bin | 0 -> 1843 bytes |
5 files changed, 164 insertions, 0 deletions
diff --git a/tools/crx_id/PRESUBMIT.py b/tools/crx_id/PRESUBMIT.py new file mode 100644 index 0000000..1473a3c --- /dev/null +++ b/tools/crx_id/PRESUBMIT.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Presubmit script for crx_id. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for +details on the presubmit API built into gcl. +""" + +UNIT_TESTS = [ + 'crx_id_unittest', +] + +def CheckChangeOnUpload(input_api, output_api): + return input_api.canned_checks.RunPythonUnitTests(input_api, + output_api, + UNIT_TESTS) + +def CheckChangeOnCommit(input_api, output_api): + output = [] + output.extend(input_api.canned_checks.RunPythonUnitTests(input_api, + output_api, + UNIT_TESTS)) + output.extend(input_api.canned_checks.CheckDoNotSubmit(input_api, + output_api)) + return output diff --git a/tools/crx_id/__init__.py b/tools/crx_id/__init__.py new file mode 100644 index 0000000..b2e61d3 --- /dev/null +++ b/tools/crx_id/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +'''Module crx_id +''' + +pass diff --git a/tools/crx_id/crx_id.py b/tools/crx_id/crx_id.py new file mode 100755 index 0000000..6350068 --- /dev/null +++ b/tools/crx_id/crx_id.py @@ -0,0 +1,92 @@ +#!/usr/bin/python +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" Read a CRX file and write out the App ID and the Full Hash of the ID. +See: http://code.google.com/chrome/extensions/crx.html +and 'http://stackoverflow.com/questions/' + + '1882981/google-chrome-alphanumeric-hashes-to-identify-extensions' +for docs on the format. +""" + +import sys +import hashlib + +def usage(argv): + print "%s: crx_file" % argv[0] + +EXPECTED_CRX_MAGIC_NUM = 'Cr24' +EXPECTED_CRX_VERSION = 2 + +def HexToInt(hex_chars): + """ Convert bytes like \xab -> 171 """ + val = 0 + for i in xrange(len(hex_chars)): + val += pow(256, i) * ord(hex_chars[i]) + return val + +def HexToMPDecimal(hex_chars): + """ Convert bytes to an MPDecimal string. Example \x00 -> "aa" + This gives us the AppID for a chrome extension. + """ + result = '' + base = ord('a') + for i in xrange(len(hex_chars)): + value = ord(hex_chars[i]) + dig1 = value / 16 + dig2 = value % 16 + result += chr(dig1 + base) + result += chr(dig2 + base) + return result + +def HexTo256(hex_chars): + """ Convert bytes to pairs of hex digits. E.g., \x00\x11 -> "{0x00, 0x11}" + The format is taylored for copy and paste into C code: + const uint8 sha256_hash[] = { ... }; """ + result = [] + for i in xrange(len(hex_chars)): + value = ord(hex_chars[i]) + dig1 = value / 16 + dig2 = value % 16 + result.append('0x' + hex(dig1)[2:] + hex(dig2)[2:]) + return '{%s}' % ', '.join(result) + +def GetPublicKey(f): + magic_num = f.read(4) + if magic_num != EXPECTED_CRX_MAGIC_NUM: + raise 'Invalid magic number: %s (expecting %s)' % (magic_num, + EXPECTED_CRX_MAGIC_NUM) + version = f.read(4) + if not version[0] != EXPECTED_CRX_VERSION: + raise 'Invalid version number: %s (expecting %s)' % (version, + EXPECTED_CRX_VERSION) + pub_key_len_bytes = HexToInt(f.read(4)) + sig_len_bytes = HexToInt(f.read(4)) + pub_key = f.read(pub_key_len_bytes) + return pub_key + +def GetCRXHash(filename): + f = open(filename, 'rb') + pub_key = GetPublicKey(f) + f.close() + pub_key_hash = hashlib.sha256(pub_key).digest() + return HexTo256(pub_key_hash) + +def GetCRXAppID(filename): + f = open(filename, 'rb') + pub_key = GetPublicKey(f) + f.close() + pub_key_hash = hashlib.sha256(pub_key).digest() + # AppID is the MPDecimal of only the first 128 bits of the hash. + return HexToMPDecimal(pub_key_hash[:128/8]) + +def main(argv): + if len(argv) != 2: + usage(argv) + return 1 + print 'Raw Bytes: %s' % GetCRXHash(sys.argv[1]) + print 'AppID: %s' % GetCRXAppID(sys.argv[1]) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/tools/crx_id/crx_id_unittest.py b/tools/crx_id/crx_id_unittest.py new file mode 100755 index 0000000..ce5d197 --- /dev/null +++ b/tools/crx_id/crx_id_unittest.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Verify that crx_id.py generates a reasonable string for a canned CRX file. +""" + +import crx_id +import os +import sys +import unittest + +CANNED_CRX = os.path.join(os.path.dirname(sys.argv[0]), + 'jebgalgnebhfojomionfpkfelancnnkf.crx') +CRX_ID_SCRIPT = os.path.join(os.path.dirname(sys.argv[0]), + 'crx_id.py') +EXPECTED_HASH_BYTES = \ + '{0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec,' \ + ' 0x8e, 0xd5, 0xfa, 0x54, 0xb0, 0xd2, 0xdd, 0xa5,' \ + ' 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4,' \ + ' 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40}' + +EXPECTED_APP_ID = 'jebgalgnebhfojomionfpkfelancnnkf' + +class CrxIdUnittest(unittest.TestCase): + def testHashAppId(self): + """ Test that the output generated for a canned CRX. """ + self.assertEqual(crx_id.GetCRXAppID(CANNED_CRX), + EXPECTED_APP_ID) + self.assertEqual(crx_id.GetCRXHash(CANNED_CRX), + EXPECTED_HASH_BYTES) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx b/tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx Binary files differnew file mode 100644 index 0000000..4fb2a3b --- /dev/null +++ b/tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx |