梦回从前 發表於 2019-9-6 09:37:00

javascript JS CryptoJS DES加解密CBC模式与C#DES加解密相同互通

<p>我们只知道不同的语言解密要相互通用,就需要遵循相同的加密方式,然而在具体做技术预研的时候,就发现会遇到很多问题,网上找的资料也是比较片面,所以我踩了坑,并且把解决方案和相关资料源码提供出来,给需要的朋友一些参考。</p>
<p>场景:网页客户端(html)页面通过在发起请求时,将数据加密发送给C#编写的后端。C#后端接受到数据后需要进行解密,解密后得到明文,用明文进行业务操作,操作完成后,将结果加密返回。</p>
<p>因为C#后端使用的是DES CBC模式,所以前端JS也要使用相同的方式。否则加密解密结果不以言,就无法互通了。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>使用技术:</p>
<p>1.前端javascript 使用CryptoJS进行加解密。</p>
<p>2.使用System.Security.Cryptography 命名空间下的相关类。</p>
<p>前端核心代码:</p>
<div class="cnblogs_code">
<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
    &lt;title&gt;JS_DES加解密CBC模式与C#DES加解密相同互通&lt;/title&gt;
    &lt;script type="text/javascript"&gt;
      <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> CBCJiami() {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> key = $("#desKey"<span style="color: rgba(0, 0, 0, 1)">).val();
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> iv = $("#desIV"<span style="color: rgba(0, 0, 0, 1)">).val();
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> msg = $("#source"<span style="color: rgba(0, 0, 0, 1)">).val();
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> dd =<span style="color: rgba(0, 0, 0, 1)"> encryptByDES(msg, key, iv);
            $(</span>"#JiaMiHou"<span style="color: rgba(0, 0, 0, 1)">).val(dd);
            $(</span>"#target"<span style="color: rgba(0, 0, 0, 1)">).val(toBase641(dd));
      }
      </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> CBCJiemi() {            
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> key = $("#desKey"<span style="color: rgba(0, 0, 0, 1)">).val();
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> iv = $("#desIV"<span style="color: rgba(0, 0, 0, 1)">).val();
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> msg = $("#JiaMiHou"<span style="color: rgba(0, 0, 0, 1)">).val();
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> dd =<span style="color: rgba(0, 0, 0, 1)"> decryptByDESModeEBC(msg, key, iv);
            $(</span>"#CBCJiemi"<span style="color: rgba(0, 0, 0, 1)">).val(dd);         
      }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> DES CBC模式加密</span>
      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">加密内容、秘钥、向量</span>
      <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> encryptByDES(message, key, iv) {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> keyHex =<span style="color: rgba(0, 0, 0, 1)"> CryptoJS.enc.Utf8.parse(key);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> ivHex =<span style="color: rgba(0, 0, 0, 1)"> CryptoJS.enc.Utf8.parse(iv);
            encrypted </span>=<span style="color: rgba(0, 0, 0, 1)"> CryptoJS.DES.encrypt(message, keyHex, {
                iv: ivHex,
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7
            }
            );
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> encrypted.ciphertext.toString();
      }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">DESCBC模式解密</span>
      <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> decryptByDESModeEBC(ciphertext, key, iv) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">把私钥转换成UTF - 8编码的字符串</span>
            <span style="color: rgba(0, 0, 255, 1)">var</span> keyHex =<span style="color: rgba(0, 0, 0, 1)"> CryptoJS.enc.Utf8.parse(key);
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> ivHex =<span style="color: rgba(0, 0, 0, 1)"> CryptoJS.enc.Utf8.parse(iv);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> direct decrypt ciphertext</span>
            <span style="color: rgba(0, 0, 255, 1)">var</span> decrypted =<span style="color: rgba(0, 0, 0, 1)"> CryptoJS.DES.decrypt({
                ciphertext: CryptoJS.enc.Hex.parse(ciphertext)
            }, keyHex, {
                  iv: ivHex,
                  mode: CryptoJS.mode.CBC,
                  padding: CryptoJS.pad.Pkcs7
                });
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> decrypted.toString(CryptoJS.enc.Utf8);
      }
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">十六进制字符串转为base64</span>
      <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> toBase641(input) {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> base64_rep = ""<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> cnt = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> bit_arr = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> bit_num = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> n = 0; n &lt; input.length; ++<span style="color: rgba(0, 0, 0, 1)">n) {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (input &gt;= 'A' &amp;&amp; input &lt;= 'Z'<span style="color: rgba(0, 0, 0, 1)">) {
                  ascv </span>= input.charCodeAt(n) - 55<span style="color: rgba(0, 0, 0, 1)">;
                }
                </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (input &gt;= 'a' &amp;&amp; input &lt;= 'z'<span style="color: rgba(0, 0, 0, 1)">) {
                  ascv </span>= input.charCodeAt(n) - 87<span style="color: rgba(0, 0, 0, 1)">;
                }
                </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                  ascv </span>= input.charCodeAt(n) - 48<span style="color: rgba(0, 0, 0, 1)">;
                }
                bit_arr </span>= (bit_arr &lt;&lt; 4) |<span style="color: rgba(0, 0, 0, 1)"> ascv;
                bit_num </span>+= 4<span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (bit_num &gt;= 6<span style="color: rgba(0, 0, 0, 1)">) {
                  bit_num </span>-= 6<span style="color: rgba(0, 0, 0, 1)">;
                  base64_rep </span>+= digits;
                  bit_arr </span>&amp;= ~(-1 &lt;&lt;<span style="color: rgba(0, 0, 0, 1)"> bit_num);
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (bit_num &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                bit_arr </span>&lt;&lt;= 6 -<span style="color: rgba(0, 0, 0, 1)"> bit_num;
                base64_rep </span>+=<span style="color: rgba(0, 0, 0, 1)"> digits;
            }
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> padding = base64_rep.length % 4<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (padding &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> n = 0; n &lt; 4 - padding; ++<span style="color: rgba(0, 0, 0, 1)">n) {
                  base64_rep </span>+= "="<span style="color: rgba(0, 0, 0, 1)">;
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> base64_rep;
      }
    </span>&lt;/script&gt;
    &lt;script src="jquery-3.4.1.min.js"&gt;&lt;/script&gt;
    &lt;script src="CryptoJS v3.1.2/rollups/tripledes.js"&gt;&lt;/script&gt;
    &lt;script src="CryptoJS v3.1.2/components/mode-ecb-min.js"&gt;&lt;/script&gt;
    &lt;script src="Base64Helper.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div&gt;
      &lt;fieldset&gt;
            &lt;legend&gt;DES CBC模式加密&lt;/legend&gt;
            Key:&lt;input type="text" id="desKey" value="z9j#$@4D"&gt;
            &lt;br /&gt;
            IV:&lt;input type="text" id="desIV" value="x34dg!df"&gt;
            &lt;br /&gt;
            MSG:&lt;input id="source" value="{}" /&gt;
            &lt;br /&gt;
            &lt;input type="button" onclick="CBCJiami();" name="" value="CBC加密" /&gt;
            &lt;br /&gt;
            加密后:&lt;input id="JiaMiHou" value="" /&gt;
            &lt;br /&gt;
            转base64后:&lt;input id="target" value="" /&gt;
            &lt;br /&gt;
            &lt;input type="button" onclick="CBCJiemi();" name="" value="CBC解密" /&gt;
            &lt;br /&gt;
            解密后:&lt;input id="CBCJiemi" value="" /&gt;
      &lt;/fieldset&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<p>后端核心代码:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:cpp;collapse:true;;gutter:false;">using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsTest
{
    public class DESHelper
    {
      /// &lt;summary&gt;
      /// DES加密字符串
      /// &lt;/summary&gt;
      /// &lt;param name="encryptString"&gt;待加密的字符串&lt;/param&gt;
      /// &lt;param name="encryptKey"&gt;加密密钥,要求为8位&lt;/param&gt;
      /// &lt;returns&gt;加密成功返回加密后的字符串,失败返回源串&lt;/returns&gt;
      public static string EncryptDES(string encryptString, string encryptKey, string iv)
      {
            try
            {
                //将字符转换为UTF - 8编码的字节序列
                byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
                byte[] rgbIV = Encoding.UTF8.GetBytes(iv);
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                //用指定的密钥和初始化向量创建CBC模式的DES加密标准
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                dCSP.Mode = CipherMode.CBC;
                dCSP.Padding = PaddingMode.PKCS7;
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);//写入内存流
                cStream.FlushFinalBlock();//将缓冲区中的数据写入内存流,并清除缓冲区
                return Convert.ToBase64String(mStream.ToArray()); //将内存流转写入字节数组并转换为string字符
            }
            catch
            {
                return encryptString;
            }
      }

      /// &lt;summary&gt;
      /// DES解密字符串
      /// &lt;/summary&gt;
      /// &lt;param name="decryptString"&gt;待解密的字符串&lt;/param&gt;
      /// &lt;param name="decryptKey"&gt;解密密钥,要求为8位,和加密密钥相同&lt;/param&gt;
      /// &lt;returns&gt;解密成功返回解密后的字符串,失败返源串&lt;/returns&gt;
      public static string DecryptDES(string decryptString, string decryptKey, string iv)
      {
            try
            {
                //将字符转换为UTF - 8编码的字节序列
                byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 8));
                byte[] rgbIV = Encoding.UTF8.GetBytes(iv);
                byte[] inputByteArray = Convert.FromBase64String(decryptString);
                //用指定的密钥和初始化向量使用CBC模式的DES解密标准解密
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                dCSP.Mode = CipherMode.CBC;
                dCSP.Padding = PaddingMode.PKCS7;
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return Encoding.UTF8.GetString(mStream.ToArray());
            }
            catch
            {
                return decryptString;
            }


      }
    }
}
</pre>
</div>
<p>  运行效果:</p>
<p><img src="https://img2018.cnblogs.com/blog/495573/201909/495573-20190906091739364-369228980.png"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><img src="https://img2018.cnblogs.com/blog/495573/201909/495573-20190906091751359-1472145179.png"></p>
<p><strong><span style="background-color: rgba(255, 102, 0, 1)">&nbsp;其中要注意一点:前端加密后有个转Base64的操作,加密解密后才会相同,原因是C#加密后的数据是转成base64的。</span></strong></p>
<p>多说无益,直接上代码:&nbsp;</p>
<p>链接:https://pan.baidu.com/s/1FqpRa9LGuSfRZ9ZZ7Hau0g <br>提取码:hjvu</p>
<p>最后感谢网络上我参考过的文章、博客。有的代码是直接抄过来改的,参考太多无法一一列出,但要感谢他们无私精神。</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/yuanjiedao/p/11471078.html
頁: [1]
查看完整版本: javascript JS CryptoJS DES加解密CBC模式与C#DES加解密相同互通