Tải bản đầy đủ (.pdf) (33 trang)

Mã hoá khoá phi đối xứng antisymetric encryption mã hoá khoá công khai

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.11 MB, 33 trang )

Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 1

MỤC LỤC
MỤC LỤC 1
DANH MỤC CÁC TỪ VIẾT TẮT 2
DANH MỤC BẢNG BIỂU 3
DANH MỤC HÌNH VẼ 4
LỜI NÓI ĐẦU 5
Chương 1 MẬT MÃ KHÓA CÔNG KHAI 6
1.1. Mật mã khóa công khai 6
1.1.1. Giới thiệu chung về mật mã khóa công khai 6
1.1.2. Nguyên tắc cấu tạo của mã khóa công khai 7
1.1.3. Phân loại các hệ mật khóa công khai 8
1.2. Các hệ mật mã khóa công khai 9
1.2.1. Hệ mật RSA 10
1.2.2. Hệ mật ElGamal 12
1.2.3. Hệ mật trên các đường cong Elliptic 13
1.2.4. Giải pháp về vấn đề an toàn 14
Chương 2 THƯ VIỆN GMP HỖ TRỢ TÍNH TOÁN VỚI SỐ LỚN 15
2.1. Giới thiệu 15
2.2. Các phép toán trên số nguyên 16
2.3. Hiệu suất 19
2.4. Cài đặt 20
Chương 3 CÀI ĐẶT THUẬT TOÁN RSA SỬ DỤNG THƯ VIỆN GMP 22
3.1. Tạo khóa RSA 22
3.2. Mã hóa bằng RSA 26
3.3. Giải mã bằng RSA 28
3.4. Cài đặt, biên dịch và thực thi 29
3.5. Phân tích thời gian thực hiện 30
3.5.1. RSA 1024 bít 30


3.5.2. RSA với kích cỡ khóa khác nhau 30
KẾT LUẬN 32
TÀI LIỆU THAM KHẢO 33
PHỤ LỤC Error! Bookmark not defined.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 2

DANH MỤC CÁC TỪ VIẾT TẮT
TỪ VIẾT TẮT
VIẾT ĐẦY ĐỦ
ANSI
American National Standards Institute -Viện tiêu chun quốc gia
ca M
ASCII
American Standard Code for Infornation Interchange
CBC
Cipher Block Chaining
DES
Data encryption Standard
IDEA
International Data Encryption Algorithm
IEEE
Institute of Electrical and Electronic Engineers - Viện k thuật ca
k sư điện và điện t
IETF
Internet Engineering Task Force
IMAP
Internet Message Access protocol
MIME
Multipurpose Internet Mail Extensions

PCBC
Propagating cipher block chaining
PGP
Pretty Good Privacy
PKCS
Public Key Cryptography Standard
S/ MIME
Secure-MIME
TLS
Transport Layer Security
MIT
Học viện Công nghệ Massachusetts
GCHQ
Cơ quan Thông tin chính ph
RSA
Rivest Shamir Adleman
GCD
Great Comon Divisor
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 3

DANH MỤC BẢNG BIỂU
Bảng 1.1: Các bài toán để so sánh 8
Bảng 3.1: Thời gian mã hóa và giải mã RSA (10.000 ký tự) 30
Bảng 3.2: Thời gian cho các độ dài khóa khác nhau (10.000 ký tự) 30
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 4

DANH MỤC HÌNH VẼ
Hình 1.1: Mô hình mã hóa và giải mã trong mật mã khóa công khai 7

Hình 1.2: Mô hình ký và kiểm tra chữ ký trong mật mã khóa công khai 7
Hình 1.3: Sơ đồ mã hóa và giải mã thông tin dựa trên thuật thoát RSA 11


Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 5

LỜI NÓI ĐẦU
Khi quá trình tin học hóa xã hội đang diễn ra nhanh chóng như hiện
nay thì vấn đề đảm bảo an toàn thông tin trở nên quan trọng hơn bao giờ hết.
Việc đảm bảo an toàn thông tin đòi hỏi phải kết hợp nhiều biện pháp, công
cụ, trong đó mật mã đóng vai trò hết sức quan trọng. Thông thường, người ta
s dụng mật mã đối xứng để mã hóa dữ liệu, còn khóa để thực hiện việc mã
hóa đó lại được trao đổi nhờ mật mã khóa công khai. Vai trò ca mật mã
khóa công khai không chỉ dừng lại ở việc trao đổi khóa. Một chức năng rất
quan trọng ca mật mã khóa công khai là tạo và kiểm tra chữ ký số.
Dù là mật mã đối xứng hay mật mã khóa công khai, độ an toàn là vấn
đề đầu tiên cần xem xét khi quyết định s dụng một hệ mật nào đó. Độ an
toàn phải được đánh giá căn cứ vào trình độ phát triển ca k thuật thám mã
(bao gồm thuật toán thám mã và sức mạnh tính toán ca các thiết bị hỗ trợ)
không chỉ ở thời điểm hiện tại mà cả trong tương lai. Theo như bài báo
“Factorization of a 768-bit RSA modulus” ngày 18/02/2010 RSA 768 bit đã
bị thám thành công hiện trên 80 vi x lí Opteron. Theo bài báo này, RSA 768
bit khó hơn 1000 lần so với RSA 512 bit (bị phá vỡ cách đây một thập kỉ), và
RSA 1024 bit khó hơn 1000 lần so với RSA 768 bit. Theo công bố ca bài
báo trên (tháng 2/2010), RSA 1024 bit có thể bị phá vỡ bằng sức tính toán
tương đương với 1500 năm, dùng một vi x lý Opteron 2,2 GHz. Và cho đến
bây giờ theo cách tấn công mới, RSA 1024 bit đã bị bẻ gãy trong 100 giờ [8].
Như thế, muốn tăng độ an toàn thì cần tăng kích thước ca khóa.
Qua việc tìm hiểu một số hệ mật khóa công khai, có thể thấy rằng, để

cài đặt chúng bằng chương trình, ta cần thực hiện các phép nhân (lũy thừa)
modulo với các số hàng trăm, hàng nghìn bít (số lớn). Một vấn đề thực sự
khó giải quyết đối với mật mã khóa công khai. Chính vì vậy em đã chọn đề
tài bài tập lớn “Mã hoá khoá Phi đối xứng (AntiSymetric Encryption) Mã
hoá khoá Công khai”.
Nội dung bao gồm:
1. Mật mã khóa công khai
2. Thư viện gmp hỗ trợ tính toán với số lớn
3. Cài đặt thuật toán rsa s dụng thư viện gmp

Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 6

Chương 1
MẬT MÃ KHÓA CÔNG KHAI
1.1. Mật mã khóa công khai
1.1.1. Giới thiệu chung về mật mã khóa công khai
Vào năm 1976 Diffie và Hellman đã đề xuất ra các ý tưởng cho phép
xây dựng các hệ mã hoạt động theo nguyên tắc mới, gắn liền với các bên
truyền tin chứ không gắn với các cặp truyền tin. Nguyên tắc hoạt động ca
các hệ mã đó là mỗi bên tham gia truyền tin sẽ có hai khóa, một khóa gọi là
khóa bí mật (K
s
) và một khóa gọi là khóa công khai (K
p
). Khóa bí mật là
khóa dùng để giải mã và được giữ bí mật, khóa công khai là khóa dùng để
sinh mã được công khai hóa để bất cứ ai cũng có thể s dụng khóa này gi
tin cho người ch ca hệ mã. Nhờ mật mã khóa công khai ta có thể mã hóa
một bức thư hay một tin nhắn thông qua mạng Internet mà không bị lộ thông

tin bằng cách mã hóa nó bằng khóa công khai người gi và chỉ người nhận
mới có thể biết được thông tin sau khi giải mã bức thư hay tin nhắn đó bằng
chính khóa bí mật ca mình. Trong mật mã khóa công khai, việc phân phối
khóa trở nên dễ dàng hơn qua các kênh cung cấp khóa công cộng, số lượng
khóa hệ thống quản lý cũng sẽ ít hơn. Trong các mạng kết nối với quy mô
lớn, mật mã khóa công khai đỏi hỏi ít tham số hơn, do đó ít dữ liệu về khoá
hơn, nhờ đó làm tăng tính bảo mật trong mạng. Các dịch vụ mới như chữ ký
điện t, thỏa thuận khóa cũng được xây dựng dựa trên mật mã khóa công
khai.
Các yêu cầu đối với một hệ mật mã khóa công khai bao gồm:
‒ Việc sinh K
p
, K
s
phải dễ dàng;
‒ Việc tính E(K
p
, M) là dễ dàng;
‒ Nếu có C = E(K
p
, M) và K
s
thì việc tìm bản rõ cũng là dễ;
‒ Nếu biết K
p
thì việc dò tìm K
s
là khó;
‒ Việc khôi phục bản rõ từ bản mã là khó.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai

Trần Ngọc Sơn 7

Trong mật mã khóa công khai, khi A muốn truyền tin cho B, A sẽ s
dụng khóa K
p
ca B để mã hóa tin tức và truyền bản mã tới cho B, B sẽ s
dụng khóa bí mật ca mình để giải mã và đọc tin (Hình 1.1):

Hình 1.1: Mô hình mã hóa và giải mã trong mật mã khóa công khai
Khi A muốn ký một văn bản thì A sẽ dùng khóa bí mật K
s
ca mình để
ký, A gi văn bản cho B và B sẽ s dụng khóa công khai ca A để giải mã.
Nếu giải mã được thì đó đúng là văn bản đã được A ký. Vì chỉ có A mới có
khóa bí mật để mã hóa văn bản này (Hình 1.2):

Hình 1.2: Mô hình ký và kiểm tra chữ ký trong mật mã khóa công khai
Mật mã công khai thường được s dụng để phân phối khoá bí mật hơn
là để mã hoá bản tin. Lý do là mật mã khóa công khai đòi hỏi nhiều tài
nguyên tính toán hơn (và do đó chậm hơn) so với mật mã đối xứng. Hệ thống
lai ghép s dụng mật mã đối xứng để mã hóa dữ liệu cho phiên truyền thông,
và s dụng mật mã khóa công khai để bảo vệ bí mật cho khóa được s dụng
trong phiên đó.
1.1.2. Nguyên tắc cấu tạo của mã khóa công khai
Các hệ mã khóa công khai được xây đựng dựa trên các hàm một chiều
(one-way functions). Hàm một chiều f: X

Y làm một hàm mà nếu biết x



X, ta có thể dễ dàng tính được y = f(x). Nhưng với y bất kỳ

Y việc tìm x


X sao cho y = f(x) là khó. Có nghĩa là việc hàm ngược f
-1
là khó. Ví dụ, nếu
Khóa bí
mật (K
s
)

Khóa công
khai (K
p
)
Plaintext
Plaintext
B
A
Mã hóa

Giải mã
Signed message

Khóa công
khai (K
p
)

Khóa bí
mật (K
s
)
Ciphertext
Plaintext
Plaintext
B
Mã hóa
Giải mã
A
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 8

có các số nguyên tố P
1
,P
2
,…,P
n
thì việc tính N = P
1
∙P
2
∙…∙P
n
là dễ, nhưng nếu
có N thì việc phân tích ngược lại là một bài toàn khó.
Để thuận tiện các hàm một phía được s dụng trong các hệ mã khóa
công khai thường được trang bị các ca bẫy (trapdoor) giúp cho việc tìm x

thỏa mã y = f(x) là dễ dàng nếu biết được ca bẫy này.
Hàm ca bẫy (trapdoor function): là hàm một chiều trong đó việc tính
f
-1
là rất nhanh khi chúng ta biết được ca bẫy ca hàm. Ví dụ việc tìm
nghiệm ca bài toán xếp ba lô 0/1 trong hệ mã xếp ba lô là một hàm một phía
(việc mã hóa rất nhanh và dễ dàng nhưng tìm vectơ nghiệm tương ứng là
khó) nhưng nếu ta biết ca bẫy (vectơ xếp balô siêu tăng A’) thì bài toán tính
f
-1
lại rất dễ dàng.
Độ an toàn ca các hệ mật khóa công khai được đảm bảo bới các bài
toán khó giải. Hiện nay, các bài toán đó là:
‒ Bài toán phân tích thừa số nguyên tố (IFP)
‒ Bài toán tính lôgarít rời rạc (DLP)
‒ Bài toán tính lôgarít rời rạc trên đường cong Elliptic (ECDLP)
Nội dung cụ thể ca các bài toán này được trình bày trong Bảng 1.1.
Bảng 1.1: Các bài toán để so sánh
Bài toán
IFP
DLP
ECDLP
Cho
N=p.q, trong đó p
và q là các số
nguyên tố chưa
biết.
g, p và y=g
x
mod

p, trong đó p là số
nguyên tố đã biết
P, và Q=kP, P là
một điển trên
đường cong
Elliptic
Tìm
p và q
x
k
Khóa công khai
dựa trên vấn đề đã
cho
RSA
DH/DSA
ECDH/ECDSA
1.1.3. Phân loại các hệ mật khóa công khai
Ý tưởng về mật mã khóa công khai được Diffie và Heliman đưa ra vào
năm 1975. Nhưng việc hiện thực hóa nó thì lại được Rivest, Shamin và
Adieman thực hiện đầu năm 1977, khi xây dựng nên hệ mật RSA nổi tiếng.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 9

Đến nay đã có nhiều hệ mật khóa công khai được công bố, trong đó quan
trọng nhất là:
‒ Hệ mật RSA. Độ bảo mật ca hệ RSA dựa trên độ khó ca việc phân
tích ra thừa số nguyên tố các số nguyên lớn.
‒ Hệ mật McEliece. Hệ mật này dựa trên lý thuyết mã đại số và vẫn
được coi là an toàn. Hệ mật McEliece dựa trên bài toán giải mã cho
các mã tuyến tính.

‒ Hệ mật ElGamal. Hệ ElGamal dựa trên tính khó giải ca bài toán
Logarit rời rạc trên các trường hữu hạn.
‒ Hệ mật Chor-Rivest. Hệ mật Chor-Rivest cũng được xem như một
loại hệ mật xếp ba lô. Tuy nhiên hệ mật này vẫn còn được coi là hệ
mật an toàn.
‒ Hệ mật trên các đường cong Elliptic. Các hệ này là biến tướng ca
hệ mật khác, chúng làm việc trên các đường cong Elliptic chứ
không phải trên các trường hữu hạn. Hệ mật này đảm bảo độ mật
với khoá số nhỏ hơn các hệ mật khoá công khai khác.
Độ an toàn ca từng hệ mật dựa trên các bài toán khác nhau, nhưng tất
cả chúng có một điểm chung, đó là để đảm bảo an toàn thì chúng phải s
dụng các số lớn. Đó là những số nguyên có kích thước từ hàng trăm đến hàng
nghìn bít trong biểu diễn nhị phân.
1.2. Các hệ mật mã khóa công khai
Từ khi ra đời vào những năm 50 ca thế kỷ trước, tốc độ bộ vi x lý
ca máy tính đã tăng nhanh chóng: từ hàng trăm KHz ban đầu đến hơn 3
GHz ngày nay. Bên cạnh đó, hiệu năng tính toán bộ ca vi x lý còn được
tăng cường bằng các thay đổi trong kiến trúc ca nó, bao gồm việc thiết kế
nhiều nhân trong một vi x lý. Có một đặc tính ca bộ vi x lý rất ít thay đổi
– đó là độ dài thanh ghi. Những bộ vi x lý thời kỳ đầu có thanh ghi 8 bít thì
ngày nay, độ dài thanh ghi trong các vi x lý hiện đại mới là 64 bít (một số vi
x lý chuyên dụng có độ dài thanh ghi lớn hơn). Tương ứng với độ dài thanh
ghi ca bộ vi x lý, các ngôn ngữ lập trình như C, C++,… cung cấp các kiểu
dữ liệu số có độ dài tối đa là 64 bít, tức là ít hơn nhiều so với nhu cầu s
dụng trong các hệ mật khóa công khai. Do vậy, các số có độ dài quá 64 bít
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 10

trong biểu diễn nhị phân, tức vượt quá khả năng lưu trữ ca kiểu dữ liệu số
nguyên chun, được coi là các số lớn.

1.2.1. Hệ mật RSA
RSA được Rivest, Shamir và Adleman phát triển, là một thuận toán
mật mã hóa khóa công khai. Nó đánh dấu một sự tiến hóa vượt bậc ca lĩnh
vực mật mã học trong việc s dụng khóa công khai. RSA đang được s dụng
phổ biến trong thương mại điện t và được cho là đảm bảo an toàn với điều
kiện độ dài khóa đ lớn. Thuật toán được công bố vào năm 1977 tại Học viện
Công nghệ Massachusetts (MIT). Tên ca thuật toán lấy từ ba chữ cái đầu
ca tên ba tác giả. Trước đó, vào năm 1973, Clifford Cocks, một nhà toán
học người Anh làm việc tại Trung tâm thông tin chính ph (GCHQ:
Government Communications Headquarters) thuộc Cục Trinh sát radio hoàng
gia (SIGINT: Her Majesty's Government's Signal Intelligence) Anh quốc, đã
mô tả một thuật toán tương tự. Với khả năng tính toán tại thời điểm đó thì
thuật toán này không khả thi và chưa bao giờ được thực nghiệm. Tuy nhiên,
phát minh này chỉ được công bố vào năm 1997 vì được xếp vào loại tuyệt
mật.
Sơ đồ ca quá trình mã hóa và giải mã thông tin dựa trên thuật thoát
RSA được thể hiện trên Hình 1.3.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 11


Hình 1.3: Sơ đồ mã hóa và giải mã thông tin
dựa trên thuật thoát RSA
RSA là một thí dụ điển hình về một đề tài toán học trừu tượng lại có
thể áp dụng thực tiễn vào đời sống thường nhật. Khi nghiên cứu về các số
nguyên tố, ít có ai nghĩ rằng khái niệm số nguyên tố lại có thể hữu dụng vào
lãnh vực truyền thông. Hệ mật RSA hoạt động như sau:
a) Tạo khoá
Bước 1: B (người nhận tin) tạo hai số nguyên tố lớn ngẫu nhiên p và q (p≠q)
Bước 2: B tính n = p.q và Φ(n) = (p – 1)(q – 1)

Bước 3: B chọn một số ngẫu nhiên e (0 < e < Φ (n)) sao cho ƯCLN(b, Φ(n))
= 1
Chọn p và q
Tính n =pq
Tính
()n


Chọn
1 ( )en



Tính d
1(mod ( ))de n




mod
d
m c n

mod
e
c m n

Thông tin m
Bản mã C
Thông tin m

e
d
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 12

Bước 4: B tính d = e
–1
(mod m) hay e*d = 1 (mod m) bằng cách dùng thuật
toán Euclide
Bước 5: B công bố n và e trong danh bạ làm khoá công khai (public key),
còn d làm khoá bí mật (private key).
b) Mã hoá
Bước 1: A (người gi tin) nhận khoá công khai ca B.
Bước 2: A biểu diễn thông tin cần gi thành số m (0 ≤ m ≤ n – 1)
Bước 3: Tính bản mã c = m
e
mod n
Bước 4: Gi c cho B.
c) Giải mã
B giải mã bằng cách tính m = c
d
mod n
Để thám hệ mật RSA, người ta cần phân tích n (là một thành phần ca
khóa công khai) ra hai thừa số p và q. Đến nay, người ta chưa tìm được thuật
toán có độ phức tạp tính toán đa thức để giải bài toán này. Do vậy, nó là bài
toán khó khi n lớn (1024 bít trở lên). Và như thế, mấu chốt để tăng tính an
toàn ca hệ mật RSA là s dụng các số nguyên tố p, q lớn. Điều đó kéo theo
n, m, e, d đều là các số lớn. Như vậy, tất cả các pha (tạo khóa, mã hóa, giải
mã) ca hệ mật RSA đều đòi hỏi thực hiện các phép toán trên số lớn.
1.2.2. Hệ mật ElGamal

Hệ mã Elgamal là một biến thể ca sơ đồ phân phối khóa Diffie-
Hellman. Hệ mã này được ElGamal đưa ra vào năm 1985. Giống như sơ đồ
phân phối khóa Diffie-Hellman tính an toàn ca nó dựa trên tính khó giải ca
bài toán logarit rời rạc.
Ban đầu người ta chọn một số nguyên tố lớn p và hai số nguyên tùy ý
nhở hơn p là a (a là một phần t nguyên thy ca Z
*
p
) và x (x là ca người
nhận, bí mật) sau đó tính:
x
mod y a p

(1.1)
Để mã hóa một thông điệp M (là một số nguyên trên Z
p
) thành bản mã
C người gi chọn một số ngẫu nhiên k nhỏ hơn p và tính khóa mã hóa K:
mod
k
K y p

(1.2)
Sau đó tính cặp bản mã:
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 13

1
mod
k

C a p

(1.3)
2
. modC K M p

(1.4)
Và gi bản mã C = (C
1
, C
2
) đi (chú ý là sau đó phải hy K). Như có
thể thấy, kích thước thước thông tin sau khi mã hóa sẽ tăng gấp đôi so với
thông tin gốc. Đây là nhược điểm ca hệ mật ElGamal.
Để giải mã thông điệp đầu tiên ta cần tính lại khóa mã hóa thông điệp
K:
.
1
mod mod
x k x
K C p a p

(1.5)
Sau đó tính M bằng cách giải phương trình sau đây:
1
2
. mod M C K p




(1.6)
Như vậy, trong hệ mật ElGamal, khóa công khai ca hệ mã là (p, a, y),
khóa bí mật là x.
Để thám hệ mật ElGamal khi biết bản mã
 
12
,C C C
và khóa công
khai
 
,,p a y
, người ta cần giải bài toán lôgarit rời rạc, cụ thể là tìm x để
mod
x
a p y
. Đến nay, vẫn chưa có thuật toán để giải bài toán lôgarit rời rạc
với độ phức tạp tính toán hàm đa thức. Tức là bài toán tìm lôgarit rời rạc là
bài toán khó khi p lớn. Do đó, để đảm bảo độ an toàn ca hệ mật ElGamal thì
cần chọn p lớn, từ đó kéo theo a, x, y, k, K, M, C
1
, C
2
cũng là các số lớn.
Như vậy, hệ mật ElGamal đòi hỏi thực hiện các phép toán với số lớn.
1.2.3. Hệ mật trên các đường cong Elliptic
Phép toán cộng trên đường cong elliptic tương ứng với phép nhân theo
modulo trong hệ mã RSA, còn phép toán nhân (cộng nhiều lần) trên đường
cong Elliptic tương ứng với phép lũy thừa theo modulo trong hệ mã RSA.
Tương tự như bài toán cơ sở ca hệ mã RSA là bài toán phân tích ra dạng
thừa số nguyên tố ca một số nguyên lớn, các hệ mã dựa trên các đường con

elliptic cũng có các bài toán cơ sở là một bài toán khó giải, gọi là bài toán
lôgarit trên đường cong Elliptic.
Xét phương trình Q = kP trong đó P, Q

E
p
(a, b) và k < p. Việc tính Q
nếu biết P và k là một bài toán dễ (thực hiện theo các công thức). Nhưng việc
xác định k với giá trị P, Q cho trước lại là bài toán khó.
Ví dụ: E
23
(9, 17) được xác định bởi phương trình
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 14

y
2
mod 23 = (x
3
+ 9x+ 17) mod 23.
Với Q = (4, 5) và P = (16, 5) thì k thỏa mãn Q = kP sẽ bằng bao nhiêu
? Phương pháp đơn giản nhất là nhân P lên nhiều lần cho tới khi bằng Q:
P = (16, 5), 2P = (20, 20), 3P = P = (16, 5); 2P = (20, 20); 3P = (14,
14); 4P = (19, 20); 5P = (13, 10); 6P = (7, 3); 7P = (8, 7); 8P (12, 17); 9P =
(4, 5).
Như vậy k = 9. Trên thực tế các hệ mã sẽ đảm bảo giá trị k là đ lớn để
phương pháp vét cạn như trên là không thể thực hiện được. Và như thế, để
đảm bảo độ an toàn thì hệ mật khóa công khai trên đường cong Elliptic cũng
đòi hỏi thực hiện các phép tính trên tập các số lớn.
1.2.4. Giải pháp về vấn đề an toàn

Qua việc tìm hiểu một số hệ mật khóa công khai, có thể thấy rằng, để
cài đặt chúng bằng chương trình, ta cần thực hiện các phép nhân (lũy thừa)
modulo với các số hàng trăm, hàng nghìn bít (số lớn). Trong khi đó, các máy
tính hiện đại chỉ hỗ trợ thực hiện các phép toán với các số có kích thước
không quá 64 bít. Do vậy, để có thể triển khai bằng chương trình các thuật
toán mật mã khóa công khai, cần phải có giải pháp đặc biệt để thực hiện
phép tính với các số lớn. Về mặt ý tưởng, có thể dùng mảng để lưu trữ các số
lớn, và các phép tính với số lớn có thể được xác định thông qua việc định
nghĩa các phép tính trên mảng. Tuy nhiên, đây là công việc phức tạp, nhất là
trong vấn đề tối ưu hóa thuật toán để đạt được tốc độ tính toán cao nhất có
thể. Vì lý do đó, khi cần cài đặt bằng chương trình một thuật toán mật mã
khóa công khai, nếu không có đ kiến thức uyên thâm trong k thuật lập
trình thì ta nên s dụng các thư viện có hỗ trợ thực hiện các phép tính với các
số lớn.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 15

Chương 2
THƯ VIỆN GMP HỖ TRỢ TÍNH TOÁN VỚI SỐ LỚN
2.1. Giới thiệu
GMP là thư viện do Torbjorn Granlund viết và đến bây giờ vẫn là
người phát triển chính. Rất nhiều cá nhân và tổ chức đã đóng góp xây dựng
vào thư viện GMP. Hiện giờ thư viện GMP vẫn đang được phát triển và phiên
bản hiện tại là GMP 5.0.5.
GMP là một thư viện cung cấp các hàm số học ở mức độ thấp nói
chung, không phải được thiết kế đặc biệt cho các ứng dụng mật mã. Tuy
nhiên, nó thực hiện hiệu quả hơn các phép tính so với các thư viện chuyên về
mật mã. GMP là thư viện miễn phí được viết bằng ngôn ngữ C nhằm mục
đích cung cấp thuật toán nhanh nhất có thể cho tất cả các ứng dụng cần thực
hiện các phép toán số học với độ chính xác cao hơn so với khả năng mà các

kiểu dữ liệu số trong ngôn ngữ C cơ bản cung cấp.
GMP có đặc điểm là cực nhanh, ban đầu được thiết kế cho ngôn ngữ C
nhưng sau đó có hỗ trợ cả C++. Bên cạnh C/C++, còn hỗ trợ các ngôn ngữ
khác như Perl, PHP, Java. Ví dụ PHP có extension php_gmp giúp việc s
dụng GMP trở nên rất dễ dàng [tham khảo tại php.net – GMP Functions]
Thư viện GMP có thể dùng trong tính toán cơ bản (cộng, trừ, nhân,
chia) các số nguyên, số thực. Nhược điểm ca GMP là khá khó s dụng vì
phải viết chương trình theo dạng ngôn ngữ bậc thấp, thiếu tính trừu tượng.
Các hàm cơ bản nhất ca GMP có dạng như sau:
Khai báo: mpf_f xf, yf, zf;
Khởi tạo (1): mpf_int(xf);
Khởi tạo (2): mpf_int2(xf, bits);
Giải phóng: mpf_clear(xf);
Thay thế: mpf_set_str(xf, str, base);
Cộng: mpf_add(zf, xf, yf);
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 16

Trừ: mpf_mul(zf, xf, yf);
Nhân: mpf_mul(zf, xf, yf);
Tuy nhiên khi đã làm quen với các hàm trên thì có thể viết được các
chương trình lớn thực hiện các tính toán phức tạp mà không phải lo nghĩ gì
tới giới hạn ca các con số (GMP dễ dàng tính toán các số có 600 triệu chữ
số) [9].
Để cập nhập thông tin về thư viện GMP, có thể xem ở địa chỉ
Phiên bản mới nhất có thể tìm thấy ở địa chỉ

2.2. Các phép toán trên số nguyên
a) Khởi tạo
Các hàm khởi tạo cho thuật toán số nguyên giả định rằng tất cả các đối

tượng số nguyên được khởi tạo. Ta có thể khởi tạo bằng cách gọi hàm
mpz_init.
void mpz_init (mpz_t x)
Khởi tạo x, và đặt giá trị là 0.
void mpz_inits (mpz_tx, )
Khởi tạo danh sách kết thúc là NULL ca các biến mpz_t và đặt nó =0.
void mpz_init2 (mpz_tx, mp bitcnttn)
Khởi tạo x, với khoảng trống là n bit và đặt giá trị =0. Dùng các hàm
này khi mpz_init hoặc mpz_inits không cần thiết.
void mpz_clear (mpz_tx)
b) Giải phóng bộ nhớ
Gọi hàm này cho tất cả các biến được khởi tạo khi làm việc với chúng.
void mpz_clears(mpz_tx, )
Giải phóng tất cả bộ nhớ mà các biến đã chiếm đóng.
c) Các hàm gán
Các hàm gán gán các giá trị mới vào các số nguyên đã được khởi tạo.
void mpz_set(mpz_t rop, mpz_t top)
void mpz_set_ui(mpz_t rop, unsigned long int op)
void mpz_set_si(mpz_t rop, signed long int op)
void mpz_set_d (mpz_t rop, double op)
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 17

void mpz_set_q (mpz_t rop, mpq_t op)
void mpz_set_f (mpz_t rop, mpf_t op)
Đặt giá trị ca rop từ op.
mpz_set_d, mpz_set_q và mpz_set_f chuyển op thành số nguyên.
int mpz_set_str(mpz_t rop, char *str, int base)
Đặt giá trị ca rop từ str, chuỗi trong C kết thúc bởi null. Khoảng
trống trắng được cho phép trong chuỗi. Tham số ‘base’ có thể nhận giá trị từ

2 đến 62 hoặc nếu ‘base’ bằng 0 thì các ký tự được s dụng: 0x và 0X s
dụng cho hệ 16, 0b và 0B cho hệ nhị phân, 0 cho hệ bát phân hoặc cho hệ
thập phân.
Khi ‘base’ lên 36, các ký tự in hoa và thường có giá trị giống nhau. Khi
‘base’ bằng 62, ký tự in hoa biểu diễn các giá trị từ 10 đến 35, trong khi ký
tự in thường biểu diễn từ 36 đến 61.
void mpz_swap(mpz_t rop1, mpz_t rop2)
Đổi chỗ giá trị ca rop1 và rop2.
d) Các hàm số học
void mpz_add(mpz_t rop, mpz_t op1, mpz_t op2)
void mpz_add_ui(mpz_t rop, mpz_t op1, unsigned long int op2)
Ta sẽ được: rop = op1+op2.
void mpz_sub(mpz_t rop, mpz_t op1, mpz_t op2)
void mpz_sub_ui(mpz_t rop, mpz_t op1, unsigned long int op2)
void mpz_ui_sub(mpz_t rop, unsigned long int op1, mpz_t op2)
Ta sẽ được: rop = op1- op2.
void mpz_mul(mpz_t rop, mpz_t op1, mpz_t op2)
void mpz_mul_si(mpz_t rop, mpz_t op1, long int op2)
void mpz_mul_ui(mpz_t rop, mpz_t op1, unsigned long int op2)
Ta sẽ được: rop = op1 * op2.
void mpz_addmul(mpz_t rop, mpz_t op1, mpz_t op2)
void mpz_addmul_ui (mpz_t rop, mpz_t op1, unsigned long int
op2)
Ta sẽ được: rop = rop + op1 * op2.
void mpz_submul(mpz_t rop, mpz_t op1, mpz_t op2)
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 18

void mpz_submul_ui (mpz_t rop, mpz_t op1, unsigned long int
op2)

Ta sẽ được: rop = rop - op1 * op2.
void mpz_mul_2exp(mpz_t rop, mpz_t op1, mp bitcnttop2)
Ta sẽ được: rop = op1 * 2
op2
. Phép toán này cũng được định nghĩa như
phép lệch trái op2 bits.
void mpz_neg(mpz_t rop, mpz_t op)
Ta sẽ được: rop = -op.
void mpz_abs(mpz_t rop, mpz_t op)
Ta sẽ được: rop = giá trị tuyệt đối ca op.
e) Các hàm chia và đồng dư
void mpz_mod(mpz_t r, mpz_t n, mpz_t d)
unsigned long int mpz_mod_ui(mpz_t r,mpz_t n,unsigned long
int d)
Ta sẽ được: r = n mod d.
void mpz_divexact(mpz_t q, mpz_t n, mpz_t d)
void mpz_divexact_ui(mpz_t q, mpz_t n, unsigned long d)
Ta sẽ được: q = n/d
void mpz_powm(mpz_t rop, mpz_t base, mpz_t exp, mpz_t mod)
void mpz_powm_ui(mpz_t rop, mpz_t base, unsigned long int
exp, mpz_t mod)
Ta sẽ được: rop = base
exp
mod mod
f) Các hàm lý thuyết số
int mpz_probab_prime_p(mpz_t n, int reps)
Xác định liêu n có là số nguyên tố. Trả về 2 nếu n chắc chắn là số
nguyên tố, trả về 1 nếu n có thể là số nguyên tố(không chắc chắn) hoặc trả về
0 nếu n không phải là số nguyên tố.
void mpz_nextprime (mpz_t rop, mpz_t op)

Gán số nguyên tố tiếp theo lớn hơn op vào rop. Hàm này s dụng thuật
toán xác suất để tìm các số nguyên.
void mpz_gcd(mpztrop, mpz top1, mpz top2)
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 19

Lấy ước số chung lớn nhất ca op1 và op2 và gán vào rop. Kết quả
luôn luôn dương thậm chí nếu một hoặc tất cả các phép toán đầu vào là ph
định.
unsigned long int mpz_gcd_ui(mpz_t rop, mpz_t op1, unsigned
long int op2)
Tính ước số chung lớn nhất ca op1 và op2. Nếu rop rỗng thì lưu kết
quả vào rop.
g) Các hàm so sánh
int mpz_cmp(mpztop1, mpz top2)
int mpz_cmp_d(mpztop1, double op2)
So sánh op1 và op2. Trả về giá trị dương nếu op1>op2, 0 nếu op1 =
op2, hoặc giá trị âm nếu op1 < op2.
h) Các hàm sinh số ngẫu nhiên
void mpz_urandomb(mpz_t rop,gmp_randstate_t state,
mp_bitcnt_t n)
Hàm này tạo một số nguyên ngẫu nhiên được phân bố đều trong dải từ
0 đến 2
n
– 1. Giá trị ‘state’ phải được khởi tạo bằng cách gọi một trong các
hàm gmp_randinit.
void mpz_urandomm(mpztrop, gmp randstate tstate, mpz tn)
Hàm này tạo một số nguyên ngẫu nhiên phân bố đều trong dải từ 0 đến
n-1
2.3. Hiệu suất

Nhiều ứng dụng s dụng số chính xác tới vài trăm bít, nhưng vài ứng
dụng có thể cần s dụng số chính xác tới hàng nghìn hay hàng triệu bít. GMP
được thiết kế để đáp ứng các nhu cầu đó, bằng cách chọn các thuật toán dựa
trên nhiều kích cỡ ca các toán hạng.
GMP đạt được tốc độ tính toán cao nhờ s dụng các thuật toán phức
tạp, đồng thời s dụng các đoạn mã hợp ngữ được tối ưu hóa cn thận cho
các vi x lý cụ thể: ARM, DEC Alpha 21064, 21164, và 21264, AMD 29000,
AMD K6, K6-2, Athlon, và Athlon64, Hitachi SuperH và SH-2, HPPA 1.0,
1.1 và 2.0, Intel Pentium, Pentium Pro/II/III, Pentium 4, generic x86, Intel
IA-64, i960, Motorola MC68000, MC68020, MC88100, và MC88110,
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 20

Motorola/IBM PowerPC 32 và 64, National NS32000, IBM POWER, MIPS
R3000, R4000, SPARCv7, SuperSPARC, generic SPARCv8, UltraSPARC,
DEC VAX, và Zilog Z8000. Vài sự tối ưu hóa cho các hệ thống Cray vector,
Clipper, IBM ROMP (RT), và Pyramid AP/XP.
Trong trường hợp cụ thể, các ứng dụng yêu cầu các số lớn, chạy
chương trình tuneup trong thư mục con ‘tune’ là rất quan trọng. Ví dụ:
cd tune
make tuneup
./tuneup
Các câu lệnh này sẽ tạo nội dụng tốt nhất cho tập tin tham số ‘gmp-
mparam.h’. Để s dụng các kết quả, để đầu ra vào một tập tin được xác định
trong đầu mục ‘Parameters for …’. Sau đó biên dịch lại từ đầu. Chương
trình tuneup lấy một thông số hữu dụng ‘-f NNN’ cái mà được chỉ dẫn
chương trình bao lâu để kiểm tra các thông số phép nhân FFT. Nếu có dự
định s dụng GMP cho các số lớn thì phải chạy tuneup với giá trị NNN lớn.
2.4. Cài đặt
Với hệ điều hành MS-DOS và MS Windows

Trên hệ thống MS-DOS DJGPP có thể được s dụng để build GMP, và
trên hệ thống MS Windows Cygwin, DJGPP và MINGW có thể được s
dụng. Cả ba đều là các cổng ca GCC và các công cụ khác ca GNU.



Microsoft cũng công bố một Interix “Services for Unix” có thể s dụng
để build GMP trên nền tảng Windows nhưng nó không phải là phần mềm
miễn phí.
Với MS Windows DLLs
Trên hệ thống ‘cygwin’, ‘mingw’ và ‘pw32’ có thể build GMP như một
thư viện tĩnh nhưng cũng có thể build thành thư viện động DLL.
Thư viện tĩnh và động không thể s dụng cùng 1 lúc, khi gọi ‘gmp.h’
phải gọi khác nhau.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 21

Một MINGGW DLL để build GMP có thể được s dụng với Microsoft
C. Các công cụ thư viện không cài đặt định dạng ‘.lib’ trong thư viện nhưng
nó có thể được tạo ra với MS lib như sau và ghi lại đường dẫn cài đặt. Giống
như cho ‘libmp’ và ‘libgmpxx’.
cd .libs
lib /def:libgmp-3.dll.def /out:libgmp-3.lib
MINGW s dụng thư viện C ‘msvcrt.dll’ cho I/O, vì vậy các ứng dụng
muốn s dụng chương trình I/O ca GMP phải biên dịch với ‘cl /MD’.
Với hệ điều hành linux
GMP có một tệp tin cấu hình tự động hệ thống có thể dùng lệnh sau để
triển khai:
./configure
Make

Sau đó có thể dùng lệnh sau để kiển tra
Make check
Và ta có thể cài đặt GMP và nó lưu vào /usr/local đây là nơi lưu mặc
định. Ta dùng câu lệnh sau:
Make install
Giờ ta đã có thể s dụng thư viện GMP.
Hầu hết các thuật toán đều có đặc điểm chung là kích thước khóa nhỏ
thì tốc độ sẽ nhanh còn kích thước khóa càng lớn thì tốc độ càng chậm. Kích
thước khóa nhỏ thì đồng nghĩa với tính bảo mật thấp vì dễ tìm ra khóa, để
tính bảo mật nâng cao thì kích thước khóa phải lớn. Do đó, cần phải đáp ứng
tính bảo mật cao (khóa phải lớn) bên cạnh đó tốc độ x lý phải nhanh. Giải
pháp đặt ra là phải s dụng một thư viện có tốc độ x lý các phép toán cực
nhanh. Thư viện GMP đã được kiểm tra qua các phép th trên các hệ điều
hành khác nhau và các phép toán các nhau. Nó đã đáp ứng được yêu cầu tính
toán nhanh mà ta cần.
Chương tiếp theo sẽ trình bày việc s dụng thư viện GMP để cài đặt
một trong những thuật toán mật mã khóa công khai – đó là thuật toán RSA.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 22

Chương 3
CÀI ĐẶT THUẬT TOÁN RSA SỬ DỤNG THƯ VIỆN GMP
Thư viện GMP có mục đích cung cấp thuật toán nhanh nhất cho các
ứng dụng cần sự chính xác cao hơn các thư viện cùng hỗ trợ C/C++ bằng
cách s dụng mã hợp ngữ được tối ưu hóa cao. Hơn thế nữa, thư viện GMP
là thư viện đa nền tảng, vì thế, sẽ mất ít thời gian để điều chỉnh sa đổi khi
chuyển ứng dụng từ nền tảng này sang nền tảng khác. Việc tạo khóa, mã hóa,
giải mã đều được x lý bởi các hàm được cung cấp bởi thư viện GMP.
Chương trình triển khai hệ mật RSA được xây dựng để chạy ở chế độ
dòng lệnh trên hệ điều hành UBUNTU. Kích thước khóa được điều chỉnh

bằng cách thay đổi tham số “BITSTRENGH” ở đoạn đầu ca mã nguồn
chương trình. Mỗi người dùng sẽ có một tập tin lưu trữ khóa công khai và
khóa bí mật. Ứng dụng lưu trữ khóa cho một người dùng ở trong các tập tin
$HOME/rsaprivate cho khóa bí mật và $HOME/rsapublic cho khóa công
khai.
Khi chương trình ứng dụng thực thi, sẽ hiện lên bốn tùy chọn:
1. Mã hóa
2. Giải mã
3. Thoát
Người dùng sẽ nhập và các số từ 1 đến 3 tương ứng hành động muốn
làm.
3.1. Tạo khóa RSA
Việc tạo các khóa RSA là tối quan trọng trong ứng dụng này. Để tạo
khóa, cần phải xác định được hai số nguyên tố p và q. Trong cách cài đặt này,
các số p và q được biểu diễn dưới dạng mảng, mỗi phần t ca mảng là một
chữ số nhị phân trong biểu diễn ca p và q. Việc sinh hai số nguyên tố p, q
được thực hiện qua hai bước.
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 23

Trước hết, cần lấp đầy hai mảng nói trên bởi một dãy các bít ngẫu
nhiên. Số ngẫu nhiên được tạo ra bằng cách s dụng hàm srand(). Để tránh
trường hợp thu được hai giá trị giống nhau khi gọi hàm srand(), bộ sinh số
ngẫu nhiên được khởi tạo bằng giá trị ca hàm time(). Để tránh trùng giá trị
khởi tạo thì chương trình s dụng hàm sleep() để độ trễ quá trình tạo khóa là
một giây và giá trị hàm time() trả về sẽ khác nhau, khi đó mỗi lần gọi hàm
srand() thì giá trị khởi tạo sẽ khác nhau.
Ở cuối quá trình tạo khóa này, chúng ta có các chuỗi bao gồm các số
nhị phân ca các số p và q, nhưng chúng không phải là số nguyên tố. Để trở
thành số nguyên tố, hai số nguyên gmp được tạo với nội dung ca các chuỗi

này. Sau đó, hàm mpz_nextprime() được gọi, nó thay đổi p và q thành các
số nguyên tố. Hàm này s dụng thuật toán xác suất để xác định các số
nguyên tố.
Sau khi đã có hai số p và q là số nguyên tố kích cỡ khoảng 512 bit,
thực hiện tính giá trị ca n (với n = pq) và x (với x = (p-1)*(q-1)) là các tham
số ca hàm mpz_mul(). Tiếp theo là xác định giá trị ca e. Giá trị ca e được
tìm kiếm tuần tự, bắt đầu với giá trị 65537, và tăng nó lên cho đến khi
gcd(e,x)=1 được thỏa mãn.
Trong thư viện gmp có hàm int mpz_invert(mpz_t ROP, mpz_t
OP1, mpz_t OP2), hàm này tính ‘OP1
-1
mod OP2’ và đưa kết quả vào ROP.
Như vậy, giá trị ca d đã được xác định và quá trình tạo khóa RSA coi như
hoàn tất. Cuối cùng khóa (d,e,n) được lưu trữ vào hai tập tin priv và pub.
Một điểm nữa là để bảo mật hơn ta có thể s dụng kích cỡ khóa lớn
hơn bằng cách thay đổi thông số ‘BITSTRENGTH’ ở đoạn đầu mã nguồn
bằng cách chỉnh sa đơn giản mã nguồn.
#define BITSTRENGTH 1024
Thay đổi thành
#define BITSTRENGTH 2048
Ví dụ tạo khóa:
Khi tạo khóa các số p và q được tạo ra
Số nguyên tố ngẫu nhiên 'p' =
163871860160621677387593390045385844209267730673336825398559
802699334515655657281314337655644306493328742151291653348883
222687785704918798048535154897345553201037953276938538820122
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 24

211406388097115072889306662915045361171309297667623133707930

552883415798837270190446115783270285140942131788222917259590
346696391
Số nguyên tố ngẫu nhiên 'q' =
135291925137332797768770980652163720789285790719700539504900
198706558199375140601656470373344769330903877340931688272732
747901640061965541029694866315333888724795024312780790518649
384806749444149149006509924174076202176561284451451868444642
855556162576439622582035143935235767699253719089436459515833
519137507

Khóa công khai (e,n):
Giá trị ca 'e' : 65537
Giá trị ca 'n' :
221705394369662969619274557079613079739833007206730567823307
344860685129515473781319603082509937014126291999072846229274
407343352462919599191128856961971016473648650281323281470105
731593183119229261641422105109008235140215454739857950452550
636785143219525103102092434761285350680948696688031734776013
483839501334420219181959261892478354250785000152124270131897
169385395442636004194348801367634145365730345247808168895205
559651618537516411419873593404504650780900888413469414438469
687509712589452519432612235342202648658662705068473909609750
524662779537643914211113786313085517248977518349095000528379
12883933109637237
Mã hoá khoá Phi đối xứng_AntiSymetric Encryption_Mã hoá khoá Công khai
Trần Ngọc Sơn 25


Khóa bí mật :
Giá trị ca 'd' :

139044129566228044879860580207917005713819922520271599229039
755992246825355829582675409705926780767423270118343716155997
935374314859253877442571040463416584816209268411171544547115
152966156714017442238517652077306811125518952968821299105859
839070188696597659149826865031331163826363021366121127954647
088099410422891508852276442368978770348184123022828988021957
363526838178515571671943572149378780333966441935079727394252
117727149990041255527028142700731599517235822439454802986458
677559276521295659879286626080178824782910562529298685783568
956161234756235480081463759062746136693274274391674994033628
05608006880675113

×