我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
本文是国密起步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
所以不会有冲突。
(这里是文档结束)