zoukankan      html  css  js  c++  java
  • javascript JS CryptoJS DES加解密CBC模式与C#DES加解密相同互通

    我们只知道不同的语言解密要相互通用,就需要遵循相同的加密方式,然而在具体做技术预研的时候,就发现会遇到很多问题,网上找的资料也是比较片面,所以我踩了坑,并且把解决方案和相关资料源码提供出来,给需要的朋友一些参考。

    场景:网页客户端(html)页面通过在发起请求时,将数据加密发送给C#编写的后端。C#后端接受到数据后需要进行解密,解密后得到明文,用明文进行业务操作,操作完成后,将结果加密返回。

    因为C#后端使用的是DES CBC模式,所以前端JS也要使用相同的方式。否则加密解密结果不以言,就无法互通了。

    使用技术:

    1.前端javascript 使用CryptoJS进行加解密。

    2.使用System.Security.Cryptography 命名空间下的相关类。

    前端核心代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JS_DES加解密CBC模式与C#DES加解密相同互通</title>
        <script type="text/javascript">
            function CBCJiami() {
                var key = $("#desKey").val();
                var iv = $("#desIV").val();
                var msg = $("#source").val();
                var dd = encryptByDES(msg, key, iv);
                $("#JiaMiHou").val(dd);
                $("#target").val(toBase641(dd)); 
            }
            function CBCJiemi() {            
                var key = $("#desKey").val();
                var iv = $("#desIV").val();
                var msg = $("#JiaMiHou").val();
                var dd = decryptByDESModeEBC(msg, key, iv);
                $("#CBCJiemi").val(dd);          
            }
            // DES CBC模式加密
            //加密内容、秘钥、向量
            function encryptByDES(message, key, iv) {
                var keyHex = CryptoJS.enc.Utf8.parse(key);
                var ivHex = CryptoJS.enc.Utf8.parse(iv);
                encrypted = CryptoJS.DES.encrypt(message, keyHex, {
                    iv: ivHex,
                    mode: CryptoJS.mode.CBC,
                    padding: CryptoJS.pad.Pkcs7
                }
                );
                return encrypted.ciphertext.toString();
            }
            //DES  CBC模式解密
            function decryptByDESModeEBC(ciphertext, key, iv) {
                //把私钥转换成UTF - 8编码的字符串
                var keyHex = CryptoJS.enc.Utf8.parse(key);
                var ivHex = CryptoJS.enc.Utf8.parse(iv);
                // direct decrypt ciphertext
                var decrypted = CryptoJS.DES.decrypt({
                    ciphertext: CryptoJS.enc.Hex.parse(ciphertext)
                }, keyHex, {
                        iv: ivHex,
                        mode: CryptoJS.mode.CBC,
                        padding: CryptoJS.pad.Pkcs7
                    });
                return decrypted.toString(CryptoJS.enc.Utf8);
            }
            //十六进制字符串转为base64
            function toBase641(input) {
                var digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
                var base64_rep = "";
                var cnt = 0;
                var bit_arr = 0;
                var bit_num = 0;
                for (var n = 0; n < input.length; ++n) {
                    if (input[n] >= 'A' && input[n] <= 'Z') {
                        ascv = input.charCodeAt(n) - 55;
                    }
                    else if (input[n] >= 'a' && input[n] <= 'z') {
                        ascv = input.charCodeAt(n) - 87;
                    }
                    else {
                        ascv = input.charCodeAt(n) - 48;
                    }
                    bit_arr = (bit_arr << 4) | ascv;
                    bit_num += 4;
                    if (bit_num >= 6) {
                        bit_num -= 6;
                        base64_rep += digits[bit_arr >>> bit_num];
                        bit_arr &= ~(-1 << bit_num);
                    }
                }
                if (bit_num > 0) {
                    bit_arr <<= 6 - bit_num;
                    base64_rep += digits[bit_arr];
                }
                var padding = base64_rep.length % 4;
                if (padding > 0) {
                    for (var n = 0; n < 4 - padding; ++n) {
                        base64_rep += "=";
                    }
                }
                return base64_rep;
            }
        </script>
        <script src="jquery-3.4.1.min.js"></script>
        <script src="CryptoJS v3.1.2/rollups/tripledes.js"></script>
        <script src="CryptoJS v3.1.2/components/mode-ecb-min.js"></script>
        <script src="Base64Helper.js"></script>
    </head>
    <body>
        <div>
            <fieldset>
                <legend>DES CBC模式加密</legend>
                Key:<input type="text" id="desKey" value="z9j#$@4D">
                <br />
                IV:<input type="text" id="desIV" value="x34dg!df">
                <br />
                MSG:<input id="source" value="{}" />
                <br />
                <input type="button" onclick="CBCJiami();" name="" value="CBC加密" />
                <br />
                加密后:<input id="JiaMiHou" value="" />
                <br />
                转base64后:<input id="target" value="" />
                <br />
                <input type="button" onclick="CBCJiemi();" name="" value="CBC解密" />
                <br />
                解密后:<input id="CBCJiemi" value="" />
            </fieldset>
        </div>
    </body>
    </html>

    后端核心代码:

    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
        {
            /// <summary>
            /// DES加密字符串
            /// </summary>
            /// <param name="encryptString">待加密的字符串</param>
            /// <param name="encryptKey">加密密钥,要求为8位</param>
            /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
            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;
                }
            }
    
            /// <summary>
            /// DES解密字符串
            /// </summary>
            /// <param name="decryptString">待解密的字符串</param>
            /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
            /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
            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;
                }
    
    
            }
        }
    }
    

      运行效果:

     其中要注意一点:前端加密后有个转Base64的操作,加密解密后才会相同,原因是C#加密后的数据是转成base64的。

    多说无益,直接上代码: 

    链接:https://pan.baidu.com/s/1FqpRa9LGuSfRZ9ZZ7Hau0g
    提取码:hjvu

    最后感谢网络上我参考过的文章、博客。有的代码是直接抄过来改的,参考太多无法一一列出,但要感谢他们无私精神。

  • 相关阅读:
    resteasy和springmvc的区别
    队列
    栈的顺序存储和链式存储
    线性表链表存储结构(单链表)
    线性表顺序存储结构
    maven创建分model的工程
    使用throw和throws 引发异常
    手写web框架之加载Controller,初始化框架
    手写web框架之实现依赖注入功能
    Kruskal算法(贪心+并查集=最小生成树)
  • 原文地址:https://www.cnblogs.com/yuanjiedao/p/11471078.html
Copyright © 2011-2022 走看看