đề tài “ tích hợp thuật toán mật mã rijndael trên FPGA”

76 602 2
đề tài “ tích hợp thuật toán mật mã rijndael trên FPGA”

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

LỜI NÓI ĐẦU Sự phát triển ngày càng nhanh chóng của Internet và các ứng dụng giao dịch điện tử trên mạng, nhu cầu bảo vệ thông tin trong các hệ thống và ứng dụng điện tử ngày càng được quan tâm và có ý nghĩa hết sức quan trọng. Các kết quả của khoa học mật ngày càng được triển khai trong nhiều lĩnh vực khác nhau của đời sống xã hội, trong đó phải kể đến rất nhiều ứng dụng dân sự, thương mại, quân sự… Các ứng ụng hoá thông tin cá nhân, trao đổi thông tin kinh doanh, thực hiện các giao dịch điện tử qua mạng…đã trở nên gần gũi và quen thuộc với mọi người. Nhất là trong lĩnh vực quân sự cần phải có độ bảo mật cao. Với sự phát triển của công nghệ hiện nay, các bộ xử lý có tốc độ và khả năng xử lý ngày càng cao, nhiều phương pháp hoá đã không còn đảm bảo độ an toàn cao, đòi hỏi cần phải có một phương pháp hoá mới có thể đảm bảo độ an toàn cho thông tin. Phương pháp hoá Rijndael ra đời đã đáp ứng được phần nào độ an toàn các phương pháp mật trước còn hạn chế. Bên cạnh đó, các phương pháp thiết kế với trợ giúp đắc lực của máy tính dựa trên nền tảng công nghệ FPGA đã và đang tỏ rõ tính ưu việt của nó. Không những chúng đáp ứng được yêu cầu về mặt tích hợp, về tính bảo mật còn giúp giảm thiểu giá thành thiết kế và rút ngẵn thời gian thiết kế. Mặc dù ra đời từ cách đây hơn 2 thập kỷ, công nghệ FPGA ở nước ta vẫn còn là một lĩnh vực tương đối mới mẻ, đặc biệt là đối với các sinh viên. Vì thế tôi chọn đề tài: Tích hợp thuật toán mật Rijndael trên FPGA”. Nhệm vụ đặt ra của đề tài là: nghiên cứu về công nghệ FPGA, tìm hiểu về thuật toán mật Rijndael và cài đặt thuật toán bằng ngôn ngữ mô tả phần cứng VHDL, sử dụng phần mềm tích hợp để mô phỏng thực hiện 1 của thuật toán khi tích hợp trên FPGA. Từ nhiệm vụ đặt ra đó đề tài chia làm 3 chương sau: Chương I : FPGA và ngôn ngữ mô tả phần cứng VHDL. Chương II: Thuật toán mật Rijndael. Chương III: Thực hiện thuật toán Rijndael trên FPGA Trong quá trình làm đồ án tôi đã được các thầy giáo, đặc biệt thầy giúp đỡ trong việc tìm hiểu các kiến thức cần thiết cho đồ án, và phương pháp để hoàn thành đồ án; đồng thời cán bộ chỉ huy các cấp đã tạo điều kiện rất nhiều về mặt thời gian cho tôi thực hiện nhiêm vụ đồ án được giao. Tôi rất chân thành cảm ơn các thầy và cán bộ chỉ huy các cấp là những người đóng góp một phần rất lớn cho việc hoàn thành đồ án này của tôi. 2 MỤC LỤC CHƯƠNG 1 4 CÔNG NGHỆ FPGA VÀ NGÔN NGỮ MÔ TẢ PHẦN CỨNG VHDL 4 1.1.1.Sự phát triển của các thiết bị lập trình được 5 1.1.2.Cấu trúc cơ bản của FPGA 8 1.1.3.Ứng dụng của FPGA 12 1.2.1.Ngôn ngữ mô phỏng phần cứng (HDL) 13 1.2.1.1 Các phương pháp truyền thống 13 1.2.1.2 Ngôn ngữ mô phỏng phần cứng (HDL) 15 1.2.2.Ngôn ngữ mô phỏng phần cứng VHDL 15 1.2.2.1 Giới thiệu 15 1.2.2.2 VHDL có một số ưu điểm hơn hẳn các ngôn ngữ mô phỏng phần cứng khác 16 1.2.2.3 Cấu trúc một mô hình hệ thống mô tả bằng VHDL 18 THUẬT TOÁN MẬT RIJNDAEL 26 2.6.1. Khả năng an toàn 54 2.6.2. Đánh giá 55 CHƯƠNG 3 56 THỰC HIỆN THUẬT TOÁN RIJNDAEL TRÊN FPGA VÀ KẾT QUẢ 56 3.1. THỰC HIỆN THUẬT TOÁN RIJNDAEL TRÊN FPGA 56 3.1.1 Quá trình hóa và giải 56 3.1.2. Xây dựng các modul 58 3.1.3. Thực hiện thiết kế 65 3.2. KẾT QUẢ THỰC HIỆN 71 KẾT LUẬN 75 TÀI LIỆU THAM KHẢO 76 3 CHƯƠNG 1 CÔNG NGHỆ FPGA VÀ NGÔN NGỮ MÔ TẢ PHẦN CỨNG VHDL 1.1. TỔNG QUAN VỀ CÔNG NGHỆ FPGA Công nghệ chế tạo vi mạch điện tử ngày nay đang có sự thay đổi lớn: từ một mạch tích hợp vi điện tử với cơ sở thiết bị công nghệ tiên tiến chế tạo ra với số lượng lớn chuyển dần sang các mạch chuyên dụng sản xuất với lô nhỏ tại các cơ sở có điều kiện công nghệ chưa phát triển. Sự thay đổi đó được hình thành nhờ các công cụ thiết kế tự động. Động lực chính của quá trình thay đổi này là nhằm giảm thời gian thiết kế, chế tạo vi mạch và tăng tính linh hoạt cho người thiết kế lập trình với những ứng dụng riêng biệt. FPGA (Field-programmable Gate Array) là một thiết bị bán dẫn (IC) chứa các cổng logic có khả năng lập trình được. Chúng bao gồm các khối logic thực hiện các chức năng cơ bản như AND, OR… hay phức tạp hơn như các hàm toán học, bộ giải mã, trigger, register… và cả các phần tử nhớ, các mạng lưới kết nối có thể lập trình và các khối vào ra với các mạch khác. FPGA còn được gọi là thiết bị có khả năng tái cấu hình, được ứng dụng rộng rãi cho việc thiết kế các vi mạch chuyên dụng. Và chúng ta có thể biến nó thành một con IC có chức năng và tốc độ rất cao. Một cách tổng quát FPGA được cấu tạo từ 3 thành phần:  Khối Logic  Mạng kết nối trong có thể lập trình  Khối vào/ra 4 Có thể tổ hợp tuỳ ý các thành phần này để tạo ra các mạch chức năng như ý muốn. 1.1.1. Sự phát triển của các thiết bị lập trình được Các thiết bị lập trình được đóng vai trò quan trọng lâu dài trong thiết kế các vi mạch với những ứng dụng riêng biệt trong ngành điện tử - viễn thông. Chúng là các chíp đa dụng có thể được cấu hình theo nhiều cách cho ứng dụng. Loại đầu tiên của thiết bị lập trình được sử dụng rộng rãi là PROM (Programmable Read Only Memory). PROM là thiết bị lập trình được một lần gồm một dãy các ô nhớ chỉ đọc. Có hai loại PROM cơ bản, một loại chỉ có thể lập trình bởi nhà sản xuất gọi là mask programmable và một loại có thể lập trình bởi người sử dụng gọi là field programmable. Các chíp mask programmable có tốc độ làm việc cao vì các kết nối bên trong thiết bị được thực hiện bằng phần cứng ngay từ khi sản xuất. Ngược lại, các kết nối của field programmable luôn cần đến một số loại chuyển mạch lập trình được (cầu chì, transistos ) vì vậy tốc độ chậm hơn kết nối cứng. Tuy nhiên, thiết bị field programmable có nhiều ưu điểm giá trị hơn là sự hạn chế về tốc độ như :  Các chíp field programmable rẻ hơn các chíp mask programmable khi sản xuất với số lượng nhỏ  Các chíp field programmable có thể lập trình tức thì trong một thời gian rất ngắn, trong khi các chíp mask programmable khi sản xuất phải mất hàng tháng. Hai biến thể của PROM là EPROM (Erasable Programmble Read Only Memory) và EEPROM (Electrically Erasable Programmable Read Only Memory) chúng đều có chung một ưu điểm là có thể xóa và lập trình nhiều lần. 5 Một loại thiết bị lập trình được khác được thiết kế đặc biệt để thể hiện các mạch logic là PLD (Programmable Logic Device) : Một PLD thông thường gồm một dãy các cổng AND được nối với một dãy các cổng OR. Loại cơ bản nhất của PLD là PAL ( Programmable Array Logic). PAL gồm một khối các cổng AND lập trình được nối đến một khối các cổng OR cố định. Một loại PLD khác linh hoạt hơn đó là PLA (Programmable Logic Array) cũng có cấu trúc giống PAL nhưng tất cả các kết nối là lập trình được. Cấu trúc này có các mắt lưới của các đường nối theo chiều ngang và chiều đướng. Tại mỗi điểm giao nhau là một cầu chì, với sự trợ giúp của các công cụ phần mềm, người thiết kế có thể lựa chọn mỗi nối nào không được nối thì hủy cầu chì không cần dùng đó đi ( nung nóng và đốt đứt cầu chì đó). Điều nầy được thực hiện bởi một bộ nạp chương trình. Cả hai loại PAL và PLA cho phép thực hiện các mạch logic tốc độ cao, tuy nhiên cấu trúc đơn giản của chúng chỉ cho phép thực hiện các mạch logic cỡ nhỏ. Hình1.1: Cấu trúc của PLA Hình1.2: Cấu trúc của PAL Để thực thi các mạch yêu cầu nhiều đầu vào và nhiều đầu ra có nhiều chíp tinh vi hơn gọi là thiết bị logic lập trình phức hợp CPLD ( Complex Programmable Logic Device), họ này là kết quả của việc tăng mật độ của họ PLDs lên nhiều lần. Khái niệm này được hiểu là có một số khối PLD hoặc macrocell (tế bào vĩ mô ) ở trong một thiết bị đơn cùng với các đường 6 nối liền đa năng giữa chúng. Các đường nối của các đơn vị logic đơn giản có thể được thực thi ở trong một khối đơn. Nhiều đơn vị logic phức tạp yêu cầu nhiều khối và sử dụng các đường nối đa năng giữa chúng để tạo nên các kết nối phức tạp hơn. Các CPLDs cực kỳ thích hợp trong việc mô tả các cổng logic phức tạp với tốc độ lớn 200 Mhz. Khuôn mẫu thời gian cho CPLD rất dễ tính toán, bởi thế trước khi bắt đầu thiết kế chúng ta có thể tính toán các tốc độ từ đầu vào đến đầu ra của mình dựa trên khuôn mẫu này. CPLDs đưa ra cách đơn giản nhất để thực hiện một thiêt kế, một thiết kế có thể được mô tả bởi các sơ đồ hoặc bằng một ngôn ngữ mô tả phần cứng, đơn giản khi sử dụng các công cụ phát triển để tối ưu hóa, nạp và mô phỏng thiết kế. Các công cụ thiết kế tạo ra một file chương trình ma file này được dùng để đưa các chuẩn logic vào trong một chíp CPLD cùng với chức năng mong muốn. Giả sử nếu cần có một sự thay đổi về thiết kế, chúng ta có thể đưa sự thay đổi dó vào trong công cụ phát triển CPLD và thực thi trên nó sau đó có thể kiểm tra lại ngay thiết kế. CPLD có mức tích hợp rất cao và được đóng gói trong một khuôn dạng rất nhỏ. Điều này đã cung cấp một giải pháp tuyệt vời cho những người thiết kế cần sản phẩm của mình được gói nhỏ gọn với diện tích bo mạch bị giới hạn về khoảng không gian. Hình 1.3 : Cấu trúc của CPLD 7 FPGA được công ty Xilinx giới thiệu lần đầu vào năm 1985 nhằm tạo ra một thiết bị lập trình có độ tích hợp cao. FPGA cho phép tính hợp số lượng tương đối lớn các phần tử bán dẫn vào một vi mạch so với kiến trúc trước đó là CPLD. FPGA có khả năng chứa tới từ 100 000 đến hàng tỷ cổng logic, trong khi CPLD chỉ chứa từ 10 000 đến 100 000 cổng logic, con số này đối với PAL, PLA còn thấp hơn nữa chỉ đạt vài nghìn đến 10000. Kiến trúc của FPGA là kiến trúc mảng các khối logic, khối logic nhỏ hơn nhiều nếu đem so sánh với một khối SPLD ( SPLD thường là một mảng logic AND/OR lập trình được có kích thước xác định và chứa một số lượng hạn chế các phần tử logic đồng bộ), ưu điểm này giúp FPGA có thể chứa nhiều hơn các phần tử logic và phát huy tối đa khả năng lập trình của các phần tử logic và hệ thống mạch kết nối, để đạt được mục đích này thì kiến trúc FPGA phức tạp hơn nhiều so với CPLD. Một điểm khác biệt với CPLD là trong những FPGA hiện đại được tích hợp nhiều những bộ logic số học đã sơ bộ tối ưu hóa, hỗ trợ RAM, ROM, tốc độ cao, hay các bộ nhân cộng. Ngoài khả năng tái cấu trúc vi mạch toàn cục, một số FPGA hiện đại còn hỗ trợ tái cấu trúc bộ phận, tức là khả năng tái cấu trúc một bộ phận riêng lẻ trong khi vẫn bảo đảm hoạt động bình thường cho các bộ phận khác. 1.1.2. Cấu trúc cơ bản của FPGA FPGA gồm một dãy các phần tử rời rạc có thể được kết nối với nhau bằng các nguồn kết nối chung, các kết nối giữa các phần tử có thể lập trình được. Hình 1.4 giới thiệu về mô hình tổng quát của một FPGA. Nó gồm dãy 2 chiều các logic block có thể được kết nối bằng các nguồn kết nối 8 chung. Nguồn kết nối là các đoạn dây (segment) có thể có chiều dài khác nhau, bên trong các kết nối là các chuyển mạch lập trình được dùng để nối các logic block với các segment hoặc giữa các segment với nhau. Mạch logic được cài đặt trong FPGA bằng cách ánh xạ logic vào các logic block riêng rẽ và sau đó nối các logic block cần thiết qua các chuyển mạch. Trong đó có các khối:  Các khối logic (logic block) : cấu trúc và nội dung của khối logic được gọi là kiến trúc của nó. Kiến trúc của khối logic có thể được thiết kế theo nhiều cách khác nhau. Một số khối logic có thể chỉ là các cổng NAND 2 đầu vào, tuy nhiên cũng có thể nó là một bộ dồn kênh, hay các bảng tìm kiếm LUT ( Luck-Up Table ). Trong một số loại FPGA các khối logic có thể có cấu trúc hoàn toàn giống như PAL. Hầu hết các khối logic chứa một số loại flip-flop để hỗ trợ cho việc thực hiện các mạch tuần tự.  Các nguồn tài nguyên kết nối : Cấu trúc và nội dung của các nguồn kết nối trong FPGA được gọi là kiến trúc routing. Kiến trúc routing gồm các đoạn dây nối và các chuyển mạch lập trình được. Các chuyển mạch lập trình được có thể có nhiều cấu tạo khác nhau. Giống như khối logic, có nhiều cách để thiết kế kiến trúc routing như : Transistor truyền ( pass - transistor) được điều khiển bởi cell SRAM, cầu chì nghịch ( anti -fuse), EPROM transistor và EEPROM transistor  Các cổng vào/ra : Các đặc tính I/O của các đầu vào và đầu ra được hỗ trợ tới 19 các chuẩn tín hiệu khác nhau bao gồm : LVDS, BLVDS, LVPECL, LVCMOS, HSTL, SSTL và GTL. 9 Hình 1.4 : Mô tả mô hình của một FPGA Các khối cơ bản của LB ( Logic block ) của FPGA chính là logic cell ( LC : gọi là tế bào logic).  Mỗi một logic cell bao gồm một bộ tạo chức năng ( hay bộ tạo hàm ) 4 đầu vào, logic nhớ và phần tử lưu trữ ( Filip – Flop loại D ). Đầu ra bộ tạo chức năng của mỗi Logic Cell điều khiển cả đầu ra LB hoặc đầu vào D của Flip – Flop. Mỗi một LB có chứa 4 Logic Cell và được tổ chức thành hai Slice tương tự nhau, một slice đơn có dạng như hình 1.5.  Look – Up Table ( LUT ): Các bộ tạo chức năng của FPGA thực hiện như LUT có bốn đầu vào. Để hoạt động như một bộ tạo chức năng, mỗi một LUT có thể cung cấp một RAM 16 x 1 bit đồng bộ. Hơn nữa hai LUT trong một Slice có thể được kết hợp để tạo RAM 16 x 2 bit hoặc 32 x 1 bit đồng bộ.  Storage Element : Các phần tử lưu trữ trong Slice của FPGA có thể được xếp đặt như một Flip – Flop loại D kích hoạt bằng sườn, hoặc như một bộ đốt nhạy mức. Các đầu vào D có thể được điều khiển hoặc bởi bộ tạo chức năng trong Slice hoặc trực tiếp từ đầu vào các Slice ( bỏ qua bộ 10 [...]... ra của thuật toán Rijndael gồm chuỗi 128 bit, được xem như một khối (block) Khoá mật cho thuật toán Rijndael là một chuỗi 128, 192 hoặc 256 bit Chiều dài của đầu vào, đầu ra, khoá mật khác không được chấp nhận bởi chuẩn hoá này 26 2.2.2 Bytes Đơn vị cơ sở của quá trình xử lý trong thuật toán Rijndael là một byte, gồm một chuỗi của 8 bit liên tiếp Chuỗi bit đầu vào, đầu ra và khoá mật được... CHƯƠNG 2 THUẬT TOÁN MẬT RIJNDAEL 2.1 GIỚI THIỆU THUẬT TOÁN Với tốc độ và khả năng xử lý ngày càng được nâng cao của các bộ vi xử lý hiện nay, các phương pháp hoá trước trở nên không an toàn trong bảo mật thông tin Do đó, Viện Tiêu Chuẩn và Công Nghệ Hoa kỲ ( National Institute of Standards and Technology - NIST) đã quyết định chọn một chuẩn hoá mới với độ an toàn cao nhằm phục vụ nhu cầu bảo mật. .. sự Thuật toán Rijndael do Vincent Rijmen và Joan Deaman đã được chính thức chọn trở thành chẩn hoá nâng cao AES ( Advanced Encryption Standard) từ ngày 02 tháng 10 năm 2000 Phương pháp hoá Rijndael là phương pháp hoá khối đối xứng, nó có thể thực hiện với các khối dữ liệu 128 bit thông qua sử dụng các khoá hoá với các kích thước 128, 192, hay 256 bit Phương pháp này thích hợp ứng dụng trên. .. động của thuật toán Rijndael được thực hiện trên một mảng hai chiều, được gọi là trạng thái Một mảng trạng thái có 4 hàng, và N b cột, ở đây N b được tính bằng chiều dài của khối dữ liệu chia cho 32 Mảng trạng thái được ký hiệu là S[ r ,c ] , với 0 ≤ r ≤ 3, 0 ≤ c ≤ N b −1 Mỗi phần tử trong mảng trạng thái chứa một byte dữ liệu Khi thực hiện hoá hoặc giải mã bằng thuật toán Rijndael đầu vào được... , 0 ≤ r ≤ 3, 0 ≤ c ≤ N b −1 Tại thời điểm kết thúc thuật toán, mảng trạng thái được copy vào mảng ra, với output[r + 4c ] = S[ r ,c ] , 0 ≤ r ≤ 3, 0 ≤ c ≤ N b −1 Ví dụ: Đầu vào là chuỗi 128 bit thì N b =4, ta có sơ đồ sau (Hình 2.1): Hình 2.1 Sơ đồ mảng trạng thái 2.3 MỘT SỐ KHÁI NIỆM TOÁN HỌC Mỗi byte trong thuật toán Rijndael được biểu diễn như trên đã trình bày, mỗi byte xem như một phần tử của... khoá chia cho 32 Trong một số tình huống , ma trận biểu diễn một trạng thái hay khoá có thể được khảo sát như 35 mảng một chiều chứa các phần tử có độ dài 4 byte, mỗi phần tử tương ứng với một cột của ma trận Một số ký hiệu sử dụng trong thuật toán:  N w : Số lượng byte trong một đơn vị dữ liệu “từ” Trong thuật toán Rijndael, với 128 bit vào thì Nw là 4  K : Khoá chính  N b : Số lượng cột trong... trong khoá chính Giá trị N k = 4 với độ dài khoá bằng 128 bit  công thức: Nr : Số lượng chu kỳ, phụ thuộc vào giá trị N k và N b theo N r = max( N b , N k ) + 6 2.4.1 Quá trình hoá Quá trình hoá của thuật toán mật Rijndael có sơ đồ như sau (Hình 2.2): 36 ... ( x 8 +x 4 +x 3 +x + ) = x 7 + x 6 +1 Phép nhân được định nghĩa trên đây có tính kết hợp, tính phân phối đối với phép cộng và có phần tử đơn vị la {01} Với mọi đa thức b(x) có hệ số nhị phân với bậc nhỏ hơn 8 tồn tại phần tử nghịch đảo của b(x), ký hiệu là b − 1 ( x) , được thực hiện bằng cách sử dụng thuật toán Euclide mở rộng để tính toán đa thức a(x) và c(x) sao cho: b(x)a(x) + m(x)c(x) = 1 => b... hầu hết các ứng dụng hiện đang dùng CPLD, PLD và các mạch tích hợp nhỏ Dưới đây là các ứng dụng điển hình của FPGA :  Các mạch tính hợp ứng dụng đặc biệt  Thiết kế mạch ngẫu nhiên: Mạch logic ngẫu nhiên thường được thực hiện bằng PAL Nếu tốc độ của mạch không đòi hỏi khắt khe thì mạch có thể thực hiện thay thế bằng FPGA  Thay thế các chíp tích hợp nhỏ cho mạch ngẫu nhiên: Các mạch trong các sản phẩm... của 8 bit liền nhau thành dạng các mảng của các byte Một đầu vào, đầu ra hoặc khoá mật (Cipher Key) được biểu hiện một trong hai dạng a n hoặc a[n], với n phụ thuộc vào chiều dài của khoá, chiều dài của khoá là 128 bít thì 0 < n < 16, dài 192 bit thì 0 < n < 24, dài 256 bit thì 0 < n < 32 Các byte trong thuật toán Rijndael được biểu diễn dưới dạng xích chuỗi các bit 0 hoặc 1, dạng như sau{ b7 , b6 . tôi chọn đề tài: “ Tích hợp thuật toán mật mã Rijndael trên FPGA”. Nhệm vụ đặt ra của đề tài là: nghiên cứu về công nghệ FPGA, tìm hiểu về thuật toán mật mã Rijndael và cài đặt thuật toán bằng. VHDL 18 THUẬT TOÁN MẬT MÃ RIJNDAEL 26 2.6.1. Khả năng an toàn 54 2.6.2. Đánh giá 55 CHƯƠNG 3 56 THỰC HIỆN THUẬT TOÁN RIJNDAEL TRÊN FPGA VÀ KẾT QUẢ 56 3.1. THỰC HIỆN THUẬT TOÁN RIJNDAEL TRÊN FPGA. mềm tích hợp để mô phỏng thực hiện 1 của thuật toán khi tích hợp trên FPGA. Từ nhiệm vụ đặt ra đó đề tài chia làm 3 chương sau: Chương I : FPGA và ngôn ngữ mô tả phần cứng VHDL. Chương II: Thuật

Ngày đăng: 18/06/2014, 22:10

Mục lục

    CÔNG NGHỆ FPGA VÀ NGÔN NGỮ MÔ TẢ PHẦN CỨNG VHDL

    1.1.1. Sự phát triển của các thiết bị lập trình được

    1.1.2. Cấu trúc cơ bản của FPGA

    1.1.3. Ứng dụng của FPGA

    1.2.1. Ngôn ngữ mô phỏng phần cứng (HDL)

    1.2.1.1 Các phương pháp truyền thống

    1.2.1.2 Ngôn ngữ mô phỏng phần cứng (HDL)

    1.2.2. Ngôn ngữ mô phỏng phần cứng VHDL

    1.2.2.2 VHDL có một số ưu điểm hơn hẳn các ngôn ngữ mô phỏng phần cứng khác

    1.2.2.3 Cấu trúc một mô hình hệ thống mô tả bằng VHDL

Tài liệu cùng người dùng

Tài liệu liên quan