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 )
2024-04-22 12:54:38 +02:00
cipher = 0
2024-04-21 17:39:00 +02:00
carry = 0
2024-04-22 12:54:38 +02:00
if isinstance ( text , int ) :
Bytes = text . to_bytes ( ( text . bit_length ( ) + 7 ) / / 8 , ' big ' )
elif isinstance ( text , bytes ) :
Bytes = text
else :
raise TypeError ( " input text should be bytes or integer " )
for byte in Bytes :
2024-04-21 17:39:00 +02:00
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
2024-04-22 12:54:38 +02:00
# print(cipher_byte.to_bytes((cipher_byte.bit_length() + 7) // 8, 'big'))
cipher = ( cipher << 8 ) | cipher_byte
cipher_bytes = b ' \x00 ' * ( len ( Bytes ) - len ( cipher . to_bytes ( ( cipher . bit_length ( ) + 7 ) / / 8 , ' big ' ) ) ) + cipher . to_bytes ( ( cipher . bit_length ( ) + 7 ) / / 8 , ' big ' ) # padding
return cipher_bytes
2024-04-21 17:39:00 +02:00
2024-04-21 17:48:31 +02:00
def test_encrypt ( ) :
print ( " test encryption: text 0xffffffffff, key 0x0 ∈ { 0, 1}^40 " )
2024-04-22 12:54:38 +02:00
cipher = int . from_bytes ( css_encrypt ( 0xffffffffff , [ 0 ] * 40 ) , byteorder = ' big ' )
2024-04-21 17:48:31 +02:00
print ( f ' cipher: { hex ( cipher ) } ' )
2024-04-22 12:54:38 +02:00
clear = int . from_bytes ( css_encrypt ( cipher , [ 0 ] * 40 ) )
2024-04-21 17:48:31 +02:00
print ( f ' decrypted: { hex ( clear ) } ' )
print ( f ' original text and decrypted message are the same: { clear == 0xffffffffff } ' )
2024-04-22 12:54:38 +02:00
def gen_6_bytes ( ) :
# key = [randint(0, 1) for _ in range(40)]
# key = [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
key = [ 0 ] * 40
text = b ' \x00 \x00 \x00 \x00 \x00 \x00 '
print ( key )
cipher = css_encrypt ( text , key )
print ( cipher )
print ( css_encrypt ( cipher , key ) )
return cipher
2024-04-21 15:28:24 +02:00
test_lfsr17 ( )
2024-04-21 17:48:31 +02:00
print ( )
test_encrypt ( )
2024-04-22 12:54:38 +02:00
print ( )
gen_6_bytes ( )