README + comments
This commit is contained in:
parent
3f661dab69
commit
aa9e11caed
12
README.md
12
README.md
@ -1,2 +1,14 @@
|
|||||||
# IN603
|
# IN603
|
||||||
|
|
||||||
|
attack against Content Scrambling System cipher
|
||||||
|
|
||||||
|
|
||||||
|
### execution
|
||||||
|
|
||||||
|
```
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
+ 17 bits lfsr check
|
||||||
|
+ 0xffffffffff encryption and decryption test
|
||||||
|
+ testing attack in 2^16 with 6 output bytes provided against CSS n times (by default 5), with keys randomly generated
|
||||||
|
+ testing safer attack (same as above but use a 7th byte in case of a collision between 2 keys with 6 output bytes)
|
||||||
|
19
main.py
19
main.py
@ -5,8 +5,11 @@ import multiprocessing
|
|||||||
|
|
||||||
class lfsr(object):
|
class lfsr(object):
|
||||||
def __init__(self, state, taps):
|
def __init__(self, state, taps):
|
||||||
self.state = state
|
if max(taps) > len(state):
|
||||||
self.taps = taps
|
raise ValueError("inconsistent taps and initial state")
|
||||||
|
else:
|
||||||
|
self.state = state
|
||||||
|
self.taps = taps
|
||||||
|
|
||||||
# getters and setters (private attributes)
|
# getters and setters (private attributes)
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
@ -104,25 +107,30 @@ def attack_worker(start, end, Bytes, result_queue, stop_event):
|
|||||||
taps17 = [0, 14]
|
taps17 = [0, 14]
|
||||||
taps25 = [0, 3, 4, 12]
|
taps25 = [0, 3, 4, 12]
|
||||||
for i in range(start, end):
|
for i in range(start, end):
|
||||||
if stop_event.is_set():
|
if stop_event.is_set(): # stop key search as soon as one worker finds a solution
|
||||||
return
|
return
|
||||||
lfsr17_init = [int(bit) for bit in bin(i)[2:].zfill(16)]+[1]
|
lfsr17_init = [int(bit) for bit in bin(i)[2:].zfill(16)]+[1]
|
||||||
lfsr17 = lfsr(lfsr17_init, taps17)
|
lfsr17 = lfsr(lfsr17_init, taps17)
|
||||||
x = []
|
x = []
|
||||||
|
# generate first 3 output bytes from lfsr 17
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
x_bin = ""
|
x_bin = ""
|
||||||
for _ in range(8):
|
for _ in range(8):
|
||||||
x_bin += str(lfsr17.shift())
|
x_bin += str(lfsr17.shift())
|
||||||
x.append(int(x_bin[::-1], 2))
|
x.append(int(x_bin[::-1], 2))
|
||||||
|
# calculate corresponding output bytes from lfsr 25
|
||||||
y = [(Bytes[0]-x[0])%256]
|
y = [(Bytes[0]-x[0])%256]
|
||||||
c=1 if x[0]+y[0]>255 else 0
|
c=1 if x[0]+y[0]>255 else 0
|
||||||
y.append((Bytes[1]-(x[1]+c))%256)
|
y.append((Bytes[1]-(x[1]+c))%256)
|
||||||
c=1 if x[1]+y[1]>255 else 0
|
c=1 if x[1]+y[1]>255 else 0
|
||||||
y.append((Bytes[2]-(x[2]+c))%256)
|
y.append((Bytes[2]-(x[2]+c))%256)
|
||||||
|
|
||||||
lfsr25_init = [int(bit) for bit in (bin(y[0])[2:].zfill(8)[::-1] + bin(y[1])[2:].zfill(8)[::-1] + bin(y[2])[2:].zfill(8)[::-1] ) ]+[1]
|
lfsr25_init = [int(bit) for bit in (bin(y[0])[2:].zfill(8)[::-1] + bin(y[1])[2:].zfill(8)[::-1] + bin(y[2])[2:].zfill(8)[::-1] ) ]+[1]
|
||||||
lfsr25 = lfsr(lfsr25_init, taps25)
|
lfsr25 = lfsr(lfsr25_init, taps25)
|
||||||
|
# first 3 bytes from lfsr 25 are already known
|
||||||
for _ in range(24):
|
for _ in range(24):
|
||||||
lfsr25.shift()
|
lfsr25.shift()
|
||||||
|
# generate next 3 bytes from lfsr 25 and lfsr 17
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
x_bin = ""
|
x_bin = ""
|
||||||
y_bin = ""
|
y_bin = ""
|
||||||
@ -131,13 +139,14 @@ def attack_worker(start, end, Bytes, result_queue, stop_event):
|
|||||||
y_bin += str(lfsr25.shift())
|
y_bin += str(lfsr25.shift())
|
||||||
x.append(int(x_bin[::-1], 2))
|
x.append(int(x_bin[::-1], 2))
|
||||||
y.append(int(y_bin[::-1], 2))
|
y.append(int(y_bin[::-1], 2))
|
||||||
|
# check if we can generate the next 3 output bytes z4,z5,z6 correctly
|
||||||
c=1 if x[2]+y[2]>255 else 0
|
c=1 if x[2]+y[2]>255 else 0
|
||||||
z4 = (x[3]+y[3]+c)%256
|
z4 = (x[3]+y[3]+c)%256
|
||||||
c=1 if x[3]+y[3]>255 else 0
|
c=1 if x[3]+y[3]>255 else 0
|
||||||
z5 = (x[4]+y[4]+c)%256
|
z5 = (x[4]+y[4]+c)%256
|
||||||
c=1 if x[4]+y[4]>255 else 0
|
c=1 if x[4]+y[4]>255 else 0
|
||||||
z6 = (x[5]+y[5]+c)%256
|
z6 = (x[5]+y[5]+c)%256
|
||||||
if z4 == Bytes[3] and z5 == Bytes[4] and z6 == Bytes[5]:
|
if z4 == Bytes[3] and z5 == Bytes[4] and z6 == Bytes[5]: # if these bytes are correct the key found is most likely the correct one
|
||||||
key = bin(x[0])[2:].zfill(8)[::-1] + bin(x[1])[2:].zfill(8)[::-1] + bin(y[0])[2:].zfill(8)[::-1] + bin(y[1])[2:].zfill(8)[::-1] + bin(y[2])[2:].zfill(8)[::-1]
|
key = bin(x[0])[2:].zfill(8)[::-1] + bin(x[1])[2:].zfill(8)[::-1] + bin(y[0])[2:].zfill(8)[::-1] + bin(y[1])[2:].zfill(8)[::-1] + bin(y[2])[2:].zfill(8)[::-1]
|
||||||
result_queue.put(key)
|
result_queue.put(key)
|
||||||
stop_event.set()
|
stop_event.set()
|
||||||
@ -387,7 +396,7 @@ print("\n")
|
|||||||
# time to test attack with 100 keys
|
# time to test attack with 100 keys
|
||||||
# CPU: 6 cores at 3.8GHz
|
# CPU: 6 cores at 3.8GHz
|
||||||
# ~65 seconds
|
# ~65 seconds
|
||||||
test_attack(10)
|
test_attack(5)
|
||||||
print("\n")
|
print("\n")
|
||||||
test_fail()
|
test_fail()
|
||||||
print("\n")
|
print("\n")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user