diff --git a/README.md b/README.md index ca386e6..29c4674 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ # 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) diff --git a/main.py b/main.py index 5084c5a..199b00e 100755 --- a/main.py +++ b/main.py @@ -5,8 +5,11 @@ import multiprocessing class lfsr(object): def __init__(self, state, taps): - self.state = state - self.taps = taps + if max(taps) > len(state): + raise ValueError("inconsistent taps and initial state") + else: + self.state = state + self.taps = taps # getters and setters (private attributes) def get_state(self): @@ -104,25 +107,30 @@ def attack_worker(start, end, Bytes, result_queue, stop_event): taps17 = [0, 14] taps25 = [0, 3, 4, 12] 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 lfsr17_init = [int(bit) for bit in bin(i)[2:].zfill(16)]+[1] lfsr17 = lfsr(lfsr17_init, taps17) x = [] + # generate first 3 output bytes from lfsr 17 for _ in range(3): x_bin = "" for _ in range(8): x_bin += str(lfsr17.shift()) x.append(int(x_bin[::-1], 2)) + # calculate corresponding output bytes from lfsr 25 y = [(Bytes[0]-x[0])%256] c=1 if x[0]+y[0]>255 else 0 y.append((Bytes[1]-(x[1]+c))%256) c=1 if x[1]+y[1]>255 else 0 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 = lfsr(lfsr25_init, taps25) + # first 3 bytes from lfsr 25 are already known for _ in range(24): lfsr25.shift() + # generate next 3 bytes from lfsr 25 and lfsr 17 for _ in range(3): x_bin = "" y_bin = "" @@ -131,13 +139,14 @@ def attack_worker(start, end, Bytes, result_queue, stop_event): y_bin += str(lfsr25.shift()) x.append(int(x_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 z4 = (x[3]+y[3]+c)%256 c=1 if x[3]+y[3]>255 else 0 z5 = (x[4]+y[4]+c)%256 c=1 if x[4]+y[4]>255 else 0 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] result_queue.put(key) stop_event.set() @@ -387,7 +396,7 @@ print("\n") # time to test attack with 100 keys # CPU: 6 cores at 3.8GHz # ~65 seconds -test_attack(10) +test_attack(5) print("\n") test_fail() print("\n")