Signal database password on Android
#1
I want to test recover of my old Signal Android database password with Hashcat.  The sourcecode for the app https://github.com/signalapp/Signal-Andr...ecret.java makes it look like database uses PBDKF2 with SHA1 but when I try crack known password using hashcat format 12000 sha1:iteration:hashConfusedalt I exhaust the guesses. The hash ends in = and salt in == so that looks right, but I notice Signal doing some weird PCKS 5 stuff in https://github.com/signalapp/Signal-Andr...tUtil.java

Can I use last 20 bytes of mastersecret or is there AES component prior to PBKDF2 comparison?
Reply
#2
Usually the hash output is used as a key for the encryption. Having the hash in the file would mean the AES key is in the file which they are very likely not doing. Hence you have to use the pbkdf2 result as AES key and decrypt the data (at least in parts) and verify it's what you expect.
Reply
#3
I looked at code and the problem might be Android crypto objects, but maybe someone understand:

Code:
 public static MasterSecret getMasterSecret(Context context, String passphrase)
     throws InvalidPassphraseException
 {
   try {
     byte[] encryptedAndMacdMasterSecret = retrieve(context, "master_secret");
     byte[] macSalt                      = retrieve(context, "mac_salt");
     int    iterations                   = retrieve(context, "passphrase_iterations", 100);
     byte[] encryptedMasterSecret        = verifyMac(macSalt, iterations, encryptedAndMacdMasterSecret, passphrase);
     byte[] encryptionSalt               = retrieve(context, "encryption_salt");
     byte[] combinedSecrets              = decryptWithPassphrase(encryptionSalt, iterations, encryptedMasterSecret, passphrase);
     byte[] encryptionSecret             = Util.split(combinedSecrets, 16, 20)[0];
     byte[] macSecret                    = Util.split(combinedSecrets, 16, 20)[1];

     return new MasterSecret(new SecretKeySpec(encryptionSecret, "AES"),
                             new SecretKeySpec(macSecret, "HmacSHA1"));
   } catch (GeneralSecurityException e) {
     Log.w("keyutil", e);
     return null; //XXX
   } catch (IOException e) {
     Log.w("keyutil", e);
     return null; //XXX
   }
}

I have all the above data and I see SHA1 so I think great, will be easy and can just compare the MAC:
Code:
 private static byte[] verifyMac(byte[] macSalt, int iterations, byte[] encryptedAndMacdData, String passphrase) throws InvalidPassphraseException, GeneralSecurityException, IOException {
   Mac hmac        = getMacForPassphrase(passphrase, macSalt, iterations);

   byte[] encryptedData = new byte[encryptedAndMacdData.length - hmac.getMacLength()];
   System.arraycopy(encryptedAndMacdData, 0, encryptedData, 0, encryptedData.length);

   byte[] givenMac      = new byte[hmac.getMacLength()];
   System.arraycopy(encryptedAndMacdData, encryptedAndMacdData.length-hmac.getMacLength(), givenMac, 0, givenMac.length);

   byte[] localMac      = hmac.doFinal(encryptedData);

   if (Arrays.equals(givenMac, localMac)) return encryptedData;
   else                                   throw new InvalidPassphraseException("MAC Error");
}

Code:
 private static Mac getMacForPassphrase(String passphrase, byte[] salt, int iterations)
     throws GeneralSecurityException
 {
   SecretKey     key     = getKeyFromPassphrase(passphrase, salt, iterations);
   byte[]        pbkdf2  = key.getEncoded();
   SecretKeySpec hmacKey = new SecretKeySpec(pbkdf2, "HmacSHA1");
   Mac           hmac    = Mac.getInstance("HmacSHA1");
   hmac.init(hmacKey);

   return hmac;
}

But then I do further and getKeyFromPassphrase() does something different:
Code:
 private static SecretKey getKeyFromPassphrase(String passphrase, byte[] salt, int iterations)
     throws GeneralSecurityException
 {
   PBEKeySpec keyspec    = new PBEKeySpec(passphrase.toCharArray(), salt, iterations);
   SecretKeyFactory skf  = SecretKeyFactory.getInstance("PBEWITHSHA1AND128BITAES-CBC-BC");
   return skf.generateSecret(keyspec);
}

There is AES step?  I try to run code backward in jshell but get NoSuchAlgorithmException on second line. 

What hashcat mode correspond to this operation?  It look like it should be PBKDF2-HMAC-SHA1 but hashcat exhausted a list with known password.  Can two hashcat mode be run consecutive?

I test the bytes 17-37 in the Signal master_secret as the hash, then use the mac_salt and passphrase_iterations in mode 12000.

Signal is popular - if hashcat cannot crack it should add support!
Reply