mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-07 01:35:16 +08:00
Add tests for A5KeyStreamGenerator.java
, improve documentation (#5595)
This commit is contained in:
@ -633,6 +633,7 @@
|
|||||||
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
|
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
|
||||||
* ciphers
|
* ciphers
|
||||||
* a5
|
* 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)
|
* [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)
|
* [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)
|
* [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
|
||||||
|
@ -2,15 +2,39 @@ package com.thealgorithms.ciphers.a5;
|
|||||||
|
|
||||||
import java.util.BitSet;
|
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 {
|
public class A5KeyStreamGenerator extends CompositeLFSR {
|
||||||
|
|
||||||
private BitSet initialFrameCounter;
|
private BitSet initialFrameCounter;
|
||||||
private BitSet frameCounter;
|
private BitSet frameCounter;
|
||||||
private BitSet sessionKey;
|
private BitSet sessionKey;
|
||||||
private static final int INITIAL_CLOCKING_CYCLES = 100;
|
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
|
@Override
|
||||||
public void initialize(BitSet sessionKey, BitSet frameCounter) {
|
public void initialize(BitSet sessionKey, BitSet frameCounter) {
|
||||||
this.sessionKey = sessionKey;
|
this.sessionKey = sessionKey;
|
||||||
@ -26,10 +50,26 @@ public class A5KeyStreamGenerator extends CompositeLFSR {
|
|||||||
registers.forEach(lfsr -> lfsr.initialize(sessionKey, 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() {
|
public void reInitialize() {
|
||||||
this.initialize(sessionKey, initialFrameCounter);
|
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() {
|
public BitSet getNextKeyStream() {
|
||||||
for (int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle) {
|
for (int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle) {
|
||||||
this.clock();
|
this.clock();
|
||||||
@ -45,12 +85,37 @@ public class A5KeyStreamGenerator extends CompositeLFSR {
|
|||||||
return result;
|
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() {
|
private void reInitializeRegisters() {
|
||||||
incrementFrameCounter();
|
incrementFrameCounter();
|
||||||
registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
|
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() {
|
private void incrementFrameCounter() {
|
||||||
Utils.increment(frameCounter, FRAME_COUNTER_LENGTH);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user