summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Normand <philn@igalia.com>2015-03-13 09:32:11 +0100
committerMatěj Cepl <mcepl@cepl.eu>2024-02-19 13:50:27 +0100
commit38e3eb1f3ca5d23db45d554bd32052375d8d8077 (patch)
tree6a9ffd2c3b9db83881b858fc74f8de93231687b2
parent1b6e7f17a1dc3ae5c8c8a23248a6613e2f157edc (diff)
downloadgit-bz-38e3eb1f3ca5d23db45d554bd32052375d8d8077.tar.gz
Chrome/ium: decrypt cookies stored in sqlite database
Chrome and Chromium now have cookies stored in their sqlite database encrypted, there's a new column 'encrypted_value' in the cookies table. See also https://codereview.chromium.org/24734007 https://bugzilla.gnome.org/show_bug.cgi?id=746137
-rwxr-xr-xgit-bz74
1 files changed, 64 insertions, 10 deletions
diff --git a/git-bz b/git-bz
index 5e0ab56..8bd55f5 100755
--- a/git-bz
+++ b/git-bz
@@ -591,7 +591,7 @@ class BugHandle:
class CookieError(Exception):
pass
-def do_get_cookies_from_sqlite(host, cookies_sqlite, browser, query, chromium_time):
+def do_get_cookies_from_sqlite(host, cookies_sqlite, browser, query):
result = {}
# We use a timeout of 0 since we expect to hit the browser holding
# the lock often and we need to fall back to making a copy without a delay
@@ -602,7 +602,12 @@ def do_get_cookies_from_sqlite(host, cookies_sqlite, browser, query, chromium_ti
cursor.execute(query, { 'host': host })
now = time.time()
- for name,value,path,expiry in cursor.fetchall():
+ cookies = list(cursor.fetchall())
+ chromium_time = False
+ if browser in ('Google Chrome', 'Chromium'):
+ cookies = decrypt_cookie_values(cookies, browser)
+ chromium_time = True
+ for name,value,path,expiry in cookies:
# Excessive caution: toss out values that need to be quoted in a cookie header
expiry = float(expiry)
if chromium_time:
@@ -614,7 +619,6 @@ def do_get_cookies_from_sqlite(host, cookies_sqlite, browser, query, chromium_ti
expiry -= 11644473600
if float(expiry) > now and not re.search(r'[()<>@,;:\\"/\[\]?={} \t]', value):
result[name] = value
-
return result
finally:
connection.close()
@@ -632,15 +636,13 @@ def get_cookies_from_sqlite_with_copy(host, cookies_sqlite, browser, *args, **kw
finally:
os.remove(db_copy)
-def get_cookies_from_sqlite(host, cookies_sqlite, browser, query, chromium_time=False):
+def get_cookies_from_sqlite(host, cookies_sqlite, browser, query):
try:
- result = do_get_cookies_from_sqlite(host, cookies_sqlite, browser, query,
- chromium_time=chromium_time)
+ result = do_get_cookies_from_sqlite(host, cookies_sqlite, browser, query)
except sqlite.OperationalError, e:
if "database is locked" in str(e):
# Try making a temporary copy
- result = get_cookies_from_sqlite_with_copy(host, cookies_sqlite, browser, query,
- chromium_time=chromium_time)
+ result = get_cookies_from_sqlite_with_copy(host, cookies_sqlite, browser, query)
else:
raise
@@ -705,6 +707,59 @@ def get_bugzilla_cookies_epy(host):
return get_cookies_from_sqlite_xulrunner(host, cookies_sqlite, "Epiphany")
+def decrypt_cookie_values(cookies, browser):
+ # Code inspired by this blog post: http://n8henrie.com/2014/05/decrypt-chrome-cookies-with-python/
+
+ try:
+ from Crypto.Cipher import AES
+ from Crypto.Protocol.KDF import PBKDF2
+ except ImportError:
+ print >>sys.stderr, "Import of PyCrypto failed, please make sure AES and PBKDF2 modules are available in your PyCrypto package"
+
+ if os.uname()[0] == 'Darwin':
+ # The following module is needed only on Apple platforms for now.
+ # https://pypi.python.org/pypi/keyring
+ import keyring
+
+ if browser == 'Google Chrome':
+ service_name = 'Chrome Safe Storage'
+ username = 'Chrome'
+ else:
+ service_name = 'Chromium Safe Storage'
+ username = 'Chromium'
+ password = keyring.get_password(service_name, username)
+ password = password.encode('utf8')
+ iterations = 1003
+ elif os.uname()[0] == 'Linux':
+ # Chrome and Chromium don't use the GNOME keyring. See also
+ # https://code.google.com/p/chromium/issues/detail?id=364326
+ password = 'peanuts'.encode('utf8')
+ iterations = 1
+ else:
+ print >>sys.stderr, "%s cookies decryption not supported on this platform" % browser
+ return cookies
+
+ # Default values used by both Chrome and Chromium in OSX and Linux
+ salt = b'saltysalt'
+ iv = b' ' * 16
+ length = 16
+
+ new_cookies = []
+ for name, encrypted_value, path, expiry in cookies:
+ # Trim off the 'v10' that Chrome/ium prepends
+ if encrypted_value[:3] != 'v10':
+ print >>sys.stderr, "Unknown cookie encrypted_value header found: %s. Skipping." % encrypted_value[:3]
+ continue
+ encrypted_value = encrypted_value[3:]
+ key = PBKDF2(password, salt, length, iterations)
+ cipher = AES.new(key, AES.MODE_CBC, IV=iv)
+
+ decrypted = cipher.decrypt(encrypted_value)
+ # Get rid of padding.
+ new_cookies.append((name, decrypted[:-ord(decrypted[-1])], path, expiry))
+
+ return new_cookies
+
# Shared for Chromium and Google Chrome
def get_bugzilla_cookies_chr(host, browser, config_dir):
config_dir = os.path.expanduser(config_dir)
@@ -712,8 +767,7 @@ def get_bugzilla_cookies_chr(host, browser, config_dir):
if not os.path.exists(cookies_sqlite):
raise CookieError("%s doesn't exist" % cookies_sqlite)
return get_cookies_from_sqlite(host, cookies_sqlite, browser,
- "select name,value,path,expires_utc from cookies where host_key in (:host, '.'||:host)",
- chromium_time=True)
+ "select name,encrypted_value,path,expires_utc from cookies where host_key in (:host, '.'||:host)")
def get_bugzilla_cookies_chromium(host):
if os.uname()[0] == 'Darwin':