From 93cfa86a97c9c13a7387f4e39388261eb1f90282 Mon Sep 17 00:00:00 2001 From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:53:21 +0530 Subject: [PATCH] Add tests for `A5KeyStreamGenerator.java`, improve documentation (#5595) --- DIRECTORY.md | 1 + .../ciphers/a5/A5KeyStreamGenerator.java | 69 ++++++++++++++++++- .../ciphers/a5/A5KeyStreamGeneratorTest.java | 60 ++++++++++++++++ 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java diff --git a/DIRECTORY.md b/DIRECTORY.md index 2b4dc078c..6e9524120 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -633,6 +633,7 @@ * [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java) * ciphers * a5 + * [A5KeyStreamGeneratorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java) * [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java) * [AutokeyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AutokeyTest.java) * [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java) diff --git a/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java b/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java index 0b17a685b..ee837ef42 100644 --- a/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java +++ b/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java @@ -2,15 +2,39 @@ package com.thealgorithms.ciphers.a5; import java.util.BitSet; -// TODO: raise exceptions for improper use +/** + * The A5KeyStreamGenerator class is responsible for generating key streams + * for the A5/1 encryption algorithm using a combination of Linear Feedback Shift Registers (LFSRs). + * + *
+ * This class extends the CompositeLFSR and initializes a set of LFSRs with + * a session key and a frame counter to produce a pseudo-random key stream. + *
+ * + *+ * Note: Proper exception handling for invalid usage is to be implemented. + *
+ */ public class A5KeyStreamGenerator extends CompositeLFSR { private BitSet initialFrameCounter; private BitSet frameCounter; private BitSet sessionKey; private static final int INITIAL_CLOCKING_CYCLES = 100; - 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; + /** + * Initializes the A5KeyStreamGenerator with the specified session key and frame counter. + * + *+ * This method sets up the internal state of the LFSRs using the provided + * session key and frame counter. It creates three LFSRs with specific + * configurations and initializes them. + *
+ * + * @param sessionKey a BitSet representing the session key used for key stream generation. + * @param frameCounter a BitSet representing the frame counter that influences the key stream. + */ @Override public void initialize(BitSet sessionKey, BitSet frameCounter) { this.sessionKey = sessionKey; @@ -26,10 +50,26 @@ public class A5KeyStreamGenerator extends CompositeLFSR { registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter)); } + /** + * Re-initializes the key stream generator with the original session key + * and frame counter. This method restores the generator to its initial + * state. + */ public void reInitialize() { this.initialize(sessionKey, initialFrameCounter); } + /** + * Generates the next key stream of bits. + * + *+ * This method performs an initial set of clocking cycles and then retrieves + * a key stream of the specified length. After generation, it re-initializes + * the internal registers. + *
+ * + * @return a BitSet containing the generated key stream bits. + */ public BitSet getNextKeyStream() { for (int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle) { this.clock(); @@ -45,12 +85,37 @@ public class A5KeyStreamGenerator extends CompositeLFSR { return result; } + /** + * Re-initializes the registers for the LFSRs. + * + *+ * This method increments the frame counter and re-initializes each LFSR + * with the current session key and frame counter. + *
+ */ private void reInitializeRegisters() { incrementFrameCounter(); registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter)); } + /** + * Increments the current frame counter. + * + *+ * This method uses a utility function to increment the frame counter, + * which influences the key stream generation process. + *
+ */ private void incrementFrameCounter() { Utils.increment(frameCounter, FRAME_COUNTER_LENGTH); } + + /** + * Retrieves the current frame counter. + * + * @return a BitSet representing the current state of the frame counter. + */ + public BitSet getFrameCounter() { + return frameCounter; + } } diff --git a/src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java b/src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java new file mode 100644 index 000000000..bb18d4500 --- /dev/null +++ b/src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java @@ -0,0 +1,60 @@ +package com.thealgorithms.ciphers.a5; + +import static com.thealgorithms.ciphers.a5.A5KeyStreamGenerator.FRAME_COUNTER_LENGTH; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.BitSet; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class A5KeyStreamGeneratorTest { + + private A5KeyStreamGenerator keyStreamGenerator; + private BitSet sessionKey; + private BitSet frameCounter; + + @BeforeEach + void setUp() { + keyStreamGenerator = new A5KeyStreamGenerator(); + + // Initialize session key and frame counter for testing + sessionKey = BitSet.valueOf(new long[] {0b1010101010101010L}); // Example 16-bit key + frameCounter = BitSet.valueOf(new long[] {0b0000000000000001L}); // Example 16-bit frame counter + keyStreamGenerator.initialize(sessionKey, frameCounter); + } + + @Test + void testInitialization() { + // Verify that the internal state is set up correctly + assertNotNull(keyStreamGenerator, "KeyStreamGenerator should be initialized"); + } + + @Test + void testIncrementFrameCounter() { + // Generate key stream to increment the frame counter + keyStreamGenerator.getNextKeyStream(); + + // The frame counter should have been incremented + BitSet incrementedFrameCounter = keyStreamGenerator.getFrameCounter(); + + // Check if the incremented frame counter is expected + BitSet expectedFrameCounter = (BitSet) frameCounter.clone(); + Utils.increment(expectedFrameCounter, FRAME_COUNTER_LENGTH); + + assertEquals(expectedFrameCounter, incrementedFrameCounter, "Frame counter should be incremented after generating key stream"); + } + + @Test + void testGetNextKeyStreamProducesDifferentOutputs() { + // Generate a key stream + BitSet firstKeyStream = keyStreamGenerator.getNextKeyStream(); + + // Generate another key stream + BitSet secondKeyStream = keyStreamGenerator.getNextKeyStream(); + + // Assert that consecutive key streams are different + assertNotEquals(firstKeyStream, secondKeyStream, "Consecutive key streams should be different"); + } +}