Programming lesson
Building SDPEncryptor: A Step-by-Step Android Affine Cipher App Tutorial
Learn how to build the SDPEncryptor Android app for CS6601 Assignment 4. This tutorial covers affine cipher encryption, EditText error handling, and Android Studio setup for Fall 2025.
Introduction to SDPEncryptor and the Affine Cipher
In CS6601 Assignment 4 (Fall 2025), you'll create SDPEncryptor, an Android app that encrypts messages using a simple affine cipher. This tutorial walks you through the essential steps, from setting up Android Studio to implementing the cipher logic and handling user input errors. By the end, you'll have a solid foundation for the group project. Think of this app as your own personal encryption tool — similar to how apps like Signal or WhatsApp protect messages, but with a classic cipher twist.
Why Affine Cipher? A Trendy Analogy
Affine ciphers are a type of substitution cipher that uses a linear function: E(x) = (a*x + b) mod m. This might remind you of AI models that transform inputs using mathematical functions. Or consider fintech apps that scramble transaction IDs for security. Even gaming leaderboards use similar transformations to encode player scores. The affine cipher is a simple yet powerful concept that underpins many modern encryption algorithms.
Prerequisites: Android Studio Setup
Before coding, ensure your environment matches the assignment specs:
- Package name:
edu.gatech.seclass.sdpencryptor - Language: Java (Kotlin is allowed but support is limited)
- Minimum SDK: API 34 (Android 14)
- Build configuration: Groovy DSL (
build.gradle) - Android Studio version: Ladybug Feature Drop | 2024.2.2 (or similar)
Set your compileSdk and targetSdk to 34, and use Java 17. Add these dependencies:
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.11.1'
Also enable unit test support and disable lint:
android {
testOptions {
unitTests {
includeAndroidResources = true
}
}
lintOptions {
tasks.lint.enabled = false
abortOnError false
}
}
UI Design: Widgets and Identifiers
Your app must use these exact widget IDs for auto-grading:
editTextMessage– input for the plaintext messageeditTextA– input for parameter 'a' (must be coprime to 26)editTextB– input for parameter 'b' (0-25)buttonEncrypt– triggers encryptiontextViewResult– displays the encrypted message
You can design the layout freely, but keep these IDs. A typical layout uses ConstraintLayout with EditText fields and a Button.
Affine Cipher Logic in Java
Implement the cipher in a helper method. Remember: E(x) = (a*x + b) mod 26. Only letters are encrypted; spaces and punctuation remain unchanged.
private String encrypt(String message, int a, int b) {
StringBuilder result = new StringBuilder();
for (char c : message.toCharArray()) {
if (Character.isLetter(c)) {
char base = Character.isUpperCase(c) ? 'A' : 'a';
int x = c - base;
int encrypted = (a * x + b) % 26;
if (encrypted < 0) encrypted += 26;
result.append((char) (base + encrypted));
} else {
result.append(c);
}
}
return result.toString();
}
Error Handling with setError
When the user presses the button, validate inputs and show errors using EditText.setError(). Three error situations:
- Empty message field – show "Message cannot be empty"
- Invalid 'a' (not coprime to 26) – show "'a' must be coprime to 26"
- Invalid 'b' (out of range 0-25) – show "'b' must be between 0 and 25"
Example validation code:
public void onEncryptClick(View view) {
EditText etMessage = findViewById(R.id.editTextMessage);
EditText etA = findViewById(R.id.editTextA);
EditText etB = findViewById(R.id.editTextB);
TextView tvResult = findViewById(R.id.textViewResult);
boolean valid = true;
String message = etMessage.getText().toString().trim();
if (message.isEmpty()) {
etMessage.setError("Message cannot be empty");
valid = false;
} else {
etMessage.setError(null);
}
int a = 0, b = 0;
try {
a = Integer.parseInt(etA.getText().toString());
if (gcd(a, 26) != 1) {
etA.setError("'a' must be coprime to 26");
valid = false;
} else {
etA.setError(null);
}
} catch (NumberFormatException e) {
etA.setError("Enter a valid integer");
valid = false;
}
try {
b = Integer.parseInt(etB.getText().toString());
if (b < 0 || b > 25) {
etB.setError("'b' must be between 0 and 25");
valid = false;
} else {
etB.setError(null);
}
} catch (NumberFormatException e) {
etB.setError("Enter a valid integer");
valid = false;
}
if (valid) {
String result = encrypt(message, a, b);
tvResult.setText(result);
}
}
private int gcd(int x, int y) {
while (y != 0) {
int temp = y;
y = x % y;
x = temp;
}
return x;
}
Testing Your App
Use JUnit and Robolectric for unit tests. Example test for encryption:
@Test
public void testEncrypt() {
MainActivity activity = new MainActivity();
String result = activity.encrypt("HELLO", 5, 8);
assertEquals("RCLLA", result);
}
Also test error conditions: empty fields, invalid a, etc.
Common Pitfalls and Tips
- Package name mismatch: Double-check it's
edu.gatech.seclass.sdpencryptor. - Widget IDs: Use exactly the IDs given; auto-grading depends on them.
- Affine cipher math: Ensure 'a' is coprime to 26 (i.e., gcd(a,26)=1).
- Error persistence:
setErrorremains until cleared; callsetError(null)when valid. - Build configuration: Use Groovy DSL, not Kotlin DSL.
Conclusion
By following this tutorial, you've built a functional SDPEncryptor app. This assignment not only teaches you about affine ciphers but also reinforces Android development skills like UI design, event handling, and error management. As you move to the group project, these skills will be invaluable. Remember, encryption is everywhere — from secure messaging to blockchain transactions. Happy coding!