node.JS的crypto加密模块使用方法详解(MD5,AES,Hmac,Diffie-Hellman加密)
node.JS的加密模块crypto提供了HTTP或HTTPS连接过程中封装安全凭证的方法。也提供了OpenSSL的哈希,hmac,加密(cipher),解密(decipher),签名(sign)和验证(verify)方法的封装
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()
返回支持的加密算法名数组
varcrypto=require('crypto'); console.log(crypto.getCiphers()); //['aes-128-cbc','aes-128-ccm','aes-128-cfb','aes-128-cfb1','aes-128-cfb8','aes-128-ctr','aes-128-ecb','aes-128-gcm','aes-128-ofb','aes-128-xts','aes-192-cbc','aes-192-ccm','aes-192-cfb','aes-192-cfb1','aes-192-cfb8','aes-192-ctr','aes-192-ecb','aes-192-gcm','aes-192-ofb','aes-256-cbc','aes-256-ccm','aes-256-cfb','aes-256-cfb1','aes-256-cfb8','aes-256-ctr','aes-256-ecb','aes-256-gcm','aes-256-ofb','aes-256-xts','aes128','aes192','aes256','bf','bf-cbc','bf-cfb','bf-ecb','bf-ofb','blowfish','camellia-128-cbc','camellia-128-cfb','camellia-128-cfb1','camellia-128-cfb8','camellia-128-ecb','camellia-128-ofb','camellia-192-cbc','camellia-192-cfb','camellia-192-cfb1','camellia-192-cfb8','camellia-192-ecb','camellia-192-ofb','camellia-256-cbc','camellia-256-cfb','camellia-256-cfb1','camellia-256-cfb8','camellia-256-ecb','camellia-256-ofb','camellia128','camellia192','camellia256','cast','cast-cbc','cast5-cbc','cast5-cfb','cast5-ecb','cast5-ofb','des','des-cbc','des-cfb','des-cfb1','des-cfb8','des-ecb','des-ede','des-ede-cbc','des-ede-cfb','des-ede-ofb','des-ede3','des-ede3-cbc','des-ede3-cfb','des-ede3-cfb1','des-ede3-cfb8','des-ede3-ofb','des-ofb','des3','desx','desx-cbc','id-aes128-CCM','id-aes128-GCM','id-aes128-wrap','id-aes192-CCM','id-aes192-GCM','id-aes192-wrap','id-aes256-CCM','id-aes256-GCM','id-aes256-wrap','id-smime-alg-CMS3DESwrap','idea','idea-cbc','idea-cfb','idea-ecb','idea-ofb',...15moreitems]
crypto.getCiphers()
返回支持的哈希算法名数组。
varcrypto=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()
返回支持的椭圆曲线名数组。
varcrypto=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']
crypto的MD5加密
MD5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示:
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对象。
varcrypto=require('crypto'); varhash=crypto.createHash('md5'); //可任意多次调用update(): hash.update('Hello,world!'); hash.update('Hello,nodejs!'); console.log(hash.digest('hex'));//7e1977739c748beac0c0fd14fd26a544
crypto的Hmac加密
Hmac算法也是一种哈希算法,它可以利用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对象
varcrypto=require('crypto'); varhmac=crypto.createHmac('sha256','match'); hmac.update('Hello,world!'); hmac.update('Hello,nodejs!'); //e82a58066cae2fae4f44e58be1d589b66a5d102c2e8846d796607f02a88c1649 console.log(hmac.digest('hex'));
crypto的AES加密
AES是一种常用的对称加密算法,加解密都用同一个密钥。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()方法之后调用。
varcrypto=require('crypto'); functionaesEncrypt(data,key){ constcipher=crypto.createCipher('aes192',key); varcrypted=cipher.update(data,'utf8','hex'); crypted+=cipher.final('hex'); returncrypted; } vardata='Hello,thisisasecretmessage!'; varkey='Password!'; varencrypted=aesEncrypt(data,key); //8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0c console.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()方法之后使用。
varcrypto=require('crypto'); functionaesDecrypt(encrypted,key){ constdecipher=crypto.createDecipher('aes192',key); vardecrypted=decipher.update(encrypted,'hex','utf8'); decrypted+=decipher.final('utf8'); returndecrypted; } vardata='Hello,thisisasecretmessage!'; varkey='Password!'; varencrypted='8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0c'; vardecrypted=aesDecrypt(encrypted,key); console.log(decrypted);//Hello,thisisasecretmessage!
可以看出,加密后的字符串通过解密又得到了原始内容。
注意到AES有很多不同的算法,如aes192,aes-128-ecb,aes-256-cbc等,AES除了密钥外还可以指定IV(InitialVector),不同的系统只要IV不同,用相同的密钥加密相同的数据得到的加密结果也是不同的。
加密结果通常有两种表示方法:hex和base64,这些功能Nodejs全部都支持,但是在应用中要注意,如果加解密双方一方用Nodejs,另一方用Java、PHP等其它语言,需要仔细测试。
如果无法正确解密,要确认双方是否遵循同样的AES算法,字符串密钥和IV是否相同,加密后的数据是否统一为hex或base64格式
crypto.createCipheriv(algorithm,key,iv)
创建并返回一个加密对象,用指定的算法,key和iv。
algorithm参数和createCipher()一致。key在算法中用到.iv是一个initializationvector.
key和iv必须是'binary'的编码字符串或buffers.
crypto.createDecipheriv(algorithm,key,iv)
根据传入的算法,密钥和iv,创建并返回一个解密对象。这是createCipheriv()的镜像。
constcrypto=require('crypto'); functionaesEncryptiv(data,key,iv){ constcipher=crypto.createCipher('aes192',key,iv); varcrypted=cipher.update(data,'utf8','hex'); crypted+=cipher.final('hex'); returncrypted; } functionaesDecryptiv(encrypted,key,iv){ constdecipher=crypto.createDecipher('aes192',key,iv); vardecrypted=decipher.update(encrypted,'hex','utf8'); decrypted+=decipher.final('utf8'); returndecrypted; } vardata='Hello,thisisasecretmessage!'; varkey='Password!'; variv='match'; varencrypted=aesEncryptiv(data,key,iv); vardecrypted=aesDecryptiv(encrypted,key,iv); //Hello,thisisasecretmessage! console.log(data); //8a944d97bdabc157a5b7a40cb180e713f901d2eb454220d6aaa1984831e17231f87799ef334e3825123658c80e0e5d0c console.log(encrypted); //Hello,thisisasecretmessage! console.log(decrypted);
cryptoDiffie-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作为第三方公钥来计算并返回共享秘密(sharedsecret)。秘钥用input_encoding编码。编码方式为:'binary','hex',或'base64'。如果没有指定编码方式,默认为buffer。
如果没有指定返回编码方式,将返回buffer。
DH算法
DH算法是一种密钥交换协议,它可以让双方在不泄漏密钥的情况下协商出一个密钥来。DH算法基于数学原理,比如小明和小红想要协商一个密钥,可以这么做:
1、小明先选一个素数和一个底数,例如,素数p=23,底数g=5(底数可以任选),再选择一个秘密整数a=6,计算A=g^amodp=8,然后大声告诉小红:p=23,g=5,A=8;
2、小红收到小明发来的p,g,A后,也选一个秘密整数b=15,然后计算B=g^bmodp=19,并大声告诉小明:B=19;
3、小明自己计算出s=B^amodp=2,小红也自己计算出s=A^bmodp=2,因此,最终协商的密钥s为2。
在这个过程中,密钥2并不是小明告诉小红的,也不是小红告诉小明的,而是双方协商计算出来的。第三方只能知道p=23,g=5,A=8,B=19,由于不知道双方选的秘密整数a=6和b=15,因此无法计算出密钥2。
用crypto模块实现DH算法如下:
varcrypto=require('crypto'); //xiaoming'skeys: varming=crypto.createDiffieHellman(512); varming_keys=ming.generateKeys(); varprime=ming.getPrime(); vargenerator=ming.getGenerator(); //Prime:8df777257625c66821af697652f28e93af05b9f779af919111b89816faa11c36fcf9df04c76811471a6099800213c4fe8e3fbec8d2f90bd00795e4b7fd241603 console.log('Prime:'+prime.toString('hex')); //Generator:02 console.log('Generator:'+generator.toString('hex')); //xiaohong'skeys: varhong=crypto.createDiffieHellman(prime,generator); varhong_keys=hong.generateKeys(); //exchangeandgeneratesecret: varming_secret=ming.computeSecret(hong_keys); varhong_secret=hong.computeSecret(ming_keys); //SecretofXiaoMing:4237157ab4c9211f78ffdb67d127d749cec91780d594b81a7e75f1fb591fecb84f33ae6591e1edda4bc9685b503010fe8f9928c6ed69e4ff9fdb44adb9ba1539 console.log('SecretofXiaoMing:'+ming_secret.toString('hex')); //SecretofXiaoHong:4237157ab4c9211f78ffdb67d127d749cec91780d594b81a7e75f1fb591fecb84f33ae6591e1edda4bc9685b503010fe8f9928c6ed69e4ff9fdb44adb9ba1539 console.log('SecretofXiaoHong:'+hong_secret.toString('hex'))
[注意]每次输出都不一样,因为素数的选择是随机的。
更多关于node.JS加密方法请点击下面的相关链接
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。