Master Android Encryption: From MD5 to RSA with Java Code
This tutorial explains why encryption matters in Android reverse engineering, distinguishes standard and custom algorithms, lists common hash, symmetric, and asymmetric methods, and provides complete Java code examples for Hex, Base64, MD5, SHA‑1, MAC, DES, 3DES, AES, and RSA, all runnable in Android Studio.
Why Learn Encryption Algorithms
When reverse‑engineering Android apps, you often encounter mysterious strings such as 81dc9bdb52d04dc20036dbd8313ed055; these are results of encryption algorithms, which are divided into two major categories: standard algorithms (identical across languages) and non‑standard algorithms (custom implementations).
Common Standard Algorithms
Message digest (hash) algorithms: MD5, SHA, MAC
Symmetric encryption: DES, 3DES, AES
Asymmetric encryption: RSA
Digital signature: MD5withRSA, SHA1withRSA, SHA256withRSA
For Android reverse engineering, we will reproduce the most commonly used standard algorithms.
My Environment
AndroidStudio 2020.3.1 version
Jdk 8 versionProject
CryptologyDemo.zip
Hex and Base64
Hex and Base64 are not encryption; they are encoding methods used to represent binary data as readable strings. They are the most common encodings for displaying encrypted results.
Adding Dependency
api 'com.squareup.okhttp3:okhttp:3.10.0'Remember to click Sync Now .
Hex
Hex encoding uses 16 characters (0‑9 a‑f) to represent any binary data; it is an encoding, not encryption, and is often used to display MD5 results.
Code
// from string to hex
byte[] bytes = "zhangsan".getBytes(StandardCharsets.UTF_8);
ByteString of = ByteString.of(bytes);
String hex = of.hex();
Log.d(TAG, "hex:" + hex);Example
Base64
Base64 uses 64 characters (A‑Z a‑z 0‑9 + / =) to represent binary data; it is also an encoding, widely used for images, long ciphertexts, and files.
Code
// from string to base64
byte[] bytes = "zhangsan".getBytes(StandardCharsets.UTF_8);
ByteString of = ByteString.of(bytes);
String base64 = of.base64();
Log.d(TAG, "base64_1:" + base64);
// alternative using java.util.Base64
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
String s = Base64.getEncoder().encodeToString("zhangsan".getBytes(StandardCharsets.UTF_8));
byte[] encode = Base64.getEncoder().encode("zhangsan".getBytes(StandardCharsets.UTF_8));
Log.d(TAG, "base64_2:" + s);
Log.d(TAG, "base64_2:" + new String(encode));
}
// Android util Base64
String s = android.util.Base64.encodeToString("zhangsan".getBytes(StandardCharsets.UTF_8), 0);
Log.d(TAG, "base64_3:" + new String(s));Example
Message Digest Algorithms
Message digests are one‑way functions; the ciphertext cannot be reversed. They produce fixed‑length output from variable‑length input.
MD5
MD5 processes data via MessageDigest, then typically displays the result in hex.
MD Series Table
Algorithm
Digest Length
Implementation
MD2
128
Java6
MD5
128
Java6
MD5
128
Bouncy Castle
Code
// md5
public static String md5(String plainText) throws Exception {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(plainText.getBytes(StandardCharsets.UTF_8));
byte[] digest = md5.digest();
ByteString of = ByteString.of(digest);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}SHA
SHA‑1 is the most common; switching the algorithm name yields other SHA variants.
SHA Series Table
Algorithm
Digest Length
Implementation
SHA‑1
160
Java6
SHA‑256
256
Java6
SHA‑384
384
Java6
SHA‑512
512
Java6
SHA‑224
224
Bouncy Castle
Code
// SHA‑1
public static String sha_1(String plainText) throws Exception {
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update(plainText.getBytes(StandardCharsets.UTF_8));
byte[] digest = sha1.digest();
ByteString of = ByteString.of(digest);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}MAC
MAC adds a secret key to the hash process, providing authentication.
MAC Series Table
Algorithm
Digest Length
Implementation
HmacMD5
128
Java6
HmacSHA1
160
Java6
HmacSHA256
256
Java6
HmacSHA384
384
Java6
HmacSHA512
512
Java6
HmacMD2
128
Java6
HmacMD4
128
Bouncy Castle
HmacSHA224
224
Bouncy Castle
Code
public static String mac(String plainText) throws Exception {
SecretKeySpec hmacMD5 = new SecretKeySpec("123".getBytes(StandardCharsets.UTF_8), "HmacMD5");
Mac instance = Mac.getInstance(hmacMD5.getAlgorithm());
instance.init(hmacMD5);
instance.update(plainText.getBytes(StandardCharsets.UTF_8));
byte[] doFinal = instance.doFinal();
ByteString of = ByteString.of(doFinal);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}Symmetric Encryption Algorithms
Symmetric algorithms use the same key for encryption and decryption, unlike asymmetric algorithms.
DES
DES supports ECB and CBC modes; CBC requires an IV vector.
DES ECB Encryption
public static String des_encrypt_ECB(String plainText) throws Exception {
SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(StandardCharsets.UTF_8), "DES");
Cipher instance = Cipher.getInstance("DES/ECB/PKCS5Padding");
instance.init(Cipher.ENCRYPT_MODE, desKey);
byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
ByteString of = ByteString.of(doFinal);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}DES CBC Encryption
public static String des_encrypt_CBC(String plainText) throws Exception {
SecretKeySpec desKey = new SecretKeySpec("12345678".getBytes(StandardCharsets.UTF_8), "DES");
Cipher instance = Cipher.getInstance("DES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("12345678".getBytes());
instance.init(Cipher.ENCRYPT_MODE, desKey, iv);
byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
ByteString of = ByteString.of(doFinal);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}DESede (3DES/TripleDES)
public static String DESede_encrypt(String plainText) throws Exception {
SecretKeySpec desKey = new SecretKeySpec("123456781234567812345678".getBytes(), "DESede");
Cipher instance = Cipher.getInstance("DESede/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("12345678".getBytes());
instance.init(Cipher.ENCRYPT_MODE, desKey, iv);
byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
ByteString of = ByteString.of(doFinal);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}
public static String DESede_decrypt(byte[] cipherBytes) throws Exception {
SecretKeySpec desKey = new SecretKeySpec("123456781234567812345678".getBytes(StandardCharsets.UTF_8), "DESede");
Cipher instance = Cipher.getInstance("DESede/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("12345678".getBytes());
instance.init(Cipher.DECRYPT_MODE, desKey, iv);
byte[] doFinal = instance.doFinal(cipherBytes);
return new String(doFinal);
}AES
public static String AES_encrypt(String plainText) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789abcdef".getBytes(), "AES");
Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
instance.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] doFinal = instance.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
ByteString of = ByteString.of(doFinal);
String hex = of.hex();
String base64 = of.base64();
return hex + "||" + base64;
}
public static String AES_decrypt(byte[] cipherBytes) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec("0123456789abcdef".getBytes(), "AES");
Cipher instance = Cipher.getInstance("AES/ECB/PKCS5Padding");
instance.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] doFinal = instance.doFinal(cipherBytes);
return new String(doFinal);
}Asymmetric Encryption (RSA)
RSA uses a public key for encryption and a private key for decryption (or vice‑versa). Keys must be in proper formats (X.509 for public, PKCS8 for private).
RSA Code
public static PublicKey generatePublic(String publicKeyBase64) throws Exception {
byte[] bytes = ByteString.decodeBase64(publicKeyBase64).toByteArray();
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
public static PrivateKey generatePrivate(String privateKeyBase64) throws Exception {
byte[] bytes = ByteString.decodeBase64(privateKeyBase64).toByteArray();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
public static String RSAPrivateDecrypt(byte[] cipherBytes) throws Exception {
String BEGIN_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMOVkFb2U8aOxLZr..."; // truncated for brevity
PrivateKey privateKey = generatePrivate(BEGIN_PRIVATE_KEY);
Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
instance.init(Cipher.DECRYPT_MODE, privateKey);
byte[] doFinal = instance.doFinal(cipherBytes);
return new String(doFinal);
}
public static String RSAPublicEncrypt(String plainText) throws Exception {
String BEGIN_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDlZBW9lPGjsS2a7/0f1av/Prw..."; // truncated
PublicKey publicKey = generatePublic(BEGIN_PUBLIC_KEY);
Cipher instance = Cipher.getInstance("RSA/ECB/PKCS1Padding");
instance.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] doFinal = instance.doFinal(plainText.getBytes());
ByteString of = ByteString.of(doFinal);
return of.base64();
}Summary
The article covered three major categories of encryption algorithms used in Java/Android: message digest (MD5, SHA‑1, MAC), symmetric encryption (DES, 3DES, AES), and asymmetric encryption (RSA). It highlighted how to generate digests with MessageDigest, MACs with Mac, and encrypt/decrypt data with Cipher, providing ready‑to‑run code snippets for each algorithm.
Python Crawling & Data Mining
Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
