Encode、Encrypt 跟 Hash 的差別

小知識大學問。

懶人包

Encode 編碼

  • 用另一種方式表示資料
  • 毫無安全性,因為本來的用途就不是為了安全

Encrypt 加密

  • 一對一的關係(一個明文對應一組密文)
  • 需要透過 key(金鑰)來執行
  • 可以從結果逆推回去
  • 可以在細分為對稱式與非對稱式

Hash 雜湊

  • 一對多的關係(無限的輸入,有限的輸出)
  • 不可以逆推回去(就算你知道演算法是什麼)
  • 同樣的東西丟進去,出來的結果永遠一樣

Encode 編碼

其實只用另一種方式來「表示資料」,例如 URI 編碼,假設我們有段網址是 https://www.google.com/search?q=無慘,接著用 JavaScript 中的 encodeURI 就會變成 'https://www.google.com/search?q=%E7%84%A1%E6%85%98',如果要轉回去就改用 decodeURI

1
2
3
4
encodeURL('https://www.google.com/search?q=無慘')
// https://www.google.com/search?q=%E7%84%A1%E6%85%98
decodeURI('https://www.google.com/search?q=%E7%84%A1%E6%85%98')
// https://www.google.com/search?q=無慘

為什麼要做編碼,以 URI 來說有兩個理由:

  1. 不是每個人的電腦都有支援中文
  2. 某些字元會跟程式產生衝突,例如 = ' " 等等

還有另外一個很有趣的例子是 base64。假設我想要把圖片用「純文字」傳給某個人,我可以這樣做:

1
cat picture.jpg | base64 > picture.txt

這時候 picture.txt 的內容就會是一段看了就暈的碼:

1
2
3
4
5
6
/9j/4AAQSkZJRgABAQEAeAB4AAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK
CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAOGBagDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
.....

接著拿到文字檔的人只要解碼就可以得到圖片:

1
2
# 加上 -d = decode
cat picture.txt | base64 -d > cool.jpg

一樣附上精美圖片:

base64

Encrypt 加密

加密就是用一個 key(金鑰)來把「明文」變成「密文」,最簡單的例子是「凱薩加密」。凱薩加密是把每個字母做位移,而位移的數量就是加密的 key。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function caesarCipher(s, key) {
let result = ''
for (let i = 0; i < s.length; i++) {
// 取得 ASCII CODE
const code = s.charCodeAt(i)
// 位移後的數字
let m = code + (key % 26)
// 如果超出範圍
if (m > 122) {
// 取餘數,並加上 96,因為 a 從 97 開始
m = (m % 122) + 96
}
// 轉回文字
result += String.fromCharCode(m)
}
return result
}
caesarCipher('A', 3) // 位移三次,所以是 D

只要知道 key,就可以把結果逆推回去。

這個是加密最大的特點。像上面的例子只要知道 key 是 3,就能逆推回去,從 D 推回 A。

對稱式加密與非對稱式加密

另外加密還可以分成「對稱式加密」跟「非對稱式加密」。簡單來說,對稱式就是雙方都是用同一個 key 來做加密跟解密,而非對稱式是把 key 分成「公鑰」與「私鑰」。

為什麼要這樣做?假設小明跟小美的對話是用凱薩加密來做加密,那雙方一定要知道 key 是什麼才能加密跟解密對吧?但網路的世界是不安全的(在沒有 HTTPS 以前),除非小明小美在現實就約出來事先講好 key 是什麼,不然只要透過網路就有機會被「中間人」把 key 偷走,這樣就算你用在厲害的加密方式都沒有意義了。

非對稱式加密就是為了解決同一個 key 的問題而誕生。你要對一個檔案加密就用「公鑰」,要解密就用只有你自己知道的「私鑰」。這樣子就算中間人把公鑰偷走了他也沒辦法解密,因為用公鑰加密的內容只能用私鑰解。

參考這段例子:

同樣的情況當你要傳檔案給 Alice,就先請 Alice 生一組 Key 然後把公鑰傳給你。你有了 Alice 產生的公鑰之後,就用公鑰幫檔案加密再傳給她,Alice 收到就可以用她自己手上的私鑰解開

安全性方面,因為私鑰從頭到尾都在 Alice 手上,完全沒有傳出去過,所以即便中間人取得公鑰加密後的檔案也沒辦法解開,超安全 der

Hash 雜湊

Hash 就是把一個 function,把一段文字或數字丟進去之後會產生一個結果,例如說:

1
2
3
let str = 'hello'
let hash = SHA256(str)
console.log(hash) // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

我不管丟進去幾次 hello 永遠都會得到 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824,這個是雜湊的特性。所以要判斷兩個東西是不是一樣的,只要看雜湊後的值一不一樣就知道了。

另外有一種可能是不同的 input 雜湊後的值一樣,這個叫做「碰撞」,但機率很小很小很小(1/2¹²⁸),所以基本上可以忽略。

這是因為無限的輸入,有限的輸出所造成的,就好像鴿籠原理一樣,所以難免會有這種情況發生。

備註:鴿籠原理 = 10 隻鴿子放進 9 個鴿籠,那麼一定有一個鴿籠放進了至少兩隻鴿子

所以雜湊有個最重要的特性是:

  • 沒有辦法從結果逆推回去
  • 沒有辦法從結果逆推回去
  • 沒有辦法從結果逆推回去

為什麼?假設我有個雜湊函式長這樣:

1
2
3
4
5
6
7
function hash(n) {
return n % 999
}
console.log(hash(1)) // 1
console.log(hash(1000)) // 1
console.log(hash(1001)) // 2
console.log(hash(2000)) // 2

就算我現在知道這個 hash 的演算法是什麼,但是在我只知道結果是 2 的時候要怎麼知道原本是 1001 還是 2000?都有可能阿。所以這就是為什麼雜湊沒有辦法被逆推。

mentor-program-day57 當 Cookie 被竄改會怎麼樣?
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×