用 Node.js 輕鬆實現雜湊演算法 — — Hash 與 Hmac

Roan
6 min readJan 9, 2024

--

機密訊息或密碼等資料因為較為敏感或重要,因此會用到一些資料處理方法、或是加密演算法,經過處理後以保護資料。本文簡單介紹 Hash Function(雜湊演算法)與 HMAC(雜湊訊息鑑別碼),這兩種方法能夠保護資料確保不被竄改;並且分享 JavaScript 如何使用程式碼實現雜湊演算法。

Engineer locking a pile of files by a giant padlock — ar 3:2 — style raw — stylize 0 — v 6.0

什麼是 Hash Function

雜湊函式,或稱雜湊演算法。Hash 是一種資料處理方法。被 Hash 函式處理過的資料,會被打亂再重新組合,變成一連串固定長度、由字母與數字組成的字串。例如,阿拉伯數字「1」以 SHA 256 雜湊處理過後,Hash 值為:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b;中文字「一」則為 51a75f4634dfa8598a0a1436da0b7764830edd1f3a97661222387da2fe2b38d1。

Hash 處理過的資料,會有以下特性:

1. 不可逆:單向處理後的 Hash 值無法推算回處理前的原始資料。
2. 一樣的輸入,就會得到一樣的 Hash 值。
3. 長度一致:不管資料長度如何,都會有一樣的長度資料。

既然被處理過的資料是一連串亂七八糟的數字與字母,那麼實務上能怎麼用?舉簡單的例子來說,假設我有一份資料,經過雜湊處理後得到其 Hash 值。爾後同時傳遞該資料與其 Hash 值給 Alice,對方把得到的資料再次雜湊處理,也會得到其 Hash 值。比較自己的 Hash 值以及之前我所提供的 Hash 值,只要一樣,就能知道這個資料在傳輸的過程中沒有被竄改過。

Hash 能夠用來確認資料有沒有被竄改,那麼如果想辨認這份資料來源的真假呢?

movie screenshot of two agents transmitting classified files , atmospheric, tense — ar 3:2 — v 6.0

什麼是 Hmac

Hmac 是 Hash-based Message Authentication Code 的簡稱。相較於 Hash,Hmac 還需要一把「加密金鑰」,將資料與加密金鑰結合,經過處理後得到 Hash 值。相較於前述的 Hash Function 可以確認資料有無被竄改,Hmac 還能夠辨認資料來源。

舉個簡單的例子說明 Hash 與 Hmac。假設你開了一間飲料店,網路會員可以在下單點飲料,你的系統就會收到下單資料。

但如何防止惡意人士假冒會員,胡亂下單?這時可以給每位會員一個獨特的密碼,或說密鑰。只有你跟會員知道密碼。會員要下單點飲料時,必須傳一組資料給你:

1. 下單的資料 2. 下單的資料加上密鑰後經過雜湊運算得到的 Hash 值

把會員下單的資料加上其密鑰,再計算 Hash 值,並且比較:自己算的 Hash 值與對方提供的 Hash 值是否相同?在運算時用的演算相同,且密鑰沒有外洩的前提下,只要 Hash 值相同,就能辨認出這組資料確實就是這位會員傳過來的。將資料加上密鑰進行 Hash 運算,就是 Hmac。

用 Node.js 輕鬆實現雜湊演算法

那麼要怎麼用 JavaScript 計算資料的 Hash 值呢?Hash 與 Hmac 背後的數學算式非常龐大複雜,但我們不用從零開始寫,因為 Node.js 已經有內建的 crypto 模組了,只要引用這些模組就能立即使用!

程式碼如下。只要修改變數就好。

- data1 / data2:想要加密的訊息
- algorithm1 / algorithm2:要加密的演算法(註)。
- digest1 / digest2: 輸出格式,有 ‘hex’、’binary’、’base64'。
- key:HMAC 另外需要的密鑰。

//請先確保有安裝 Node.js
import { createHmac, createHash } from 'crypto';
//變數,修改這裡就好
const data1 = '54321';
const algorithm1 = 'sha256';
const digest1 = 'hex';
const key = '99';
const data2 = '12345';
const algorithm2 = 'sha256';
const digest2 = 'hex';

//函式
function hmacFunc(data, algorithm, key, digest) {
return createHmac(algorithm, key).update(data).digest(digest);
}
function hashFunc(algorithm, data, digest) {
return createHash(algorithm).update(data).digest(digest);
}
const hmac = hmacFunc(data1, algorithm1, key, digest1);
const hash = hashFunc(algorithm2, data2, digest2);

// 得到結果
console.log('HMAC:', hmac); //HMAC: 7aeeaa6cceb60a4a6ec8eeccdf11f0a2ca1ca5b0f1b18e1348e623a54198ae89
console.log('HASH:', hash); //HASH: 5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5

(註)
要知道總共有哪些演算法可用,可以用以下程式碼檢視 OpenSSL 支援的演算法:

import { getHashes } from 'crypto';
console.log(getHashes());

Hash 與 Hmac 有眾多應用場景

Hash 與 Hmac 可以讓資料在傳輸時,可以確保資料的完整性與來源,更進階的應用例如數位簽章、區塊鏈技術、SSL / TLS 傳輸……等等。當我們在使用網路傳輸資料時,早已應用到這些演算法;Node.js 也早已含有演算法模組,任何人都能輕易將資料算出 Hash 值,來達成資料安全的需求!

Movie scene of Security protecting critical data and servers from evil — ar 3:2 — style raw — stylize 10 — v 6.0

--

--

Roan

Javascript/HTML/CSS/React/Node.JS 我是光頭工程師