using System;
using System.Text;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;

namespace Com.Bocom.OpenApi
{
    namespace Security
    {
        namespace Crypt
        {
            public class SM4Cryptor
            {
                public static string Encrypt(string data, string secretKey, string charset)
                {
                    KeyParameter keyParameter = new KeyParameter(Convert.FromBase64String(secretKey));
                    byte[] dataByteArray = Encoding.GetEncoding(charset).GetBytes(data);
                    
                    // 生成SM4加密器，CBC模式，PKCS7填充
                    CbcBlockCipher cbcBlockCipher = new CbcBlockCipher(new SM4Engine());
                    PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(cbcBlockCipher, new Pkcs7Padding());
                    paddedBufferedBlockCipher.Init(true, keyParameter);
                    
                    // 根据明文长度获取密文长度
                    byte[] output = new byte[paddedBufferedBlockCipher.GetOutputSize(dataByteArray.Length)];
                    
                    // 先处理一部分字节
                    int len = paddedBufferedBlockCipher.ProcessBytes(dataByteArray, 0, dataByteArray.Length, output, 0);
                    // 再处理末尾凑不够一个分组的字节
                    paddedBufferedBlockCipher.DoFinal(output, len);

                    return Convert.ToBase64String(output);
                }

                public static string Decrypt(string encryptedData, string secretKey, string charset)
                {
                    KeyParameter keyParameter = new KeyParameter(Convert.FromBase64String(secretKey));
                    byte[] encryptedDataByteArray = Convert.FromBase64String(encryptedData);
                    
                    // 生成SM4解密器，CBC模式，PKCS7填充
                    CbcBlockCipher cbcBlockCipher = new CbcBlockCipher(new SM4Engine());
                    PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(cbcBlockCipher, new Pkcs7Padding());
                    paddedBufferedBlockCipher.Init(false, keyParameter);
                    
                    // 填充后的明文
                    byte[] output = new byte[paddedBufferedBlockCipher.GetOutputSize(encryptedDataByteArray.Length)];
                    
                    // 获取明文的真实长度
                    int len1 = paddedBufferedBlockCipher.ProcessBytes(encryptedDataByteArray, 0,
                        encryptedDataByteArray.Length, output, 0);
                    int len2 = paddedBufferedBlockCipher.DoFinal(output, len1);
                    
                    // 填充前的明文
                    byte[] rawDataByteArray = new byte[len1 + len2];
                    Array.Copy(output, 0, rawDataByteArray, 0, rawDataByteArray.Length);

                    return Encoding.GetEncoding(charset).GetString(rawDataByteArray);
                }

                public static void Main(string[] args)
                {
                    string sm4Key = "teFsqfOOV2NMOZs98AKq9w==";
                    string data = "Today is not a day!";
                    string encryptedData = SM4Cryptor.Encrypt(data, sm4Key, "UTF-8");
                    Console.WriteLine("加密后的密文：" + encryptedData);
                    Console.WriteLine("解密后的原文：" + SM4Cryptor.Decrypt(encryptedData, sm4Key, "UTF-8"));
                }
            }
        }
    }
}