您好,欢迎访问一九零五行业门户网

nodeJS之crypto加密方式的详解

前面的话加密模块提供了 http 或 https 连接过程中封装安全凭证的方法。也提供了 openssl 的哈希,hmac, 加密(cipher), 解密(decipher), 签名(sign) 和 验证(verify) 方法的封装。本文将详细介绍加密crypto
crypto【crypto.setengine(engine[, flags])】
为某些/所有 openssl 函数加载并设置引擎(根据参数 flags 来设置)。
engine 可能是 id,或者是指向引擎共享库的路径。
flags是可选参数,默认值是engine_method_all ,可以是以下一个或多个参数的组合(在constants里定义)
engine_method_rsa engine_method_dsa engine_method_dh engine_method_rand engine_method_ecdh engine_method_ecdsa engine_method_ciphers engine_method_digests engine_method_store engine_method_pkey_meth engine_method_pkey_asn1_meth engine_method_all engine_method_none
【crypto.getciphers()】
返回支持的加密算法名数组
 crypto = require('crypto'
【crypto.getciphers()】
返回支持的哈希算法名数组。
var crypto = require('crypto'); console.log(crypto.gethashes());//[ 'dsa',  'dsa-sha',  'dsa-sha1',  'dsa-sha1-old',  'rsa-md4',  'rsa-md5',  'rsa-mdc2',  'rsa-ripemd160',  'rsa-sha',  'rsa-sha1',  'rsa-sha1-2',  'rsa-sha224',  'rsa-sha256',  'rsa-sha384',  'rsa-sha512',  'dsaencryption',  'dsawithsha',  'dsawithsha1',  'dss1',  'ecdsa-with-sha1',  'md4',  'md4withrsaencryption',  'md5',  'md5withrsaencryption',  'mdc2',  'mdc2withrsa',  'ripemd',  'ripemd160',  'ripemd160withrsa',  'rmd160',  'sha',  'sha1',  'sha1withrsaencryption',  'sha224',  'sha224withrsaencryption',  'sha256',  'sha256withrsaencryption',  'sha384',  'sha384withrsaencryption',  'sha512',  'sha512withrsaencryption',  'shawithrsaencryption',  'ssl2-md5',  'ssl3-md5',  'ssl3-sha1',  'whirlpool' ]
【crypto.getcurves()】
返回支持的椭圆曲线名数组。
var crypto = require('crypto'); console.log(crypto.getcurves());//[ 'oakley-ec2n-3',  'oakley-ec2n-4',  'brainpoolp160r1',  'brainpoolp160t1',  'brainpoolp192r1',  'brainpoolp192t1',  'brainpoolp224r1',  'brainpoolp224t1',  'brainpoolp256r1',  'brainpoolp256t1',  'brainpoolp320r1',  'brainpoolp320t1',  'brainpoolp384r1',  'brainpoolp384t1',  'brainpoolp512r1',  'brainpoolp512t1',  'c2pnb163v1',  'c2pnb163v2',  'c2pnb163v3',  'c2pnb176v1',  'c2pnb208w1',  'c2pnb272w1',  'c2pnb304w1',  'c2pnb368w1',  'c2tnb191v1',  'c2tnb191v2',  'c2tnb191v3',  'c2tnb239v1',  'c2tnb239v2',  'c2tnb239v3',  'c2tnb359v1',  'c2tnb431r1',  'prime192v1',  'prime192v2',  'prime192v3',  'prime239v1',  'prime239v2',  'prime239v3',  'prime256v1',  'secp112r1',  'secp112r2',  'secp128r1',  'secp128r2',  'secp160k1',  'secp160r1',  'secp160r2',  'secp192k1',  'secp224k1',  'secp224r1',  'secp256k1',  'secp384r1',  'secp521r1',  'sect113r1',  'sect113r2',  'sect131r1',  'sect131r2',  'sect163k1',  'sect163r1',  'sect163r2',  'sect193r1',  'sect193r2',  'sect233k1',  'sect233r1',  'sect239k1',  'sect283k1',  'sect283r1',  'sect409k1',  'sect409r1',  'sect571k1',  'sect571r1',  'wap-wsg-idm-ecid-wtls1',  'wap-wsg-idm-ecid-wtls10',  'wap-wsg-idm-ecid-wtls11',  'wap-wsg-idm-ecid-wtls12',  'wap-wsg-idm-ecid-wtls3',  'wap-wsg-idm-ecid-wtls4',  'wap-wsg-idm-ecid-wtls5',  'wap-wsg-idm-ecid-wtls6',  'wap-wsg-idm-ecid-wtls7',  'wap-wsg-idm-ecid-wtls8',  'wap-wsg-idm-ecid-wtls9' ]
md5md5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示:
【crypto.createhash(algorithm)】
创建并返回一个哈希对象,使用指定的算法来生成哈希摘要。
参数 algorithm 取决于平台上 openssl 版本所支持的算法。例如,'sha1', 'md5', 'sha256', 'sha512' 等等
【hash.update(data[, input_encoding])】
根据 data 来更新哈希内容,编码方式根据 input_encoding 来定,有 'utf8', 'ascii' 或 'binary'。如果没有传入值,默认编码方式是'utf8'。如果 data 是 buffer, input_encoding 将会被忽略。
因为它是流式数据,所以可以使用不同的数据调用很多次。
【hash.digest([encoding])】
计算传入的数据的哈希摘要。encoding 可以是 'hex', 'binary' 或 'base64',如果没有指定encoding ,将返回 buffer。
[注意]调用 digest() 后不能再用 hash 对象。
var crypto = require('crypto');var hash = crypto.createhash('md5');// 可任意多次调用update():hash.update('hello, world!'); hash.update('hello, nodejs!'); console.log(hash.digest('hex')); // 7e1977739c748beac0c0fd14fd26a544
hmachmac算法也是一种哈希算法,它可以利用md5或sha1等哈希算法。不同的是,hmac还需要一个密钥:
【crypto.createhmac(algorithm, key)】
创建并返回一个 hmac 对象,用指定的算法和秘钥生成 hmac 图谱。
它是可读写的流 stream 。写入的数据来用计算 hmac。当写入流结束后,使用 read() 方法来获取计算后的值。也支持老的 update 和 digest 方法。
参数 algorithm 取决于平台上 openssl 版本所支持的算法,参见前面的 createhash。key是 hmac 算法中用的 key
【hmac.update(data)】
根据 data 更新 hmac 对象。因为它是流式数据,所以可以使用新数据调用多次。
【hmac.digest([encoding])】
计算传入数据的 hmac 值。encoding可以是 'hex', 'binary' 或 'base64',如果没有指定encoding ,将返回 buffer。
[注意]调用 digest() 后不能再用 hmac 对象
var crypto = require('crypto');var hmac = crypto.createhmac('sha256', 'match'); hmac.update('hello, world!'); hmac.update('hello, nodejs!');//e82a58066cae2fae4f44e58be1d589b66a5d102c2e8846d796607f02a88c1649console.log(hmac.digest('hex'));
aesaes是一种常用的对称加密算法,加解密都用同一个密钥。crypto模块提供了aes支持,但是需要自己封装好函数,便于使用:
【crypto.createcipher(algorithm, password)】
使用传入的算法和秘钥来生成并返回加密对象。
algorithm 取决于 openssl,例如'aes192'等。password 用来派生 key 和 iv,它必须是一个'binary' 编码的字符串或者一个buffer。
它是可读写的流 stream 。写入的数据来用计算 hmac。当写入流结束后,使用 read() 方法来获取计算后的值。也支持老的update 和 digest 方法。
【cipher.update(data[, input_encoding][, output_encoding])】
根据 data 来更新哈希内容,编码方式根据 input_encoding 来定,有 'utf8', 'ascii' or 'binary'。如果没有传入值,默认编码方式是'binary'。如果data 是 buffer,input_encoding 将会被忽略。
output_encoding 指定了输出的加密数据的编码格式,它可用是 'binary', 'base64' 或 'hex'。如果没有提供编码,将返回 buffer 。
返回加密后的内容,因为它是流式数据,所以可以使用不同的数据调用很多次。
【cipher.final([output_encoding])】
返回加密后的内容,编码方式是由 output_encoding 指定,可以是 'binary', 'base64' 或 'hex'。如果没有传入值,将返回 buffer。
[注意]cipher 对象不能在 final() 方法之后调用。
var 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; }var data = 'hello, this is a secret message!';var key = 'password!';var encrypted = aesencrypt(data, key);//8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0cconsole.log(encrypted);
【crypto.createdecipher(algorithm, password)】
根据传入的算法和密钥,创建并返回一个解密对象。这是 createcipher() 的镜像
【decipher.update(data[, input_encoding][, output_encoding])】
使用参数 data 更新需要解密的内容,其编码方式是 'binary','base64' 或 'hex'。如果没有指定编码方式,则把 data 当成 buffer 对象。
如果 data 是 buffer,则忽略 input_encoding 参数。
参数 output_decoding 指定返回文本的格式,是 'binary', 'ascii' 或 'utf8' 之一。如果没有提供编码格式,则返回 buffer。
【decipher.final([output_encoding])】
返回剩余的解密过的内容,参数 output_encoding 是 'binary', 'ascii' 或 'utf8',如果没有指定编码方式,返回 buffer。
[注意]decipher对象不能在 final() 方法之后使用。
var crypto = require('crypto');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 = '8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0c';var decrypted = aesdecrypt(encrypted, key); console.log(decrypted);//hello, this is a secret message!
可以看出,加密后的字符串通过解密又得到了原始内容。
注意到aes有很多不同的算法,如aes192,aes-128-ecb,aes-256-cbc等,aes除了密钥外还可以指定iv(initial vector),不同的系统只要iv不同,用相同的密钥加密相同的数据得到的加密结果也是不同的。加密结果通常有两种表示方法:hex和base64,这些功能nodejs全部都支持,但是在应用中要注意,如果加解密双方一方用nodejs,另一方用java、php等其它语言,需要仔细测试。如果无法正确解密,要确认双方是否遵循同样的aes算法,字符串密钥和iv是否相同,加密后的数据是否统一为hex或base64格式
【crypto.createcipheriv(algorithm, key, iv)】
创建并返回一个加密对象,用指定的算法,key 和 iv。
algorithm 参数和 createcipher() 一致。key 在算法中用到.iv 是一个initialization vector.
key 和 iv 必须是 'binary' 的编码字符串或buffers.
【crypto.createdecipheriv(algorithm, key, iv)】
根据传入的算法,密钥和 iv,创建并返回一个解密对象。这是 createcipheriv() 的镜像。
const crypto = require('crypto');function aesencryptiv(data, key,iv) {     const cipher = crypto.createcipher('aes192', key, iv);var crypted = cipher.update(data, 'utf8', 'hex');     crypted += cipher.final('hex');return crypted; }function aesdecryptiv(encrypted, key,iv) {     const decipher = crypto.createdecipher('aes192', key, iv);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 iv = 'match';var encrypted = aesencryptiv(data, key, iv);var decrypted = aesdecryptiv(encrypted, key, iv);//hello, this is a secret message!console.log(data);//8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0cconsole.log(encrypted);//hello, this is a secret message!console.log(decrypted);
diffie-hellman【crypto.creatediffiehellman(prime[, prime_encoding][, generator][, generator_encoding])】
使用传入的 prime 和 generator 创建 diffie-hellman 秘钥交互对象。
generator 可以是数字,字符串或buffer。如果没有指定 generator,使用 2
prime_encoding 和 generator_encoding 可以是 'binary', 'hex', 或 'base64'。
如果没有指定 prime_encoding, 则 buffer 为 prime。如果没有指定 generator_encoding ,则 buffer 为 generator。
【diffiehellman.generatekeys([encoding])】
生成秘钥和公钥,并返回指定格式的公钥。这个值必须传给其他部分。编码方式: 'binary', 'hex', 或 'base64'。如果没有指定编码方式,将返回 buffer。
【diffiehellman.getprime([encoding])】
用参数 encoding 指明的编码方式返回 diffie-hellman 质数,编码方式为: 'binary', 'hex', 或 'base64'。 如果没有指定编码方式,将返回 buffer。
【diffiehellman.getgenerator([encoding])】
用参数 encoding 指明的编码方式返回 diffie-hellman 生成器,编码方式为: 'binary', 'hex', 或 'base64'. 如果没有指定编码方式 ,将返回 buffer。
【diffiehellman.computesecret(other_public_key[, input_encoding][, output_encoding])】
使用 other_public_key 作为第三方公钥来计算并返回共享秘密(shared secret)。秘钥用input_encoding 编码。编码方式为:'binary', 'hex', 或 'base64'。如果没有指定编码方式 ,默认为 buffer。
如果没有指定返回编码方式,将返回 buffer。
dh算法
dh算法是一种密钥交换协议,它可以让双方在不泄漏密钥的情况下协商出一个密钥来。dh算法基于数学原理,比如小明和小红想要协商一个密钥,可以这么做:
1、小明先选一个素数和一个底数,例如,素数p=23,底数g=5(底数可以任选),再选择一个秘密整数a=6,计算a=g^a mod p=8,然后大声告诉小红:p=23,g=5,a=8;
2、小红收到小明发来的p,g,a后,也选一个秘密整数b=15,然后计算b=g^b mod p=19,并大声告诉小明:b=19;
3、小明自己计算出s=b^a mod p=2,小红也自己计算出s=a^b mod p=2,因此,最终协商的密钥s为2。
在这个过程中,密钥2并不是小明告诉小红的,也不是小红告诉小明的,而是双方协商计算出来的。第三方只能知道p=23,g=5,a=8,b=19,由于不知道双方选的秘密整数a=6和b=15,因此无法计算出密钥2。
用crypto模块实现dh算法如下:
var crypto = require('crypto');// xiaoming's keys:var ming = crypto.creatediffiehellman(512);var ming_keys = ming.generatekeys();var prime = ming.getprime();var generator = ming.getgenerator();//prime: 8df777257625c66821af697652f28e93af05b9f779af919111b89816faa11c36fcf9df04c76811471a6099800213c4fe8e3fbec8d2f90bd00795e4b7fd241603console.log('prime: ' + prime.tostring('hex'));//generator: 02console.log('generator: ' + generator.tostring('hex'));// xiaohong's keys:var hong = crypto.creatediffiehellman(prime, generator);var hong_keys = hong.generatekeys();// exchange and generate secret:var ming_secret = ming.computesecret(hong_keys);var hong_secret = hong.computesecret(ming_keys);//secret of xiao ming: 4237157ab4c9211f78ffdb67d127d749cec91780d594b81a7e75f1fb591fecb84f33ae6591e1edda4bc9685b503010fe8f9928c6ed69e4ff9fdb44adb9ba1539console.log('secret of xiao ming: ' + ming_secret.tostring('hex'));//secret of xiao hong: 4237157ab4c9211f78ffdb67d127d749cec91780d594b81a7e75f1fb591fecb84f33ae6591e1edda4bc9685b503010fe8f9928c6ed69e4ff9fdb44adb9ba1539console.log('secret of xiao hong: ' + hong_secret.tostring('hex'))
[注意]每次输出都不一样,因为素数的选择是随机的。
以上就是nodejs之crypto加密方式的详解的详细内容。
其它类似信息

推荐信息