原创

javascript JS CryptoJS DES加解密CBC模式与C#DES加解密相同互通(C#,JQUERY,java) 通用

https://www.cnblogs.com/yuanjiedao/p/11471078.html# 

https://blog.csdn.net/gs12software/article/details/83899389 

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

场景:网页客户端(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

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



以下是JAVA 

Java实现DES加密解密

DES(Data Encryption Standard)是一种对称加密算法,所谓对称加密就是加密和解密都是使用同一个密钥

加密原理:

DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行"异或"运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用 16 个循环,使用异或,置换,代换,移位操作四种基本运算。

不过,DES已可破解,所以针对保密级别特别高的数据推荐使用非对称加密算法。

下面介绍基于Java实现的DES加解密方法,该方法同样适用于Android平台,使用的是JDK1.8。

  1. public class DESUtil {
  2. /**
  3. * 偏移变量,固定占8位字节
  4. */
  5. private final static String IV_PARAMETER = "12345678";
  6. /**
  7. * 密钥算法
  8. */
  9. private static final String ALGORITHM = "DES";
  10. /**
  11. * 加密/解密算法-工作模式-填充模式
  12. */
  13. private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
  14. /**
  15. * 默认编码
  16. */
  17. private static final String CHARSET = "utf-8";
  18. /**
  19. * 生成key
  20. *
  21. * @param password
  22. * @return
  23. * @throws Exception
  24. */
  25. private static Key generateKey(String password) throws Exception {
  26. DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
  27. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
  28. return keyFactory.generateSecret(dks);
  29. }
  30. /**
  31. * DES加密字符串
  32. *
  33. * @param password 加密密码,长度不能够小于8位
  34. * @param data 待加密字符串
  35. * @return 加密后内容
  36. */
  37. public static String encrypt(String password, String data) {
  38. if (password== null || password.length() < 8) {
  39. throw new RuntimeException("加密失败,key不能小于8位");
  40. }
  41. if (data == null)
  42. return null;
  43. try {
  44. Key secretKey = generateKey(password);
  45. Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
  46. IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
  47. cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
  48. byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
  49. //JDK1.8及以上可直接使用Base64,JDK1.7及以下可以使用BASE64Encoder
  50. //Android平台可以使用android.util.Base64
  51. return new String(Base64.getEncoder().encode(bytes));
  52. } catch (Exception e) {
  53. e.printStackTrace();
  54. return data;
  55. }
  56. }
  57. /**
  58. * DES解密字符串
  59. *
  60. * @param password 解密密码,长度不能够小于8位
  61. * @param data 待解密字符串
  62. * @return 解密后内容
  63. */
  64. public static String decrypt(String password, String data) {
  65. if (password== null || password.length() < 8) {
  66. throw new RuntimeException("加密失败,key不能小于8位");
  67. }
  68. if (data == null)
  69. return null;
  70. try {
  71. Key secretKey = generateKey(password);
  72. Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
  73. IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
  74. cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
  75. return new String(cipher.doFinal(Base64.getDecoder().decode(data.getBytes(CHARSET))), CHARSET);
  76. } catch (Exception e) {
  77. e.printStackTrace();
  78. return data;
  79. }
  80. }
  81. /**
  82. * DES加密文件
  83. *
  84. * @param srcFile 待加密的文件
  85. * @param destFile 加密后存放的文件路径
  86. * @return 加密后的文件路径
  87. */
  88. public static String encryptFile(String password, String srcFile, String destFile) {
  89. if (password== null || password.length() < 8) {
  90. throw new RuntimeException("加密失败,key不能小于8位");
  91. }
  92. try {
  93. IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
  94. Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
  95. cipher.init(Cipher.ENCRYPT_MODE, generateKey(key), iv);
  96. InputStream is = new FileInputStream(srcFile);
  97. OutputStream out = new FileOutputStream(destFile);
  98. CipherInputStream cis = new CipherInputStream(is, cipher);
  99. byte[] buffer = new byte[1024];
  100. int r;
  101. while ((r = cis.read(buffer)) > 0) {
  102. out.write(buffer, 0, r);
  103. }
  104. cis.close();
  105. is.close();
  106. out.close();
  107. return destFile;
  108. } catch (Exception ex) {
  109. ex.printStackTrace();
  110. }
  111. return null;
  112. }
  113. /**
  114. * DES解密文件
  115. *
  116. * @param srcFile 已加密的文件
  117. * @param destFile 解密后存放的文件路径
  118. * @return 解密后的文件路径
  119. */
  120. public static String decryptFile(String password, String srcFile, String destFile) {
  121. if (password== null || password.length() < 8) {
  122. throw new RuntimeException("加密失败,key不能小于8位");
  123. }
  124. try {
  125. File file = new File(destFile);
  126. if (!file.exists()) {
  127. file.getParentFile().mkdirs();
  128. file.createNewFile();
  129. }
  130. IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSET));
  131. Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
  132. cipher.init(Cipher.DECRYPT_MODE, generateKey(key), iv);
  133. InputStream is = new FileInputStream(srcFile);
  134. OutputStream out = new FileOutputStream(destFile);
  135. CipherOutputStream cos = new CipherOutputStream(out, cipher);
  136. byte[] buffer = new byte[1024];
  137. int r;
  138. while ((r = is.read(buffer)) >= 0) {
  139. cos.write(buffer, 0, r);
  140. }
  141. cos.close();
  142. is.close();
  143. out.close();
  144. return destFile;
  145. } catch (Exception ex) {
  146. ex.printStackTrace();
  147. }
  148. return null;
  149. }
  150. }
正文到此结束
该篇文章的评论功能已被站长关闭
本文目录