C# 使用国密SM4加密解密

首先需第三方Nuget包:Portable.BouncyCastle (源码来自http://www.bouncycastle.org/csharp/),支持.NET 4,.NET Standard 2.0

目录

目录

使用BouncyCastle指定填充方案

零填充(Zero Padding)

PKCS7填充(PKCS7 Padding)

示例(SM4 CBC 模式加密(使用 Zero Padding))

代码解析


使用BouncyCastle指定填充方案

在BouncyCastle中,可以通过选择不同的PaddedBufferedBlockCipher实现来指定填充方案。这里我们将展示如何使用零填充(Zero Padding)和PKCS7填充(PKCS7 Padding)。

零填充(Zero Padding)

对于零填充,您需要自定义填充处理,因为BouncyCastle不直接提供零填充实现。

PKCS7填充(PKCS7 Padding)

如果你想使用PKCS7填充,可以使用BouncyCastle中的PaddedBufferedBlockCipher类直接指定Pkcs7Padding

示例(SM4 CBC 模式加密(使用 Zero Padding))

采用国密SM4 CBC 模式加密(使用 Zero Padding)

SM4HttpUtilsV2.cs

using System;
using System.Collections.Generic;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;public class SM4HttpUtilsV2
{public static Dictionary<string, string> CreateCommonParam(string appKey, string appSecret, string codeData, string iv){// 时间戳long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();// 签名 appKey + apiAppInfo.getAppSecret() + encryptString + timestampConsole.WriteLine($"签名: {appKey}{appSecret}{codeData}{timestamp}{iv}");Console.WriteLine($"appKey={appKey}");Console.WriteLine($"appSecret={appSecret}");Console.WriteLine($"encryptStr={codeData}");Console.WriteLine($"timestamp={timestamp}");Console.WriteLine($"iv={iv}");// 使用 MD5 生成签名string sig = CalculateMD5Hash(appKey + appSecret + codeData + timestamp + iv);Console.WriteLine($"签名值: {sig}");var requestParam = new Dictionary<string, string>{{ "timestamp", timestamp.ToString() },{ "sign", sig },{ "iv", iv }};return requestParam;}private static string CalculateMD5Hash(string input){using (var md5 = MD5.Create()){byte[] inputBytes = Encoding.UTF8.GetBytes(input);byte[] hashBytes = md5.ComputeHash(inputBytes);StringBuilder sb = new StringBuilder();for (int i = 0; i < hashBytes.Length; i++){sb.Append(hashBytes[i].ToString("x2"));}return sb.ToString();}}/// <summary>/// Post请求数据/// </summary>/// <param name="url"></param>/// <param name="appKey"></param>/// <param name="appSecret"></param>/// <param name="parameters"></param>/// <returns></returns>public static async Task<string> PostJsonAsync(string url, string appKey, string appSecret, Dictionary<string, object> obj){string requestBody = JsonConvert.SerializeObject(obj);Console.WriteLine($"原始数据: {requestBody}");// 生成随机的 IV(初始化向量)byte[] ivBytes = new byte[16];using (var rng = RandomNumberGenerator.Create()){rng.GetBytes(ivBytes);}string ivBase64 = Convert.ToBase64String(ivBytes);// 使用 SM4 进行加密(需要实现 SM4 加密算法)string codeData = EncryptSM4CBC(appSecret, requestBody, ivBytes);Console.WriteLine($"原始: {codeData}");var requestParam = new Dictionary<string, object>{{ "appKey", appKey },{ "version", "1" },{ "encryptStr", codeData }};foreach (var param in CreateCommonParam(appKey, appSecret, codeData, ivBase64)){requestParam.Add(param.Key, param.Value);}Console.WriteLine($"请求数据: {JsonConvert.SerializeObject(requestParam)}");using (var httpClient = new HttpClient()){var content = new StringContent(JsonConvert.SerializeObject(requestParam), Encoding.UTF8, "application/json");HttpResponseMessage response = await httpClient.PostAsync(url, content);string result = await response.Content.ReadAsStringAsync();Console.WriteLine(result);var ret = JsonConvert.DeserializeObject<Dictionary<string, object>>(result);if (ret.ContainsKey("data") && !string.IsNullOrEmpty(ret["data"]?.ToString())){string data = ret["data"].ToString();return DecryptSM4CBC(appSecret, data, ivBytes);}else{return result;}}}/// <summary>/// SM4 加密 CBC 模式/// </summary>/// <param name="key"></param>/// <param name="data"></param>/// <param name="iv"></param>/// <returns></returns>public static string EncryptSM4CBC(string key, string data, byte[] iv){byte[] keyBytes = Encoding.UTF8.GetBytes(key);byte[] dataBytes = Encoding.UTF8.GetBytes(data);// 应用 Zero PaddingdataBytes = ApplyZeroPadding(dataBytes, 16); // SM4 的块大小是 16 字节SM4Engine engine = new SM4Engine();CbcBlockCipher cipher = new CbcBlockCipher(engine);PaddedBufferedBlockCipher bufferedCipher = new PaddedBufferedBlockCipher(cipher);KeyParameter keyParam = new KeyParameter(keyBytes);ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv);bufferedCipher.Init(true, keyParamWithIV);byte[] outputBytes = new byte[bufferedCipher.GetOutputSize(dataBytes.Length)];int length = bufferedCipher.ProcessBytes(dataBytes, 0, dataBytes.Length, outputBytes, 0);length += bufferedCipher.DoFinal(outputBytes, length);// 直接返回加密后的Base64字符串return Convert.ToBase64String(outputBytes, 0, length);}/// <summary>/// 自定义 Zero Padding 方法/// </summary>/// <param name="input"></param>/// <param name="blockSize"></param>/// <returns></returns>public static byte[] ApplyZeroPadding(byte[] input, int blockSize){int paddingLength = blockSize - (input.Length % blockSize);if (paddingLength == blockSize){return input; // 无需填充}byte[] paddedData = new byte[input.Length + paddingLength];Array.Copy(input, paddedData, input.Length);return paddedData;}/// <summary>/// SM4 解密 CBC 模式/// </summary>/// <param name="key"></param>/// <param name="encryptedData"></param>/// <param name="iv"></param>/// <returns></returns>public static string DecryptSM4CBC(string key, string encryptedData, byte[] iv){byte[] keyBytes = Encoding.UTF8.GetBytes(key);byte[] encryptedBytes = Convert.FromBase64String(encryptedData);// 应用 Zero PaddingencryptedBytes = ApplyZeroPadding(encryptedBytes, 16); // SM4 的块大小是 16 字节SM4Engine engine = new SM4Engine();CbcBlockCipher cipher = new CbcBlockCipher(engine);BufferedBlockCipher bufferedCipher = new BufferedBlockCipher(cipher);KeyParameter keyParam = new KeyParameter(keyBytes);ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv);bufferedCipher.Init(false, keyParamWithIV);byte[] outputBytes = new byte[bufferedCipher.GetOutputSize(encryptedBytes.Length)];int length = bufferedCipher.ProcessBytes(encryptedBytes, 0, encryptedBytes.Length, outputBytes, 0);try{length += bufferedCipher.DoFinal(outputBytes, length);}catch (InvalidCipherTextException e){throw new Exception("解密失败:密文损坏或密钥/IV不正确", e);}return Encoding.UTF8.GetString(outputBytes, 0, length);}
}

当您遇到 Org.BouncyCastle.Crypto.InvalidCipherTextException: "pad block corrupted" 错误时,这通常意味着解密过程中,填充的块(pad block)不符合预期的格式或长度。

需要添加如下代码,指定填充方案

/// <summary>/// 自定义 Zero Padding 方法/// </summary>/// <param name="input"></param>/// <param name="blockSize"></param>/// <returns></returns>public static byte[] ApplyZeroPadding(byte[] input, int blockSize){int paddingLength = blockSize - (input.Length % blockSize);if (paddingLength == blockSize){return input; // 无需填充}byte[] paddedData = new byte[input.Length + paddingLength];Array.Copy(input, paddedData, input.Length);return paddedData;}

代码解析

  1. 自定义 Zero Padding:

    • ApplyZeroPadding方法用于将数据填充到符合块大小(16字节)的倍数。
    • 如果数据已经是块大小的倍数,则不进行填充。
  2. 加密过程:

    • 创建一个SM4Engine实例,并将其包装在CbcBlockCipher中以使用CBC模式。
    • 使用BufferedBlockCipher来处理加密操作。
    • 使用提供的密钥和IV参数初始化加密器。
  3. 处理填充后的数据:

    • 在加密之前,调用ApplyZeroPadding方法对数据进行零填充。
    • 加密完成后,输出结果为Base64编码的字符串。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

排查SQL Server中的内存不足及其他疑难问题

文章目录 引言I DMV 资源信号灯资源信号灯 DMV sys.dm_exec_query_resource_semaphores( 确定查询执行内存的等待)查询性能计数器什么是内存授予?II DBCC MEMORYSTATUS 查询内存对象III DBCC 命令释放多个 SQL Server 内存缓存 - 临时度量值IV 等待资源池 %ls (%ld)中的内存…

Matlab R2022b使用Camera Calibrator工具箱张正友标定法进行相机标定附带标定前后对比代码

打开Camera Calibrator 在这添加你拍摄的图片 根据你每个方块的实际边长填写&#xff0c;我是15mm。 通俗一点&#xff0c;要k3就选3 Coefficients&#xff0c;否则为0&#xff1b;要p1、p2就选Tangential Distortion。然后进行计算。 可以点击右侧误差高的选中图像进行移…

vuex 基础使用

1、封装使用 在项目中的 Store 文件夹下创建 modules 文件夹 getters.js 和 index.js 然后如下&#xff1a; modules 文件夹下创建 一个 index.js 文件 存放需要的功能方法 // 写一个简单的菜单切换&#xff0c;获取当前点击菜单的索引 const Index {state: {menuIndex: 0,…

AI-Talk开发板之LED

一、说明 AI-Talk开发板上有一颗用户LED&#xff0c;连接在CH32 PA2管脚&#xff0c;低电平亮&#xff0c;高电平灭。 相关电路图如下&#xff1a; 二、工程 1、创建项目 进入snap/examples/目录&#xff0c;执行创建项目的命令&#xff1a; lisa zep create ? 选择sam…

C# 窗体中Control以及Invalidate,Update,Refresh三种重绘方法的区别

在 C# 中&#xff0c;Control 类是 Windows Forms 应用程序中所有控件的基类。它提供了控件的基本功能和属性&#xff0c;这些功能和属性被所有继承自 Control 类的子类所共享。这意味着 Control 类是构建 Windows Forms 应用程序中用户界面元素的基础。 以下是 Control 类的一…

【编程基础】跳房子

题目描述 奶牛们按不太传统的方式玩起了小孩子们玩的"跳房子"游戏。奶牛们创造了一个5x5的、由与x,y轴平行的数字组成的直线型网格&#xff0c;而不是用来在里面跳的、线性排列的、带数字的方格。然后他们熟练地在网格中的数字中跳&#xff1a;向前跳、向后跳、向左…

C# 特性与属性的区别

在 C# 中&#xff0c;"特性"&#xff08;Attribute&#xff09;和"属性"&#xff08;Property&#xff09;是两种不同的概念&#xff0c;它们在编程中扮演不同的角色&#xff1a; 属性&#xff08;Property&#xff09;&#xff1a; 属性是类或结构的一部分…

第66期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

C++:关于反向迭代器的学习分享

前言&#xff1a; 小编仅是一位初学者&#xff0c;所以对于C的理解有限&#xff0c;文章大概率会出现表达不清楚可能也只是因为小编不知道如何更好表达&#xff0c;本文章仅作为一个学习的总结分享。 反向迭代器的概念 反向迭代器故名思意解释反向的迭代器&#xff0c;与正向迭…

golang context介绍

在 Go 语言中&#xff0c;context 是一个用于在 goroutines 之间传递上下文信息的包。它主要用于控制请求的生命周期和管理跨 API 边界的信号传递。以下是 context 的一些关键特性和用途&#xff1a; 1. 主要用途 取消信号&#xff1a;允许在多个 goroutines 中发出取消信号&…

银行接口测试的具体流程及内容?

银行接口测试的具体流程及内容可以概括为以下几个关键步骤&#xff1a; 一、测试前准备 接口测试计划制定&#xff1a; 确定测试目标、范围、人员分工、时间计划等。 编写接口测试计划文档&#xff0c;明确测试策略、测试方法、测试工具等。 接口文档解析&#xff1a; 深入理…

批量插入的艺术:SQL高效数据处理指南

批量插入的艺术&#xff1a;SQL高效数据处理指南 在数据库的日常操作中&#xff0c;数据的批量插入是一项常见的任务。无论是数据迁移、初始数据填充还是定期的数据同步&#xff0c;批量插入都能显著提高效率。本文将深入探讨如何使用SQL进行数据的批量插入&#xff0c;并提供…

Oracle 和 PostgreSQL 常用数据类型的对比

Oracle 和 PostgreSQL 常用数据类型的对比 在进行数据库迁移或在一个环境中使用多个数据库时&#xff0c;了解不同数据库系统支持的数据类型之间的对比是非常重要的。以下是 Oracle 和 PostgreSQL 常用数据类型的对比 数字数据类型 数据类型OraclePostgreSQL小整数NUMBER(3,…

边缘智能网关 P1600:智慧城市的创新引擎

智慧城市&#xff08;Smart City&#xff09;是以发展更科学、管理更高效、生活更美好为目标&#xff0c;以信息技术和通信技术为支撑&#xff0c;通过透明、充分的信息获取&#xff0c;广泛、安全的信息传递和有效、科学的信息处理&#xff0c;提高城市运行效率&#xff0c;改…

数据库管理-第238期 23ai:全球分布式数据库-架构与组件(20240904)

数据库管理238期 2024-09-04 数据库管理-第238期 23ai&#xff1a;全球分布式数据库-架构与组件&#xff08;20240904&#xff09;1 架构图2 分片数据库与分片3 Shard Catalog4 Shard Director5 Global Service6 管理界面总结 数据库管理-第238期 23ai&#xff1a;全球分布式数…

Python案例 | 四阶龙格库塔法简介

1.引言 在数值分析中&#xff0c;龙格-库塔法&#xff08;Runge-Kutta methods&#xff09;是用于非线性常微分方程的解的重要的一类隐式或显式迭代法。这些技术由数学家卡尔龙格和马丁威尔海姆库塔于1900年左右发明。 龙格-库塔(Runge-Kutta)方法是一种在工程上应用广泛的高…

HALCON与LabVIEW的联合编程 视觉与控制结合

HALCON与LabVIEW的联合编程在工业自动化和视觉检测领域中越来越受到重视。通过将HALCON的强大图像处理能力与LabVIEW的灵活控制功能相结合&#xff0c;工程师们可以开发出高效且精确的自动化系统。这种整合不仅提高了系统的整体性能&#xff0c;还简化了开发流程。本文将详细介…

人工智能造福公众:未来一片光明

作者&#xff1a;来自 Elastic Peter Dutton 我们如何衡量人工智能对政府的影响&#xff1f;毫无疑问&#xff0c;人工智能将为运营流程和决策带来的好处已被广泛讨论 —— 从自动化工作流程到节省成本再到减少重复工作。 但对于以服务公众为目标的组织来说&#xff0c;人工智…

2024 年 Web3 融资情况解析:公售项目占比超八成,散户抱团取暖

作者&#xff1a;Jasper De Maere&#xff0c;Outlier Ventures 编译&#xff1a;J1N&#xff0c;Techub News 自 2024 年 3 月以来&#xff0c; 加密货币市场出现大幅度回调&#xff0c; 多数 Altcoin &#xff08;除了比特币、以太坊等以外的代币&#xff09;&#xff0c;特…

echo命令、重定向、zip讲解

一、echo echo命令的使用方法&#xff1a; echo “hello Linux”屏幕上面打印Linux 本质上&#xff1a;这个就是从键盘上面输入数据&#xff0c;从屏幕上面输出数据 二、重定向 1、输出重定向 符号&#xff1a;“>”。 使用方法&#xff1a;在echo后面加上“>”文件…