Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,39 @@

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).
*
* <p>
* 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.
* </p>
*
* <p>
* Note: Proper exception handling for invalid usage is to be implemented.
* </p>
*/
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.
*
* <p>
* 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.
* </p>
*
* @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;
Expand All @@ -26,10 +50,26 @@ public void initialize(BitSet sessionKey, BitSet frameCounter) {
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.
*
* <p>
* 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.
* </p>
*
* @return a BitSet containing the generated key stream bits.
*/
public BitSet getNextKeyStream() {
for (int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle) {
this.clock();
Expand All @@ -45,12 +85,37 @@ public BitSet getNextKeyStream() {
return result;
}

/**
* Re-initializes the registers for the LFSRs.
*
* <p>
* This method increments the frame counter and re-initializes each LFSR
* with the current session key and frame counter.
* </p>
*/
private void reInitializeRegisters() {
incrementFrameCounter();
registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
}

/**
* Increments the current frame counter.
*
* <p>
* This method uses a utility function to increment the frame counter,
* which influences the key stream generation process.
* </p>
*/
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;
}
}
Original file line number Diff line number Diff line change
@@ -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");
}
}