Skip to content

Instantly share code, notes, and snippets.

@danzek
Last active October 17, 2022 18:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save danzek/f9416b1404570754b10f to your computer and use it in GitHub Desktop.
Save danzek/f9416b1404570754b10f to your computer and use it in GitHub Desktop.
Prototype code for brute forcing Android gesture.key files
#!/usr/bin/env python
"""Cracks a gesture.key file (Android pattern lock), reverse-engineers the Android method of creating an unsalted SHA1
hash value from the 3-9 digit pattern code (each digit consisting of 9 possible values: 0-8).
Note that Android > v2.33 requires minimum of four values, but three makes this work for old ones too.
The original Android source code for pattern locks:
/*
* Generate an SHA-1 hash for the pattern. Not the most secure, but it is
* at least a second level of protection. First level is that the file
* is in a location only readable by the system process.
* @param pattern the gesture pattern.
* @return the hash of the pattern in a byte array.
*/
private static byte[] patternToHash(List pattern) {
if (pattern == null) {
return null;
}
final int patternSize = pattern.size();
byte[] res = new byte[patternSize];
for (int i = 0; i < patternSize; i++) {
LockPatternView.Cell cell = pattern.get(i);
res[i] = (byte) (cell.getRow() * 3 + cell.getColumn());
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] hash = md.digest(res);
return hash;
} catch (NoSuchAlgorithmException nsa) {
return res;
}
}
Credit must be given to Michael Spreitzenbarth's helpful blog post:
http://forensics.spreitzenbarth.de/2012/02/28/cracking-the-pattern-lock-on-android/
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
import binascii
import hashlib
import itertools
import os
import sys
__author__ = "Dan O'Day"
__credits__ = ["Michael Spreitzenbarth", "Chema Garcia", "Kieron Craggs"]
__version__ = "0.1"
__maintainer__ = "Dan O'Day"
__email__ = "d@4n68r.com"
__status__ = "Prototype"
def brute_force_gesture_key_file(gestureSHA1):
"""
Brute forces possible permutations of gesture.key file until one of them matches the supplied SHA1 hash sum.
:param sha1sum: SHA1 hash sum value from gesture.key file
:return: numeric permutation that matches the supplied SHA1 hash sum or null value (None) if not found
"""
for i in range(3, 10): # pattern length between 3-9 digits
print 'checking patterns with length %d...' % i
perms = itertools.permutations([0, 1, 2, 3, 4, 5, 6, 7, 8], i)
for combo in perms:
pattern = ''.join(str(v) for v in combo)
key = binascii.unhexlify(''.join('%02x' % int(c) for c in pattern))
sha1 = hashlib.sha1(key).hexdigest()
if sha1 == gestureSHA1: # eureka! we found it!
return pattern
return None # fail
def main():
fn = sys.argv[1]
if not fn and not os.path.isfile(fn):
print 'usage: bruteforcegesture.py gesture.key [more gesture.key files]'
sys.exit(1)
with open(fn, 'rb') as f:
gestureSHA1 = f.read(hashlib.sha1().digest_size).encode('hex')
if len(gestureSHA1) / 2 != hashlib.sha1().digest_size:
print 'invalid gesture.key file'
sys.exit(1)
cracked_pattern = brute_force_gesture_key_file(gestureSHA1)
if cracked_pattern:
print 'pattern found:', cracked_pattern
else:
print 'pattern not found'
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment