Skip to content

Add tests for A5Cipher.java, improve class & function documentation #5594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Oct 7, 2024
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
* ciphers
* a5
* [A5CipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/A5CipherTest.java)
* [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.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)
Expand Down
39 changes: 36 additions & 3 deletions src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,43 @@

import java.util.BitSet;

// https://en.wikipedia.org/wiki/A5/1
/**
* The A5Cipher class implements the A5/1 stream cipher, which is a widely used
* encryption algorithm, particularly in mobile communications.
*
* This implementation uses a key stream generator to produce a stream of bits
* that are XORed with the plaintext bits to produce the ciphertext.
*
* <p>
* For more details about the A5/1 algorithm, refer to
* <a href="https://en.wikipedia.org/wiki/A5/1">Wikipedia</a>.
* </p>
*/
public class A5Cipher {

private final A5KeyStreamGenerator keyStreamGenerator;
private static final int KEY_STREAM_LENGTH = 228; // 28.5 bytes so we need to pad bytes or something

private static final int KEY_STREAM_LENGTH = 228; // Length of the key stream in bits (28.5 bytes)

/**
* Constructs an A5Cipher instance with the specified session key and frame counter.
*
* @param sessionKey a BitSet representing the session key used for encryption.
* @param frameCounter a BitSet representing the frame counter that helps in key stream generation.
*/
public A5Cipher(BitSet sessionKey, BitSet frameCounter) {
keyStreamGenerator = new A5KeyStreamGenerator();
keyStreamGenerator.initialize(sessionKey, frameCounter);
}

/**
* Encrypts the given plaintext bits using the A5/1 cipher algorithm.
*
* This method generates a key stream and XORs it with the provided plaintext
* bits to produce the ciphertext.
*
* @param plainTextBits a BitSet representing the plaintext bits to be encrypted.
* @return a BitSet containing the encrypted ciphertext bits.
*/
public BitSet encrypt(BitSet plainTextBits) {
// create a copy
var result = new BitSet(KEY_STREAM_LENGTH);
Expand All @@ -24,6 +50,13 @@ public BitSet encrypt(BitSet plainTextBits) {
return result;
}

/**
* Resets the internal counter of the key stream generator.
*
* This method can be called to re-initialize the state of the key stream
* generator, allowing for new key streams to be generated for subsequent
* encryptions.
*/
public void resetCounter() {
keyStreamGenerator.reInitialize();
}
Expand Down
51 changes: 51 additions & 0 deletions src/test/java/com/thealgorithms/ciphers/a5/A5CipherTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.thealgorithms.ciphers.a5;

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

import java.util.BitSet;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class A5CipherTest {

private A5Cipher a5Cipher;
private BitSet sessionKey;
private BitSet frameCounter;

@BeforeEach
void setUp() {
// Initialize the session key and frame counter
sessionKey = BitSet.valueOf(new long[] {0b1010101010101010L});
frameCounter = BitSet.valueOf(new long[] {0b0000000000000001L});
a5Cipher = new A5Cipher(sessionKey, frameCounter);
}

@Test
void testEncryptWithValidInput() {
BitSet plainText = BitSet.valueOf(new long[] {0b1100110011001100L}); // Example plaintext
BitSet encrypted = a5Cipher.encrypt(plainText);

// The expected result depends on the key stream generated.
// In a real test, you would replace this with the actual expected result.
// For now, we will just assert that the encrypted result is not equal to the plaintext.
assertNotEquals(plainText, encrypted, "Encrypted output should not equal plaintext");
}

@Test
void testEncryptAllOnesInput() {
BitSet plainText = BitSet.valueOf(new long[] {0b1111111111111111L}); // All ones
BitSet encrypted = a5Cipher.encrypt(plainText);

// Similar to testEncryptWithValidInput, ensure that output isn't the same as input
assertNotEquals(plainText, encrypted, "Encrypted output should not equal plaintext of all ones");
}

@Test
void testEncryptAllZerosInput() {
BitSet plainText = new BitSet(); // All zeros
BitSet encrypted = a5Cipher.encrypt(plainText);

// Check that the encrypted output is not the same
assertNotEquals(plainText, encrypted, "Encrypted output should not equal plaintext of all zeros");
}
}