C# + Vue3采用SM4
引用
类库:
1 2 3 4 5 | using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.Encoders; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | 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; } } |
调用:
1 2 | 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 ); |
密钥生成方法:
1 | var SM4_KEY = Guid.NewGuid().ToString( "N" ); //生成key 32位 16进制字符串 |
解密方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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
1 2 | import { sm4, sm3, sm2 } from "sm-crypto" ; import { Base64 } from "js-base64" ; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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×tamp=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)); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端