[Galaxy Note II Q&A, Help & Troubleshooting] pulser_g2:
OK... So you've got your Note II, you've played around with it, rooted it, and now think "hey maybe I should enable encryption just in case". This sound familiar? I have wanted to do this for a while with my phone, but never got round to doing it.

Unfortunately, Samsung (and Android in general) are missing a trick - your lockscreen password must be the same as used to decrypt your device. This initially seems logical - give the user less to remember. Unfortunately it's not brilliant for security, as you are left needing to type in a lengthy encryption key every time you want to unlock your phone to make a call.

As such, you are going to use a short password. Samsung's software requires you to use at least 6 characters including 1 number. So naturally you're going to use the shortest possible password, meaning it's fairly crackable or "shoulder-surfable". Who wants to be typing in their encryption key every time they check their emails?

Alas, there is no obvious way to get around this, and that remains true unless you root. But once you have rooted, it's possible. Here's how, for the Galaxy Note II (as Samsung devices differ from others).

Disclaimer: These instructions work fine for me. If you don't understand them, or how it works, or if you think it's confusing, or if you care if you break something, then do not use them. This is for stock ROMs. Using winzip-wizard kaknoob or "custom" ROMs that promise the earth but really are a rename of the ROM and addition of donation buttons may break this, or it may not. I don't use them, so who knows... Try at your own risk. These instructions will work fine for people who know what they're doing. This is XDA-Developers, so there is an expectation you're not a noob :)

1) Root. If you don't know what this is or how to do it, just leave this thread. Learn about it, then return.

2) Install SL4A (https://code.google.com/p/android-scripting/)

3) Install Python4Android (https://code.google.com/p/android-scripting/downloads/detail?name=PythonForAndroid_r4.apk)

4) Encrypt your device using the security menu, and set a password lockscreen as required

5) Make the following script in /sdcard/sl4a/scripts/ called "pin.py" or something else of your choosing.

#
# Android pin change
# change the pin without Android UI restrictions bothering you
# allows to use a different pin on the lockscreen than the password
# for device encryption
#
# Version 1.0 / 2012-05-29
# by robberknight
#
# modified by Pulser_G2 (pulser_at_xda-developers.com) to work with
# Samsung devices (tested on Galaxy Note II N7100 JB 4.1.1)
# No Warranty!

import android
import subprocess
import sys
import hashlib
import struct
import binascii

class PinChange(object):

def __init__(self):
self.droid = android.Android()

def askNewPin(self):
pin1 = self.droid.dialogGetInput('New PIN (numeric)').result
if not pin1:
return False

if not pin1.isdigit() or len(pin1) < 4 or len(pin1) > 16:
self.droid.dialogCreateAlert("Error", "Invalid PIN")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
return False

pin2 = self.droid.dialogGetInput('Confirm PIN').result
if not pin2:
return False

if pin1 != pin2:
self.droid.dialogCreateAlert("Error", "PINs don't match")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
return False

return pin1

def getFileContent(self,filename):
try:
catpipe = subprocess.Popen(["su", "-c", "cat \""+filename+"\" 2>/dev/null"], stdout = subprocess.PIPE)
catoutput = catpipe.communicate()[0]
if catpipe.returncode == 0:
return catoutput
else:
return None
except:
self.droid.dialogCreateAlert("Error", "Can't execute su call (not rooted?)")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)

def sqliteFound(self):
try:
statpipe = subprocess.Popen(["sqlite3", "-version"], stdout = subprocess.PIPE)
statoutput = statpipe.communicate()[0]
if statpipe.returncode == 0 and statoutput[0] >= '3':
return True
except:
pass
self.droid.dialogCreateAlert("Error", "Can't find sqlite3 command")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)

def createBackup(self):
if self.getFileContent("/data/system/password.sav") == None or \
len(self.getFileContent("/data/system/password.sav")) == 0:
try:
statpipe = subprocess.Popen(["su", "-c", "cat /data/system/password.key >/data/system/password.sav"], stdout = subprocess.PIPE)
statoutput = statpipe.communicate()[0]
if statpipe.returncode != 0:
self.droid.dialogCreateAlert("Error", "Can't create password backup")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)
chmodpipe = subprocess.Popen(["su", "-c", "chmod 600 /data/system/password.sav"], stdout = subprocess.PIPE)
chmodpipe.communicate()[0]
if chmodpipe.returncode != 0:
self.droid.dialogCreateAlert("Error", "Can't secure password backup")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)
sqlitepipe = subprocess.Popen(["su", "-c", "sqlite3 -batch \
/data/system/locksettings.db \"SELECT value FROM locksettings WHERE name = 'lockscreen.password_type'\" >/data/system/password_type.sav"],
stdout = subprocess.PIPE)
sqlitepipe.communicate()[0]
if sqlitepipe.returncode != 0:
self.droid.dialogCreateAlert("Error", "Can't backup password type")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)
except:
self.droid.dialogCreateAlert("Error", "Can't execute su call (not rooted?)")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)

def restoreBackup(self):
if self.getFileContent("/data/system/password.sav") != None and \
len(self.getFileContent("/data/system/password.sav")) > 0 and \
self.getFileContent("/data/system/password_type.sav") != None and \
len(self.getFileContent("/data/system/password_type.sav")) > 0:
try:
statpipe = subprocess.Popen(["su", "-c", "cat /data/system/password.sav >/data/system/password.key"], stdout = subprocess.PIPE)
statoutput = statpipe.communicate()[0]
if statpipe.returncode != 0:
self.droid.dialogCreateAlert("Error", "Can't restore password backup")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)
except:
self.droid.dialogCreateAlert("Error", "Can't execute su call (not rooted?)")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)
pwdtype=self.getFileContent("/data/system/password_type.sav")
pwdtype=pwdtype.splitlines()[0].strip()
self.writePasswordType(pwdtype)
self.droid.dialogCreateAlert("Success", "Backup restored")
self.droid.dialogSetPositiveButtonText('Ok')
self.droid.dialogShow()

def writePasswordType(self,typeno):
try:
sqlitepipe = subprocess.Popen(["su", "-c", "sqlite3 -batch \
/data/system/locksettings.db \"UPDATE locksettings SET value='"+str(typeno)+"' WHERE name = 'lockscreen.password_type'\""],
stdout = subprocess.PIPE)
sqlitepipe.communicate()
if sqlitepipe.returncode == 0:
return
except:
pass
self.droid.dialogCreateAlert("Error", "Can't write pwd type")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)

def writePassword(self,pwdhash):
try:
catpipe = subprocess.Popen(["su", "-c", "cat >/data/system/password.key"],
stdout = subprocess.PIPE, stdin = subprocess.PIPE)
catoutput = catpipe.communicate(pwdhash)[0]
if catpipe.returncode == 0:
return
except:
pass
self.droid.dialogCreateAlert("Error", "Can't write password")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)

def readSalt(self):
try:
sqlitepipe = subprocess.Popen(["su", "-c", "sqlite3 -batch \
/data/system/locksettings.db \"SELECT value FROM locksettings WHERE name = 'lockscreen.password_salt'\""],
stdout = subprocess.PIPE)
sqliteoutput = sqlitepipe.communicate()[0].splitlines()[0].strip()
salt=long(sqliteoutput)
if sqlitepipe.returncode == 0 and sqliteoutput == str(salt):
return salt
except:
pass
self.droid.dialogCreateAlert("Error", "Can't read salt")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
sys.exit(1)

def saltToHex(self,saltlong):
blob=struct.pack(">q",saltlong)
longagain=struct.unpack(">Q",blob)[0]
hexstr=hex(longagain).lstrip("0x").rstrip("L")
return hexstr.lower()

def hashPinOriginal(self,pin,salt):
# this is what google is doing in stock android
salted=str(pin)+self.saltToHex(salt)
md5str=hashlib.md5(salted).hexdigest()
sha1str=hashlib.sha1(salted).hexdigest()
return (sha1str+md5str).upper()

def hashPinSamsung(self,pin,salt):
# samsung has modified the code, at least on the GT-I9100
salted=str(pin)+self.saltToHex(salt)
hashbuf=str()
i=0
while i < 1024:
hashbuf=hashlib.sha1(hashbuf+str(i)+salted).digest()
i=i+1
return binascii.hexlify(hashbuf).upper()

def checkCurrentPassword(self,salt):
pwd = self.droid.dialogGetInput('Enter current Password').result
if not pwd:
return False

pwdfile=self.getFileContent("/data/system/password.key")
pwdhash=self.hashPinOriginal(pwd,salt)

if pwdhash == pwdfile:
return "original"
else:
pwdhash=self.hashPinSamsung(pwd,salt)
if pwdhash == pwdfile:
return "samsung"
else:
self.droid.dialogCreateAlert("Error", "Password hash compare mismatch")
self.droid.dialogSetNeutralButtonText('Abort')
self.droid.dialogShow()
return False

def setNewPin(self):
salt=self.readSalt()
curpwdtype=self.checkCurrentPassword(salt)
if not curpwdtype:
return False
newpin = self.askNewPin()
if not newpin:
return False
if curpwdtype == "original":
newhash=self.hashPinOriginal(newpin,salt)
elif curpwdtype == "samsung":
newhash=self.hashPinSamsung(newpin,salt)
else:
return
self.createBackup()
self.writePassword(newhash)
# pwd types:
# 65536 = no protection
# 131072 = numeric pin
# 262144 = alphanumeric password
self.writePasswordType(131072)
self.droid.dialogCreateAlert("Success", "New Password written")
self.droid.dialogSetPositiveButtonText('Ok')
self.droid.dialogShow()

def run(self):
self.sqliteFound()
if self.getFileContent("/data/system/password.sav") != None:
self.droid.dialogCreateAlert("Backup found", "Restore from backup or set new PIN?")
self.droid.dialogSetPositiveButtonText('Restore')
self.droid.dialogSetNegativeButtonText('Set PIN')
self.droid.dialogShow()
if self.droid.dialogGetResponse().result['which'] == 'positive':
self.restoreBackup()
if self.droid.dialogGetResponse().result['which'] == 'negative':
self.setNewPin()
else:
self.setNewPin()

pinchange = PinChange()
pinchange.run()

5) Run the sl4a app, select the script, select the icon of a "command window" to run it. Follow the prompts on screen to enter your old password, then the new desired PIN.

6) If all goes well, you will now have a PIN (numerical) lockscreen with the code of your choosing, and encryption via the password. The former is needed when you unlock the phone each time. The latter is used when you reboot the phone.

7) (optional) If you wish to change your encryption password in future, use the app EncPassChanger (http://xdaforums.com/showthread.php?t=1732856), since using the Android interface in security will change your lockscreen again. If you do it by mistake, simply use the python script again per step 5. That can also be done if you wish to change your numerical PIN in future.

How it works: The python script (See reference) was modified by myself to look at the right database for lockscreen. Either Samsung or JB has changed the location of these settings, so I tweaked the script to access the right databases. The script simply changes the type of lock on the device manually, without changing the volume encryption password. This bypasses the Samsung-imposed requirement of 6 characters for your "password" to unlock the screen too, as that's enforced at time of entering it in the UI.

Hope this helps someone, and please consider encrypting your phone - it's worth it in the long run to save a lot of hassle in the future if you ever lose it or it gets stolen.

References:

http://xdaforums.com/showthread.php?t=1680857

http://xdaforums.com/showthread.php?t=1732856