AES - Advanced Encryption Standard
Giới thiệu
AES là chuẩn mã hoá được sử dụng khắp nơi hiện nay. Bài viết bạn đang đọc, video bạn hay xem trên Youtube hoặc tin nhắn bạn gởi qua Messenger hàng ngày cũng được mã hoá bằng AES thông qua giao thức https. Năm 1997, NIST (National Institute of Standards and Technology) muốn tìm một giải pháp mã hoá mới cho chính phủ Mỹ thay thế DES đã lỗi thời và gặp nhiều vấn đề về bảo mật. Rjindael đã được chọn vào tháng 2 năm 2000. Và từ đó được dùng rộng rãi đến ngày nay.
Hoạt động
Hôm nay mình không quá đi vào chi tiết AES hoạt động như thế nào mà mình sẽ tập trung vào cách sử dụng AES, input là gì, output là gì, làm thế nào để cài đặt bằng swift.
Input của AES là
PlainText
vàKey
, output làCipherText
tức nội dung đã được mã hoá.PlainText
sẽ được chia nhỏ thành các đoạn 128 bit, mỗi đoạn đó sẽ được mã hoá riêng biệt sau đó nối lại thànhCipherText
.Key
có độ dài 128, 192 hoặc 256 bit. Dựa vào độ dài củaKey
mà khi mã hoá chúng ta cần lặp lại số bước (K) khác nhau.
Khi bắt đầu với AES chúng ta cần xác định: Block Mode, Padding, Key. Key mặc nhiên phải cần, nhưng tại sao lại có BlockMode và Padding?
Như trên hình chúng ta đã miêu tả, PlainText sẽ được chia nhỏ thành nhiều Block 128bit và sau khi encrypt xong sẽ được nối lại. Việc chia nhỏ và nối lại sẽ phát sinh một số vấn đề về bảo mật (?) vì vậy cần tăng thêm sự phức tạp ở mỗi bước. BlockMode quy định cách thức thực hiện chia nhỏ / nối như thế nào. Mã hoá và giải mã phải dùng cùng một BlockMode.
Block Mode và Padding
1. Block Mode:
Mình sẽ giới thiệu một số mode sau vì được sử dụng nhiều.
- ECB : đơn giản chia nhỏ PlainText thành 128bits, mã hoá, nối lại. Tương tự cho việc giải mã, cắt CipherText thành 128 bits, giải mã từng đoạn rồi nối lại. Gặp vấn đề khi mỗi đoạn giống nhau sẽ ra CipherText giống nhau.
- CBC : block đầu sẽ XOR với một InitVector (IV - chuỗi random) rồi mới đưa vào AES, kết quả (cipher block) sẽ được dùng làm InitVector cho block tiếp theo. Việc làm này sẽ đảm bảo PlainText giống nhau nhưng CipherText sẽ khác nhau. CBC được dùng phổ biến nhất.
- CFB : Giống CBC, nhưng IV sẽ được mã hoá bằng Key + xử lý một vài bước trước khi XOR với PlainBlock.
- OFB : Gần giống CFB. CFB và CBC dùng CipherBlock làm IV cho bước tiếp theo, nhưng OFB không dùng CipherBlock mà dùng IV của bước trước mã hoá lần nữa làm IV mới. IV ở OFB là
Nonce
, không phải chuỗi random. - CTR : IV ở mỗi bước là độc lập và không dùng cho bước tiếp theo. IV ở CTR là Counter , không phải chuỗi random.
Ngoài các mode trên còn có CCM, GCM, PCBC. Mình sẽ đi sâu ở một topic khác.
2. Padding:
Mỗi block cần đúng 128bit, nếu PlainBlock có ít hơn 128 bit thì chúng ta cần thêm padding. Padding có thể là chuỗi bit 0 hoặc chuỗi random với bit cuối cùng bằng số lượng padding.
- NoPadding : không làm gì
- ZeroPadding : thêm bit 0 cho đủ block size
- Pkcs7, Pkcs5:
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
let padding = UInt8(blockSize - (bytes.count % blockSize))
var withPadding = bytes
if padding == 0 {
// If the original data is a multiple of N bytes, then an extra block of bytes with value N is added.
for _ in 0..<blockSize {
withPadding += Array<UInt8>(arrayLiteral: UInt8(blockSize))
}
} else {
// The value of each added byte is the number of bytes that are added
for _ in 0..<padding {
withPadding += Array<UInt8>(arrayLiteral: UInt8(padding))
}
}
return withPadding
}
- Iso78164
func add(to bytes: Array<UInt8>, blockSize: Int) -> Array<UInt8> {
var padded = Array(bytes)
padded.append(0x80)
while (padded.count % blockSize) != 0 {
padded.append(0x00)
}
return padded
}
Toàn bộ code minh hoạ mình đều lấy ở thư viện này
Tổng kết
Khi sử dụng một giải thuật việc đầu tiên là cần hiểu rõ input + output, sau đó hiểu căn bản cách thức hoạt động như thế nào. Như vậy mới sử dụng hiệu quả nhất và tránh gặp lỗi không mong đợi. Hy vọng các bạn sẽ thích bài viết này. Happy Coding.