summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjvoung@google.com <jvoung@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-21 22:08:09 +0000
committerjvoung@google.com <jvoung@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-21 22:08:09 +0000
commit0d43d1e12a082b486cd1a8726313520c3ca6a907 (patch)
tree00814395fb61d97f269e4f33b093be68586dfe0b
parent2de2d62f73f4e58000055c0522a62af5d6da3cf5 (diff)
downloadchromium_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.py28
-rw-r--r--tools/crx_id/__init__.py8
-rwxr-xr-xtools/crx_id/crx_id.py92
-rwxr-xr-xtools/crx_id/crx_id_unittest.py36
-rw-r--r--tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crxbin0 -> 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
new file mode 100644
index 0000000..4fb2a3b
--- /dev/null
+++ b/tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx
Binary files differ