Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@
* ciphers
* a5
* [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java)
* [AffineCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java)
* [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
* [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java)
* [DESTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/DESTest.java)
Expand Down
51 changes: 40 additions & 11 deletions src/main/java/com/thealgorithms/ciphers/AffineCipher.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
package com.thealgorithms.ciphers;

/**
* The AffineCipher class implements the Affine cipher, a type of monoalphabetic substitution cipher.
* It encrypts and decrypts messages using a linear transformation defined by the formula:
*
* E(x) = (a * x + b) mod m
* D(y) = a^-1 * (y - b) mod m
*
* where:
* - E(x) is the encrypted character,
* - D(y) is the decrypted character,
* - a is the multiplicative key (must be coprime to m),
* - b is the additive key,
* - x is the index of the plaintext character,
* - y is the index of the ciphertext character,
* - m is the size of the alphabet (26 for the English alphabet).
*
* The class provides methods for encrypting and decrypting messages, as well as a main method to demonstrate its usage.
*/
final class AffineCipher {
private AffineCipher() {
}
Expand All @@ -8,45 +26,56 @@ private AffineCipher() {
static int a = 17;
static int b = 20;

/**
* Encrypts a message using the Affine cipher.
*
* @param msg the plaintext message as a character array
* @return the encrypted ciphertext
*/
static String encryptMessage(char[] msg) {
/// Cipher Text initially empty
// Cipher Text initially empty
String cipher = "";
for (int i = 0; i < msg.length; i++) {
// Avoid space to be encrypted
/* applying encryption formula ( a x + b ) mod m
/* applying encryption formula ( a * x + b ) mod m
{here x is msg[i] and m is 26} and added 'A' to
bring it in range of ascii alphabet[ 65-90 | A-Z ] */
bring it in the range of ASCII alphabet [65-90 | A-Z] */
if (msg[i] != ' ') {
cipher = cipher + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
cipher += (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
} else { // else simply append space character
cipher += msg[i];
}
}
return cipher;
}

/**
* Decrypts a ciphertext using the Affine cipher.
*
* @param cipher the ciphertext to decrypt
* @return the decrypted plaintext message
*/
static String decryptCipher(String cipher) {
String msg = "";
int aInv = 0;
int flag = 0;
int flag;

// Find a^-1 (the multiplicative inverse of a
// in the group of integers modulo m.)
// Find a^-1 (the multiplicative inverse of a in the group of integers modulo m.)
for (int i = 0; i < 26; i++) {
flag = (a * i) % 26;

// Check if (a*i)%26 == 1,
// Check if (a * i) % 26 == 1,
// then i will be the multiplicative inverse of a
if (flag == 1) {
aInv = i;
}
}
for (int i = 0; i < cipher.length(); i++) {
/*Applying decryption formula a^-1 ( x - b ) mod m
/* Applying decryption formula a^-1 * (x - b) mod m
{here x is cipher[i] and m is 26} and added 'A'
to bring it in range of ASCII alphabet[ 65-90 | A-Z ] */
to bring it in the range of ASCII alphabet [65-90 | A-Z] */
if (cipher.charAt(i) != ' ') {
msg = msg + (char) (((aInv * ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A');
msg += (char) (((aInv * ((cipher.charAt(i) - 'A') - b + 26)) % 26) + 'A');
} else { // else simply append space character
msg += cipher.charAt(i);
}
Expand Down
39 changes: 39 additions & 0 deletions src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.thealgorithms.ciphers;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class AffineCipherTest {

@Test
public void testEncryptMessage() {
String plaintext = "AFFINE CIPHER";
char[] msg = plaintext.toCharArray();
String expectedCiphertext = "UBBAHK CAPJKX"; // Expected ciphertext after encryption

String actualCiphertext = AffineCipher.encryptMessage(msg);
assertEquals(expectedCiphertext, actualCiphertext, "The encryption result should match the expected ciphertext.");
}

@Test
public void testEncryptDecrypt() {
String plaintext = "HELLO WORLD";
char[] msg = plaintext.toCharArray();

String ciphertext = AffineCipher.encryptMessage(msg);
String decryptedText = AffineCipher.decryptCipher(ciphertext);

assertEquals(plaintext, decryptedText, "Decrypted text should match the original plaintext.");
}

@Test
public void testSpacesHandledInEncryption() {
String plaintext = "HELLO WORLD";
char[] msg = plaintext.toCharArray();
String expectedCiphertext = "JKZZY EYXZT";

String actualCiphertext = AffineCipher.encryptMessage(msg);
assertEquals(expectedCiphertext, actualCiphertext, "The encryption should handle spaces correctly.");
}
}