Trong cuộc sống
ngày nay, mạng internet có lẽ đã trở thành một thứ không thể thiếu đối với
chúng ta. Mạng internet giúp chúng ta tra cứu thông tin, làm việc, học tập, kết
nối với mọi người. Nếu thiếu nó thì có lẽ thế giới này sẽ trở lên lạc hậu hơn
rất nhiều so với bây giờ.
Vậy có bao giờ bạn
nghĩ đến thực chất internet là gì, mà tại sao nó lại quan trọng đến vậy? Về cơ
bản, ta có thể coi internet như là một môi trường trung gian để trao đổi THÔNG
TIN, mọi hoạt động trên internet đều HẦU NHƯ CHỈ xoay quanh việc tiếp nhận,
trao đổi và truyền nhận THÔNG TIN. Qua đó ta có thể thấy được thông tin quan
trọng như thế nào.
Thật sự thông tin
còn quan trọng hơn những gì bạn tưởng. Một số thông tin có thể quan trọng hơn
bất cứ thứ gì hữu hình trên thế giới này, nó có thể đáng giá hàng trăm tỷ, hàng
tỷ tỷ đô la, hoặc có thể là vô giá.
Vì thông tin là
quan trọng, nên chúng ta sẽ cần phải có những phương pháp để bảo vệ nó. Đó là
Mã hóa dữ liệu. Vậy, mã hóa là gì, các phương pháp mã hóa như thế nào, chúng ta
hãy cùng tìm hiểu nhé.
I. KHÁI NIỆM
Hiểu
nôm na Mã hóa là phương thức ngụy trang hoặc che giấu một tin nhắn bằng cách áp
dụng một số bước lập trình máy tính thành các chuỗi ký tữ đặc biệt để ngăn những
người không phận sự tiếp cận vào thông tin đó. Ví dụ: tin nhắn có nội dung như
“tôi sẽ gặp anh vào ngày mai tại Hà Nội” được chuyển thành tin nhắn mã hóa như
“p98hUls#yeb!”. Làm thế nào để mã hóa được như vậy thì chúng ta cần có thuật
toán mã hóa.
Mã hóa (encryption) tức là biến đổi “thông tin gốc” dạng
tường minh (plaintext) thành “thông tin mã hóa” dạng ẩn tàng (cipher text) bằng
cách sử dụng một khóa mã (thuật toán mã hóa) nào đó. Chỉ có những người giữ
chìa khóa (key) bí mật mới có thể giải mã (decryption) thông tin dạng ẩn tàng
trở lại thành dạng thông tin có dạng tường minh.
Giải mã (decrypt, decipher, decryption) đó là quá trình ngược
lại với mã hóa, khôi phục lại những thông tin dạng ban đầu từ thông tin ở dạng
đã được mã hóa.
Thuật toán mã hóa là một tập hợp các quy tắc được sử dụng để
thực hiện quá trình mã hóa và giải mã nhằm che giấu thông tin hoặc giải mã
thông tin
Ví dụ :
Người Hebrew (Do Thái cổ) đã sáng tạo một
thuật toán mã hóa đơn giản và hiệu quả gọi là thuật toán atbash mà chìa khóa mã
hóa và giải mã là một sự thay thế (substitution) trong bảng chữ cái. Giả sử
dùng chìa khóa mã hóa là bảng hoán vị:
Khi đó chẳng hạn từ gốc (plaintext): JERUSALEM sẽ được mã hóa
thành từ mã (ciphertext): QVIFHZOVN. Nếu người nhận tin có chìa khóa thì việc
biến đổi QVIFHZOVN trở lại thành JERUSALEM là điều hoàn toàn đơn giản, nhưng
nếu không có chìa khóa thì quả là khó khăn, người nhận được thông điệp không
thể nào hiểu nổi QVIFHZOVN có nghĩa là gì cả! Cho dù biết rằng quy luật mã hóa
chỉ là một sự thay thế của 25 chữ cái nhưng nếu tấn công bạo lực thì phải thử
lần lượt hết mọi khả năng tạo chìa khóa, tức là phải thử 25! khả năng (tất
nhiên về sau người ta có rất nhiều biện pháp để giảm bớt khả năng dò tìm, chẳng
hạn nếu plaintext có độ dài khá lớn thì có thể sử dụng dò tìm theo tần suất
xuất hiện của các ký tự).
Thuật toán mã hóa
là một thuật toán nhằm mã hóa thông tin của chúng ta, biến đổi thông tin từ
dạng rõ sang dạng mờ, để ngăn cản việc đọc trộm nội dung của thông tin (Dù
hacker có được thông tin đó cũng không hiểu nội dung chứa trong nó là gì).
Thông thường các
thuật toán sử dụng một hoặc nhiều key (Một chuỗi chìa khóa để mã hóa và giải mã
thông tin) để mã hóa và giải mã (Ngoại trừ những thuật toán cổ điển). Bạn có
thể coi key này như một cái password để có thể đọc được nội dung mã hóa. Người
gửi sẽ dùng key mã hóa để mã hóa thông tin sang dạng mờ, và người nhận sẽ sử
dụng key giải mã để giải mã thông tin sang dạng rõ. Chỉ những người nào có key
giải mã mới có thể đọc được nội dung.
Nhưng đôi khi
"kẻ thứ ba" (hacker) không có key giải mã vẫn có thể đọc được thông
tin, bằng cách phá vỡ thuật toán. Và có một nguyên tắc là bất kì thuật toán mã
hóa nào cũng đều có thể bị phá vỡ. Do đó không có bất kì thuật toán mã hóa nào
được coi là an toàn mãi mãi. Độ an toàn của thuật toán được dựa vào nguyên tắc:
Nếu chi phí để giải mã một khối lượng thông
tin lớn hơn giá trị của khối lượng thông tin đó thì thuật toán đó được tạm coi
là an toàn. (Không ai lại đi bỏ ra 50 năm để giải mã một thông tin mà chỉ mang
lại cho anh ta 1000 đô).
Nếu thời gian để phá vỡ một thuật toán là
quá lớn (giả sử lớn hơn 100 năm, 1000 năm) thì thuật toán được tạm coi là an
toàn.
II. PHÂN LOẠI MÃ HÓA
Ngày nay người ta phân biệt ra hai nhóm
thuật toán mã hóa chính là: Các thuật toán mã hóa cổ điển và các thuật toán
hiện đại.
1. Các thuật toán cổ điển
Các thuật toán cổ
điển: (những thuật toán này ngày nay đôi khi vẫn còn được dùng chẳng hạn trong
trò chơi tìm mật thư) gồm: Thuật toán thay thế, Thuật toán chuyển vị.
1.1. Thuật toán thay thế
Thuật toán thay
thế (Substitution) là thuật toán mã hóa trong đó từng ký tự (hoặc từng nhóm ký
tự) của plaintext được thay thế bằng một (hay một nhóm) ký tự khác. Thuật toán
atbash của người Hebrew hay thuật toán vòng của Caesar đều là các thuật toán
thay thế. Chính ý tưởng của mã vòng Caesar đã được ứng dụng trong máy Enigma.
Đây
là phương pháp mã hóa đầu tiên, và cố xưa nhất, và hiện nay rất ít được dùng
đến so với các phương pháp khác. Ý tưởng của phương pháp này rất đơn giản, bên
A mã hóa thông tin bằng thuật toán mã hóa cổ điển, và bên B giải mã thông tin,
dựa vào thuật toán của bên A, mà không dùng đến bất kì key nào. Do đó, độ an
toàn của thuật toán sẽ chỉ dựa vào độ bí mật của thuật toán, vì chỉ cần ta biết
được thuật toán mã hóa, ta sẽ có thể giải mã được thông tin.
1.2. Thuật toán chuyển vị
Thuật toán chuyển
vị (Transposition) là thuật toán mã hóa trong đó các ký tự trong văn bản ban
đầu chỉ thay đổi vị trí cho nhau còn bản thân các ký tự không hề bị biến đổi.
2. Các thuật toán hiện đại
Thuật toán hiện
đại là thuật ngữ dùng để chỉ các thuật toán được phát triển trong những năm gần
đây, thường dựa trên các lý thuyết và kỹ thuật tiên tiến. Thuật toán hiện đại
thường có hiệu quả hơn các thuật toán truyền thống, và có thể giải quyết các
vấn đề mà các thuật toán truyền thống không thể. Người ta thường chia thành 3
loại sau đây : Mã hóa đối xứng hay khóa bí mật SKC (Secret Key Cryptography),
Mã hóa bất đối xứng hay khóa công khai và khóa riêng PKC (Public and Private
Keys Cryptography) và Hàm băm (Hash function)
2.1. Hàm băm (Hash
function)
Hàm băm
(Hash function): Mã hóa một chiều (one-way cryptography) dùng một biến đổi toán
học để “mã hóa” thông tin gốc thành một dạng không biến đổi ngược được: không
có chìa khóa vì từ ciphertext không tìm ngược lại được plaintext!
Đôi khi ta chỉ cần
mã hóa thông tin chứ không cần giải mã thông tin, khi đó ta sẽ dùng đến phương
pháp mã hóa một chiều (Chỉ có thể mã hóa chứ không thể giải mã). Thông thường
phương pháp mã hóa một chiều sử dụng một hàm băm (hash function) để biến một chuỗi
thông tin thành một chuỗi hash có độ dài nhất định. Ta không có bất kì cách nào
để khôi phục (hay giải mã) chuỗi hash về lại chuỗi thông tin ban đầu.
Hàm băm (Hash function) là một hàm mà nó nhận vào một chuỗi có độ dài bất
kì, và sinh ra một chuỗi kết quả có độ dài cố định (Gọi là chuỗi hash), dù hai
chuỗi dữ liệu đầu vào, được cho qua hàm băm thì cũng sinh ra hai chuỗi hash kết
quả khác nhau rất nhiều. Ví dụ như đối với kiểu dữ liệu Hash-table, ta có thể
coi đây là một dạng kiểu dữ liệu mảng đặc biệt mà index nó nhận vào là một chuỗi,
nó được định nghĩa bằng cách bên trong nó chứa một mảng thông thường, mỗi khi
truyền vào index là một chuỗi, thì chuỗi này sẽ đi qua hàm băm và ra một giá trị
hash, giá trị này sẽ tương ứng với index thật của phần tử đó trong mảng bên dưới.
Đặc điểm của hash
function là khi thực hiên băm hai chuỗi dữ liệu như nhau, dù trong hoàn cảnh
nào thì nó cũng cùng cho ra một chuỗi hash duy nhất có độ dài nhất định và
thường nhỏ hơn rất nhiều so với chuỗi gốc, và hai chuỗi thông tin bất kì dù
khác nhau rất ít cũng sẽ cho ra chuỗi hash khác nhau rất nhiều. Do đó hash
function thường được sử dụng để kiểm tra tính toàn vẹn của dữ liệu.
Ngoài ra có một
ứng dụng mà có thể bạn thường thấy, đó là để lưu giữ mật khẩu. Vì mật khẩu là
một thứ cực kì quan trọng, do đó ta không nên lưu mật khẩu của người dùng dưới
dạng rõ, vì như vậy nếu bị hacker tấn công, lấy được CSDL thì hacker có thể
biết được mật khẩu của người dùng. Do đó, mật khẩu của người dùng nên được lưu
dưới dạng chuỗi hash, và đối với server thì chuỗi hash đó chỉnh là “mật khẩu”
đăng nhập (lúc đăng nhập thì mật khẩu mà người dùng nhập cũng được mã hóa thành
chuỗi hash và so sánh với chuỗi hash trong CSDL của server). Dù hacker có lấy
được CSDL thì cũng không tài nào có thể giải mã được chuỗi hash để tìm ra mật
khẩu của người dùng.
Các loại Thuật toán mã hóa
một chiều (hàm băm) phổ
biến là:
+ MD5 (Message
Digest Algorithm 5): Dù vẫn còn sử dụng, nhưng đã bị coi là không an toàn
do nhiều lỗ hổng bảo mật. Độ dài hash là 128-bit.
+ SHA-1 (Secure
Hash Algorithm 1): Cũng không an toàn nữa do các phương pháp tấn công đã
được phát triển. Độ dài hash là 160-bit.
+ SHA-256,
SHA-384, SHA-512: Là các biến thể của SHA-2, cung cấp độ dài hash lớn
hơn (tương ứng là 256-bit, 384-bit, và 512-bit) và được xem là an toàn cho đến
thời điểm hiện tại.
+ Whirlpool: Một hàm băm có
độ dài hash lên đến 512-bit, được coi là an toàn và phổ biến trong một số ứng
dụng bảo mật.
+ bcrypt: Thường được sử
dụng cho lưu trữ mật khẩu, có thể được điều chỉnh để yêu cầu nhiều tài nguyên
tính toán, làm chậm quá trình tấn công brute-force.
+ Scrypt: Tương tự như
bcrypt, nhưng còn sử dụng bộ nhớ nhiều hơn, làm cho nó trở nên khó khăn hơn cho
tấn công brute-force.
+ SHA-3 (Secure Hash
Algorithm 3): Một trong những tiếp nối của họ SHA, được thiết kế để cung cấp
một lựa chọn mới với cấu trúc khác biệt.
2.2. Mã hóa đối xứng
hay khóa bí mật SKC
Mã hóa
đối xứng hay khóa bí mật SKC (Secret Key Cryptography): Là phương pháp mã hóa mà
key mã hóa và key giải mã là như nhau (Sử dụng cùng một secret key để mã hóa và
giải mã). Đây là phương pháp thông dụng nhất hiện nay dùng để mã hóa dữ liệu
truyền nhận giữa hai bên. Vì chỉ cần có secret key là có thể giải mã được, nên
bên gửi và bên nhận cần làm một cách nào đó để cùng thống nhất về secret key.
Để thực hiện mã
hóa thông tin giữa hai bên thì:
Đầu tiên bên gửi và bên nhận bằng cách nào
đó sẽ phải thóa thuận secret key (khóa bí mật) được dùng để mã hóa và giải mã.
Vì chỉ cần biết được secret key này thì bên thứ ba có thể giải mã được thông
tin, nên thông tin này cần được bí mật truyền đi (bảo vệ theo một cách nào đó).
Sau đó bên gửi sẽ dùng một thuật toán mã hóa
với secret key tương ứng để mã hóa dữ liệu sắp được truyền đi. Khi bên nhận nhận
được sẽ dùng chính secret key đó để giải mã dữ liệu. Vấn đề lớn nhất của phương
pháp mã hóa đối xứng là làm sao để “thỏa thuận” secret key giữa bên gửi và bên
nhận, vì nếu truyền secret key từ bên gửi sang bên nhận mà không dùng một phương
pháp bảo vệ nào thì bên thứ ba cũng có thể dễ dàng lấy được secret key này.
Các loại mã hóa đối xứng phổ biến là:
+ DES (Data Encryption Standard): Một
trong những thuật toán mã hóa đối xứng đầu tiên và phổ biến, được sử dụng trong
nhiều ứng dụng.
+ AES (Advanced
Encryption Standard): Tiêu chuẩn hiện đại thay thế DES, với khóa có thể là
128, 192, hoặc 256 bit.
+ IDEA
(International Data Encryption Algorithm) :Một thuật
toán mã hóa đối xứng mạnh mẽ và an toàn.
+ Blowfish: Thuật toán mã
hóa đối xứng với khóa có thể được điều chỉnh linh hoạt.
+ Twofish: Một phiên bản
nâng cao của Blowfish, thiết kế để cung cấp độ bảo mật cao.
+ RC4 (Rivest
Cipher 4): Một thuật toán mã hóa dựa trên việc tạo ra dãy khóa ngẫu nhiên,
thường được sử dụng trong các ứng dụng như SSL/TLS.
+ 3DES (Triple
DES): Sự kết hợp của ba chu kỳ mã hóa DES, tăng cường độ bảo mật so với
DES.
+ RC6: Một thuật toán
mã hóa đối xứng phức tạp dựa trên cấu trúc Feistel.
2.3. Mã hóa bất đối xứng
hay khóa công khai và khóa riêng PKC
Mã hóa
bất đối xứng hay khóa công khai và khóa riêng PKC (Public and Private Keys
Cryptography): Sử dụng hai khóa riêng biệt: một khóa để mã hóa (khóa công khai:
public key) và một khóa khác để giải mã (khóa riêng: private key).
Nghĩa
là key ta sử dụng để mã hóa dữ liệu sẽ khác với key ta dùng để giải mã dữ liệu.
Tất cả mọi người đều có thể biết được public key (kể cả hacker), và có thể dùng
public key này để mã hóa thông tin. Nhưng chỉ có người nhận mới nắm giữ private
key, nên chỉ có người nhận mới có thể giải mã được thông tin.
Để thực hiện mã hóa bất đối xứng thì:
Bên nhận sẽ tạo ra một
gặp khóa (public key và private key). Bên nhận sẽ dữ lại private key và truyền
cho bên gửi public key. Vì public key này là công khai nên có thể truyền tự do
mà không cần bảo mật.
Bên gửi trước khi gửi dữ
liệu sẽ mã hóa dữ liệu bằng thuật toán mã hóa bất đối xứng với key là public
key từ bên nhận.
Bên nhận sẽ giải mã dữ
liệu nhận được bằng thuật toán được sử dụng ở bên gửi, với key giải mã là
private key.
Điểm yếu lớn nhất
của mã hóa bất đối xứng là tốc độ mã hóa và giải mã rất chậm so với mã hóa đối
xứng, nếu dùng mã hóa bất đối xứng để mã hóa dữ liệu truyền – nhận giữa hai bên
thì sẽ tốn rất nhiều chi phí.
Do đó, ứng dụng
chỉnh của mã hóa bất đối xứng là dùng để bảo mật secret key cho mã hóa đối
xứng: Ta sẽ dùng phương pháp mã hóa bất đối xứng để truyền secret key của bên
gửi cho bên nhận. Và hai bên sẽ dùng secret key này để trao đổi thông tin bằng
phương pháp mã hóa đối xứng.
Các loại mã hóa bất đối xứng phổ biến là:
+ RSA (Rivest–Shamir–Adleman): Sử dụng cặp khóa
công khai và khóa riêng tư, phổ biến trong bảo mật truyền thông và chữ ký số.
+ Diffie-Hellman: Dùng để trao đổi
khóa bí mật qua kênh không an toàn, thường được sử dụng trong quá trình thiết
lập kết nối an toàn.
+ Elliptic Curve
Cryptography (ECC): Sử dụng toán học đại số đồng dư trên các đường cong
elip, cung cấp độ bảo mật cao với chi phí tính toán thấp.
+ DSA (Digital
Signature Algorithm): Một thuật toán chữ ký số được sử dụng để xác minh tính
toàn vẹn của dữ liệu và xác nhận danh tính của người ký.
+ ElGamal: Kết hợp việc
trao đổi khóa Diffie-Hellman với mã hóa bất đối xứng, thường được sử dụng trong
bảo mật truyền thông.
+ Blum Blum Shub: Sử dụng số
nguyên tố và toán học modular, thường được sử dụng trong sinh số ngẫu nhiên an
toàn.
+ Lattice-based
Cryptography: Dựa trên khái niệm lưới số học, được xem là an toàn
trước nhiều thuật toán phân tích của máy tính lượng tử.
III. TẠI SAO PHẢI MÃ HÓA
Bởi vì mã hóa là
một phần quan trọng của bảo mật thông tin và bảo vệ dữ liệu giúp giảm bị mất
hoặc đánh cắp dữ liệu khi bị tấn công từ môi trường bên ngoài .
Dưới đây là một số
lý do chính tại sao phải sử dụng mã hóa:
+ Bảo vệ dữ liệu
riêng tư : Mã hóa giúp bảo vệ thông tin cá nhân và nhạy cảm khỏi sự truy
cập trái phép. Điều này đặc biệt quan trọng khi truyền dữ liệu qua các kênh
không an toàn như internet.
+ Ngăn chặn thay
đổi dữ liệu hay lộ lọt dữ liệu : Mã hóa giúp đảm bảo tính toàn vẹn
của dữ liệu bằng cách ngăn chặn sự thay đổi trái phép từ bên thứ ba.
+ Bảo vê mật khẩu: Khi lưu trữ mật
khẩu, sử dụng hàm băm hoặc mã hóa đảm bảo rằng mật khẩu không thể dễ dàng bị
đọc được nếu hệ thống bị tấn công.
+ Bảo mật thông
tin truyền tải :Trong quá trình truyền tải dữ liệu giữa hai đối
tượng, mã hóa giúp ngăn chặn sự đánh cắp thông tin trên đường truyền.
+ Đảm bảo quy
chuẩn trong an toàn thông tin: Nhiều lĩnh vực, như y tế và tài chính,
yêu cầu việc bảo mật thông tin. Mã hóa giúp tự động đáp ứng nhiều yêu cầu an ninh
thông tin.
+ Bảo vệ dữ liệu
cất trữ : Khi lưu trữ dữ liệu trên các thiết bị lưu trữ hoặc trong các cơ
sở dữ liệu, mã hóa ngăn chặn sự truy cập trái phép vào dữ liệu đó.
Tóm lại, việc sử dụng mã hóa đóng vai trò quan
trọng trong việc bảo vệ dữ liệu, đảm bảo an toàn thông tin và tuân thủ các
chuẩn mực an ninh.
IV. CHI TIẾT MỘT SỐ THUẬT TOÁN MÃ HÓA THƯỜNG
DÙNG
1.
DES
1.1. Tổng quan về DES
DES (Data Encryption Standard) là chuẩn mã hóa dữ liệu đầu
tiên trên thế giới, do Cơ quan an ninh Quốc gia Hoa Kỳ (NSA) đề xuất trên cơ sở
cải tiến thuật toán Lucifer do hãng IBM công bố năm 1964. DES đã được sử dụng rộng
rãi ở Hoa Kỳ và nhiều quốc gia khác trong các thập kỷ 70, 80, 90 cho đến khi được
thay thế bởi Tiêu chuẩn mã hóa dữ liệu tiên tiến AES (Advanced Encryption
Standard) vào năm 2002.
Đầu vào của DES là khối 64 bit, đầu ra cũng là khối 64 bit.
Khóa mã hóa có độ dài 56 bit, nhưng thực chất ban đầu là 64 bit, được lấy đi
các bit ở vị trí chia hết cho 8 dùng để kiểm tra tính chẵn lẻ.
1.2. Thuật toán
DES là thuật toán mã hóa theo khối, nó xử
lý từng khối thông tin của bản rõ có độ dài xác định là 64 bit. Trước khi đi
vào 16 chu trình chính, khối dữ liệu cần bảo mật sẽ được tách ra thành từng
khối 64 bit, và từng khối 64 bit này sẽ lần lượt được đưa vào 16 vòng mã hóa
DES để thực hiện. Input: Bản rõ M = m1m2…m64 là một khối 64
bit, khóa 64 bit K = k1k2…k64. Output: Bản mã 64 bit C = c1c2…
c64
+ Bước 1: Sinh khóa con: Sử dụng thuật toán sinh khóa con từ
khóa K ta sẽ được 16 khóa con K1, K2, … K16
+ Bước 2: Sử dụng phép hoán vị khởi đầu IP (Initial Permutation)
để hoán vị các bit của M, kết quả nhận được chia thành 2 nửa là L0 =
m63m62…m32, R0 = m31m30…m0.
+ Bước 3: Với i chạy từ i = 1 đến 16 thực hiện: Tính các Li và
Ri theo công thức: Li = Ri-1 Ri = Li-1 XOR f(Ri-1, Ki) trong đó f(Ri-1, Ki) =
R(S(E(Ri-1) XOR Ki)). Việc tính f(Ri-1, Ki) sẽ được trình bày chi tiết ở phần
sau.
+ Bước 4: Đổi vị trí khối L16, R16 ta được khối R16L16 =
b1b2…b64.
+ Bước 5: Sử dụng phép hoán vị kết thúc FP(Final Permutation –
nghịch đảo với hoán vị khởi đầu IP) ta thu được bản mã cần tìm : C =
IP-1(b1b2…b64)
1.3. Quá trình sinh khóa con
16 vòng lặp của
DES chạy cùng thuật toán như nhau nhưng với 16 khóa con khác nhau. Các khóa con
đều được sinh ra từ khóa chính của DES bằng thuật toán sinh khóa con.
Khóa ban đầu là 1 xâu có độ dài 64 bit, bit thứ 8 của mỗi
byte sẽ được lấy ra để kiểm tra phát hiện lỗi, tạo ra chuỗi 56 bit. Sau khi bỏ
các bit kiểm tra ta sẽ hoán vị chuỗi 56 bit này. Hai bước trên được thực hiện
thông qua hoán vị ma trận PC-1 (Permuted choice 1).
Tiếp theo ta kết quả sau khi PC-1 thành 2 phần : C0 : 28 bit
đầu. D0 : 28 bit cuối. Mỗi phần sẽ được xử lý 1 cách độc lập. Ci = LSi(Ci-1) Di
= LSi(Ci-1) với 1 ≤ i ≤ 16. LSi là biểu diễn phép dịch bit vòng (cyclic shift)
sang trái 1 hoặc 2 vị trí tùy thuộc vào i.
Cuối cùng sử dụng hoán vị cố định PC-2 (Permuted choice 2) để
hoán vị chuỗi CiDi 56 bit tạo thành khóa Ki với 48 bit.
1.4. Quá trình mã hóa DES
Chia thành 3 giai
đoạn:
Giai đoạn 1:
Với bản rõ cho
trước x, 1 xâu x’ sẽ được tạo ra bằng cách hoán vị các bit của x theo hoán vị
ban đầu IP.
Tiếp theo x’ sẽ
được chia thành 2 phần L0,R0. x’ = IP(x) = L0R0 Trong đó L0 là 32 bit đầu, R0
là 32 bit cuối.
Giai đoạn 2:
Tính toán 16 lần bằng 1 hàm xác định. Ta sẽ tính Li, Ri (1 ≤
i ≤ 16) theo quy tắc: Li = Ri-1. Ri = Li-1 XOR f(Ri-1, Ki). Với Ki là khóa được
sinh ra ở quá trình tạo khóa, f là một hàm sẽ được trình bày ở phần sau.
Giai đoạn 3:
Áp dụng hoán vị
kết thúc FP cho xâu bit R16L16 ta thu được bản mã y: y = FP(R16L16).
1.5. Giải mã DES
Quá trình giải mã
của DES cũng tương tự quá trình mã hóa. Chỉ khác nhau ở: Li = Ri-1. Ri = Li-1
XOR f(Ri-1, K16-i+1). Như vậy khóa K của hàm F sẽ đi từ khóa K16 đến khóa K1.
1.6. Hàm F
Đầu vào hàm f có 2 biến:
+ Biến thứ nhất: Ri-1 là xâu bit có độ dài 32 bit. - Biến thứ
hai: Ki là xâu bit có độ dài 48 bit. Đầu ra của hàm f là xâu có độ dài 32 bit.
Quy trình hoạt động của hàm f như sau:
+ Biến thứ nhất Ri-1 được mở rộng thành một xâu có độ dài 48 bit
theo một hàm mở rộng hoán vị E (Expansion permutation). Thực chất hàm mở rộng
E(Ri-1) là một hoán vị có lặp trong đó lặp lại 16 bit của Ri-1.
+ Tính E(Ri-1) XOR Ki.
+ Tách kết quả của phép tính trên thành 8 xâu 6 bit B1, B2, …,
B8.
+ Đưa các khối 8 bit Bi vào 8 bảng S1, S2, …, S8 (được gọi là
các hộp S-box). Mỗi hộp S-Box là một bảng 4*16 cố định có các cột từ 0 đến 15
và các hàng từ 0 đến 3. Với mỗi xâu 6 bit Bi = b1b2b3b4b5b6 ta tính được SiBi
như sau: hai bit b1b6 xác định hàng r trong hộp Si, bốn bit b2b3b4b5 xác định
cột c trong hộp Si. Khi đó, Si(Bi) sẽ xác định phần tử Ci = Si(r,c), phần tử
này viết dưới dạng nhị phân 4 bit. Như vậy, 8 khối 6 bit Bi (1 ≤ i ≤ 8) sẽ cho
ra 8 khối 4 bit Ci với (1 ≤ i ≤ 8).
+ Xâu bit C = C1C2C3C4C5C6C7C8 có độ dài 32 bit được hoán vị
theo phép toán hoán vị P (hộp P-Box). Kết quả P(C) sẽ là kết quá của hàm
f(Ri-1,Ki).
Hàm mở rộng E
Hàm ở rộng E sẽ
tăng độ dài Ri-1 từ 32 bit lên 48 bit bằng cách thay đổi thứ tự các bit cũng
như lặp lại các bit. Việc thực hiện này nhằm hai mục đích:
+ Làm độ dài của Ri-1
cùng cỡ với khóa K để thực hiện việc cộng modulo XOR.
+ Cho kết quả dài hơn để
có thể được nén trong suốt quá trình thay thế. Tuy nhiên, cả hai mục đích này
nhằm một mục tiêu chính là bảo mật dữ liệu. Bằng cách cho phép 1 bit có thể
chèn vào hai vị trí thay thế, sự phụ thuộc của các bit đầu ra với các bit đầu
vào sẽ trải rộng ra.
Các hộp S-box
Sau khi thực hiện
phép XOR giữa E(Ri-1) và Ki, kết quả thu được chuỗi 48 bit chia làm 8 khối đưa
vào 8 hộp S-box. Mỗi hộp S-Box sẽ có 6 bit đầu vào và 4 bit đầu ra. Kết quả thu
được là một chuỗi 32 bit tiếp tục vào hộp P-Box.
+ Mỗi hàng trong mỗi hộp
S là hoán vị của các số nguyên từ 0 đến 15
+ Các hộp S-box phi tuyến
tính. nói cách khác, đầu ra không phải là biến đối tuyến tính của đầu vào.
+ Sự thay đổi của một
bit, hai bit hoặc nhiều hơn sẽ dẫn đến sự biến đổi ở đầu ra.
+ Nếu hai đầu vào của một S-box bất kì chỉ khác nhau 2 bit ở giữa (bit 3 và 4) thì đầu ra sẽ khác nhau ít nhất 2 bit. Nói cách khác, S(x) và S(x XOR 001100) phải khác nhau ít nhất 2 bit.
Hộp P-box
Mỗi 4 bit đầu ra
của các hộp S-box sẽ được ghép lại, theo thứ tự các hộp và được đem vào hộp
P-box. Hộp P-Box đơn giản chỉ là hoán vị các bit với nhau.
Ví dụ:
Ta có 1 bản tin M,
M = 0123456789ABCDEF và một khóa K = 13345799BBCDDFF1 với M, K được định dạng
dưới dạng hệ thập lục phân, ta tiến hành mã hóa và giải mã theo giải thuật DES
theo các bước sau. Ta viết lại M, K dưới dạng nhị phân , chúng ta nhận được khối
64bit của của văn bản M và khóa K M = 0000 0001 0010 0011 0100 0101 0110 0111
1000 1001 1010 1011 1100 1101 1110 1111 chia 64 bit trên thành 2 nửa trái và
phải, lấy từ trái qua phải mỗi phần 32 bit L = 0000 0001 0010 0011 0100 0101
0110 0111
R = 1000 1001 1010 1011 1100 1101 1110 1111 DES hoạt động trên các khối 64-bit
sử dụng kích thước chính của 56- bit. Các khóa thực sự được lưu trữ dài 64 bit,
nhưng mỗi bit thứ 8 trong khóa không được sử dụng (tức là bit số 8, 16, 24, 32,
40, 48, 56, và 64). Tuy nhiên, chúng ta sẽ vẫn đánh số các bit 1-64, đi từ trái
sang phải, trong các tính toán sau đây. Tuy nhiên, ta sẽ thấy, tám bit đề cập
đến được loại trừ khi chúng ta tạo ra khóa. Đưa K về dạng nhị phân: K =
00010011 00110100 01010111 01111001 10011011 10111100 11011111 11110001 Thuật
toán DES sử dụng các bước sau:
Bước 1: Tạo 16 khóa con,
mỗi khóa có chiều dài 48 bit Khóa 64 bit được hoán vị theo bảng dưới đây, PC-1.
Chỉ có 56 bit của khóa ban đầu xuất hiện trong khóa hoán vị PC-1
Từ khóa 64 bit ban đầu: K = 00010011 00110100 01010111
01111001 10011011 10111100 11011111 11110001 Từ bảng hoán vị trên ta thấy: bit
thứ 57 của K là bit ‘1’, thứ 49 của K là bit ‘1’, bít thứ 41, 33, 25, 17, 9 lần
lượt là 11000…. Chúng ta nhận được hoán vị 56 bit: K+ = 1111000 0110011 0010101
0101111 0101010 1011001 1001111 0001111 Tiếp theo, chia khóa này thành 2 nửa
trái và phải , C0 và D0, mỗi nửa 28 bit, ta được: C0 = 1111000 0110011 0010101
0101111 D0 = 0101010 1011001 1001111 0001111 Với C0 và D0 đã được xác định, bây
giờ chúng ta tạo ra 16 khối CnDn 1<=n<=16. Mỗi cặp CnDn được hình thành từ
các cặp trước nó Cn-1Dn-1 bằng cách sử dụng quy luật sau đối với khối trước nó
Điều này có nghĩa
là , ví dụ C3, D3 thu được nhờ sự dịch trái 2 lần C2, D2, hay C2, D2 thu được
nhờ sự dịch trái 1 lần của C1, D1 Ta đã có C0 = 1111000 0110011 0010101 0101111
D0 = 0101010 1011001 1001111 0001111
Từ bảng quy luật
trên ta thấy, C1D1 được sinh ra khi thực hiện dịch trái 1 lần đối với C0D0 ta
thu được : C1 = 111000 0110011 0010101 01011111 D1 = 101010 1011001 1001111
00011110 Tương tự ứng với bảng quy luật trên ta thu được các khối CnDn
(1<=n<=16) như sau:
C2 =
1100001100110010101010111111
D2 =
0101010110011001111000111101
C3 =
0000110011001010101011111111
D3 =
0101011001100111100011110101
C4 =
0011001100101010101111111100
D4 =
0101100110011110001111010101
C5 =
1100110010101010111111110000
D5 =
0110011001111000111101010101
C6 =
0011001010101011111111000011
D6 =
1001100111100011110101010101
C7 =
1100101010101111111100001100
D7 =
0110011110001111010101010110
C8 =
0010101010111111110000110011
D8 =
1001111000111101010101011001
C9 =
0101010101111111100001100110
D9 =
0011110001111010101010110011
C10 =
0101010111111110000110011001
D10 =
1111000111101010101011001100
C11 = 0101011111111000011001100101
D11 =
1100011110101010101100110011
C12 =
0101111111100001100110010101
D12 =
0001111010101010110011001111
C13 =
0111111110000110011001010101
D13 =
0111101010101011001100111100
C14 =
1111111000011001100101010101
D14 =
1110101010101100110011110001
C15 =
1111100001100110010101010111
D15 =
1010101010110011001111000111
C16 =
1111000011001100101010101111
D16 =
0101010101100110011110001111
Bây giờ chúng ta
xây dựng các khóa Kn (1<=k<=16) bằng cách áp dụng bảng hoán vị sau cho
mỗi cặp CnDn. Mỗi cặp có 56 bit, nhưng PC-2 chỉ sử dụng 48 trong số này. PC-2
Từ C1D1 = 1110000 1100110 0101010 1011111 1010101 0110011
0011110 0011110 Từ bảng trên ta thấy: bit thứ 14 của C1D1 là bít đầu tiên của
K1 tức là bit ‘0’, bit thứ 17 là bít thứ 2 của K1, tức bit ‘0’…bít cuối cùng của
K1 là bít thứ 32 của C1D1 tức là bit ‘0’
K1 = 000110 110000 001011 101111 111111 000111 000001 110010
Tương tự cho các khóa khác, ta có:
K2 = 011110 011010 111011 011001 110110 111100 100111 100101
K3 = 010101 011111 110010 001010 010000 101100 111110 011001
K4 = 011100 101010 110111 010110 110110 110011 010100 011101
K5 = 011111 001110 110000 000111 111010 110101 001110 101000
K6 = 011000 111010 010100 111110 010100 000111 101100 101111
K7 = 111011 001000 010010 110111 111101 100001 100010 111100
K8 = 111101 111000 101000 111010 110000 010011 101111 111011
K9 = 111000 001101 101111 101011 111011 011110 011110 000001
K10 = 101100 011111 001101 000111 101110 100100 011001 001111
K11 = 001000 010101 111111 010011 110111 101101 001110 000110
K12 = 011101 010111 000111 110101 100101 000110 011111 101001
K13 = 100101 111100 010111 010001 111110 101011 101001 000001
K14 = 010111 110100 001110 110111 111100 101110 011100 111010
K15 = 101111 111001 000110 001101 001111 010011 111100 001010
K16 = 110010 110011 110110 001011 000011 100001 011111 110101
Bước 2: Mã hóa 64 bit khối dữ liệu Có một hoán vị IP ban đầu của 64
bit của dữ liệu M, sắp xếp lại các bit này theo quy luật bảng dưới đây IP
Áp dụng hoán vị cho khối văn bản ban đầu M, ta nhận được: M =
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
IP = 1100 1100 0000 0000 1100 1100 1111 1111 1111 0000 1010 1010 1111 0000 1010
1010 Chia khối IP hoán vị thành 1 nửa trái L0 32 bit và một nửa phải R0 32bit,
từ IP ta nhận được: L0 = 1100 1100 0000 0000 1100 1100 1111 1111 R0 = 1111 0000
1010 1010 1111 0000 1010 1010 Bây giờ chúng ta tiến hành thông qua 16 vòng lặp,
sử dụng một hàm f mà hoạt động trên 2 khối – một khối dữ liệu 32bit và 1 khóa
Kn 48bit để sinh ra một khối 32bit Ln = Rn-1 Rn = Ln-1 f(Rn-1, Kn) For n = 1,
ta có K1 = 000110 110000 001011 101111 111111 000111 000001 110010 L1 = R0=
1111 0000 1010 1010 1111 0000 1010 1010 R1 = L0 f(R0,K1) Để tính hàm f, chúng
ta mở rộng mỗi khối Rn-1 từ 32bit lên 48bit bằng cách sử dụng một bảng một bảng
lựa chọn mà lặp đi lặp lại một số bit trong Rn-1. Ta gọi việc sử dụng mỗi lựa
chọn bảng này là hàm E. Vì vậy, E(Rn-1) có khối đầu vào 32bit và một khối đầu
ra 48bit 48bit đầu ra được viết như 8 khối 6bit thu được bằng cách chọn các các
bit trong đầu vào của nó theo theo bảng sau: E BIT-SELECTION TABLE
Ta tính E(R0) từ R0 như sau: R0 = 1111 0000 1010 1010 1111
0000 1010 1010 E(R0) = 011110 100001 010101 010101 011110 100001 010101 010101
Ta thấy mỗi khối 4bit ban đầu đã được mở rộng đến một khối 6 bit đầu ra. Tiếp
theo để tính f , ta XOR đầu ra E(Rn-1) với khóa Kn: Kn E(Rn-1) Ví dụ: Cho K1,
E(R0) ta có K1= = 000110 110000 001011 101111 111111 000111 000001 110010 E(R0)
= 011110 100001 010101 010101 011110 100001 010101 010101 K1 E(R0) = 011000
010001 011110 111010 100001 100110 010100 100111 Tiếp theo ta sẽ sử dụng mỗi
nhóm 6bit như các địa chỉ trong bảng gọi lại “S boxes”. Mỗi nhóm 6bit sẽ cung cấp
1 địa chỉ trong một S box khác nhau. Nằm tại địa chỉ đó sẽ có 1 số 4bit. Số
4bit này sẽ thay thế 6bit ban đầu . Kết quả cuối cùng là 8 nhóm 6bit được chuyển
thành 8 nhóm 4bit, tổng số sẽ là 32 bit. Viết kết quả trước đó với 48bit dưới dạng
sau: Kn E(Rn-1) = B1B2B3B4B5B6B7B8 Trong đó mỗi Bi là một nhóm 6 bit như ta đã
xã định với trường hợp K1 E(R0) ở trên. Bây giờ ta phải tính
S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8) Với Si(Bi) tương ứng là đầu ra
của hộp thứ i S box Mỗi hàm S1, S2,…, S8 có một khối 6bit là đầu vào và một khối
4bit là đầu ra. Bảng xác định S1: S1
S1 là hàm được xác định trong bảng này và B là một khối 6 bit
đầu vào, S1(B) được xác định như sau: xác định bit đầu tiên và cuối cùng của B:
nó là một số nhị phân có dạng 00,01, 10 hoặc 11, tức là có giá trị từ 0-3 dạng
thập phân. Đặt giá trị này là i. còn lại 4 bit giữa của B sẽ có giá trị trong
khoảng từ 0 đến 15 dạng thập phân (vì dạng nhị phân của B nằm trong khoảng
0000-1111). Đặt giá trị này là j. Tra trong bảng số S1 ở trên hàng thứ i và cột
thứ j. Đó là một số trong khoảng từ 0 đến 15 và biểu diễn nó bởi một khối 4
bit. Khối đó là đầu ra S1(B) của S1 cho đầu vào B. Ví dụ, khối đầu vào B1 =
011000, bit đầu tiên là "0" và bit cuối cùng "0" 00= 0
=> i=0. Đây là hàng 0. bốn bit giữa là "1100", 1101 = 12=>
j=12. vì vậy cột là cột số 12. Tìm tới hàng 0 cột 12 (0,12) = 5 , 5 nhị phân là
0101. Do đó S1(B1) = 0101. Ta có các bảng xác định S2, S3, …S8 như sau:
S2
Đối với vòng đầu tiên, đã đã tính toán và có: K1 E(R0) =
011000 010001 011110 111010 100001 100110 010100 100111 Từ các bảng trên với
B1, B2, …, B8 đã xác định ta tính được:
S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8) =
0101 1100 1000 0010 1011 0101 1001 0111
Cuối cùng trong việc tính toán f là làm một hàm hoán vị P của
các đầu ra S-box để có được giá trị cuối cùng của f:
f(R0,K1) = P(S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8)
)
Hoán vị P được xác định trong bảng dưới đây: P
Từ đầu ra của 8
boxes:
S1(B1)S2(B2)S3(B3)S4(B4)S5(B5)S6(B6)S7(B7)S8(B8)
= 0101 1100 1000 0010 1011 0101 1001 0111
Ta có: f(R0,K1) =
0010 0011 0100 1010 1010 1001 1011 1011 R1 = L0 f(R0,K1) = 1100 1100 0000 0000
1100 1100 1111 1111 0010 0011 0100 1010 1010 1001 1011 1011 = 1110 1111 0100
1010 0110 0101 0100 0100
Vòng lặp tiếp theo
, sẽ có L2 = R1, R2 = L1 f(R1, K2) cứ làm tương tự trên cho 16 vòng lặp.
Vòng cuối cùng ta có các khối L16R16. Ta đảo ngược thứ tự của 2 khối và áp dụng một hoán vị IP-1 được xác định bởi bảng sau : IP-1
Xử lý tất cả 16 khối sử dụng phương pháp xác định như trên, tới
vòng lặp thứ 16 ta có được : L16 = 0100 0011 0100 0010 0011 0010 0011 0100
R16 = 0000 1010 0100 1100 1101 1001 1001 0101 Chúng ta đảo ngược thứ tự của 2
khối này và áp dụng hoán vị cuối cùng R16L16 = 0000 1010 0100 1100 1101 1001
1001 01010100 0011 0100 0010 0011 0010 0011 0100 IP-1 = 10000101 11101000
00010011 01010100 00001111 00001010 10110100 00000101 Chuyển đổi IP-1 về dạng
thập lục phân ta được : 85E813540F0AB405
Kết luận : Vậy dạng mã hóa của
M = 0123456789ABCDEF là C = 85E813540F0AB405
Giải mã : Quá trình giải mã
chỉ đơn giản là nghịch đảo của mã hóa, các bước thực hiện tương tự như trên
nhưng đảo ngược thứ tự các khóa được áp dụng, tức là áp dụng khóa K16 tới K1,
làm hoàn toàn giống các bước và trình tự như mã hóa.
2. RSA
RSA là một thuật ngữ vô cùng quen thuộc đối với những người học
trong lĩnh vực mật mã học. RSA đánh dấu sự phát triển vượt bậc trong lĩnh vực mật
mã học nói chung và được sử dụng rộng rãi trong các hoạt động thương mại điện tử.
RSA là một sản phẩm nghiên cứu với sự hợp lực của 3 nhà khoa
học lớn là Adi Shamir, Len Adleman và Ron Rivest và được đưa ra mô tả lần đầu
vào năm 1977 tại Học viện MIT. Cái tên RSA được lấy từ những chữ cái đầu tiên của
3 nhà khoa học.
RSA là một thuật
toán hay còn được gọi là hệ mã hóa đối xứng có phạm vi ứng dụng rộng rãi và phổ
biến. Người ta thường sử dụng RSA ở công tác mã hóa hay thiết lập chữ ký điện
tử với vai trò là mã hóa khóa công khai. Bất kỳ ai cũng có thể sử dụng khóa
công khai để mã hóa được dữ liệu muốn gửi đi nhưng để giải mã được chúng cần
phải có sự hỗ trợ của khóa bí mật.
Hoạt động gửi và
nhận cần có sự can thiệp bởi RSA vì bản thân nó chứa hai khóa là công khai và
bí mật để đảm nhận hai nhiệm vụ bất đối xứng là mã hóa và giải mã. Điều này
cũng tương tự như cơ chế đóng và mở khóa cửa vậy tuy nhiên RSA sẽ phức tạp hơn
nhiều vì nó là một thuật toán. Việc mã hóa giúp bảo mật thông tin nhưng cũng
gây bất lợi cho người nhận khi không biết cách giải mã để xem được những thông
tin bên trong. Chính vì lý do này mà khóa bí mật luôn được đi kèm với việc mã
hóa.
Khác với các loại
mã hóa có khóa đối xứng, khóa bí mật của RSA không truyền được tin ra bên ngoài
kể cả có kẻ tấn công nếu không có khóa bí mật cũng sẽ không giải mã được những
thông tin đó. Như vậy ta có thể thấy hai tính năng mã hóa và giải mã tối ưu đến
tuyệt đối của RSA, đây cũng là lý do chúng được sử dụng ở hầu hết các trường
hợp cần bảo mật thông tin. Giao thức SSL hay HTTPS cùng với chứng chỉ điện tử
đều sử dụng RSA.
2.1. RSA hoạt động như thế nào?
Hoạt
động của RSA dựa trên 4 bước chính: sinh khóa, chia sẻ key, mã hóa và giải mã. Mấu
chốt cơ bản của việc sinh khóa trong RSA là tìm được bộ 3 số tự nhiên e
, d
và n
sao
cho:
và một điểm không thể bỏ qua là cần bảo
mật cho d sao cho dù
biết e, n hay thậm chí cả m cũng không thể tìm ra d được.
Cụ thể, khóa của RSA được sinh như sau:
+ Chọn 2 số nguyên tố p và q
+ Tính n = pq. Sau
này, n sẽ được dùng làm
modulus trong cả public key và private key.
+ Tính một số giả nguyên tố bằng phi hàm Carmichael như sau: λ(n) = BCNN(λ(p), λ(q)) = BCNN(p − 1, q − 1).
Giá trị này sẽ được giữ bí mật.
+ Chọn một số tự nhiên e trong
khoảng (1, λ(n)) sao
cho ƯCLN(e, λ(n)) = 1, tức
là e và λ(n) nguyên tố cùng nhau.
+ Tính toán số d sao
cho d ≡ 1/e (mod λ(n)) hay
viết dễ hiểu hơn thì de ≡ 1 (mod λ(n)).
Số d được gọi là số nghịch
đảo modulo của e (theo
modulo mod λ(n)).
Public key sẽ là bộ số (n, e), và private key sẽ là bộ số (n, d). Chúng ta cần giữ private key thật cẩn
thận cũng như các số nguyên tố p và q vì từ đó có thể tính toán các khóa rất
dễ dàng.
Trong thực hành,
chúng ta thường chọn e
tương đối
nhỏ để việc mã hóa và giải mã nhanh chóng hơn. Giá trị thường được sử dụng
là e = 65537
. Ngoài ra, chúng ta có thể tính số giả
nguyên tố bằng phi hàm Euler φ(n)
= (p − 1)(q − 1)
và dùng nó như λ(n)
. Vì φ(n)
là bội
của λ(n)
nên các số d
thỏa
mãn de ≡ 1 (mod φ(n))
cũng sẽ thỏa
mãn d ≡ 1/e (mod λ(n))
. Tuy nhiên, một
số tác dụng phụ của việc này là d
thường sẽ
trở nên lớn hơn mức cần thiết.
2.2.
Mã hóa và giải mã
Trong phần này,
chúng ta sẽ tìm hiểu cách mã hóa với public key (n,
e)
và giải mã với private key (n,
d)
.
Nếu chúng ta có bản rõ M
, chúng ta cần chuyển nó
thành một số tự nhiên m
trong khoảng (0, n)
sao cho m
, n
nguyên tố cùng
nhau. Việc này rất dễ dàng thực hiện bằng cách thêm một các kỹ thuật padding.
Tiếp theo, chúng ta sẽ má hóa m
, thành c
như sau:
Sau đó giá
trị c
sẽ được chuyển cho người nhận.
Ở phía người nhận,
họ sẽ giải mã từ c
để lấy
được m
như sau:
Từ m có
thể lấy lại được bản tin bằng cách đảo ngược padding
Chúng ta lấy một ví dụ đơn giản như sau:
p = 5, q = 7
=> n = pq = 35
=> φ(n) = 24
Chúng ta chọn e = 5 vì ƯCLN(5, 24)
= 1, cuối cùng chọn d = 29 vì ed - 1 = 29x5 - 1 chia hết cho 24.
Giả sử m
= 32 (dấu cách), chúng ta sẽ mã hóa m và thu được
c = 32 ^ 5 % 35 = 2
Giải mã c
để thu
được m
m = 2 ^ 29 % 35 = 32
Đây chính là m
ban đầu. Bạn
có thể thứ m
với các giá
trị khác nhau để thấy thuật toán hoàn toàn chính xác. Tất nhiên rồi, nó đã được
chứng minh mà. Việc chứng minh RSA hoạt động chính xác là một vấn đề toán học
khá phức tạp mà bài viết này sẽ không đi vào chi tiết của nó.
Mức độ bảo mật của
RSA phụ thuộc rất lớn vào khả năng phân tích thừa số nguyên tố của các số lớn.
Bởi vì chúng ta cung cấp public một cách rộng rãi, nếu việc phân tích thừa số
nguyên tố đơn giản, thì việc bị lộ private là không thể tránh khỏi.
Vì vậy, khi sinh
khóa, chúng ta cần chọn các số nguyên tố p
và q
một cách
ngẫu nhiên. Bản thân hai số nguyên tố này cũng rất lớn, và để việc phân tích
thừa số nguyên tố khó khăn hơn, hai số nguyên tố này sẽ không có cùng độ dài.
Trong tương lai gần, có lẽ vẫn chưa có một phương pháp hiệu quả nào cho phép
thực hiện điều này với các máy tính cá nhân.
Tuy nhiên, với sự
phát triển của công nghệ, các siêu máy tính xuất hiện ngày càng nhiều. Cùng với
chúng ta máy tính lượng tử cho phép tính toán với tốc độ cao hơn rất nhiều có
thể sẽ phá vỡ sự bảo mật của RSA.
Ngày từ năm
1993, thuật toán Shor đã được phát
triển và chỉ ra rằng máy tính lượng tử có thể giải
bài toán phân tích ra thừa số trong thời gian đa thức. Rất may là những điều
này mới chỉ là lý thuyết vì đến thời điểm hiện tại và trong vài năm tới, máy
tính lượng tử vẫn chưa hoàn thiện.
Một câu hỏi khá
thú vị là có thể đảo vai trò của public key và private key hay không? Tức là
chúng ta dùng private key để mã hóa và dùng public key để giải mã hay không?
Câu trả lời là có. Tuy nhiên, không ai làm như vậy cả vì rất đơn giản: từ
public key rất khó để suy ra private key nhưng từ private để suy ra public thì
rất đơn giản. Nếu cho người khác private key (để họ mã hóa), những kẻ tấn công
man in the middle sẽ dễ dàng tính toán được public và thay đổi hoàn toàn cuộc
hội thoại của chúng ta.
Tuy nhiên, có một trường hợp chúng ta đã đảo vai trò của
private key và public key như vậy. Đó chính là khi chúng ta sử dụng chữ ký số.
2.3.
Ứng dụng của RSA trong cuộc sống
RSA trong bảo mật dữ liệu
RSA ra đời với mục
đích bảo vệ dữ liệu, do vậy chúng được ứng dụng rất nhiều trong hoạt động hiện
đại. Những ứng dụng của RSA trong bảo mật dữ liệu như:
Chứng thực dữ
liệu: chắc hẳn các bạn đã từng gặp tình trạng yêu cầu xác minh bằng cách đưa ra
các con số gửi về email hay số điện thoại trước khi đăng nhập. Đây chính là
phương pháp bảo mật thông tin, dữ liệu ứng dụng thuật toán RSA để tránh những
tình trạng mạo danh, hack tài khoản gây ảnh hưởng cho người dùng và xã hội.
Việc chứng thực giúp bảo vệ được tài khoản của bản thân người sử dụng giúp an
tâm hơn khi sử dụng các dịch vụ trực tuyến. Truyền tải dữ liệu an toàn: hiện
nay tình trạng nghe lén, theo dõi hoạt động cũng như lấy cắp dữ liệu cá nhân
trên mạng xã hội bị lên án và chỉ trích rất nhiều, bao gồm cả ông lớn Facebook.
Không chỉ những trang mạng xã hội, các trang web cũng không tránh khỏi việc lưu
lại các hoạt động, hành vi truy cập để phục vụ các mục đích Marketing. Do đó
với thuật toán RSA giúp dữ liệu khỏi các cuộc tấn công của kẻ xấu. Chữ ký số/
chữ ký điện tử: trên các thẻ ATM luôn có phần chữ ký điện tử đã được mã hóa từ
chữ ký của khách hàng khi đăng ký tài khoản tại ngân hàng. Có thể nói, trong
lĩnh vực ngân hàng, vấn đề bảo mật thông tin của khách hàng cần được đặt lên
hàng đầu, chúng quyết định chất lượng của dịch vụ. RSA được ứng dụng để bảo mật
dữ liệu khi người dùng thực hiện những giao dịch ngân hàng, đem lại trải nghiệm
tốt và giúp khách hàng an tâm hơn.
Ứng dụng của RSA trong công nghệ thông tin
Trong ngôn ngữ lập
trình Java, các nhà lập trình viên thường sử dụng những đoạn code chứa RSA để
tăng tính bảo mật cho trang web và ứng dụng cũng như đảm bảo an toàn cho người
sử dụng.
Các đoạn code RSA
này có thể hoạt động dưới bất kỳ sự thay đổi nào của môi trường. Ngoài ra, các
lập trình viên cũng sử dụng các ngôn ngữ lập trình khác bên cạnh Java có thể
tìm hiểu và ứng dụng những tính năng của RSA trong hoạt động làm việc và bảo
mật thông tin.
Ngày nay việc sử
dụng các ứng dụng, trang web trên internet ngày càng gia tăng khiến cho vấn đề
bảo mật dữ liệu càng được chú trọng. Những dữ liệu này có thể là những thông
tin bí mật cá nhân, thông tin về tài chính,… gây không ít nguy hại cho người sử
dụng. Cũng chính vì lý do này mà thuật toán RSA được biết đến và sử dụng nhiều
hơn trong tất cả các lĩnh vực đặc biệt là trong ngành ngân hàng. Với những chia
sẻ trong bài viết, chúng tôi hy vọng bạn đã giải mã được câu hỏi RSA là gì cũng
như những thông tin liên quan đến thuật toán này. Mong rằng các bạn đã có thêm
một bí quyết để bảo vệ những dữ liệu của mình một cách tốt hơn nhé!
Chữ ký số sử dụng hệ
mã hóa RSA
Việc ký tên và xác
thực chữ ký số sử dụng hệ mã hóa RSA tương tự như quá trình mã hóa mà giải mã ở
trên. Tuy nhiên vai trò của public key và private thì có thay đổi đôi chút.
Để tạo chữ ký,
người gửi sẽ dùng private key và người nhận sẽ dùng public key để xác thực chữ
ký đó.
Tuy nhiên, vì bản
tin rất dài nên việc mã hóa toàn bộ bản tin sẽ rất mất thời gian. Vì vậy, trong
thực hành, chữ ký số thường sử dụng phương pháp mã hóa giá trị hash của bản
tin. Việc này mang lại rất nhiều lợi ích như:
+ Các hàm hash là hàm 1 chiều, vì vậy dù có được
hash cũng không thể biết được bản tin gốc như thế nào.
+ Độ dài hash là cố định và thường rất nhỏ, vì
vậy chữ số sẽ không chiếm quá nhiều dung lượng.
+ Giá trị hash còn có thể dùng để kiểm tra lại
bản tin nhận được có nguyên vẹn hay không?
Chữ ký số đem lại
nhiều giá trị hơn chữ ký tay rất nhiều. Có lẽ cũng vì vậy, việc xử lý chữ ký số
phức tạp hơn hẳn chữ ký tay truyền thống.
Xác
định nguồn gốc
Hệ mã hóa bất đối
xứng cho phép tạo chữ ký với private key mà chỉ người chủ mới biết. Khi nhận gói
tin, người nhận xác thực chữ ký bằng cách dùng public key giải mã, sau đó tính
giá trị hash của bản tin gốc và so sánh với hash trong gói tin nhận được. Hai
chuỗi này phải trùng khớp với nhau. Tất nhiêu hệ mã hóa RSA vẫn có những thách
thức về an ninh nhất định nhưng dù sao thì nó vẫn khá an toàn.
Dữ
liệu được giữ một cách toàn vẹn
Tin nhắn gửi từ
chủ private key rất khó có thể bị giả mạo. Bởi vì nếu thay đổi tin nhắn thì giá
trị hash cũng phải thay đổi theo. Những kẻ nghe lén trong mạng đương nhiên là
có thể tìm cách đọc tin nhắn gốc và cả hash của nó. Nhưng hắn ta không thể thay
đổi tin nhắn được vì hắn không có private key để sửa đổi chữ ký số cho phù hợp.
Chữ
ký số không thể phủ nhận
Trong giao dịch,
một gói tin kèm chữ ký số rất dễ dàng tìm ra được nguồn gốc của chữ ký đó. Bởi
vì private key là bí mật và chỉ người chủ của nó mới có thể biết, họ không thể
chối cãi rằng chữ ký này không phải do họ phát hành. Cũng tương tự trường hợp
trên, hệ mã hóa RSA hay bất kỳ hệ mã hóa nào khác cũng đều có những vấn đề về
an ninh nên việc này không thể đảm bảo tuyệt đối chính xác được.
2.4. Kết luận
Công nghệ ngày
càng phát triển, các giao dịch điện tử, đặc biệt là thương mại điện tử đang
được thực hiện liên tục hàng ngày, hàng giờ. Chữ ký số là một công nghệ cho
phép xác định chủ nhân của dữ liệu nào đó và kiểm tra dữ liệu có nguyên vẹn hay
không.
Ở nước ta, chữ ký
số áp được áp dụng trong một số hoạt động ngành ngân hàng và kế toán. Nhưng
trong thời gian tới, rất có thể chữ ký số sẽ phổ biến hơn, khi chúng ta đang dần
dần hướng đến một thế giới không còn giấy bút.
3. AES
AES là một mã khối, nhưng khác với các mã khối khác được biết
đến trước đây (DES, IDEA,…), dữ liệu trong AES không được biểu diễn dưới dạng một
mảng các byte hay các bit mà được biểu diễn dưới dạng một ma trận 4xNb và được
gọi là mảng trạng thái (state). Trong đó, đối với AES, Nb luôn có giá trị bằng
4. Trong khi thuật toán Rijndael hỗ trợ ba giá trị của Nb là 4, 6, 8 tương ứng
với kích thước khối 128, 192 và 256 bit Dữ liệu đầu vào được đọc vào ma trận
state theo từng cột, theo thứ tự từ trên xuống dưới, từ trái qua phải. Dữ liệu
đầu ra được đọc từ ma trận cũng theo quy tắc trên.
Khóa vòng trong AES cũng được biểu diễn hoàn toàn tương tự
như cách biểu diễn dữ liệu. Tuy nhiên, tùy vào kích thước khóa mà số cột của ma
trận khóa vòng Nk sẽ khác nhau. Cụ thể, Nk nhận các giá trị 4, 6, 8 tương ứng với
các kích thước khóa là 128, 192 và 256 bit. Đây chính là điểm mạnh của thuật
toán AES trong vấn đề mở rộng khóa.
Số vòng lặp ký hiệu là Nr, phụ thuộc vào hai đại lượng Nb và
Nk. Vì Nb trong AES có giá trị cố định nên Nr chỉ phụ thuộc vào Nk. Giá trị của
Nr tương ứng với ba giá trị của Nk là Nr = 10, 12, 14. Cụ thể, giá trị Nr được
xác định bởi
3.1. Khái niệm từ (Word) trong AES
Bốn byte trên mỗi
cột trong mảng trạng thái state tạo thành 1 từ 32 bit, trong đó số thứ tự của
hàng r (0≤r<4) cho biết chỉ số của bốn byte trong mỗi từ. Từ định nghĩa
state ở trên có thể coi state là mảng một chiều chứa các từ 32 bit
Tương tự như đối
với mảng khóa cũng có thể biểu diễn thành mảng một chiều chứa các từ 32 bit như
công thức dưới đây với số lượng từ khóa phụ thuộc vào Nk (Nk=4, 6, 8).
3.2.
Thuật toán của AES
Thuật toán AES khá phức tạp, được mô tả
khái quát gồm 3 bước như sau:
+ 1
Vòng khởi tạo chỉ gồm phép AddRoundKey
+ Nr -1
Vòng lặp gồm 4 phép biển đổi lần lượt: SubBytes, ShiftRows, MixColumns,
AddRoundKey.
+ 1
Vòng cuối gồm các phép biến đổi giống vòng lặp và không có phép MixColumns.
Khái quát:
·
Mở rộng khóa - Các khóa phụ dùng
trong các vòng lặp được sinh ra từ khóa chính AES sử dụng thủ tục sinh khóa
Rijndael.
·
InitialRound - AddRoundKey— Mỗi
byte trong state được kết hợp với khóa phụ sử dụng XOR
·
Rounds - SubBytes—bước thay thế
phi tuyến tính, trong đó mỗi byte trong state được thay thế bằng một byte khác
sử dụng bảng tham chiếu - ShiftRows—bước đổi chỗ, trong đó mỗi dòng trong state
được dịch một số bước theo chu kỳ - MixColumns—trộn các cột trong state, kết
hợp 4 bytes trong mỗi cột - AddRoundKey
·
Final Round (không MixColumns) -
SubBytes - ShiftRows - AddRoundKey.
Thuật toán giải mã khá giống với thuật toán mã hóa về mặt cấu
trúc nhưng 4 hàm sử dụng là 4 hàm ngược của quá trình mã hóa. Riêng đối với cấu
trúc giải mã trong AES gồm 2 chế độ giải mã:
- Ở cấu trúc giải mã ngược, gồm vòng khởi tạo, Nr-1 vòng lặp
và vòng kết thúc. Trong đó vòng khởi tạo chỉ có phép biến đổi AddRounKey, vòng
lặp gồm lần lượt 4 phép biến đổi chính: InvShiftRows, InvSubBytes, AddRounKey,
InvMixColumns; vòng kết thúc khác với vòng lặp chính ở chỗ không có phép
InvMixColumns.
- Ngược lại với cấu trúc giải mã ngược là cấu trúc giải mã
xuôi, việc ngược lại thể hiện ở điểm: trong cấu trúc giải mã xuôi việc sắp xếp
các phép biến đổi ngược giống hệt với cấu trúc mã hóa, cụ thể bao gồm: vòng khởi
tạo, Nr-1 vòng lặp và vòng kết thúc. Trong đó vòng khởi là phép AddRounKey; ở
vòng lặp thứ tự các phép biến đổi ngược lần lượt là: InvSubBytes, InvShiftRows,
InvMixColumns, AddRounKey; vòng kết thúc giống vòng lặp nhưng được lược bỏ phép
InvMixColumns. Một điểm khác biệt nữa trong hai cấu trúc giải mã ngược và giải
mã xuôi đó là: Trong giải mã ngược khóa vòng giải mã chính là khóa vòng mã hóa
với thứ tự đảo ngược. Còn trong giải mã xuôi thì khóa giải mã ngoài việc đảo
ngược thứ tự khóa vòng mã hóa còn phải thực hiện phép InvMixColumns đối với các
khóa vòng của vòng lặp giải mã.
3.3. SubBytes và InvSubBytes
Phép biến đổi
SubBytes: Là phép thay thế byte phi tuyến tính, ở phép thay thế này nó tác động
độc lập đến từng byte trong trạng thái hiện hành. Phép biến đổi SubBytes được
thực hiện bằng cách tra cứu bảng thay thế (S-box) với tham số đầu vào là các
byte trong bảng trạng thái. S-box được xây dựng như sau: Bước 1: Điền các con
số từ 0 đến 255 vào bảng theo từng hàng. Vậy hàng 0 gồm các con số {00}, {01},
…{0F} (thập lục phân). Hàng 1 gồm các con số {10}, {11},…, {1F}. Điều này có
nghĩa là tại hàng x cột y có giá trị {xy}. Bước 2: Thay thế mỗi byte trong bảng
bằng giá trị nghịch đảo trong trường GF(28 ). Quy ước nghịch đảo của {00} cũng
là {00}. Bước 3: Mỗi byte trong ma trận state được thay thế bởi 1 byte trong
Rijndael S-box, hay bij = S(aij).
trong đó, 0 ≤ i ≤8 là bit thứ i của byte b tương ứng và ci là
bit thứ thứ i của byte c với giá trị {63} hay {01100011}.
Trong đó phép cộng thực hiện như phép XOR. Bảng sau trình bày
nội dung bảng S-box sau khi tính toán.
Phép biến đổi ngược InvSubBytes: là phép thay thế biến đổi
ngược với SubBytes. Là một phép thay thế byte, các byte thay thế được thực hiện
bằng cách tra bảng thay thế ngược IS. Bảng thay thế ngược IS này được xây dựng
như sau: Trước tiên, cũng phải xây dựng một bảng Inverse SubBytes (IS- box).
Nghĩa là nếu với đầu vào {95}, S-box cho ra kết quả {2A}, thì với đầu vào là
{2A}, IS sẽ cho ra lại kết quả {95}. Việc xây dựng hộp IS cũng giống như xây dựng
S-box tại bước 1 và bước 2. Tại bước 3, IS thực hiện phép thay thế sau:
Với di là bit thứ i của số {05} tức
d7 d6 d0 = 00000101.
Bảng sau trình bày nội dung bảng
thay thế ngược IS sau khi tính toán.
Như vậy: phép biến
đổi InvSubBytes thực hiện như sau: Mỗi byte trong ma trận state S, dưới dạng
thập lục phân là {xy}, được thay thế bằng giá trị trong bảng IS tại dòng x cột
y.
Mục đích của phép
biến đổi SubBytes: S-box dùng để chống lại hình thức tấn công thám mã vi sai và
thám mã tuyến tính. Giữa input và output của phép Substitute bytes không thể mô
tả bằng một công thức toán đơn giản
3.4. ShiftRows và InvShiftRows
Phép biến đổi ShiftRows:
Thao tác ShiftRows thực hiện hoán vị các byte trong ma trận state theo cách
thức sau:
·
Dòng thứ nhất giữ nguyên
·
Dòng thứ 2 dịch vòng trái 1 byte
·
Dòng thứ 3 dịch vòng trái 2 byte
· Dòng thứ 4 dịch vòng trái 3 byte
Phép biến đổi InvShiftRows:
Phép biến đổi InvShiftRows thực hiện ngược lại với phép ShiftRows, nghĩa là:
·
Dòng thứ nhất giữ nguyên
·
Dòng thứ 2 dịch vòng phải 1 byte
·
Dòng thứ 3 dịch vòng phải 2 byte
·
Dòng thứ 4 dịch vòng phải 3 byte Mục đích của ShiftRows: Xáo
trộn các byte để tạo các cột khác nhau trước khi sử dụng cột cho thao tác
MixColumns.
3.5.
MixColumns và InvMixColumns
Phép biến đổi MixColumns:
Phép biến đổi MixColumns thực hiện biến đổi độc lập từng cột trong ma trận
state bằng một phép nhân đa thức. Mỗi cột của state đươc coi là biểu diễn của
một đa thức f(x) trong GF(2^8) như vậy phép biến đổi MixColumns chính là phép
nhân theo modulo với x^4+1 với một đa thức cố định định nghĩa như sau:
Phép nhân đa thức trên có thể biểu
diễn dưới dạng phép nhân ma trận như sau:
Phép biến đổi ngược InvMixColumns: Là phép biến đổi ngược
với phép biến đổi MixColumns. InvMixColumns cũng thực hiện thao tác theo từng cột
của trạng thái, xem mỗi cột như một đa thức bậc 3 gồm 4 hạng tử trên trường
GF(2^8). Các cột của phép InvMixColumns được nhân theo modulo ( x^4 + 1 ) với
đa thức nghịch đảo a(x) chính là đa thức a^-1(x) được định nghĩa:
Như vậy phép InvMixColumns cũng được
biểu diễn tương đương với phép nhân ma trận sau
Mục đích của
MixColumns: Việc coi mỗi cột là một đa thức bậc 3, rồi nhân mỗi cột với đa thức
a(x) sau đó modulo ( x4 +1 ) đã làm cho mỗi
byte trong cột kết quả đều phụ thuộc vào bốn byte trong cột ban đầu. Thao tác
MixColumns kết hợp với ShiftRows đảm bảo rằng sau một vài vòng biến đổi, 128
bit trong kết quả đều phụ thuộc vào tất cả 128 bit ban đầu. Điều này tạo ra
tính khuếch tán (diffusion) cần thiết cho mã hóa.
3.6. AddRoundKey
Trong thao tác
AddRoundKey, 128 bit của ma trận state sẽ được XOR với 128 bit của khóa con của
từng vòng. Vì sử dụng phép XOR nên phép biến đổi ngược của AddRoundKey trong
cấu trúc giải mã cũng chính là AddRoundKey. Việc kết hợp với khóa bí mật tạo ra
tính làm rối (confusion) của mã hóa. Sự phức tạp của thao tác mở rộng khóa
(KeySchedule) giúp gia tăng tính làm rối này.
3.7. Mở rộng khóa (ExpandKey )
ExpandKey là thao tác tạo lược đồ khóa hay mở rộng khóa, tạo ra Nr+1 khóa vòng từ khóa chính K, mỗi khóa vòng gồm Nb từ 32 bit, trong đó đối với AES thì Nb = 4, còn Nr được xác định theo. Các phép biến đổi để tạo khóa vòng trong ExpandKey là khác nhau đối với các giá trị khác nhau của kích thước khóa K. Sau đây là việc mở rộng khóa đối với khóa mã 128 bit
Trong thao tác mở rộng khóa với khóa mã
128 bit có đầu vào là 16 byte (4 word) của khóa mã, và sinh ra một mảng khóa
vòng (Nr+1)x4=44 từ (word) hay 176 byte. 44 word này được sử dụng cho 11 vòng
mã hóa của AES, mỗi vòng dùng 4 word. Từ bốn word đầu vào w0w1w2w3, trong lần
lặp đầu tiên thao tác ExpandKey sinh ra bốn word w4w5w6w7, lần lặp thứ 2 từ
w4w5w6w7 sinh ra w8w9w10w11 , cứ như thế cho đến lần lặp thứ 10 (tùy thuộc
chiều dài khóa) sinh ra bốn word cuối cùng w40w41w42w43 như hình vẽ
Mục đích của ExpandKey: dùng để chống lại
known-plaintext attack
·
Biết một số bit của khóa hay khóa con cũng không thể tính các
bit còn lại.
·
Không thể tính ngược: biết một khóa con cũng không thể tính lại
các khóa con trước đó.
·
Tính khuếch tán: một bit của khóa chính tác động lên tất cả các
bit của các khóa con.
4. Hàm băm MD5
MD5 được phát minh bởi Ron Rivest ,người
đã tham gia xây dựng RSA. MD5 viết tắt của chữ Message Digest,được phát triển
lên từ MD4 và trước đó là MD2,do MD2 và MD4 không còn an toàn. Kích thước của
MD5 là 128 bit được tính giá trị của thông điệp có kích thước tối đa 2^4 bit.
4.1. Thuật toán MD5
-Input:
xâu đầu vào x có độ dài tối đa 2^64
-Output:
chuỗi băm 128 bit
-Sơ đồ
thuật toán:
Trước tiên thông điệp được đệm vào dãy
padding 100...00. Chiều dài của dãy padding được chọn sao cho thông điệp cuối
cùng có thể chia làm N block 512 bit M1,M2,...,MN. Quá trình tính giá trị băm
của thông điệp là quá trình lũy tiến. Trước tiên block M1 kết hợp với giá trị
khởi tạo H0 thông qua hàm F để tính giá trị hash H1. Sau đó block M2 đượckết
hợp với H1 để cho ra giá trị hash là H2. Block M3 kết hợp với H2 cho ra giá trị
H3. Cứ như vậy cho đến block MN thì có giá trị băm của toàn bộ thông điệp là
HN.
·
H0 là một dãy 128 bit được chia thành 4 từ 32 bit, ký hiệu 4 từ
32 bit trên là abcd. Với a, b, c, d là các hằng số như sau (viết dưới dạng thập
lục phân):
a = 01234567
b =
89abcdef
c =
fedbca98
d =
76543210
4.2. Cấu
trúc của hàm F như sau:
Tại mỗi bước lũy tiến, các giá trị abcd của giá trị hash Hi-1
được biến đổi qua 64 vòng từ 0 đến 63. Tại vòng thứ j sẽ có 2 tham số là Kj và
Wj đều có kích thước 32 bit. Các tham số Kj được tính từ công thức: Kj là phần
nguyên của số 2^32 abs(sin(i)) với i biểu diễn theo rad.
Giá trị block Mi 512 bit được biến
đổi qua một hàm message schedule cho ra 64 giá trị W0, W1,…, W63 mỗi giá trị 32
bit. Block Mi 512 bit được chia thành 16 block 32 bit ứng với các giá trị W0,
W1, …, W15 (16×32=512). Tiếp theo, 16 giá trị này được lặp lại 3 lần tạo thành
dãy 64 giá trị.
Sau vòng cuối cùng, các giá trị abcde được cộng
với các giá trị abcd của Hi-1 để cho ra các giá trị abcd của Hi. Phép cộng ở
đây là phép cộng modulo 232.
Tiếp theo tìm hiểu cấu trúc của một vòng. Việc
biến đổi các giá trị abcd trong vòng thứ i được thể hiện trong hình bên dưới.
Note:Phép + trong sơ đồ trên là
phép cộng modul 2^32
Ở đây c lấy giá trị của b, d lấy giá trị của c,
a lấy giá trị của d.
Giá trị b được tính qua hàm:
t = a + f(b,c,d) + Wi + Ki
b = b + ROTL(t,s)
Trong đó : Hàm f(x,y,z):
f
(x,y,z) = (x ^ y) v (_x ^ z) nếu vòng từ 0 đến 15
f
(x,y,z) = (z ^ x) v (_z ^ y) nếu vòng từ 16 đến 32
f
(x,y,z) = x xor y xor z nếu vòng từ 32 đến 48
f
(x,y,z) = y xor (x v _z) nếu vòng từ 49 đến 63
Hàm
ROTL(t, s): t được dịch vòng trái s bit, với s là các hằng số cho vòng thứ i
như sau:
5. SHA-256
SHA-2
(Thuật toán băm an toàn 2), trong đó SHA-256 cũng là một phần, chúng là một
trong những thuật toán băm phổ biến nhất hiện nay. Ở bài viết này, mình sẽ chia
sẻ cho các bạn cách thức mà thuật toán hoạt động. Với SHA-2 được biết đến với
khả năng bảo mật cấp cao (không giống như SHA-1) và tốc độ của nó. Trong các
trường hợp không tạo key, chẳng hạn như khai thác Bitcoin, thuật toán băm nhanh
như SHA-2 sẽ là lợi thế cho bạn.
5.1. Hàm băm là gì
?
Hàm băm được chia
làm 3 loại chính:
·
Xáo trộn dữ liệu.
·
Chấp nhận đầu vào tùy ý
và đầu ra cố định.
·
Giúp thao tác dữ liệu mà
không thay đổi.
SHA-2 có họ hàng với SHA-256 ?
SHA-2 là một thuật
toán băm dữ liệu. Chúng đều sử dụng cùng một thuật toán nhưng sử dụng các hằng số
khác nhau. Ví dụ: SHA-256 đặt các hằng số bổ sung xác định hành vi của thuật
toán SHA-2, một trong những hằng số này là kích thước đầu ra, 256 và 512 trong
SHA-256 và SHA-512 tham chiếu đến kích thước tương ứng với các bit.
SHA-2 là con của SHA-1 ?
SHA-2 là sự kế
thừa của hàm băm SHA-1 và vẫn là một trong những hàm băm mạnh nhất được sử dụng
ngày nay. SHA-256, trái ngược với SHA-1, chúng không bị xâm phạm. Vì lý do này,
bạn chẳng có lý do gì để sử dụng SHA-1 vì nó không an toàn. Tính linh hoạt của
kích thước đầu ra (224, 256, 512, ....) cũng cho phép SHA-2 ghép nối tốt với
các KDF và mật mã phổ biến như AES-256.
"hello world" đầu tiên
Bước xử lý:
Trước tiên ta cần
đổi chữ hello world
thành nhị
phân.
01101000 01100101 01101100
01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100
Tiếp đên ta nối 1 sau chuỗi nhị
phân.
01101000 01100101 01101100
01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100 1
Nối 0 cho đến khi dữ liệu là bội số
của 512, ít hơn 64 bit (Ở đây của mình là 448 bit).
01101000 01100101
01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100
01100100 10000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000
Nối 64 bit vào cuối, trong đó 64
bit là số nguyên big-endian đại diện cho độ dài của đầu vào ban đầu ở dạng nhị
phân. Ở đây của mình là 88 hoặc trong hệ nhị phân là “1011000”.
01101000 01100101
01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100
01100100 10000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 01011000
Bây giờ đã có đầu vào của mình, và
đầu vào đó sẽ luôn chia hết cho 512.
Khởi tạo Giá trị băm (h)
Bây giờ chúng ta
tạo 8 giá trị băm. Đây là các hằng số được mã hóa cứng đại diện cho 32 bit đầu
tiên của phần phân số của căn bậc hai của 8 số nguyên tố đầu tiên: 2, 3, 5, 7, 11, 13, 17, 19.
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
Khởi tạo Hằng số tròn (k)
Tương tự như trên
đây, ở đây ta tạo một số hằng số (Tìm hiểu thêm về hằng số và khi nào sử dụng
chúng). Lần này chúng ta có 64 hằng số, mỗi giá trị (0-63) là 32 bit đầu tiên
của các phần phân số của căn bậc hai của 64 số nguyên tố đầu tiên (2 - 311).
0x428a2f98 0x71374491
0xb5c0fbcf 0xe9b5dba5 0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed5 0xd807aa98
0x12835b01 0x243185be 0x550c7dc3 0x72be5d74 0x80deb1fe 0x9bdc06a7 0xc19bf174 0xe49b69c1
0xefbe4786 0x0fc19dc6 0x240ca1cc 0x2de92c6f 0x4a7484aa 0x5cb0a9dc 0x76f988da 0x983e5152
0xa831c66d 0xb00327c8 0xbf597fc7 0xc6e00bf3 0xd5a79147 0x06ca6351 0x14292967 0x27b70a85
0x2e1b2138 0x4d2c6dfc 0x53380d13 0x650a7354 0x766a0abb 0x81c2c92e 0x92722c85 0xa2bfe8a1
0xa81a664b 0xc24b8b70 0xc76c51a3 0xd192e819 0xd6990624 0xf40e3585 0x106aa070 0x19a4c116
0x1e376c08 0x2748774c 0x34b0bcb5 0x391c0cb3 0x4ed8aa4a 0x5b9cca4f 0x682e6ff3 0x748f82ee
0x78a5636f 0x84c87814 0x8cc70208 0x90befffa 0xa4506ceb 0xbef9a3f7 0xc67178f2
Vòng lặp Chunk
Các bước sau sẽ
xảy ra cho mỗi "đoạn" dữ liệu 512-bit từ đầu vào của mình. Ở đây, vì
“hello world” quá ngắn, nên mình chỉ có một đoạn. Tại mỗi lần lặp lại của vòng
lặp, mình sẽ thay đổi các giá trị băm h0-h7 và đây sẽ là đầu ra.
Tạo lịch trình nhắn tin (w)
Sao chép dữ liệu
đầu vào từ bước 1 vào một mảng mới trong đó mỗi mục nhập là một từ 32 bit:
01101000011001010110110001101100
01101111001000000111011101101111
01110010011011000110010010000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000001011000
Thêm 48 từ khác được khởi tạo bằng
0, như vậy là có một mảng w[0… 63]
01101000011001010110110001101100
01101111001000000111011101101111
01110010011011000110010010000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000001011000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
...
...
00000000000000000000000000000000
00000000000000000000000000000000
Sửa đổi các chỉ mục zero-ed ở cuối mảng
bằng cách sử dụng thuật toán sau: Đối với mình từ w[16… 63]:
·
s0 = (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor
(w[i-15] rightshift 3)
·
s1 = (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor
(w[i- 2] rightshift 10)
·
w[i] = w[i-16] + s0 + w[i-7] + s1
Với [16] hãy xem cách hoạt động của nó như
thế nào.
w[1] rightrotate 7:
01101111001000000111011101101111
->
11011110110111100100000011101110
w[1] rightrotate 18:
01101111001000000111011101101111
->
00011101110110111101101111001000
w[1] rightshift 3:
01101111001000000111011101101111
-> 00001101111001000000111011101101
s0 =
11011110110111100100000011101110
XOR
00011101110110111101101111001000
XOR
00001101111001000000111011101101
s0 = 11001110111000011001010111001011
w[14] rightrotate 17:
00000000000000000000000000000000
->
00000000000000000000000000000000
w[14] rightrotate19:
00000000000000000000000000000000
->
00000000000000000000000000000000
w[14] rightshift 10:
00000000000000000000000000000000
->
00000000000000000000000000000000
s1 =
00000000000000000000000000000000
XOR
00000000000000000000000000000000
XOR 00000000000000000000000000000000
s1 =
00000000000000000000000000000000
w[16] = w[0] + s0 + w[9] + s1
w[16] =
01101000011001010110110001101100 + 11001110111000011001010111001011 +
00000000000000000000000000000000 + 00000000000000000000000000000000
// Mình bổ sung thêm được tính
theo modulo 2 ^ 32
w[16] =
00110111010001110000001000110111
Điều này để lại cho mình 64 từ
trong nội dung thông báo (w):
01101000011001010110110001101100
01101111001000000111011101101111
01110010011011000110010010000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000001011000
00110111010001110000001000110111
10000110110100001100000000110001
11010011101111010001000100001011
01111000001111110100011110000010
00101010100100000111110011101101
01001011001011110111110011001001
00110001111000011001010001011101
10001001001101100100100101100100
01111111011110100000011011011010
11000001011110011010100100111010
10111011111010001111011001010101
00001100000110101110001111100110
10110000111111100000110101111101
01011111011011100101010110010011
00000000100010011001101101010010
00000111111100011100101010010100
00111011010111111110010111010110
01101000011001010110001011100110
11001000010011100000101010011110
00000110101011111001101100100101
10010010111011110110010011010111
01100011111110010101111001011010
11100011000101100110011111010111
10000100001110111101111000010110
11101110111011001010100001011011
10100000010011111111001000100001
11111001000110001010110110111000
00010100101010001001001000011001
00010000100001000101001100011101
01100000100100111110000011001101
10000011000000110101111111101001
11010101101011100111100100111000
00111001001111110000010110101101
11111011010010110001101111101111
11101011011101011111111100101001
01101010001101101001010100110100
00100010111111001001110011011000
10101001011101000000110100101011
01100000110011110011100010000101
11000100101011001001100000111010
00010001010000101111110110101101
10110000101100000001110111011001
10011000111100001100001101101111
01110010000101111011100000011110
10100010110101000110011110011010
00000001000011111001100101111011
11111100000101110100111100001010
11000010110000101110101100010110
Nén
·
Khởi tạo các biến a, b, c, d, e, f, g, h và
đặt chúng bằng các giá trị băm hiện tại tương ứng. h0, h1, h2, h3, h4, h5, h6, h7
·
Chạy vòng lặp nén. Vòng lặp nén sẽ thay đổi các giá trị từ a…h.
Vòng lặp nén như sau:
o
Từ 0 đến 63
§
S1 = (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate
25)
§
ch = (e and f) xor ((not e) and g)
§
temp1 = h + S1 + ch + k[i] + w[i]
§
S0 = (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate
22)
§
maj = (a and b) xor (a and c) xor (b and c)
§
temp2 := S0 + maj
§
h = g
§
g = f
§
f = e
§
e = d + temp1
§
d = c
§
c = b
§
b = a
§
a = temp1 + temp2
Hãy xem qua lần lặp đầu tiên, tất cả phép
cộng được tính theo modulo 2 ^ 32:
a = 0x6a09e667 =
01101010000010011110011001100111
b = 0xbb67ae85 =
10111011011001111010111010000101
c = 0x3c6ef372 =
00111100011011101111001101110010
d = 0xa54ff53a =
10100101010011111111010100111010
e = 0x510e527f =
01010001000011100101001001111111
f = 0x9b05688c =
10011011000001010110100010001100
g = 0x1f83d9ab =
00011111100000111101100110101011
h = 0x5be0cd19 =
01011011111000001100110100011001
e rightrotate 6:
01010001000011100101001001111111
->
11111101010001000011100101001001
e rightrotate 11:
01010001000011100101001001111111
->
01001111111010100010000111001010
e rightrotate 25:
01010001000011100101001001111111
->
10000111001010010011111110101000
S1 =
11111101010001000011100101001001
XOR
01001111111010100010000111001010
XOR
10000111001010010011111110101000
S1 = 00110101100001110010011100101011
e and f:
01010001000011100101001001111111
&
10011011000001010110100010001100 =
00010001000001000100000000001100
not e:
01010001000011100101001001111111
->
10101110111100011010110110000000
(not
e) and g:
10101110111100011010110110000000
& 00011111100000111101100110101011 =
00001110100000011000100110000000
ch
= (e and f) xor ((not e) and g)
= 00010001000001000100000000001100
xor
00001110100000011000100110000000
= 00011111100001011100100110001100
// k[i] là hằng số
vòng
// w[i] là batch
temp1 = h + S1 + ch + k[i] + w[i]
temp1 = 01011011111000001100110100011001
+
00110101100001110010011100101011
+
00011111100001011100100110001100
+
01000010100010100010111110011000
+
01101000011001010110110001101100
temp1 =
01011011110111010101100111010100
a rightrotate 2:
01101010000010011110011001100111
-> 11011010100000100111100110011001
a rightrotate 13:
01101010000010011110011001100111
->
00110011001110110101000001001111
a rightrotate 22:
01101010000010011110011001100111
->
00100111100110011001110110101000
S0 =
11011010100000100111100110011001
XOR
00110011001110110101000001001111
XOR
00100111100110011001110110101000
S0 =
11001110001000001011010001111110
a and b:
01101010000010011110011001100111
& 10111011011001111010111010000101 =
00101010000000011010011000000101
a and c:
01101010000010011110011001100111
& 00111100011011101111001101110010 =
00101000000010001110001001100010
b and c:
10111011011001111010111010000101
& 00111100011011101111001101110010 =
00111000011001101010001000000000
maj = (a and b) xor (a and c) xor
(b and c)
= 00101010000000011010011000000101
xor
00101000000010001110001001100010
xor
00111000011001101010001000000000
= 00111010011011111110011001100111
temp2 = S0 + maj
= 11001110001000001011010001111110
+ 00111010011011111110011001100111
= 00001000100100001001101011100101
h =
00011111100000111101100110101011
g =
10011011000001010110100010001100
f =
01010001000011100101001001111111
e =
10100101010011111111010100111010
+
01011011110111010101100111010100
= 00000001001011010100111100001110
d =
00111100011011101111001101110010
c =
10111011011001111010111010000101
b =
01101010000010011110011001100111
a =
01011011110111010101100111010100
+
00001000100100001001101011100101
= 01100100011011011111010010111001
Toàn bộ phép tính đó được thực hiện
thêm 63 lần nữa, sửa đổi các biến a-h trong suốt. Chúng tôi sẽ không làm điều
đó bằng tay nhưng chúng tôi sẽ kết thúc bằng:
h0 = 6A09E667 =
01101010000010011110011001100111
h1 = BB67AE85 = 10111011011001111010111010000101
h2 = 3C6EF372 =
00111100011011101111001101110010
h3 = A54FF53A =
10100101010011111111010100111010
h4 = 510E527F =
01010001000011100101001001111111
h5 = 9B05688C =
10011011000001010110100010001100
h6 = 1F83D9AB =
00011111100000111101100110101011
h7 = 5BE0CD19 =
01011011111000001100110100011001
a = 4F434152 =
01001111010000110100000101010010
b = D7E58F83 =
11010111111001011000111110000011
c = 68BF5F65 =
01101000101111110101111101100101
d = 352DB6C0 =
00110101001011011011011011000000
e = 73769D64 =
01110011011101101001110101100100
f = DF4E1862 =
11011111010011100001100001100010
g = 71051E01 =
01110001000001010001111000000001
h = 870F00D0 =
10000111000011110000000011010000
Sửa đổi giá trị
Sau khi vòng lặp
nén, ở trên trong vòng lặp chunk, mình sửa đổi các giá trị băm bằng cách thêm
các biến tương ứng a-h. Và tất cả các phép cộng ở đây đều
là modulo 2 ^ 32.
h0 = h0 + a =
10111001010011010010011110111001
h1 = h1 + b =
10010011010011010011111000001000
h2 = h2 + c = 10100101001011100101001011010111
h3 = h3 + d =
11011010011111011010101111111010
h4 = h4 + e =
11000100100001001110111111100011
h5 = h5 + f =
01111010010100111000000011101110
h6 = h6 + g =
10010000100010001111011110101100
h7 = h7 + h =
11100010111011111100110111101001
Kết hợp Băm cuối cùng
Cuối cùng ghép tất
cả lại với nhau và tèn tèn, ta có một phép nối chuỗi đơn giản.
digest = h0 append h1 append h2
append h3 append h4 append h5 append h6 append h7
=
B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9
Nếu bạn muốn xem tất cả các bước
mình vừa làm ở trên, thì đây mình sẽ giải thích rõ hơn:
Bước 1: Tất cả các biến là số
nguyên không dấu 32 bit và phép cộng được tính theo modulo 2 ^ 32
Bước 2: Đối với mỗi vòng lặp, có
một hằng số vòng k[i] và một mục nhập trong mảng thông báo w[i], 0 ≤ i ≤ 63
Bước 3: Sử dụng 8 biến từ a đến h
Bước 4: Sử dụng quy ước big-endian
khi biểu thị các hằng số trong mã hóa này, và khi phân tích cú pháp tin nhắn sẽ
chặn dữ liệu từ byte thành từ, **Ví dụ:** từ đầu tiên của tin nhắn đầu vào
"abc" sau phần đệm là 0x61626380
Khởi tạo giá trị băm (32 bit đầu
tiên của phần phân số của căn bậc hai của 8 số nguyên tố đầu tiên 2..19):
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19
Khởi tạo mảng các hằng số vòng (32
bit đầu tiên của phần phân số của căn bậc hai của 64 số nguyên tố đầu tiên
2..311):
k[0..63] :=
0x428a2f98,
0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d,
0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85,
0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e,
0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624,
0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f,
0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
Pre-processing
(Padding):
Bắt đầu với nội dung
có độ dài L bit
Nối bit '1' duy nhất
Nối K '0' bit, trong
đó K là số nhỏ nhất >= 0 sao cho L + 1 + K + 64 là bội số của 512
Thêm L dưới dạng số
nguyên big-endian 64bit, làm cho tổng độ dài sau xử lý là bội số của 512bit
Xử lý tin nhắn theo các phần
512bit liên tiếp, chia nhỏ tin nhắn thành các đoạn 512bit
for each chunk
create
a 64-entry message schedule array w[0..63] of 32-bit words
(Các giá trị ban đầu trong w[0..63] không quan
trọng) sao chép đoạn vào 16 từ đầu tiên w[0..15] của mảng tin nhắn
Kéo
dài 16 từ đầu tiên thành 48 từ còn lại w[16..63] của mảng tin nhắn:
for
i from 16 to 63
s0
:= (w[i-15] rightrotate 7) xor (w[i-15]
rightrotate 18) xor (w[i-15] rightshift
3)
s1
:= (w[i- 2] rightrotate 17) xor (w[i- 2] rightrotate 19) xor (w[i- 2] rightshift
10)
w[i]
:= w[i-16] + s0 + w[i-7] + s1
Khởi tạo các biến thành giá trị băm hiện
tại:
a := h0
b := h1
c := h2
d := h3
e := h4
f := h5
g := h6
h := h7
Nén
vòng lặp chính:
for
i from 0 to 63
S1 := (e rightrotate 6) xor (e
rightrotate 11) xor (e rightrotate 25)
ch := (e and f) xor ((not e) and g)
temp1 := h + S1 + ch + k[i] + w[i]
S0 := (a rightrotate 2) xor (a
rightrotate 13) xor (a rightrotate 22)
maj := (a and b) xor (a and c) xor (b
and c)
temp2 := S0 + maj
h := g
g := f
f := e
e := d + temp1
d := c
c := b
b := a
a := temp1 + temp2
Thêm đoạn đã nén vào giá trị băm hiện tại:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
h4 := h4 + e
h5 := h5 + f
h6 := h6 + g
h7 := h7 + h
Tạo giá trị băm cuối cùng
(big-endian): digest: = hash: = h0 append h1 append h2 append h3 append h4
append h5 append h6 append h7.
Nguồn:
Internet, VIBLO
0 comments:
Đăng nhận xét