2024-04-13 00:28:03 +02:00
#!/usr/bin/env python3
2024-04-21 15:28:24 +02:00
from random import randint
from math import log2
2024-04-13 00:28:03 +02:00
class lfsr ( object ) :
def __init__ ( self , state , taps ) :
self . state = state
self . taps = taps
# getters and setters (private attributes)
def get_state ( self ) :
return self . __state
def set_state ( self , value ) :
self . __state = value
state = property ( fget = get_state , fset = set_state , doc = " lfsr state (current bits value in lfsr) " )
def get_taps ( self ) :
return self . __taps
def set_taps ( self , valeur ) :
self . __taps = valeur
taps = property ( fget = get_taps , fset = set_taps , doc = " lfsr taps (bit positions affecting next state) " )
def shift ( self ) :
'''
calculate next state and return the output bit
'''
feedback = sum ( self . state [ tap ] for tap in self . taps ) % 2
2024-04-21 17:39:00 +02:00
output = self . state [ 0 ]
self . state = self . state [ 1 : ] + [ feedback ]
2024-04-13 00:28:03 +02:00
return output
2024-04-21 15:28:24 +02:00
def test_lfsr17 ( ) :
2024-04-21 17:48:31 +02:00
print ( " test lfsr17 " )
2024-04-21 15:28:24 +02:00
key = [ randint ( 0 , 1 ) for _ in range ( 16 ) ] # first 16 bits
key . append ( 1 ) # prevent initial state from being {0}^17
2024-04-21 17:39:00 +02:00
taps = [ 0 , 14 ]
2024-04-21 15:28:24 +02:00
lfsr17 = lfsr ( key , taps )
states = [ lfsr17 . state ]
for _ in range ( 2 * * 17 - 2 ) :
lfsr17 . shift ( )
states . append ( lfsr17 . state )
sorted_states = sorted ( states , key = lambda x : tuple ( x ) )
for i in range ( 2 * * 17 - 2 ) :
if sorted_states [ i ] == sorted_states [ i + 1 ] : # compare each state with the next state in the sorted list, if 2 states are identical they should be next to each other
print ( f ' state { sorted_states [ i ] } appears at least 2 times ' )
return False
n_state = len ( sorted_states )
n_state_log = log2 ( n_state + 1 )
2024-04-21 17:48:31 +02:00
print ( f ' all { n_state } = 2^( { n_state_log } )-1 generated states are different ' )
2024-04-21 15:28:24 +02:00
return True
2024-04-21 17:39:00 +02:00
def css_encrypt ( text , key ) :
taps17 = [ 0 , 14 ]
lfsr17 = lfsr ( ( key [ : 16 ] + [ 1 ] ) , taps17 )
taps25 = [ 0 , 3 , 4 , 12 ]
lfsr25 = lfsr ( ( key [ 16 : ] + [ 1 ] ) , taps25 )
cipher_text = 0
carry = 0
bytes = text . to_bytes ( ( text . bit_length ( ) + 7 ) / / 8 , ' big ' )
for byte in bytes :
x_b2 = " "
y_b2 = " "
# Generate bytes from lfsr17 and lfsr25
for _ in range ( 8 ) :
x_b2 + = str ( lfsr17 . shift ( ) )
y_b2 + = str ( lfsr25 . shift ( ) )
2024-04-21 17:48:31 +02:00
x = int ( x_b2 [ : : - 1 ] , 2 )
y = int ( y_b2 [ : : - 1 ] , 2 )
2024-04-21 17:39:00 +02:00
z = ( x + y + carry ) % 256
carry = 1 if x + y > 255 else 0
cipher_byte = z ^ byte
cipher_text = ( cipher_text << 8 ) | cipher_byte
return cipher_text
2024-04-21 17:48:31 +02:00
def test_encrypt ( ) :
print ( " test encryption: text 0xffffffffff, key 0x0 ∈ { 0, 1}^40 " )
cipher = css_encrypt ( 0xffffffffff , [ 0 ] * 40 )
print ( f ' cipher: { hex ( cipher ) } ' )
clear = css_encrypt ( cipher , [ 0 ] * 40 )
print ( f ' decrypted: { hex ( clear ) } ' )
print ( f ' original text and decrypted message are the same: { clear == 0xffffffffff } ' )
2024-04-21 15:28:24 +02:00
test_lfsr17 ( )
2024-04-21 17:48:31 +02:00
print ( )
test_encrypt ( )