Setting a separate encryption password and pattern lock on Android

If you run an older version of LineageOS (14.1 or so) then by using the cryptfs utility you can separate your devices pattern lock and boot password.

This is something you want to do. While state-of-the-art for security is going to belong to Apple for the forseeable future, practical security for the every day user can be achieved (sort of) in Android by ensuring that the password to decrypt your devices storage from a cold boot is much more complicated then the online pattern lock.

A human sitting there trying it is unlikely to break the pattern lock (or will actually power off the phone). Whereas someone looking to go farming your device for personal data might try to image it and break it offline.

For peace of mind then, we want to know that if the device is powered off, they're unlikely to break the initial login password.

Irritatingly, LineageOS makes this difficult.

Thankfully (if you trust the author) the cryptfs tool makes this easy...provided you know how to convert a pattern lock key into a password to do it.

3x3 Patterns

Look around the net and 3x3 patterns don't have a clear translation table.

However, there's not too many possibilities - and in fact the basic translation is left to right, top to bottom, you get:

1 2 3
4 5 6
7 8 9

When using cryptfs, just convert your pattern to numbers using the above table. Simple right?

But I use a 4x4 pattern. What then?

4x4 Patterns

Always look at the code and think about it. Someone on StackOverflow did - but the code is not correct for current LineageOS.

The real function in LineageOS is this:

    /**
     * Serialize a pattern.
     * @param pattern The pattern.
     * @return The pattern in string form.
     */
    public static String patternToString(List<LockPatternView.Cell> pattern, byte gridSize) {
        if (pattern == null) {
            return "";
        }
        final int patternSize = pattern.size();
        LockPatternView.Cell.updateSize(gridSize);

        byte[] res = new byte[patternSize];
        for (int i = 0; i < patternSize; i++) {
            LockPatternView.Cell cell = pattern.get(i);
            res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn() + '1');
        }
        return new String(res);
    }

Found in the file frameworks/base/core/java/com/android/internal/widget/LockPatternUtils.java in the Android source tree.

The important line is here - res[i] = (byte) (cell.getRow() * gridSize + cell.getColumn() + '1');

The key being the '1' - what's happening is that the pattern lock is converted to an offset from ASCII 1, which actually converts to the (byte) number 49.

But the final conversion is just mapping the whole byte sequence to characters - so higher number patterns are just offsets into the ASCII lookup table past 1.

So for a 4x4 grid this gives us the following translation table:

1 2 3 4
5 6 7 8
9 : ; <
= > ? @

5x5 Pattern

Here's the pattern following the above for a 5x5 code if you use it:

1 2 3 4 5
6 7 8 9 :
; < = > ?
@ A B C D