這篇要介紹nodejs中的crypto module的用法,如何使用這個module來實現密碼學中常見的概念, 包含hash、salt、password hashing、 MAC(message authentication code)、 Symmetric Encryption及Asymmetric Encryption 及Digital Signature。
Hash
可以使用指令openssl list -digest-algorithms
來查詢可用的algorithms,以下使用sha256
為例, 並輸出base64
的字串。
1
2
3
4
5
const { createHash } = require('crypto');
function hash(input) {
return createHash('sha256').update(input).digest('base64');
}
Salt
randomBytes可以幫我們隨機產生你所想要長度的隨機亂數,用來作為salt, 它的回傳值是一個Buffer。
1
2
3
4
5
6
const { randomBytes } = require('crypto');
function salt(len) {
return randomBytes(len).toString('hex')
}
Password hashing
利用scrypt
及scryptSync
這個KDF(一個為非同步,一個為同步的API), function的前三個參數分別為:
- 欲hash的明文資料,此處為密碼
- salt
- output的長度
1
2
3
4
5
6
7
8
const { scryptSync, randomBytes } = require('crypto');
function passwordHash(password) {
const salt = randomBytes(16).toString('hex');
const hashedPassword = scryptSync(password, salt, 32).toString('hex');
return `${salt}:${hashedPassword}`
}
以上例子使用randomBytes
來產生salt,接著將密碼與salt一起hash成32 bytes的hash value,最後跟salt一起回傳。
MAC
跟hash一樣可以使用指令openssl list -digest-algorithms
來查詢可用的演算法。
1
2
3
4
5
6
const { createHmac } = require('crypto');
const key = 'my-secret!';
const message = 'foo bar👻';
const hmac = createHmac('sha256', key).update(message).digest('hex');
Symmetric Encryption
支援的對稱式加密的演算法一樣可以透過這個指令來取得openssl list -cipher-algorithms
,此處使用aes256
。
1
2
3
4
5
6
7
8
9
10
11
12
13
const { randomBytes, createCipheriv, createDecipheriv } = require('crypto');
const message = 'This is the message I wanna deliver';
const key = 'key shared between two parties';
const iv = randomBytes(16);
//Encrypt
const cipher = createCipheriv('aes256', key, iv);
const encryptedMessage = cipher.update(message, 'utf8', 'hex') + cipher.final('hex');
//Decrypt
const decipher = createDecipheriv('aes256', key, iv);
const decryptedMessage = decipher.update(encryptedMessage, 'hex', 'utf-8') + decipher.final('utf8');
Asymmetric Encryption
首先使用generateKeyPair
或generateKeyPairSync
來產生公鑰及私鑰。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const { generateKeyPairSync } = require('crypto');
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'top secret'
}
})
接者使用publicEncrypt
及privateDecrypt
來encrypt、decrypt message。
1
2
3
4
5
6
7
8
9
const { publicEncrypt, privateDecrypt } = require('crypto');
const message = "I am the message to be encypted🥳"
//加密 Encrypt
const encryptedData = publicEncrypt(publicKey, Buffer.from(message));
//解密 Decrypt
const decryptedData = privateDecrypt(privateKey, encryptedData);
Digital Signature
數位簽章牽扯到hash及非對稱加密,使用crypto module中的createSign
及createVerify
, 回傳的Sign
及Verify
Object都幫我們做好好囉~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const { createSign, createVerify } = require('crypto');
//取得你的公私鑰匙
const publicKey = require('./ssl/key.pem')
const privateKey = require('./ssl/cert.pem');
const message = 'this data must be signed';
//使用私鑰sign
const signer = createSign('rsa-sha256');
signer.update(message);
const signature = signer.sign(privateKey, 'hex');
// 使用公鑰verify
const verifier = createVerify('rsa-sha256');
verifier.update(message);
const isVerified = verifier.verify(publicKey, signature, 'hex');
Summay
其實就是從官方document裡,把比較常用的整理到這裡,這篇就只有紀錄在Nodejs裡如何實作, 並沒有討論為何需要上述的每一個東西,以及有何用途,有機會再陸續補上~ 掰掰👋
Comments powered by Disqus.