Skip to main content

Crypto - NodeJS 實作

https://nodejs.org/api/crypto.html#crypto

對稱加密

Cipher

Cipher 類別是實例是用來加密資料,有兩種使用方式:

  1. readstream / writestream生成加密stream資料
  2. cipher.update() 和 cipher.final()生成加密資料 Cipher 實例(instance)無法透過 new 直接建立,而是透過 crypto.createCipher() 或 crypto.createCipheriv() 這些方法。
        // 'aes-128-cbc':  {HashKey: crypto.randomBytes (16), HashIV: crypto.randomBytes (16)},
// 'aes-192-cbc': {HashKey: crypto.randomBytes (24), HashIV: crypto.randomBytes (16)},
// 'aes-256-cbc': {HashKey: crypto.randomBytes (32), HashIV: crypto.randomBytes (16)},

let info = 'orderid=abc1234';
let HashKey = 'Buffer';
let HashIV = 'Buffer';
let algorithm = 'aes-128-cbc';

let encrypt = createCipheriv (algorithm, HashKey, HashIV);
let enc = encrypt.update (info, 'utf8', 'hex');

let encode = enc + encrypt.final ('hex');

Decipher

Decipher 類別是實例是用來解密資料,有兩種使用方式:

  1. readstream / writestream生成解密stream資料
  2. cipher.update() 和 cipher.final()生成解密資料 Decipher 實例(instance)無法透過 new 直接建立,而是透過 crypto.createDecipher() 或 crypto.createDecipheriv() 這些方法。
// 'aes-128-cbc':  {HashKey: crypto.randomBytes (16), HashIV: crypto.randomBytes (16)},
// 'aes-192-cbc': {HashKey: crypto.randomBytes (24), HashIV: crypto.randomBytes (16)},
// 'aes256': {HashKey: crypto.randomBytes (32), HashIV: crypto.randomBytes (16)},

let info = 'orderid=abc1234';
let HashKey = 'Buffer';
let HashIV = 'Buffer';
let algorithm = 'aes-128-cbc';
let encode = 'utf8';

let decrypt = crypto.createDecipheriv (algorithm, HashKey, HashIV); // 'aes-128-cbc'

decrypt.setAutoPadding (false);

let text = decrypt.update (info, 'hex', encode);
let plainText = text + decrypt.final (encode);
let decode = plainText.replace (/[\x00-\x20]+/g, '');

非對稱加密

生成RSA公私鑰匙

let   { publicKey, privateKey }    = generateKeyPairSync ('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'top secret'
}
});

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiPJ5NMx3y1L0K6+oYAGjClPLC
E0t7FzYiKEEo6/rd1zxGRg1xeRH2GZzuwpIIefAAOl+nLIsDxAct79FyVqUjNXmU
oNe+1khXLx5BdLNgK61EfVujnBhfssgskUuzK9ONUiggrAK1pi5HZ2dfmsuqmFOt
dlYpiBmQdVVYeEEEhQIDAQAB
-----END PUBLIC KEY-----

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIC3TBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI0w3sm1ScM2cCAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDEqyxfB2XCpoa7JEdSOdOWBIIC
gAywshhuRc44lJ3zu+7hiC3pMLNLwT53EqiXACRH105OPXHPUvTnDWu6zSfWAhHg
EAXbl7gtjAmabbP71Q4D9NcfIpUL08SYmsVtJ63efLDEcgJAa0/NNiogsFa1v+33
6g6XsUgeEnb6iFHkfgRxKHn2QeycpaQXNPfkAefnIap+oulmo98SSaJvjKNTQWhR
0qFU/+TBwgAKW9DmSe39oA7AzcB3LI3Bj2sJhVaOeY8/0Nd4KkOGaerZe+dRCLOz
iXmPnp4y9tkjG+QHnJ5Si4fZkFSIrek2ZmFOy+DPRysoC9llJGJh0FDrJ2Tz73gU
gNdk99ZCQT/leRuNFnA3qs9VwKFDvJJFEYHEK0dNq5tk0eYaHxTE4hh5ZI9KPcln
IcIOgpCkYRnDkv2OoTziYrkgQYvx1hCgiFLId+hLxVeOdaImUBLmnHsQZrI9FVpM
Pk/nSyZxvphlUkeAaqZ/0XmzDUVzqE4JStMgT5OzLfcoKNKpIQTPcV/DPTGi5krS
sJm4h+EpAZLdHd9Qdi/LVcDKik6NN0zA87LaxFAsZ69J6krvz8wHHvYRCULWUFEd
G+SAkIYifPY4BzouEnXsBceoAfH9adGGL0VY3qFN3S62+j/47IkVfgg6eDIZ4UaH
hHC856+x/w2ljrQTwuHaTB7Jom/LCZh8tWoo1joSbhWAuJum4tpY3hStfIvGeOYU
SkPQFgDZA5rte7PeZoG0ZwnBO1YIH+qmUiZ1MsrJ9mW3h1SMRGNBUq69qNMFU2LT
lx0QXtWKyhW8tiM4vNk1Gw3JkiqapXibuYucnKcbLvWqtIKcQ55I1et5ysbOqvlL
3TsJwGgsXSndqTFxcYKqjK8=
-----END ENCRYPTED PRIVATE KEY-----

安全散列算法 SHA (Secure Hash Algorithm)

CreateHash

依據algorithm生成固定長度Hash code,支援的algorithms,在terminal 執行 openssl list -digest-algorithms

let     sha         = createHash (algorithm);   // * algorithm SHA256、SHA512
let plainText = `HashKey=${HashKey}&${TradeInfo}&HashIV=${HashIV}`;

return sha.update (plainText).digest ('hex').toUpperCase ();

加解密

Base64 encoding

Cache Flow

加解密例子

默認是使用的 PKCS7 填充模式

const   key             = crypto.randomBytes (192 / 8);  // * based on algorithm
const iv = crypto.randomBytes (128 / 8); // * fixed length
const algorithm = 'aes-192-cbc';
const encoding = 'hex';

const encrypt = (text) => {
let cipher = crypto.createCipheriv (algorithm, key, iv);
let ctext = cipher.update (text, 'utf8', 'hex');

return ctext + cipher.final('hex');
};

const decrypt = (encrypted) => {
let decipher = crypto.createDecipheriv (algorithm, key, iv);
let dtext = decipher.update (encrypted, 'hex', 'utf8');

// * 禁用自動填充
decrypt.setAutoPadding (false);
let plainText = dtext + decipher.final ('utf8');

return plainText.replace (/[\x00-\x20]+/g, '');

};

const content = 'Hello Node.js';
const crypted = encrypt (content);
const decrypted = decrypt (crypted);