Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 39 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
39
Dung lượng
650,69 KB
Nội dung
HỌC VIỆN CƠNG NGHỆ BƯU CHÍNH VIỄN THƠNG KHOA CƠNG NGHỆ THÔNG TIN I Học phần: Mật mã học nâng cao Bài báo cáo: KỸ THUẬT TẤN CÔNG VÀO DES Giảng viên hướng dẫn: TS Đỗ Xuân Chợ Sinh viên thực hiện: Nhóm 07 Vương Hải Chiến Phạm Trường Giang Đoàn Anh Nhật Nguyễn Thành Tâm Lương Ngọc Sơn Tùng Nguyễn Huy Tùng B18DCAT027 B18DCAT063 B18DCAT179 B18DCAT207 B18DCAT219 B18DCAT223 Hà Nội - 2021 MỤC LỤC I Giới thiệu DES 1 Định nghĩa Mơ hình mã Feistel .1 Thuật toán sinh khoá 4 Hàm Feistel (F) II Giới thiệu phương pháp thám mã tuyến tính với DES .8 Giới thiệu Nguyên lý chung phương pháp thám mã tuyến tính hệ DES Xấp xỉ tuyến tính hộp nén (S-boxes) 12 Xấp xỉ tuyến tính hệ mã DES 13 Tỉ lệ thành công với công rõ biết hệ mã DES 15 III Thực hành công vào DES 16 Tấn công tuyến tính với DES vịng .16 Chương trình thám mã tuyến tính với DES vịng 20 Kết thực nghiệm thám mã DES vòng .21 Tấn công rõ biết hệ mã DES vòng 21 Tấn công rõ biết hệ mã DES 16 vòng .22 Chương trình thám mã vi sai với DES vòng 23 I I Giới thiệu DES Định nghĩa DES thuật tốn mã hóa khối, xử lý khối thơng tin rõ có độ dài xác định biến đổi theo trình phức tạp để trở thành khối thơng tin mã có độ dài không thay đổi, độ dài khối 64 bit Hơn nữa, DES giải thuật đối xứng nên dùng mã khóa cho trình: mã hóa giãi mã Khóa dùng DES có độ dài tồn 64 bit Tuy nhiên có 56 bit thực sử dụng; bit cịn lại chí dùng cho việc kiểm tra Vì thế, độ dài thực tế khóa chi 56 bit DES có thiết kế liên quan tới khái niệm: mã hóa tổng (product cipher) mã Feistel (Feistel cipher) Một mã hóa tổng bao gồm hai hay nhiều mã hóa đơn giản (như phép thay hốn vị), mã hóa tổng an tồn nhiều so với mã hóa thành phần Mã Feistel mã khối lặp, kết hợp phép thay hoán vị Trong hệ mã Feistel, rõ biến đối qua số vòng mã cuối Mơ hình mã Feistel Mã Feistel mã khối lặp Có 16 chu trình giống q trình xử lý Ngồi cịn có hai lần hốn vị đầu cuối (Initial and final permutation IP & FP) Hai q trình có tính chất đối (Trong q trình mã hóa IP trước FP, giải mã ngược lại) Bản rõ P mã Ci chia thành nửa trái nửa phải: p = (L0 , R0) Ci = (Li , Ri) i=1,2, ,n Quy tắc biến đổi nửa trái phải qua vòng thực sau: Ki khóa cho vịng thứ i Khóa sinh từ khóa K ban đầu theo thuật tốn sinh khóa (key schedule): K K K2 Kn F hàm mã hóa dùng chung cho tất vịng Hàm F đóng vai trị phép thay cịn việc hốn đối nửa trái phái có vai trị hốn vị Bản mã c tính từ kết xuất vịng cuối cùng: Hình 1: Sơ đồ tính tốn hệ mã Feistel Để giải mã q trình thực qua vịng theo thứ tự ngược lại: Và cuối rõ là: P = ( L0, R0) Thuật toán sinh khoá Khóa DES khối 64-bit, bit quan trọng byte bỏ qua sử dụng đế kiêm tra chẵn lẻ, đảm bảo khóa khơng có lỗi Hoạt động thực permuted choice 1, ký hiệu PC: bit lại bị loại bỏ, 56 bit thu được chia làm hai phần nhau, phần xử lý độc lập Sau chu trình, mồi phần dịch bit (tùy thuộc chu trình, chu trình 1, 2, 9, 16 dịch bit, cịn lại dịch bit) Các khóa 48 bit tạo thành thuật toán lựa chọn (Permuted Choice 2, hay PC-2) gồm 24 bit từ mồi phần Quá trình dịch bit (được ký hiệu "16x}".format(key) key = bytearray.fromhex(key) key = bytearray(set_parity(byte) for byte in key) return key class PlaintextRandomGenerator: def generate(self, difference=None): # TODO validate difference plaintext = random.randint(0, ** 64 - 1) plaintext = "{:0>16x}".format(plaintext) plaintext = bytearray.fromhex(plaintext) if difference == None: return plaintext plaintext = ( plaintext, bytearray(p ^ d for p, d in zip(plaintext, difference)) ) return plaintext class Sbox: def init (self, pattern): self.pattern = pattern def call (self, row, column): return self.pattern[row][column] @property def pattern(self): return self._pattern @pattern.setter def pattern(self, pattern): # TODO validation 24 self._pattern = pattern class LinearTransformation: def init (self, pattern): self.pattern = pattern def call (self, bytes): if type(bytes) is not bytearray: raise Exception("Input data is not bytearray") # if ((len(bytes) * 8) < len(self.pattern)) or ((len(bytes) * 8) < max(self.pattern)): # raise Exception("Input data length not match to pattern length") def get_bit(byte, no): no = (8 - no) - return (byte & (1 > no def set_bit(byte, no, value): no = (8 - no) - if value == 1: byte |= len(pattern): # raise Exception("Values in pattern cannot be greater than pattern length") if value < 0: raise Exception("Values in pattern cannot be smaller than 0") self._pattern = pattern def function_e(data): e = LinearTransformation((32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1)) return e(data) def function_k(data, key): return bytearray([d ^ k for (d, k) in zip(data, key)]) def function_s(data): def combine_bits(bits): combined = for (i, j) in zip(reversed(range(len(bits))), range(len(bits))): combined |= bits[i] shift def get_column(byte): bits = list(range(2, 6)) return combine_bits([get_bit(byte, bit) for bit in bits]) def get_row(byte): bits = [1, 6] return combine_bits([get_bit(byte, bit) for bit in bits]) sboxes = tuple(get_sboxes()) sboxed = [0] * byte = # start from byte bit = # get bits (counting from 1) for i in range(0, len(data) * 8, 6): sbox = i // value = data[byte] >> (8 - bit) if bit < 6: value |= data[byte - 1] (4 - rotation)) result[i] &= 0x0F return result key = pc1(key) rotations = (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1) halfbytes = [] for byte in key: halfbytes.append((byte & 0xF0) >> 4) halfbytes.append(byte & 0x0F) c = halfbytes[:7] d = halfbytes[7:] for rotation in rotations[:no]: c = rotate(c, rotation) d = rotate(d, rotation) halfbytes = c + d key = [(c else -1 for key in possible_keys] print("Key candidate: " + str(round_6_key_candidate)) difference = bytearray([0x00, 0x20, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00]) subkeys = [0, 1, 3, 4, 5] # which sboxes we attack possible_keys = differential_attack_6_rounds(cipher, difference, attempts, subkeys) 31 round_6_key_candidate = [key[0]["key"] if len(key) > else -1 for key in possible_keys] print("Key candidate: " + str(round_6_key_candidate)) def main(): print("Encryption/decryption") encryption_decryption() print("6-round attack") break_6_rounds() if name == " main ": main() File test_des.py from des import Cipher, function_s, KeyRandomGenerator, LinearTransformation, permutation, permutation_inverted, \ PlaintextRandomGenerator, Sbox def test_cipher(): tuples = [("618A5B261AE3CD32", "46112C8680041B44", "060FBE89802B13AE"), ("C4F7A426A7D6430E", "771627F0C72351B4", "FB948449EA540995"), ("895D3E3885D3C289", "6916B343114A0876", "C3B914320945A917")] for key, plaintext, ciphertext in tuples: key = bytearray.fromhex(key) plaintext = bytearray.fromhex(plaintext) ciphertext = bytearray.fromhex(ciphertext) cipher assert assert assert assert assert = Cipher(key) key == cipher.key ciphertext == cipher.encrypt(plaintext) plaintext == cipher.decrypt(ciphertext) cipher.encrypt(plaintext) == cipher.encrypt(plaintext) cipher.decrypt(ciphertext) == cipher.decrypt(ciphertext) def test_function_s(): dataset = [[0x64, 0x79, 0x11, 0xCD, 0x7C, 0x74]] results = [[0x97, 0x44, 0xFE, 0x9A]] for data, expected in zip(dataset, results): data = bytearray(data) expected = bytearray(expected) assert expected == function_s(data) def test_linear_transformation(): pattern = (1, 2, 3, 4, 5, 6, 7, 8) lt0 = LinearTransformation(pattern) assert pattern == lt0.pattern dataset = [0xAB, 0xFC, 0x24, 0x5A, 0x67, 0x11] 32 lt1 = LinearTransformation((1, 2, 3, 4, 5, 6, 7, 8)) results = [0xAB, 0xFC, 0x24, 0x5A, 0x67, 0x11] for data, expected in zip(dataset, results): data = [data] data = bytearray(data) expected = [expected] expected = bytearray(expected) assert expected == lt1(data) lt2 = LinearTransformation((8, 7, 6, 5, 4, 3, 2, 1)) results = [0xD5, 0x3F, 0x24, 0x5A, 0xE6, 0x88] for data, expected in zip(dataset, results): data = [data] data = bytearray(data) expected = [expected] expected = bytearray(expected) assert expected == lt2(data) lt3 = LinearTransformation((1, 1, 1, 1, 5, 5, 5, 5)) results = [0xFF, 0xFF, 0x00, 0x0F, 0x00, 0x00] for data, expected in zip(dataset, results): data = [data] data = bytearray(data) expected = [expected] expected = bytearray(expected) assert expected == lt3(data) lt4 = LinearTransformation((1, 2, 3, 4, 5, 6, 7, 8, 5, 6, 7, 8, 1, 2, 3, 4)) results = [[0xAB, 0xBA], [0xFC, 0xCF], [0x24, 0x42], [0x5A, 0xA5], [0x67, 0x76], [0x11, 0x11]] for data, expected in zip(dataset, results): data = [data] data = bytearray(data) expected = bytearray(expected) assert expected == lt4(data) def test_key_random_generator(): generator = KeyRandomGenerator() key = generator.generate() assert type(key) is bytearray assert len(key) * == 64 for byte in key: bits = for i in range(8): if (byte & (1 0: bits += assert == (bits % 2) def test_plaintext_random_generator(): def test_plaintext(plaintext): assert type(plaintext) is bytearray assert len(plaintext) * == 64 generator = PlaintextRandomGenerator() 33 plaintext = generator.generate() test_plaintext(plaintext) difference = bytearray([0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) plaintextes = generator.generate(difference) assert type(plaintextes) is tuple assert len(plaintextes) == for plaintext in plaintextes: test_plaintext(plaintext) assert difference == bytearray(p0 ^ p1 for p0, p1 in zip(plaintextes[0], plaintextes[1])) def test_permutation_inverted(): dataset = [[0x12, 0x34, 0x56, 0x78], [0xAB, 0xCD, 0xDC, 0xBA], [0x1D, 0xE2, 0x54, 0x16], [0x82, 0x32, 0xAF, 0x3B], [0x23, 0xD7, 0x10, 0xE0]] for data in dataset: data = bytearray(data) assert data == permutation_inverted(permutation(data)) def test_sbox(): pattern = [[1, 2], [0, 3]] s0 = Sbox(pattern) assert pattern == s0.pattern s1 = Sbox([[0, 1], [3, 2]]) assert == s1(0, 0) assert == s1(1, 1) s2 = Sbox([[1, 2, assert == s2(0, assert == s2(1, assert == s2(1, assert == s2(0, 0], [3, 0, 1]]) 2) 1) 0) 1) File setup.py #!/usr/bin/env python3 from setuptools import find_packages, setup setup( name="des", version="0.0.0", packages=find_packages(), ) File README.md # Simple DES implementation in Python 34 ## Usage Install by executing `python setup.py install` or `pip install ` Import like other package ```python from des import Cipher as DES, random_key, random_message des = DES(random_key()) message = random_message() ciphertext = des.encrypt(message) plaintext = des.decrypt(ciphertext) print(plaintext == message) # should be True ``` ## 6-rounds attack Implemented 6-rounds differential attack allow to break rounds of DES using differential cryptoanalisys Example code has been placed in `des/main.py` file under `break_6_rounds` function ``` $ python -m des Encryption/decryption difference = 4008000004000000 plaintext = EB47DCC8CF3D1DD7 plaintext' = AB4FDCC8CB3D1DD7 key = DC89256D162916DF difference = 0367457805008282 (same in 12%) ciphertext = FC9CE112286E9A23 ciphertext' = FFFBA46A2D6E18A1 ciphertext = 0D6A0F43B0481DAA (final) decrypted = EB47DCC8CF3D1DD7 (valid) 6-round attack Valid key: [57, 32, 42, 3, 38, 6, 15, 49] # key used by DES in 6th round Key candidate: [-1, 32, -1, -1, 0, 6, 15, 49] # potential key (-1 inform that we cannot predict value) Key candidate: [16, 0, -1, 3, 38, 6, -1, -1] # potential key (-1 inform that we cannot predict value) ``` ## Tests Use `pytest` to run prepared unit tests ``` $ pytest verbose tests/ ===================================================================================== ================ test session starts ===================================================================================== ================ platform linux Python 3.9.0+, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -/home/user/des-attack/venv/bin/python cachedir: pytest_cache rootdir: /home/user/des-attack collected items 35 tests/test_des.py::test_cipher PASSED [ 14%] tests/test_des.py::test_function_s PASSED [ 28%] tests/test_des.py::test_linear_transformation PASSED [ 42%] tests/test_des.py::test_key_random_generator PASSED [ 57%] tests/test_des.py::test_plaintext_random_generator PASSED [ 71%] tests/test_des.py::test_permutation_inverted PASSED [ 85%] tests/test_des.py::test_sbox PASSED [100%] ===================================================================================== ================= passed in 0.20s ===================================================================================== ================= ``` 36 ... package ```python from des import Cipher as DES, random_key, random_message des = DES( random_key()) message = random_message() ciphertext = des. encrypt(message) plaintext = des. decrypt(ciphertext)... Tấn công rõ biết hệ mã DES vòng 21 Tấn công rõ biết hệ mã DES 16 vòng .22 Chương trình thám mã vi sai với DES vịng 23 I I Giới thiệu DES Định nghĩa DES thuật tốn mã hóa khối,... hệ mã DES 15 III Thực hành công vào DES 16 Tấn cơng tuyến tính với DES vịng .16 Chương trình thám mã tuyến tính với DES vịng 20 Kết thực nghiệm thám mã DES vòng