Nodejs实战系列:数据加密与crypto模块

2019/04/10 10:10
阅读数 25

<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px; color: black; padding: 10px; line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; word-break: break-word; word-wrap: break-word; text-align: left; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px;"><img src="https://tva1.sinaimg.cn/large/006tNbRwly1gb5dbjstyhj30ka0akwfw.jpg" alt style="display: block; margin: 0 auto; width: 100%;"></figure> <blockquote data-tool="mdnice编辑器" style="display: block; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); padding-top: 10px; padding-bottom: 10px; border-left-color: rgb(221, 221, 221); margin-top: 1.2em; margin-bottom: 1.2em; padding-right: 1em; padding-left: 1em; border-left-width: 4px; color: rgb(119, 119, 119); quotes: none;"> <p style="padding-top: 8px; padding-bottom: 8px; box-sizing: border-box; margin-bottom: 16px; text-align: start; white-space: normal; text-size-adjust: auto; margin: 0px; font-size: 15px; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; color: rgb(119, 119, 119); line-height: 1.75em;"><strong style="font-weight: bold; color: black;">博客地址:<a href="https://xxoo521.com/2020-01-21-crypto/" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">《NodeJS模块研究 - crypto》</a></strong></p> <p style="padding-top: 8px; padding-bottom: 8px; box-sizing: border-box; margin-bottom: 16px; text-align: start; white-space: normal; text-size-adjust: auto; margin: 0px; font-size: 15px; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; color: rgb(119, 119, 119); line-height: 1.75em;"><strong style="font-weight: bold; color: black;">Github :<a href="https://github.com/dongyuanxin/blog" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">https://github.com/dongyuanxin/blog</a></strong></p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">nodejs 中的 crypto 模块提供了各种各样加密算法的 API。这篇文章记录了常用加密算法的种类、特点、用途和代码实现。其中涉及算法较多,应用面较广,每类算法都有自己适用的场景。为了使行文流畅,列出了本文记录的几类常用算法:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">内容摘要:散列(Hash)算法</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">内容摘要:HMac 算法</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">内容加解密:对称加密(AES)与非对称加密解密(RSA)</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">内容签名:签名和验证算法</section></li></ul> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">散列(Hash)算法</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。基本原理是将任意长度数据输入,最后输出固定长度的结果。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">hash 算法具有以下特点:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">不能从 hash 值倒推原数据</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">不同的输入,会有不同的输出</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">好的 hash 算法冲突概率更低</section></li></ul> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">正因为 hash 算法的这些特点,因此 hash 算法主要用于:加密、数据检验、版本标识、负载均衡、分布式(一致性 hash)。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">下面实现了一个获取文件标识的函数:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> crypto = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"crypto"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>);

<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">function</span> <span class="hljs-title" style="color: #900; font-weight: bold; line-height: 26px;">getFileHash</span>(<span class="hljs-params" style="line-height: 26px;">file, algorithm</span>) </span>{ <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (!crypto.getHashes().includes(algorithm)) { <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">throw</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">new</span> <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">Error</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"不支持此哈希函数"</span>); }

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">return</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">new</span> <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">Promise</span>(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">resolve</span> =&gt;</span> {
    <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> hash = crypto.createHash(algorithm);

    <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> rs = fs.createReadStream(file);
    rs.on(<span class="hljs-string" style="color: #d14; line-height: 26px;">"readable"</span>, () =&gt; {
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> data = rs.read();
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (data) {
            hash.update(data);
        }
    });
    rs.on(<span class="hljs-string" style="color: #d14; line-height: 26px;">"end"</span>, () =&gt; {
        resolve(hash.digest(<span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>));
    });
});

}

<span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 用法:获取文件md5</span> getFileHash(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./db.json"</span>, <span class="hljs-string" style="color: #d14; line-height: 26px;">"md5"</span>).then(<span class="hljs-function" style="line-height: 26px;"><span class="hljs-params" style="line-height: 26px;">val</span> =></span> { <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">console</span>.log(val); }); </code></pre>

<h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">HMac 算法</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">攻击者可以借助“彩虹表”来破解哈希表。应对彩虹表的方法,是给密码加盐值(salt),将 pwd 和 salt 一起计算 hash 值。其中,salt 是随机生成的,越长越好,并且需要和用户名、密码对应保存在数据表中。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">虽然通过加盐,实现了哈希长度扩展,但是攻击者通过提交密码和哈希值也可以破解攻击。服务器会把提交的密码和 salt 构成字符串,然后和提交的哈希值对比。如果系统不能提交哈希值,不会受到此类攻击。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">显然,没有绝对安全的方法。但是不推荐使用密码加盐,而是 HMac 算法。它可以使用任意的 Hash 函数,例如 md5 =&gt; HmacMD5、sha1 =&gt; HmacSHA1。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">下面是利用 Hmac 实现加密数据的函数:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> crypto = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"crypto"</span>);

<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">function</span> <span class="hljs-title" style="color: #900; font-weight: bold; line-height: 26px;">encryptData</span>(<span class="hljs-params" style="line-height: 26px;">data, key, algorithm</span>) </span>{ <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (!crypto.getHashes().includes(algorithm)) { <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">throw</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">new</span> <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">Error</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"不支持此哈希函数"</span>); }

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> hmac = crypto.createHmac(algorithm, key);
hmac.update(data);
<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">return</span> hmac.digest(<span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>);

}

<span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// output: 30267bcf2a476abaa9b9a87dd39a1f8d6906d1180451abdcb8145b384b9f76a5</span> <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">console</span>.log(encryptData(<span class="hljs-string" style="color: #d14; line-height: 26px;">"root"</span>, <span class="hljs-string" style="color: #d14; line-height: 26px;">"7(23y*&745^%I"</span>, <span class="hljs-string" style="color: #d14; line-height: 26px;">"sha256"</span>)); </code></pre>

<h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">对称加密(AES)与非对称加密解密(RSA)</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">有很多数据需要加密存储,并且需要解密后进行使用。这和前面不可逆的哈希函数不同。此类算法一共分为两类:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">对称加密(AES):加密和解密使用同一个密钥</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">非对称加密解密(RSA):公钥加密,私钥解密</section></li></ul> <h3 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 20px; margin: 20px auto 5px; border-top: 1px solid rgb(221, 221, 221); box-sizing: border-box;"><span style="margin-top: -1px; padding-top: 6px; padding-right: 5px; padding-left: 5px; font-size: 17px; border-top: 2px solid rgb(33, 33, 34); display: inline-block; line-height: 1.1;">对称加密(AES)</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">查看 nodejs 支持的所有加密算法:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;">crypto.getCiphers(); </code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">Nodejs 提供了 Cipher 类和 Decipher 类,分别用于加密和解密。两者都继承 Transfrom Stream,API 的使用方法和哈希函数的 API 使用方法类似。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">下面是用 aes-256-cbc 算法对明文进行加密:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> crypto = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"crypto"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> secret = crypto.randomBytes(<span class="hljs-number" style="color: #008080; line-height: 26px;">32</span>); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 密钥</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> content = <span class="hljs-string" style="color: #d14; line-height: 26px;">"hello world!"</span>; <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 要加密的明文</span>

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> cipher = crypto.createCipheriv( <span class="hljs-string" style="color: #d14; line-height: 26px;">"aes-256-cbc"</span>, secret, Buffer.alloc(<span class="hljs-number" style="color: #008080; line-height: 26px;">16</span>, <span class="hljs-number" style="color: #008080; line-height: 26px;">0</span>) ); cipher.update(content, <span class="hljs-string" style="color: #d14; line-height: 26px;">"utf8"</span>); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 加密后的结果:e2a927165757acc609a89c093d8e3af5</span> <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">console</span>.log(cipher.final(<span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>)); </code></pre>

<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;"><strong style="font-weight: bold; color: black;">注意</strong>:在使用加密算法的时候,给定的密钥长度是有要求的,否则会爆出<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">this[kHandle].initiv(cipher, credential, iv, authTagLength); Error: Invalid key length...</code>的错误。以 aes-256-cbc 算法为例,需要 256 bits = 32 bytes 大小的密钥。同样地,AES 的 IV 也是有要求的,需要 128bits。(请参考“参考链接”部分)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">使用 32 个连续<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">I</code>作为密钥,用 aes-256-cbc 加密后的结果是 a061e67f5643d948418fdb150745f24d。下面是逆向解密的过程:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> secret = <span class="hljs-string" style="color: #d14; line-height: 26px;">"I"</span>.repeat(<span class="hljs-number" style="color: #008080; line-height: 26px;">32</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> decipher = crypto.createDecipheriv( <span class="hljs-string" style="color: #d14; line-height: 26px;">"aes-256-cbc"</span>, secret, Buffer.alloc(<span class="hljs-number" style="color: #008080; line-height: 26px;">16</span>, <span class="hljs-number" style="color: #008080; line-height: 26px;">0</span>) ); decipher.update(<span class="hljs-string" style="color: #d14; line-height: 26px;">"a061e67f5643d948418fdb150745f24d"</span>, <span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>); <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">console</span>.log(decipher.final(<span class="hljs-string" style="color: #d14; line-height: 26px;">"utf8"</span>)); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 解密后的结果:hello world!</span> </code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 20px; margin: 20px auto 5px; border-top: 1px solid rgb(221, 221, 221); box-sizing: border-box;"><span style="margin-top: -1px; padding-top: 6px; padding-right: 5px; padding-left: 5px; font-size: 17px; border-top: 2px solid rgb(33, 33, 34); display: inline-block; line-height: 1.1;">非对称加密解密(RSA)</span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">借助 openssl 生成私钥和公钥:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-meta" style="color: #999; font-weight: bold; line-height: 26px;">#</span><span class="bash" style="line-height: 26px;"> 生成私钥</span> openssl genrsa -out privatekey.pem 1024 <span class="hljs-meta" style="color: #999; font-weight: bold; line-height: 26px;">#</span><span class="bash" style="line-height: 26px;"> 生成公钥</span> openssl rsa -in privatekey.pem -pubout -out publickey.pem </code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">对 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">hello world!</code> 加密和解密的代码如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> crypto = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"crypto"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> privateKey = fs.readFileSync(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./privatekey.pem"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> publicKey = fs.readFileSync(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./publickey.pem"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> content = <span class="hljs-string" style="color: #d14; line-height: 26px;">"hello world!"</span>; <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 待加密的明文内容</span>

<span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 公钥加密</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> encodeData = crypto.publicEncrypt(publicKey, Buffer.from(content)); <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">console</span>.log(encodeData.toString(<span class="hljs-string" style="color: #d14; line-height: 26px;">"base64"</span>)); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 私钥解密</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> decodeData = crypto.privateDecrypt(privateKey, encodeData); <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">console</span>.log(decodeData.toString(<span class="hljs-string" style="color: #d14; line-height: 26px;">"utf8"</span>)); </code></pre>

<h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">签名和验证算法</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">除了不可逆的哈希算法、数据加密算法,还有专门用于签名和验证的算法。这里也需要用 openssl 生成公钥和私钥。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">代码示范如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> crypto = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"crypto"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> assert = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"assert"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> privateKey = fs.readFileSync(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./privatekey.pem"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> publicKey = fs.readFileSync(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./publickey.pem"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> data = <span class="hljs-string" style="color: #d14; line-height: 26px;">"传输的数据"</span>;

<span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 第一步:用私钥对传输的数据,生成对应的签名</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> sign = crypto.createSign(<span class="hljs-string" style="color: #d14; line-height: 26px;">"sha256"</span>); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 添加数据</span> sign.update(data, <span class="hljs-string" style="color: #d14; line-height: 26px;">"utf8"</span>); sign.end(); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 根据私钥,生成签名</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> signature = sign.sign(privateKey, <span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>);

<span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 第二步:借助公钥验证签名的准确性</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> verify = crypto.createVerify(<span class="hljs-string" style="color: #d14; line-height: 26px;">"sha256"</span>); verify.update(data, <span class="hljs-string" style="color: #d14; line-height: 26px;">"utf8"</span>); verify.end(); assert.ok(verify.verify(publicKey, signature, <span class="hljs-string" style="color: #d14; line-height: 26px;">"hex"</span>)); </code></pre>

<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">从前面这段代码可以看到,利用私钥进行加密,得到签名值;最后利用公钥进行验证。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">总结</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">之前一直是一知半解,一些概念很模糊,经常混淆散列算法和加密算法。整理完这篇笔记,我才理清楚了常见的加密算法的功能和用途。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">除此之外,crypto 模块还提供了其他算法工具,例如 ECDH 在区块链中有应用。这篇文章没有再记录,感兴趣的同学可以去查阅相关资料。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">参考链接</span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="http://nodejs.cn/api/crypto.html" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">NodeJS docs: crypto</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="http://blog.fens.me/nodejs-crypto/" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">推荐:Node.js 加密算法库 Crypto</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://www.zhihu.com/question/26762707/answer/890181997" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">推荐:什么是 hash? - 腾讯技术工程的回答 - 知乎</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://zh.wikipedia.org/wiki/%E6%95%A3%E5%88%97%E5%87%BD%E6%95%B8" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Wiki:散列函数</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="http://aandds.com/blog/password-hashing.html" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Store and validate hashed password</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://zh.wikipedia.org/wiki/%E5%BD%A9%E8%99%B9%E8%A1%A8" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Wiki: 彩虹表</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://stackoverflow.com/questions/44502637/nodejs-6-10-2-crypto-aes-invalid-key-length" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Nodejs 6.10.2 crypto AES Invalid key length</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://security.stackexchange.com/questions/90848/encrypting-using-aes-256-can-i-use-256-bits-iv" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Encrypting using AES-256, can I use 256 bits IV?</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://www.jianshu.com/p/e3187cf67559" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Crypto 加密与解密</a></section></li></ul> <img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbjcfr3xb5j30cw00tjrd.jpg" style="display: block; margin: 0 auto; width: 100% !important;" data-tool="mdnice编辑器"> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">👇<strong style="font-weight: bold; color: black;">扫码关注<a href="https://tva1.sinaimg.cn/large/006tNbRwly1g9xhhp50jpj31bi0hcju4.jpg" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">「心谭博客」</a>,查看「前端图谱」&amp;「算法题解」,坚持分享,共同成长</strong>👇</p> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px;"><img src="https://tva1.sinaimg.cn/large/006tNbRwly1g9xhhp50jpj31bi0hcju4.jpg" alt style="display: block; margin: 0 auto; width: 100%;"></figure> </section>

原文出处:https://www.cnblogs.com/geyouneihan/p/12283150.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部