crypto加密模块

2020-07-01 17:28:33 浏览数 (1)

crypto 模块目的是提供加密功能,包含对 OpenSSL 的哈希、HMAC、加密、解密、签名、以及验证功能的一整套封装。Nodejs用C/C 实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也较直接使用JavaScript快。

普通字符串加密

MD5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示

代码语言:javascript复制
const crypto = require('crypto');

const hash = crypto.createHash('md5');

// 可任意多次调用update():
hash.update('落帆亭');
hash.update('https://www.oecom.cn');

console.log(hash.digest('hex'));//4fa0cb3bc5ca9cd7fdf2d22f87a01f5e

在上述代码中,每调用一次update相当于加密字符串多加一段文字,与落帆亭https://www.oecom.cn调用一次update效果相同。

update方法默认字符串编码为UTF-8,当然你也可以传入Buffer。

在上例中使用的加密算法为md5加密,如果想采用sha1加密方式,只需要将md5替换为sha1即可,或者使用更为安全的sha256或sha512都是类似的写法。

Hmac算法

Hmac算法也是一种哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac还需要一个密钥:

代码语言:javascript复制
const crypto = require('crypto');

const hmac = crypto.createHmac('sha256', '落帆亭');

hmac .update('落帆亭');
hmac .update('https://www.oecom.cn');

console.log(hmac.digest('hex'));//c07e06f12b635726c5d8a227cc16e1d5

只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数“增强”的哈希算法。

AES

AES是一种常用的对称加密算法,加解密都用同一个密钥。crypto模块提供了AES支持,但是需要自己封装好函数,便于使用:

代码语言:javascript复制
const crypto = require('crypto');

function aesEncrypt(data, key) {
    const cipher = crypto.createCipher('aes192', key);
    var crypted = cipher.update(data, 'utf8', 'hex');
    crypted  = cipher.final('hex');
    return crypted;
}

function aesDecrypt(encrypted, key) {
    const decipher = crypto.createDecipher('aes192', key);
    var decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted  = decipher.final('utf8');
    return decrypted;
}

var data = 'Hello, this is a secret message!';
var key = 'Password!';
var encrypted = aesEncrypt(data, key);
var decrypted = aesDecrypt(encrypted, key);

console.log('Plain text: '   data);
console.log('Encrypted text: '   encrypted);
console.log('Decrypted text: '   decrypted);

运行结果如下:

代码语言:javascript复制
Plain text: Hello, this is a secret message!
Encrypted text: 8a944d97bdabc157a5b7a40cb180e7...
Decrypted text: Hello, this is a secret message!

可以看出,加密后的字符串通过解密又得到了原始内容。

注意到AES有很多不同的算法,如aes192aes-128-ecbaes-256-cbc等,AES除了密钥外还可以指定IV(Initial Vector),不同的系统只要IV不同,用相同的密钥加密相同的数据得到的加密结果也是不同的。加密结果通常有两种表示方法:hex和base64,这些功能Nodejs全部都支持,但是在应用中要注意,如果加解密双方一方用Nodejs,另一方用Java、PHP等其它语言,需要仔细测试。如果无法正确解密,要确认双方是否遵循同样的AES算法,字符串密钥和IV是否相同,加密后的数据是否统一为hex或base64格式。

Diffie-Hellman

DH算法是一种密钥交换协议,它可以让双方在不泄漏密钥的情况下协商出一个密钥来。DH算法基于数学原理,比如小明和小红想要协商一个密钥,可以这么做:

  1. 小明先选一个素数和一个底数,例如,素数p=23,底数g=5(底数可以任选),再选择一个秘密整数a=6,计算A=g^a mod p=8,然后大声告诉小红:p=23,g=5,A=8
  2. 小红收到小明发来的pgA后,也选一个秘密整数b=15,然后计算B=g^b mod p=19,并大声告诉小明:B=19
  3. 小明自己计算出s=B^a mod p=2,小红也自己计算出s=A^b mod p=2,因此,最终协商的密钥s2

在这个过程中,密钥2并不是小明告诉小红的,也不是小红告诉小明的,而是双方协商计算出来的。第三方只能知道p=23g=5A=8B=19,由于不知道双方选的秘密整数a=6b=15,因此无法计算出密钥2

用crypto模块实现DH算法如下

代码语言:javascript复制
const crypto = require('crypto');

// xiaoming's keys:
var ming = crypto.createDiffieHellman(512);
var ming_keys = ming.generateKeys();

var prime = ming.getPrime();
var generator = ming.getGenerator();

console.log('Prime: '   prime.toString('hex'));
console.log('Generator: '   generator.toString('hex'));

// xiaohong's keys:
var hong = crypto.createDiffieHellman(prime, generator);
var hong_keys = hong.generateKeys();

//other‘s keys;
var other = crypto.createDiffieHellman(prime,generator)
var other_keys = other.generateKeys();

// exchange and generate secret:
var ming_secret = ming.computeSecret(hong_keys);
var hong_secret = hong.computeSecret(ming_keys);
var other_secret = other.computeSecret(ming_keys);

// print secret:
console.log('Secret of Xiao Ming: '   ming_secret.toString('hex'));
console.log('Secret of Xiao Hong: '   hong_secret.toString('hex'));
console.log('Secret of Xiao Hong: '   other_secret.toString('hex'));

运行后,可以得到如下输出:

注意每次输出都不一样,因为素数的选择是随机的。例子中我还添加了一个第三方的人员输入的,由于彼此没有交换keys所以无法得出相同的结果。

0 人点赞