初级代码游戏的专栏介绍与文章目录-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
所以不会有冲突。
(这里是文档结束)