new_10009_YanCheng_Metrology/Assets/Scripts/SecretUtils/Crypto/SM4Util.cs

275 lines
9.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
namespace SecretUtils.Crypto
{
/**
* sm4加解密工具类
* <p>因为数据加解密都是对字节数据加解密,因此需要注意加密前和解密后使用的字符集保持一致
* <p>若无特殊说明接口接收的都是原始的二进制数据被hex或者base64编码的数据务必解码之后再传入接口
* @author liangruxing
*
*/
internal class SM4Util
{
private const int SM4_ENCRYPT = 1;
private const int SM4_DECRYPT = 0;
public const int SM4_PKCS8PADDING = 1;
public const int SM4_NOPADDING = 0;
public const int SM4_KEY_128 = 128;
private const String iv = "DB4433CBE745731BBFA534109636F5FD";
/// <summary>
/// 使用国密SM4对文本加密字符串
/// </summary>
/// <param name="key"></param>
/// <param name="data"></param>
/// <returns></returns>
public static string SM4EncryptData(string key, byte[] dataBytes)
{
//byte[] dataBytes = Encoding.UTF8.GetBytes(data);
byte[] cipher = SM4Util.EncryptCBC(dataBytes, Hex.Decode(key), Hex.Decode(key));
return Convert.ToBase64String(cipher);
}
public static string SM4DecryptData(string key,string data)
{
byte[] cipher = Convert.FromBase64String(data);
byte[] plain = SM4Util.DecryptCBC(cipher, Hex.Decode(key), Hex.Decode(key));
return Hex.ToHexString(cipher, 0, cipher.Length);
}
/**
* 生成sm4密钥长度使用
* @param keySize 密钥位数通过SM4Util的常量获取长度值
* @return sm4密钥
*/
public static byte[] GenerateKey(int keySize)
{
byte[] key = new byte[keySize / 8];
SecureRandom sr = new SecureRandom();
sr.NextBytes(key);
return key;
}
/**
* sm4 ecb模式加密数据数据长度非16倍数则使用默认PKCS8PADDING方式填充
* @param data 待加密的数据
* @param key sm4密钥
* @return 密文数据
*/
public static byte[] EncryptECB(byte[] data, byte[] key)
{
return EncryptECB(data, key, SM4_PKCS8PADDING);
}
/**
* sm4 ecb模式解密数据使用默认PKCS8PADDING方式去除填充
* @param cipher 密文数据
* @param key sm4密钥
* @return 明文字节数据
*/
public static byte[] DecryptECB(byte[] cipher, byte[] key)
{
return DecryptECB(cipher, key, SM4_PKCS8PADDING);
}
/**
* sm4 CBC模式加密数据数据长度非16倍数则使用默认PKCS8PADDING方式填充
* @param data 待加密数据
* @param key sm4密钥
* @param iv 向量
* @return 密文数据
*/
public static byte[] EncryptCBC(byte[] data, byte[] key, byte[] iv)
{
return EncryptCBC(data, key, iv, SM4_PKCS8PADDING);
}
/**
* sm4 cbc模式解密数据使用默认PKCS8PADDING方式去除填充
* @param cipher sm4密文数据
* @param key sm4密钥
* @param iv 向量
* @return 明文字节数据
*/
public static byte[] DecryptCBC(byte[] cipher, byte[] key, byte[] iv)
{
return DecryptCBC(cipher, key, iv, SM4_PKCS8PADDING);
}
/**
* sm4 ecb模式加密数据
* @param data 待加密数据
* @param key sm4密钥
* @param paddingMode 填充模式,具体支持请看类的常量字段,若使用不支持的模式则会默认无填充
* @return 返回密文数据
*/
public static byte[] EncryptECB(byte[] data, byte[] key, int paddingMode)
{
IBlockCipher engine = new SM4Engine();
engine.Init(true, new KeyParameter(key));
if (paddingMode == SM4_PKCS8PADDING)
{
data = padding(data, SM4_ENCRYPT);
}
else
{
data = (byte [])data.Clone();
}
int length = data.Length;
for (int i = 0; length > 0; length -= 16, i += 16)
{
engine.ProcessBlock(data, i, data, i);
}
return data;
}
/**
* sm4 ecb模式解密数据
* @param cipher 密文数据
* @param key sm4密钥
* @param paddingMode 填充模式,具体支持请看类的常量字段,若使用不支持的模式则会默认无填充
* @return 返回明文字节数据
*/
public static byte[] DecryptECB(byte[] cipher, byte[] key, int paddingMode)
{
IBlockCipher engine = new SM4Engine();
engine.Init(false, new KeyParameter(key));
int length = cipher.Length;
byte[] tmp = new byte[cipher.Length];
for (int i = 0; length > 0; length -= 16, i += 16)
{
engine.ProcessBlock(cipher, i, tmp, i);
}
byte[] plain = null;
if (paddingMode == SM4_PKCS8PADDING)
{
plain = padding(tmp, SM4_DECRYPT);
}
else
{
plain = tmp;
}
return plain;
}
/**
* CBC模式加密数据
* @param data 待加密数据
* @param key 密钥
* @param iv 向量
* @param paddingMode 填充模式,具体支持请看类的常量字段,若使用不支持的模式则会默认无填充
* @return 返回密文值
*/
public static byte[] EncryptCBC(byte[] data, byte[] key, byte[] iv, int paddingMode)
{
IBlockCipher engine = new SM4Engine();
engine.Init(true, new KeyParameter(key));
if (paddingMode == SM4_PKCS8PADDING)
{
data = padding(data, SM4_ENCRYPT);
}
else
{
data = (byte [])data.Clone();
}
int length = data.Length;
iv = (byte [])iv.Clone();
for (int i = 0; length > 0; length -= 16, i += 16)
{
for (int j = 0; j < 16; j++)
{
data[i + j] = ((byte)(data[i + j] ^ iv[j]));
}
engine.ProcessBlock(data, i, data, i);
Buffer.BlockCopy(data, i, iv, 0, 16);
}
return data;
}
/**
* CBC模式解密数据
* @param cipher 密文数据
* @param key 密钥
* @param iv 向量
* @param isPadding 填充模式,具体支持请看类的常量字段,若使用不支持的模式则会默认无填充
* @return 返回明文字节数据
*/
public static byte[] DecryptCBC(byte[] cipher, byte[] key, byte[] iv, int paddingMode)
{
IBlockCipher engine = new SM4Engine();
engine.Init(false, new KeyParameter(key));
int length = cipher.Length;
byte[] plain = new byte[cipher.Length];
iv = (byte [])iv.Clone();
for (int i = 0; length > 0; length -= 16, i += 16)
{
engine.ProcessBlock(cipher, i, plain, i);
for (int j = 0; j < 16; j++)
{
plain[j + i] = ((byte)(plain[i + j] ^ iv[j]));
}
Buffer.BlockCopy(cipher, i, iv, 0, 16);
}
byte[] res = null;
if (paddingMode == SM4_PKCS8PADDING)
{
res = padding(plain, SM4_DECRYPT);
}
else
{
res = plain;
}
return res;
}
/**
* PKCS8PADDING标准填充
* @param input 输入数据
* @param mode 填充或去除填充
* @return
*/
private static byte[] padding(byte[] input, int mode)
{
if (input == null)
{
return null;
}
byte[] ret = (byte[])null;
if (mode == SM4_ENCRYPT)
{
int p = 16 - input.Length % 16;
ret = new byte[input.Length + p];
Buffer.BlockCopy(input, 0, ret, 0, input.Length);
for (int i = 0; i < p; i++)
{
ret[input.Length + i] = (byte)p;
}
}
else
{
int p = input[input.Length - 1];
ret = new byte[input.Length - p];
Buffer.BlockCopy(input, 0, ret, 0, input.Length - p);
}
return ret;
}
}
}