惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
WordPress大学
WordPress大学
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
博客园 - Franky
D
Docker
小众软件
小众软件
阮一峰的网络日志
阮一峰的网络日志
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
U
Unit 42
M
MIT News - Artificial intelligence
B
Blog
GbyAI
GbyAI
C
Check Point Blog
P
Proofpoint News Feed
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
雷峰网
雷峰网
IT之家
IT之家
Google DeepMind News
Google DeepMind News
V
V2EX
Stack Overflow Blog
Stack Overflow Blog

博客园 - runliuv

网易 S9 PRO 椅子 螺丝规格 VISUAL STUDIO 如果查找即带Contains,又带SubAgentId 字样的代码? 屏蔽论坛头像图片 WIN10,WIN11 微信 多开 微信付款码支付:“暂无权限使用该授权码,请联系客服处理” Windows 7虚拟机安装Vmware tools 装不了 WIN7 trea 默认utf-8-bom,.editorconfig 使用 openssl 生成国密 公钥 私钥 公私钥 EC PRIVATE KEY 蓝湾 Q36 手柄 说明书 京东APP 如何查看 京东支付 的交易明细 银行卡 禁用firefox自动更新,149及以上版本 Microsoft SQL Server Enterprise 2025 v17.0 正式发布 ISO 镜像 小米电脑管家 妙享桌面 无法输入数字 建行支付接口,退款时提示:服务端返回异常(HTTP状态码:400)(如果该笔交易为帐务交易,则处理结果不确定,请先核对明细!) windows win10 win11 打开图片、照片慢、卡 微PE 官网 WINPE QKeyMapper runliuv EC版国密SM2私钥解析C#.NET FFmpeg 截取视频 runliuv 麦当劳9.9元早餐活动,到哪儿领取? 2026.03 录 MP3 录制 软件 Audacity PowerShell将我的文档、图片、视频等目录复制备份到D盘 抖音网页发布视频时,如何声明是A创作的? Realtek HD Audio Driver for DCH,这个DCH是什么意思 ? Realtek Audio Control 在微软应用商店地址 IDEA一个项目多JAR包文件夹 WIN10 WIN11 命令快速锁屏 使用PowerShell一键备份我的文档视频图片等 C#.NET MVC 前端JS的AES加密 C#.NET 从国密私钥中提取出(导出)公钥,SM2
重庆银行,国密SM4,自定义算法,C#.NET版
runliuv · 2026-02-03 · via 博客园 - runliuv
using System;

namespace Com.Qgs.Sms4
{
    public class SMS4
    {
        private const int ENCRYPT = 1;
        private const int DECRYPT = 0;
        public const int ROUND = 32;
        private const int BLOCK = 16;

        // 使用 sbyte 保持与 Java 有符号 byte 相同的数值(-128 ~ 127)
        private static readonly sbyte[] Sbox = new sbyte[]
        {
            -42, -112, -23, -2, -52, -31, 61, -73, 22, -74, 20, -62, 40, -5, 44, 5,
            43, 103, -102, 118, 42, -66, 4, -61, -86, 68, 19, 38, 73, -122, 6, -103,
            -100, 66, 80, -12, -111, -17, -104, 122, 51, 84, 11, 67, -19, -49, -84, 98,
            -28, -77, 28, -87, -55, 8, -24, -107, -128, -33, -108, -6, 117, -113, 63, -90,
            71, 7, -89, -4, -13, 115, 23, -70, -125, 89, 60, 25, -26, -123, 79, -88,
            104, 107, -127, -78, 113, 100, -38, -117, -8, -21, 15, 75, 112, 86, -99, 53,
            30, 36, 14, 94, 99, 88, -47, -94, 37, 34, 124, 59, 1, 33, 120, -121,
            -44, 0, 70, 87, -97, -45, 39, 82, 76, 54, 2, -25, -96, -60, -56, -98,
            -22, -65, -118, -46, 64, -57, 56, -75, -93, -9, -14, -50, -7, 97, 21, -95,
            -32, -82, 93, -92, -101, 52, 26, 85, -83, -109, 50, 48, -11, -116, -79, -29,
            29, -10, -30, 46, -126, 102, -54, 96, -64, 41, 35, -85, 13, 83, 78, 111,
            -43, -37, 55, 69, -34, -3, -114, 47, 3, -1, 106, 114, 109, 108, 91, 81,
            -115, 27, -81, -110, -69, -35, -68, 127, 17, -39, 92, 65, 31, 16, 90, -40,
            10, -63, 49, -120, -91, -51, 123, -67, 45, 116, -48, 18, -72, -27, -76, -80,
            -119, 105, -105, 74, 12, -106, 119, 126, 101, -71, -15, 9, -59, 110, -58, -124,
            24, -16, 125, -20, 58, -36, 77, 32, 121, -18, 95, 62, -41, -53, 57, 72
        };

        private static readonly int[] CK = new int[]
        {
            462357, 472066609, 943670861, 1415275113, 1886879365, -1936483679, -1464879427, -993275175,
            -521670923, -66909679, 404694573, 876298825, 1347903077, 1819507329, -2003855715, -1532251463,
            -1060647211, -589042959, -117504499, 337322537, 808926789, 1280531041, 1752135293, -2071227751,
            -1599623499, -1128019247, -656414995, -184876535, 269950501, 741554753, 1213159005, 1684763257
        };

        private int Rotl(int x, int y)
        {
            // 实现 Java 的 >>>(无符号右移):先转 uint 再右移
            return (x << y) | (int)((uint)x >> (32 - y));
        }

        private int ByteSub(int A)
        {
            // & 255 确保将 sbyte 转为 0-255 范围的整数
            return ((Sbox[((uint)A >> 24) & 255] & 255) & 255) << 24 |
                   ((Sbox[((uint)A >> 16) & 255] & 255) & 255) << 16 |
                   ((Sbox[((uint)A >> 8) & 255] & 255) & 255) << 8 |
                   ((Sbox[A & 255] & 255) & 255);
        }

        private int L1(int B)
        {
            return B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24);
        }

        private int L2(int B)
        {
            return B ^ Rotl(B, 13) ^ Rotl(B, 23);
        }

        public void SMS4Crypt(byte[] Input, byte[] Output, int[] rk)
        {
            int[] x = new int[4];
            int[] tmp = new int[4];

            for (int i = 0; i < 4; ++i)
            {
                tmp[0] = Input[0 + 4 * i] & 255;
                tmp[1] = Input[1 + 4 * i] & 255;
                tmp[2] = Input[2 + 4 * i] & 255;
                tmp[3] = Input[3 + 4 * i] & 255;
                x[i] = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3];
            }

            for (int r = 0; r < 32; r += 4)
            {
                int mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0];
                mid = ByteSub(mid);
                x[0] ^= L1(mid);
                mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1];
                mid = ByteSub(mid);
                x[1] ^= L1(mid);
                mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2];
                mid = ByteSub(mid);
                x[2] ^= L1(mid);
                mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3];
                mid = ByteSub(mid);
                x[3] ^= L1(mid);
            }

            for (int j = 0; j < 16; j += 4)
            {
                Output[j] = (byte)((x[3 - j / 4] >> 24) & 255);
                Output[j + 1] = (byte)((x[3 - j / 4] >> 16) & 255);
                Output[j + 2] = (byte)((x[3 - j / 4] >> 8) & 255);
                Output[j + 3] = (byte)(x[3 - j / 4] & 255);
            }
        }

        private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag)
        {
            int[] x = new int[4];
            int[] tmp = new int[4];

            for (int i = 0; i < 4; ++i)
            {
                tmp[0] = Key[0 + 4 * i] & 255;
                tmp[1] = Key[1 + 4 * i] & 255;
                tmp[2] = Key[2 + 4 * i] & 255;
                tmp[3] = Key[3 + 4 * i] & 255;
                x[i] = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3];
            }

            x[0] ^= -1548633402;
            x[1] ^= 1453994832;
            x[2] ^= 1736282519;
            x[3] ^= -1301273892;

            for (int r = 0; r < 32; r += 4)
            {
                int mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0];
                mid = ByteSub(mid);
                rk[r + 0] = x[0] ^= L2(mid);
                mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1];
                mid = ByteSub(mid);
                rk[r + 1] = x[1] ^= L2(mid);
                mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2];
                mid = ByteSub(mid);
                rk[r + 2] = x[2] ^= L2(mid);
                mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3];
                mid = ByteSub(mid);
                rk[r + 3] = x[3] ^= L2(mid);
            }

            if (CryptFlag == 0)
            {
                for (int i = 0; i < 16; ++i)
                {
                    int mid = rk[i];
                    rk[i] = rk[31 - i];
                    rk[31 - i] = mid;
                }
            }
        }

        public int sms4(byte[] inn, int inLen, byte[] key, byte[] outt, int CryptFlag)
        {
            int point = 0;
            int[] round_key = new int[32];
            SMS4KeyExt(key, round_key, CryptFlag);
            byte[] input = new byte[16];
            byte[] output = new byte[16];

            while (inLen >= 16)
            {
                Array.Copy(inn, point, input, 0, 16);
                SMS4Crypt(input, output, round_key);
                Array.Copy(output, 0, outt, point, 16);
                inLen -= 16;
                point += 16;
            }

            return 0;
        }
    }


}
using System;
using System.Text;

namespace Com.Qgs.Sms4
{
    public class SMS4Util
    {
        public static byte[] EncodeSMS4(string plaintext, byte[] key)
        {
            if (!string.IsNullOrEmpty(plaintext))
            {
                #region 2种方法都可以
                //byte[] bytes = Encoding.UTF8.GetBytes(plaintext);
                //// 填充 \0 使长度为 16 的倍数
                //StringBuilder sb = new StringBuilder(plaintext);
                //int remainder = bytes.Length % 16;
                //for (int i = remainder; i < 16; ++i)
                //{
                //    sb.Append('\0');
                //}
                //byte[] inputBytes = Encoding.UTF8.GetBytes(sb.ToString());
                #endregion

                // 使用 UTF-8 编码(跨平台一致)
                byte[] inputBytes = Encoding.UTF8.GetBytes(plaintext);
                int padding = 16 - (inputBytes.Length % 16);
                if (padding != 16)
                {
                    Array.Resize(ref inputBytes, inputBytes.Length + padding);
                    // 填充 \0(C# 中数组新元素默认为 0,无需额外处理)
                }

                return EncodeSMS4(inputBytes, key);
            }
            else
            {
                return null;
            }
        }

        public static byte[] EncodeSMS4(byte[] plaintext, byte[] key)
        {
            byte[] ciphertext = new byte[plaintext.Length];
            int k = 0;

            for (int plainLen = plaintext.Length; k + 16 <= plainLen; k += 16)
            {
                byte[] cellPlain = new byte[16];

                for (int i = 0; i < 16; ++i)
                {
                    cellPlain[i] = plaintext[k + i];
                }

                byte[] cellCipher = Encode16(cellPlain, key);

                for (int i = 0; i < cellCipher.Length; ++i)
                {
                    ciphertext[k + i] = cellCipher[i];
                }
            }

            return ciphertext;
        }

        public static byte[] DecodeSMS4(byte[] ciphertext, byte[] key)
        {
            byte[] plaintext = new byte[ciphertext.Length];
            int k = 0;

            for (int cipherLen = ciphertext.Length; k + 16 <= cipherLen; k += 16)
            {
                byte[] cellCipher = new byte[16];

                for (int i = 0; i < 16; ++i)
                {
                    cellCipher[i] = ciphertext[k + i];
                }

                byte[] cellPlain = Decode16(cellCipher, key);

                for (int i = 0; i < cellPlain.Length; ++i)
                {
                    plaintext[k + i] = cellPlain[i];
                }
            }

            return plaintext;
        }

        public static string DecodeSMS4toString(byte[] ciphertext, byte[] key)
        {
            byte[] plaintext = DecodeSMS4(ciphertext, key);
            string plain = Encoding.UTF8.GetString(plaintext);
            return plain.Trim();
        }

        private static byte[] Encode16(byte[] plaintext, byte[] key)
        {
            byte[] cipher = new byte[16];
            SMS4 sm4 = new SMS4();
            int ENCRYPT = 1;
            sm4.sms4(plaintext, 16, key, cipher, ENCRYPT);
            return cipher;
        }

        private static byte[] Decode16(byte[] ciphertext, byte[] key)
        {
            byte[] plain = new byte[16];
            SMS4 sm4 = new SMS4();
            int DECRYPT = 0;
            sm4.sms4(ciphertext, 16, key, plain, DECRYPT);
            return plain;
        }
    }
}
using Com.Qgs.Sms4;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleCQSM4
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("--");
            try
            {
                TestDecrypt();

                string inputStr = "{\"_MCHTimestamp\":\"2026-01-01 00:00:00.000\",\"_ChannelJnlNo\":\"1234\",\"ChannelUuid\":\"字符串\"}";
                string SM4_SALT = "9FE3291C77474769AB49794176DDC1DD";
                
                byte[] keyBytes = Encoding.UTF8.GetBytes(SM4_SALT);

                byte[] sourceData = Encoding.UTF8.GetBytes(inputStr);
                byte[] encryptBytes = SMS4Util.EncodeSMS4(inputStr, keyBytes);
                String payloadEncrypt = Hex.ToHexString(encryptBytes);
                Console.WriteLine(".NET 加密结果:" + payloadEncrypt);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadKey();
        }

        static void TestDecrypt() { 
            string intputStr = "09ddc944012201622519d5eab8a897b9b13d8c2c83d0b082f5514506e55ff83d4794e5a0f6ea48694e25e78d661487b0da13ded0c709db93e1fad517a02446570914a04bff5bfbaa5231dd1a6509e572f14b7e89fde074bc0a4f0644a507bdd57ce7f4a6912da07964b599e68da2f11598718463e3432338c1664eea845e1c910222eff300f21a8e4f0c9eab449b3ccbf7597288c6218577c4e44470a52ef580f42e9096df031eca40115b432bc0d2f003c774a04959938165bfd728fe40d120216ba5d1bfaa31da70bc7fdfa250cecb8cb85cb6b5895b8c6ce7a04f49bec2d700a15171707b69b5aa988b71d71e34526ffd7251c9c6e348eee833139cce85accb510c956c8279884a947f6d38d2e74e";
            Console.WriteLine("JAVA 加密结果:" + intputStr);
            string SM4_SALT = "9FE3291C77474769AB49794176DDC1DD";
            byte[] keyBytes = Encoding.UTF8.GetBytes(SM4_SALT);
            byte[] sourceData = Hex.Decode(intputStr);
            byte[] encryptBytes = SMS4Util.DecodeSMS4(sourceData, keyBytes);
            string myRst = Encoding.UTF8.GetString(encryptBytes);
            //string myRst = Hex.ToHexString(encryptBytes);

            Console.WriteLine("解密结果:" + myRst);

        }
    }
}