Skip to content

Instantly share code, notes, and snippets.

@sweis
Last active September 30, 2015 04:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sweis/eb9d9a4b43946b685208 to your computer and use it in GitHub Desktop.
Save sweis/eb9d9a4b43946b685208 to your computer and use it in GitHub Desktop.
Cryptfs from Secret's Android App
//package ly.secret.android.net;
/**
* This is source code derived from the Cryptfs class found in Secret.ly's android app.
*
* Comments and variable names are my own.
*
* Here's how I generated this file:
* 1. Downloaded the Secret.ly APK via this link:
* http://storage.evozi.com/apk/dl/14/05/21/ly.secret.android.apk?vc=1600040
* 2. Unzipped the APK
* 3. Used dex2jar (https://code.google.com/p/dex2jar/) to convert the
* classes.dex to a jar file
* 4. Unpacked the jar
* 5. Looked for instances of "aes", "sha-1", "md5", etc. in the ly.secret package:
* $ find . -name "*.class" | grep "ly" | xargs javap -c | less
* 6. Noticed the ly/secret/android/net/Crypts.class
* 7. Used JD-GUI (http://jd.benow.ca/) to generate some source code
* 8. Manually renamed variables and cleaned up code to make it readable.
*/
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
final class Crypts {
private static final byte[] ZERO_PADDING = new byte[64];
static byte[] encrypt(byte[] inputArray, byte[] keyValue) throws Exception {
byte[] sha256HashOfKeyValue =
MessageDigest.getInstance("SHA-256").digest(keyValue);
// Why are they padding with zeros?
byte[] inputPaddedWithZeros = mergeArrays(inputArray, ZERO_PADDING);
// Using a fixed zero-value IV for CBC
byte[] IV = new byte[16];
// This throws a NoSuchAlgorithmException for the default Java 6 and 7
// providers due to the PKCS7 padding
Cipher aesCbcCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
// Maybe they're using a different provider or this class is never used.
// I had to replace PKCS7 with PKCS5 to get it to work:
// Cipher aesCbcCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCbcCipher.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(sha256HashOfKeyValue, "AES"),
new IvParameterSpec(IV));
byte[] ciphertext = aesCbcCipher.doFinal(inputPaddedWithZeros);
// Using the same key for MAC as encryption
SecretKeySpec hmacMD5Key = new SecretKeySpec(sha256HashOfKeyValue, "HmacMD5");
Mac localMac = Mac.getInstance(hmacMD5Key.getAlgorithm());
localMac.init(hmacMD5Key);
// Forgot to HMAC the IV.
// Also they are MACing the plaintext, not the ciphertext.
localMac.update(inputPaddedWithZeros);
byte[] hmac = localMac.doFinal();
return mergeArrays(ciphertext, hmac);
}
// This method was generated from com.google.common.primitives.Bytes
// Merged and made readable manually.
static byte[] mergeArrays(byte[]... arraysToMerge) {
int totalLen = 0;
for (int i = 0; i < arraysToMerge.length; i++) {
totalLen += arraysToMerge[i].length;
}
byte[] outputArray = new byte[totalLen];
int outputIndexPosition = 0;
for (int i = 0; i < arraysToMerge.length; i++) {
System.arraycopy(arraysToMerge[i], 0,
outputArray, outputIndexPosition,
arraysToMerge[i].length);
outputIndexPosition += arraysToMerge[i].length;
}
return outputArray;
}
public static void main(String[] args) throws Exception {
byte[] ciphertext = encrypt("hello".getBytes(), "world".getBytes());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment