簡介編碼與加密

今天來討論概念上最好理解的編碼與加密。嚴格說起來編碼跟加密目的相差很多,但行為或過程有點類似,所以放在一起講。

編碼

編碼(encode)是把資訊轉換另一種格式以便處理或傳輸,解碼(decode)則是編碼的相反過程。

@startuml
Alice -> Encoder: Plaintext
Encoder -> Decoder: Encoded text via internet
Decoder -> Bob: Plaintext
@enduml

在 web 身分驗證上,最常使用的編碼正是 RFC 3986 section 2.1 提到的 Percent-encoding,又名 URL encoding。除了是 URI 的編碼方法,同時這也是 HTTP 提交表單時,預設的 MIME application/x-www-form-urlencoded 的編碼方法。

另一個也是大家耳熟能詳的 RFC 4648 - The Base16, Base32, and Base64 Data Encodings 裡面提到的 Base64 encoding。

兩個編碼方法都有機會讓字元變多,比方說:

Plaintext:      HTTP/1.1
URL encode: HTTP%2F1.1
Base64 encode: SFRUUC8xLjE=

好端端的為什麼要把看得懂的字編成看不懂的亂碼呢?主要理由是為了符合其他規範,比方說上例的資料是 HTTP/1.1,而 / 是 RFC 3986 定義有特殊意義的保留字元,這時就需要 URL encode 來幫助把想傳的內容轉換成可以接受的字元,才能符合 URI 規範放到網路上傳輸。Base64 encode 則是能把二進位內容如簽章,轉成文字以利於傳輸。

加密

簡介密碼學時,有簡單提過加密概念,而加密有分兩種類型:「對稱式加密」與「非對稱式加密」。對稱式加密指的是使用相同的金鑰(key)做加密與解密,非對稱式加密指的是有一組成對的金鑰,一個用來做加密,另一個用來做解密。兩者比較表如下:

類型 金鑰管理 效率 常見的演算法
對稱式加密 困難 DES、AES
非對稱式加密 方便 RSA

以下針對 AES 與 RSA 做個簡單說明。

AES

AES 全名為 Advanced Encryption Standard,它是一個區塊加密的演算法,所謂的「區塊加密」就是把明文拆成多個區段,然後分別加密再組合起來。AES 有分成幾種模式,像是 ECBCBCCFB 等。其中 CBC 是 Laravel Encryption 所使用的模式,以下以這個模式來做說明。

CBC 一樣也是縮寫,全名為 Cipher Block Chaining。它的加密運作原理簡單來說,是每個明文的區塊跟前一組密文做互斥或運算。那第一個明文該怎麼辦?因此它需要一個初始化向量(Initialization Vector,簡稱 IV)。可想而知,不同的 IV 加密後的字串是不一樣的,而同時這也是解密的必要參數之一。

因為加密與解密同時需要 IV 與 Key,曾看過有人把 IV 跟 Key 做相同的管理,比方說把 IV 設成固定值,然後跟 Key 藏在同個地方。但在實務上,IV 應該要隨機產生,並且它是可以公開的。Laravel Encryption 使用加密時,正是會將 IV 公開。如加密後的密文如下:

eyJpdiI6ImRxdDc1WFV4UERXY0k4M0gxc2VkK2c9PSIsInZhbHVlIjoiNkNyWnRiU0lJMUhDeTBuNXRVdXdQWGJ4REpQZHF0NmtxbWRVTlZHMGJRaz0iLCJtYWMiOiI3OWM1ZTBiYjZlMGVmNDQ3Zjg0M2M5MjBiOWJjMmEzMGUyOWUyOGIxMDgyZDI3NjU4NDcyNWQ0ZDA0MWFjMjljIn0=

可以推測這是 Base64,解碼後會變成 JSON:

{
"iv":"dqt75XUxPDWcI83H1sed+g==",
"value":"6CrZtbSII1HCy0n5tUuwPXbxDJPdqt6kqmdUNVG0bQk=",
"mac":"79c5e0bb6e0ef447f843c920b9bc2a30e29e28b1082d276584725d4d041ac29c"
}

其中 iv 即為剛提到的初始化相量,value 即為 AES CBC 加密後的內容,MAC 則是簡介密碼學時提到做為驗證來源的一小段訊息。

RSA

RSA 加密演算法由三個人一起開發的,這個縮寫是取自三位作者的名字。RSA 概念很簡單:兩個很大的質數 pq 相乘出 N 很容易,但從 N 要找回原本 pq 是極度困難的任務。

RSA 需要三個參數:e1e2 和剛剛的 Ne1e2 是互有關係的,會先取 e1(p-1)(q-1) 互質,接著再找出 (e2 * e1) mod ((p-1)(q-1)) = 1。最後 (N, e1) 為公鑰,*(N, e2)* 為私鑰。

一般是使用公鑰加密,私鑰解密,而運算方法如下:

plaintext = cipher ^e2 mod n
cipher = plaintext ^e1 mod n

這兩個也可以交換使用:

plaintext = cipher ^e1 mod n
cipher = plaintext ^e2 mod n

RSA 的安全性建立在:目前沒有多項式時間的演算法,可以分解出大整數的因數。因此只要質數越大,時間就會變得非常不合理的高,同時也會認為攻擊者對此束手無策。雖然是如此,但在 2009 年時,768 bit 長度的大數已成功被分解,而目前建議的長度都是 1024 bit 上,其實也是岌岌可危,只能再把長度提升至 2048 bit。

小結

簡介密碼學時,有提到密碼學的基礎是數學,最近研究這些演算法著實的吃了很多苦頭,但也了解到了不少東西。寫出來的東西有點差強人意,請大家多多包涵與指教。

參考資料