C# + Vue3采用SM4

引用 

   类库:

using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;

  

public static class SM4Util_New
    {
		/// <summary>
		/// 默认编码
		/// </summary>
		private static Encoding DefaultEncoding = Encoding.UTF8;
		//"GB2312";

		public const string ALGORITHM_NAME = "SM4";

		//SM4/ECB/NoPadding
		//SM4/CBC/NoPadding
		//SM4/CBC/PKCS7Padding

		/// <summary>
		/// ECB模式 [pkcs7padding填充方式]
		/// </summary>
		public const string ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";

		/// <summary>
		/// CBC模式 [pkcs7padding填充方式]
		/// </summary>
		public const string ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS7Padding";

		//这个不需要  SM4默认就是128位的密钥
		//public const int DEFAULT_KEY_SIZE = 128;


		/// <summary>
		/// 解密
		/// </summary>
		/// <param name="key">密钥</param>
		/// <param name="passInput"></param>
		/// <param name="encoding">编码</param>
		/// <param name="algorithmMode">默认是ECB模式 [pkcs5padding填充方式]</param>
		/// <returns></returns>
		public static string DecryptEcb(string key, string passInput, Encoding encoding, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
		{
			encoding = encoding ?? Encoding.UTF8;
			byte[] keyBytes = Hex.Decode(key);
			byte[] input = Hex.Decode(passInput);
			return encoding.GetString(DecryptEcb(keyBytes, input, algorithmMode));
		}

		/// <summary>
		/// 解密
		/// </summary>
		/// <param name="key">密钥</param>
		/// <param name="passInput"></param>
		/// <param name="algorithmMode">默认是ECB模式 [pkcs5padding填充方式]</param>
		/// <returns></returns>
		public static string DecryptEcb(string key, string passInput, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
		{
			return DecryptEcb(key, passInput, DefaultEncoding, algorithmMode);
		}

		/// <summary>
		/// 解密
		/// </summary>
		/// <param name="keyBytes">密钥</param>
		/// <param name="passInput"></param>
		/// <param name="algorithmMode">加密方式</param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public static byte[] DecryptEcb(byte[] keyBytes, byte[] passInput, string algorithmMode)
		{
			KeyParameter key = ParameterUtilities.CreateKeyParameter(ALGORITHM_NAME, keyBytes);
			IBufferedCipher inCipher = CipherUtilities.GetCipher(algorithmMode);
			//forEncryption位false表示解密
			inCipher.Init(false, key);

			MemoryStream bIn = new MemoryStream(passInput, false);
			CipherStream cIn = new CipherStream(bIn, inCipher, null);
			byte[] bytes = new byte[passInput.Length];
			byte[] totalBytes;
			try
			{
				#region 此代码一次性读取解密 可行
				/*BinaryReader dIn = new BinaryReader(cIn);
				byte[] extra = dIn.ReadBytes(passInput.Length);
				Array.Copy(extra, 0, bytes, 0, extra.Length);*/
				#endregion

				#region 官方demo 是先处理一半  再处理剩下的 最后把剩下的复制到bytes剩余部分
				BinaryReader dIn = new BinaryReader(cIn);
				for (int i = 0; i != passInput.Length / 2; i++)
				{
					bytes[i] = dIn.ReadByte();
				}

				int remaining = bytes.Length - passInput.Length / 2;
				byte[] extra = dIn.ReadBytes(remaining);

				//把为了加密补位的部分去掉
				if (extra.Length < remaining)
				{
					int len = passInput.Length / 2 + extra.Length;
					totalBytes = new byte[len];
					Array.Copy(bytes, 0, totalBytes, 0, passInput.Length / 2);
					extra.CopyTo(totalBytes, passInput.Length / 2);
					return totalBytes;
				}
				else
				{
					extra.CopyTo(bytes, passInput.Length / 2);
				}
				//throw new EndOfStreamException();
				#endregion
			}
			catch (Exception e)
			{
				throw new Exception("SM4 failed encryption - " + e, e);
			}

			return bytes;
		}

		/// <summary>
		/// 加密
		/// </summary>
		/// <param name="key">密钥</param>
		/// <param name="text"></param>
		/// <param name="encoding">编码</param>
		/// <param name="algorithmMode">默认是ECB模式 [pkcs5padding填充方式]</param>
		/// <returns></returns>
		public static string EncryptEcb(string key, string text, Encoding encoding, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
		{
			encoding = encoding ?? Encoding.UTF8;
			byte[] keyBytes = Hex.Decode(key);
			byte[] input = encoding.GetBytes(text);
			return Hex.ToHexString(EncryptEcb(keyBytes, input, algorithmMode));
		}

		/// <summary>
		/// 加密
		/// </summary>
		/// <param name="key">密钥</param>
		/// <param name="text"></param>
		/// <param name="algorithmMode"></param>
		/// <returns></returns>
		public static string EncryptEcb(string key, string text, string algorithmMode = ALGORITHM_NAME_ECB_PADDING)
		{
			return EncryptEcb(key, text, DefaultEncoding, algorithmMode);
		}



		/// <summary>
		/// 加密
		/// </summary>
		/// <param name="keyBytes">密钥</param>
		/// <param name="input"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public static byte[] EncryptEcb(byte[] keyBytes, byte[] input, string algorithmMode)
		{
			KeyParameter key = ParameterUtilities.CreateKeyParameter(ALGORITHM_NAME, keyBytes);
			IBufferedCipher outCipher = CipherUtilities.GetCipher(algorithmMode);
			//forEncryption位true表示加密
			outCipher.Init(true, key);
			MemoryStream bOut = new MemoryStream();
			CipherStream cOut = new CipherStream(bOut, null, outCipher);

			try
			{
				//处理前一半
				for (int i = 0; i != input.Length / 2; i++)
				{
					cOut.WriteByte(input[i]);
				}
				//处理后一半
				cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
				cOut.Close();
			}
			catch (IOException e)
			{
				throw new Exception("SM4 failed encryption - " + e, e);
			}
			byte[] bytes = bOut.ToArray();
			return bytes;
		}
	}

 调用:

            var encrypt = SM4Util_New.EncryptEcb(SM4_KEY, "[{\"id\":\"4c5849f2.4369f8\",\"type\":\"tab\",\"label\":\"1111\",\"disabled\":false,\"info\":\"\"}]");
            var decrypt = SM4Util_New.DecryptEcb(SM4_KEY,encrypt );

    密钥生成方法: 

var SM4_KEY = Guid.NewGuid().ToString("N");//生成key 32位 16进制字符串

 解密方法:

        public static String decrypt()
        {
            var iv = Hex.Decode("fedcba98765432100123456789abcdef");
            //byte[] plain = Hex.Decode("0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210");
            byte[] key = Hex.Decode("0123456789abcdeffedcba9876543210");
            var base64Str = Base64Util.Base64Decrypt("MGQ2Y2ZhNzNjODIzYjJhYzBkNmE5MmM1NjQxNzE4OTJmYTk1ZmE0Yjc1OTEwMzIwMjBjNGFhNDlkMmI0MmJjNQ==");
            byte[] cipher = Hex.Decode(base64Str);
            var bs = GmUtil.Sm4DecryptCBC(key, cipher, iv, GmUtil.SM4_CBC_PKCS7PADDING);

            var encrypt = Encoding.UTF8.GetString(bs);
            System.Console.Out.WriteLine(encrypt);
            return encrypt;
            //log.Info("testSm4EncEcb: " + Hex.ToHexString(bs)); ;
            //bs = Sm4DecryptECB(key, bs, GmUtil.SM4_ECB_NOPADDING);
        }

Vue3

npm install --save sm-crypto

--https://www.npmjs.com/package/sm-crypto

npm install --save js-base64

import { sm4, sm3, sm2 } from "sm-crypto";
import { Base64 } from "js-base64";
 

  

function doDecryptSm4() {
  const encryptData =
    "1118b5cec13c3bcd39e7006f9c155017948d2025fe716b45746e9b04559e77d52f2345cf9d1cf55abee0adca8f971a0693a7ea8a26f67a377a24a26a8d5f60c4f5c145149bd4de7144bbb1093374549f3c813d0b36b2284e33aacac91e5d2f62";
  const key = "8abf369903e94857bcadbcf7068d68e3";
  let decryptData = sm4.decrypt(encryptData, key); // 解密,不使用 padding
  console.log(decryptData);
  console.log(Base64.encode(decryptData));
}
function doEncryptSm4() {
  //后端返回的数据格式
  var json = [
    {
      id: "4c5849f2.4369f8",
      type: "tab",
      label: "1111",
      disabled: false,
      info: "",
    },
  ];

  const escapedJson = JSON.stringify(json);
  console.log(escapedJson);
  const msg = escapedJson;
  //"{'urlquerystring':'partner=XunChaApplet&channel=ApiApplet&clientversion=1.0&timestamp=1701956563','Sign':'0aa77898ea0181d2c0addbaff953a633'}"; // 可以为 utf8 串或字节数组
  const key = "8abf369903e94857bcadbcf7068d68e3"; // 可以为 16 进制串或字节数组,要求为 128 比特
  let encryptData = sm4.encrypt(msg, key); // 加密,默认输出 16 进制字符串,默认使用 pkcs#7 填充(传 pkcs#5 也会走 pkcs#7 填充) 默认走 ECB 模式
  //let encryptData = sm4.encrypt(msg, key, {padding: 'none'}) // 加密,不使用 padding
  //let encryptData = sm4.encrypt(msg, key, {padding: 'none', output: 'array'}) // 加密,不使用 padding,输出为字节数组
  //let encryptData = sm4.encrypt(msg, key, { mode: "cbc",iv: "fedcba98765432100123456789abcdef", }); // 加密,cbc 模式 默认使用 pkcs#7 填充
  console.log(encryptData);
  console.log(Base64.encode(encryptData));
}

  

posted @ 2023-12-09 15:20  流氓大菠萝  阅读(179)  评论(0编辑  收藏  举报