国密起步7:BouncyCastle使用SM4自定义格式加解密C#版

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。

github源码指引的指引-CSDN博客


        本文是国密起步6:GmSSL3使用SM4自定义格式加解密C++版-CSDN博客的对应C#版。

        GmSSL没有C#接口,所以C#上要用别的库,比如BouncyCastle这个著名加解密库。nuget上的名字是BouncyCastle.Cryptography。

一、源码

        因为是跟C++版是对照关系,直接上源码了:

	static public string gm4DecryptMessage(string text, string userkey)
	{
		try
		{
			byte[] encryptdata = Convert.FromBase64String(text);//格式为版本1字节、IV16字节、加密后的数据(第一个块是明文长度,仅用8字节,其余未用)

			byte[] key = new byte[16];//密钥
			var bytesUserKey = Encoding.UTF8.GetBytes(userkey);
			for (int i = 0; i < 16; ++i)
			{
				if (i < userkey.Length) key[i] = bytesUserKey[i];
				else key[i] = 0;
			}
			
			KeyParameter Key = ParameterUtilities.CreateKeyParameter("SM4", key);
			ParametersWithIV keyParamWithIv = new ParametersWithIV(Key, encryptdata.Skip(1).Take(16).ToArray());
			IBufferedCipher inCipher = CipherUtilities.GetCipher("SM4/CBC/NoPadding");

			inCipher.Init(false, keyParamWithIv);
			byte[] full_plaindata = inCipher.ProcessBytes(encryptdata.Skip(17).ToArray());

			int nPlainLength = (int)BitConverter.ToInt64(full_plaindata.Take(8).ToArray());
			text = Encoding.UTF8.GetString(full_plaindata.Skip(16).Take(nPlainLength).ToArray());
		}
		catch (Exception ex)
		{
			text = ex.ToString();
		}
		return text;
	}
	static public string gm4EncryptMessage(string text, string userkey)
	{
		try
		{
			//格式为版本1字节、IV16字节、加密后的数据(第一个块是明文长度,仅用8字节,其余未用)

			byte[] key = new byte[16];//密钥
			var bytesUserKey = Encoding.UTF8.GetBytes(userkey);
			for (int i = 0; i < 16; ++i)
			{
				if (i < userkey.Length) key[i] = bytesUserKey[i];
				else key[i] = 0;
			}
			byte[] IV = new byte[16];
			Random rand = new Random();
			for (int i = 0; i < 16; ++i) IV[i] = (byte)rand.Next(0, 255);

			KeyParameter Key = ParameterUtilities.CreateKeyParameter("SM4", key);
			ParametersWithIV keyParamWithIv = new ParametersWithIV(Key, IV);
			IBufferedCipher inCipher = CipherUtilities.GetCipher("SM4/CBC/NoPadding");

			inCipher.Init(true, keyParamWithIv);


			int plainBufLen;//明文缓冲区长度,第一个块是明文长度,其后是原始数据,按照16字节补齐
			if (0 == text.Length % 16) plainBufLen = 16 + text.Length;
			else plainBufLen = 16 + (text.Length / 16 + 1) * 16;

			byte[] plainBuf = new byte[plainBufLen];
			BitConverter.GetBytes((long)text.Length).CopyTo(plainBuf, 0);//必须是8位整数
			Encoding.UTF8.GetBytes(text).CopyTo(plainBuf, 16);

			byte[] tmp = new byte[1 + 16 + plainBufLen];//输出缓冲区
			tmp[0] = 1;
			IV.CopyTo(tmp, 1);

			byte[] cipher = inCipher.ProcessBytes(plainBuf);

			cipher.CopyTo(tmp, 17);
			text = "G" + Convert.ToBase64String(tmp);
		}
		catch (Exception ex)
		{
			text = ex.ToString();
		}
		return text;
	}

         加密后的数据转为base64编码并增加一个“G”开头。实际使用的格式是这样的:

  • 明文,json格式,总是以‘{’开头
  • 压缩,C+base64
  • AES,E+base64
  • 国密,G+base64

         所以不会有冲突。


(这里是文档结束)        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初级代码游戏

知识究竟是有价还是无价

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值