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.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Master Android Encryption: From MD5 to RSA with Java Code

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 version

Project

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.

Hashcryptographyasymmetricsymmetric
Python Crawling & Data Mining
Written by

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!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.