Loading

[转]AES.js加密解密与C#的相互转换(及MD5值计算)

[转]AES.js加密解密与C#的相互转换


原文链接:AES.js加密解密与C#的相互转换
注:删除了原文最后部分的调试截图,增加了扩展部分的内容(自己使用过程中遇到的问题)。

AES简介

AES, Advanced Encryption Standard,其实是一套标准:FIPS 197,而我们所说的AES算法其实是Rijndael算法。

NIST (National INstitute of Standards and Technology) 在1997年9月12日公开征集更高效更安全的替代DES加密算法,第一轮共有15种算法入选,其中5种算法入围了决赛,分别是MARS,RC6,Rijndael,Serpent和Twofish。又经过3年的验证、评测及公众讨论之后Rijndael算法最终入选。
image

具体实现

1.服务端加密/解密

public class DecryptStringAES
{
      /// <summary>  
      /// AES加密算法  
      /// </summary>  
      /// <param name="input">明文字符串</param>  
      /// <returns>字符串</returns>  
      public static string EncryptByAES(string input)
      {
     	  if (string.IsNullOrWhiteSpace(input))
          {
              return input;
          }
          using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
          {
              rijndaelManaged.Mode = CipherMode.CBC;
              rijndaelManaged.Padding = PaddingMode.PKCS7;
              rijndaelManaged.FeedbackSize = 128;

              rijndaelManaged.Key = Encoding.UTF8.GetBytes(Decrypt.Key);
              rijndaelManaged.IV = Encoding.UTF8.GetBytes(Decrypt.AES_IV);

              ICryptoTransform encryptor = rijndaelManaged.CreateEncryptor(rijndaelManaged.Key, rijndaelManaged.IV);
              using (MemoryStream msEncrypt = new MemoryStream())
              {
                  using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                  {
                      using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                      {
                          swEncrypt.Write(input);
                      }
                      byte[] bytes = msEncrypt.ToArray();
                      return Convert.ToBase64String(bytes);
                  }
              }
          }
      }

      /// <summary>  
      /// AES解密  
      /// </summary>  
      /// <param name="input">密文字节数组</param>  
      /// <returns>返回解密后的字符串</returns>  
      public static string DecryptByAES(string input)
      {
   		  if (string.IsNullOrWhiteSpace(input))
          {
              return input;
          }
          var buffer = Convert.FromBase64String(input);
          using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
          {
              rijndaelManaged.Mode = CipherMode.CBC;
              rijndaelManaged.Padding = PaddingMode.PKCS7;
              rijndaelManaged.FeedbackSize = 128;

              rijndaelManaged.Key = Encoding.UTF8.GetBytes(Decrypt.Key);
              rijndaelManaged.IV = Encoding.UTF8.GetBytes(Decrypt.AES_IV);

              ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor(rijndaelManaged.Key, rijndaelManaged.IV);
              using (MemoryStream msEncrypt = new MemoryStream(buffer))
              {
                  using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
                  {
                      using (StreamReader srEncrypt = new StreamReader(csEncrypt))
                      {
                          return srEncrypt.ReadToEnd();
                      }
                  }
              }
          }
      }        
  }

2.客户端(JS)

定义Key/IV:

const key = CryptoJS.enc.Utf8.parse("1234567890000000");
const iv = CryptoJS.enc.Utf8.parse("1234567890000000");

加密方法:

//**************************************************************
//*字符串/对象加密
//*   0:需要解密的字符串或对象
//****************************************************************/
function Encrypt(o) {
   if (typeof (o) === "string") {
        if (o) {
            var srcs = CryptoJS.enc.Utf8.parse(o);
            return CryptoJS.AES.encrypt(srcs, key, {
                keySize: 128 / 8,
                iv: iv,
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7
            }).toString();
        }
    }
    else if (typeof (o) === "object") {
        for (var _o in o) {
            if (o[_o]) {
                var srcs = CryptoJS.enc.Utf8.parse(o[_o]);
                o[_o] = CryptoJS.AES.encrypt(srcs, key, {
                    keySize: 128 / 8,
                    iv: iv,
                    mode: CryptoJS.mode.CBC,
                    padding: CryptoJS.pad.Pkcs7
                }).toString();
            }
        };

    }
    return o;
}

解密方法:

//**************************************************************
//*字符串解密
//*   str:需要解密的字符串
//****************************************************************/
function Decrypt(str) {
   var decrypt = CryptoJS.AES.decrypt(str, key, {
        keySize: 128 / 8,
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr;
}

注:客户端和服务端的KEY/IV必须保持一致。

扩展部分

1.前端计算MD5值

在普通 html 页面直接引入 cdn 的方式来引入 crypto-js:

<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

以下是使用CryptoJS.MD5生成字符串的MD5值,并将其转换成小写字符串、大写字符串和base64编码的示例:

  • 将MD5值转换成小写字符串:
var hash = CryptoJS.MD5('hello');
console.log(hash.toString(CryptoJS.enc.Hex)); // 输出:5d41402abc4b2a76b9719d911017c592
console.log(hash.toString(CryptoJS.enc.Latin1)); // 输出:]A@\¬K*h¹qÚ|Y
console.log(hash.toString(CryptoJS.enc.Utf8)); // 输出:]A@\¬K*h¹qÚ|Y
console.log(hash.toString(CryptoJS.enc.Base64)); // 输出:XUFBArxLK2y5ccmRGAF8Wg==
console.log(hash.toString()); // 输出:5d41402abc4b2a76b9719d911017c592
  • 将MD5值转换成大写字符串:
var hash = CryptoJS.MD5('hello');
console.log(hash.toString(CryptoJS.enc.Hex).toUpperCase()); // 输出:5D41402ABC4B2A76B9719D911017C592
console.log(hash.toString(CryptoJS.enc.Latin1).toUpperCase()); // 输出:]A@\¬K*H¹QÚ|Y
console.log(hash.toString(CryptoJS.enc.Utf8).toUpperCase()); // 输出:]A@\¬K*H¹QÚ|Y
console.log(hash.toString(CryptoJS.enc.Base64).toUpperCase()); // 输出:XUFBARXLK2Y5CCMRGAF8WQ==
console.log(hash.toString().toUpperCase()); // 输出:5D41402ABC4B2A76B9719D911017C592
  • 将MD5值转换成base64编码:
var hash = CryptoJS.MD5('hello');
console.log(hash.toString(CryptoJS.enc.Base64)); // 输出:XUFBArxLK2y5ccmRGAF8Wg==

2.CryptoJS默认编码格式

CryptoJS默认使用UTF-8编码格式处理字符串,在使用MD5算法加密字符串时,可以直接传入原始字符串,CryptoJS会自动将其转换成UTF-8编码的字节数组。

如果需要使用其他编码格式,可以在调用加密函数之前,手动将字符串转换成指定编码的字节数组,然后再传入加密函数进行处理。例如,将字符串转换成Latin1编码的字节数组:

var str = 'hello';
var latin1 = CryptoJS.enc.Latin1.parse(str);
var hash = CryptoJS.MD5(latin1);
console.log(hash.toString()); // 输出:13d2eaa6f3d80ca58f37c2597efec15f

注:在使用不同编码格式时,输出结果可能会不同,需要根据具体场景选择合适的编码方式。

参考资料

posted @ 2023-06-13 10:18  二次元攻城狮  阅读(342)  评论(0)    收藏  举报