Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing AES-256-CBC Cryptography on Android

Tech 1

Symmetric cryptography relies on a single shared secret for both encoding and decoding operations, contrasting with asymmetric systems that utilize distinct public and private key pairs. While asymmetric methods offer superior security for key distribution and certificate validation, their computational overhead introduces latency. Conversely, symmetric algorithms execute rapidly, making them ideal for high-throughput scenarios such as VPN tunnels or proxy communciations where data confidentiality must be maintained without degrading network performance.

Implementing 256-bit Advanced Encryption Standard in Cipher Block Chaining mode on Android requires careful management of the initialization vector (IV) and key material. The following implementation demonstrates a robust approach using standard cryptographic APIs, ensuring the IV is uniquely generated per operation and safely transported alongside the payload.

import android.util.Base64;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public final class CipherEngine {

    private static final String ALGORITHM = "AES/CBC/PKCS7Padding";
    private static final int VECTOR_SIZE = 16;

    public static String transformToCiphertext(String input, String hexKey) {
        if (input == null || hexKey == null) return null;
        try {
            SecretKeySpec keySpec = new SecretKeySpec(hexToBytes(hexKey), "AES");
            byte[] initializationVector = new byte[VECTOR_SIZE];
            new SecureRandom().nextBytes(initializationVector);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(initializationVector));
            byte[] encryptedData = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));

            byte[] mergedPayload = new byte[VECTOR_SIZE + encryptedData.length];
            System.arraycopy(initializationVector, 0, mergedPayload, 0, VECTOR_SIZE);
            System.arraycopy(encryptedData, 0, mergedPayload, VECTOR_SIZE, encryptedData.length);

            return Base64.encodeToString(mergedPayload, Base64.NO_WRAP);
        } catch (Exception e) {
            throw new RuntimeException("Encryption operation failed", e);
        }
    }

    public static String restorePlaintext(String encodedPayload, String hexKey) {
        if (encodedPayload == null || hexKey == null) return null;
        try {
            SecretKeySpec keySpec = new SecretKeySpec(hexToBytes(hexKey), "AES");
            byte[] mergedData = Base64.decode(encodedPayload, Base64.NO_WRAP);

            byte[] ivSegment = Arrays.copyOfRange(mergedData, 0, VECTOR_SIZE);
            byte[] cipherSegment = Arrays.copyOfRange(mergedData, VECTOR_SIZE, mergedData.length);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivSegment));
            byte[] originalBytes = cipher.doFinal(cipherSegment);

            return new String(originalBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("Decryption operation failed", e);
        }
    }

    private static byte[] hexToBytes(String hex) {
        int len = hex.length();
        byte[] buffer = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            buffer[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return buffer;
    }
}

The user interface consists of a text input field paired with two action buttons, structured within a constraint-based layout.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".CryptoDemoActivity">

    <EditText
        android:id="@+id/inputField"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Enter text to process"
        android:inputType="textMultiLine"
        android:minLines="3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/encodeAction"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Encode"
        app:layout_constraintEnd_toStartOf="@+id/decodeAction"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/inputField" />

    <Button
        android:id="@+id/decodeAction"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Decode"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/encodeAction"
        app:layout_constraintTop_toBottomOf="@id/inputField" />

</androidx.constraintlayout.widget.ConstraintLayout>

The activity bridges the UI components with the cryptographic engine, handling click events and logging the transformation results.

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.security.SecureRandom;

public class CryptoDemoActivity extends AppCompatActivity {

    private static final String TAG = "CryptoOperations";
    private EditText inputView;
    private Button encodeBtn;
    private Button decodeBtn;
    private String activeKey;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_crypto_demo);
        initializeComponents();
    }

    private void initializeComponents() {
        inputView = findViewById(R.id.inputField);
        encodeBtn = findViewById(R.id.encodeAction);
        decodeBtn = findViewById(R.id.decodeAction);

        encodeBtn.setOnClickListener(v -> processInput(true));
        decodeBtn.setOnClickListener(v -> processInput(false));
    }

    private void processInput(boolean isEncoding) {
        String currentText = inputView.getText().toString().trim();
        if (currentText.isEmpty()) {
            Toast.makeText(this, "Please provide text", Toast.LENGTH_SHORT).show();
            return;
        }

        if (isEncoding) {
            activeKey = generateHexKey();
            String encryptedResult = CipherEngine.transformToCiphertext(currentText, activeKey);
            inputView.setText(encryptedResult);
            Log.d(TAG, "Original: " + currentText);
            Log.d(TAG, "Generated Key: " + activeKey);
        } else {
            if (activeKey == null) {
                Toast.makeText(this, "Key missing. Encode first.", Toast.LENGTH_SHORT).show();
                return;
            }
            String decryptedResult = CipherEngine.restorePlaintext(currentText, activeKey);
            inputView.setText(decryptedResult);
            Log.d(TAG, "Ciphertext: " + currentText);
            Log.d(TAG, "Restored: " + decryptedResult);
        }
    }

    private String generateHexKey() {
        byte[] raw = new byte[32];
        new SecureRandom().nextBytes(raw);
        StringBuilder hex = new StringBuilder(64);
        for (byte b : raw) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.