using DataSharing.Share.Dtos.Police110;
using Org.BouncyCastle.Utilities.Encoders;
using System.Text;

namespace DataSharing.Police110.Encryption
{
    public static class Sm4Crypto
    {
        /// <summary>
        /// 描述：110对接使用ECB
        /// ECB：不需要传入iv
        /// CBC：  需要传入iv
        /// </summary>
        public static string secretKey = "";
        public static string iv = "";
        public static bool hexString = false;

        #region ECB模式加密

        /// <summary>
        /// ECB模式加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static byte[] Encrypt_ECB(string plainText)
        {
            SM4Context ctx = new SM4Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, Encoding.UTF8.GetBytes(plainText));

            // 原始代码
            //return Hex.Encode(encrypted);
            // 110对接需要如此处理
            return encrypted;
        }

        /// <summary>
        /// ECB模式加密
        /// </summary>
        /// <param name="plainBytes"></param>
        /// <returns></returns>
        public static byte[] Encrypt_ECB(byte[] plainBytes)
        {
            SM4Context ctx = new SM4Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainBytes);

            // 原始代码
            //return Hex.Encode(encrypted);
            // 110对接需要如此处理
            return encrypted;
        }

        /// <summary>
        /// ECB模式加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string Encrypt_ECB_Str(string plainText)
        {
            SM4Context ctx = new SM4Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, Encoding.UTF8.GetBytes(plainText));

            // 原始代码
            //return Encoding.UTF8.GetString(Hex.Encode(encrypted));
            // 110对接需要如此处理
            return Encoding.UTF8.GetString(encrypted);
        }

        /// <summary>
        /// ECB模式加密
        /// </summary>
        /// <param name="plainBytes"></param>
        /// <returns></returns>
        public static string Encrypt_ECB_Str(byte[] plainBytes)
        {
            SM4Context ctx = new SM4Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_ENCRYPT;

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainBytes);

            // 原始代码
            // return Encoding.UTF8.GetString(Hex.Encode(encrypted));
            // 110对接需要如此处理
            return Encoding.UTF8.GetString(encrypted);
        }

        #endregion

        #region ECB模式解密

        /// <summary>
        /// ECB模式解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static byte[] Decrypt_ECB(string cipherText)
        {
            SM4Context ctx = new SM4Context();
            ctx.isPadding = true;
            ctx.mode = SM4.SM4_DECRYPT;

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Hex.Decode(cipherText));
            return decrypted;
        }

        /// <summary>
        /// ECB模式解密
        /// </summary>
        /// <param name="cipherBytes"></param>
        /// <returns></returns>
        public static byte[] Decrypt_ECB(byte[] cipherBytes)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);

            // 原始代码
            //byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Hex.Decode(cipherBytes));
            // 110对接需要如此处理
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, cipherBytes);

            return decrypted;
        }

        /// <summary>
        /// ECB模式解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static string Decrypt_ECB_Str(string cipherText)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Hex.Decode(cipherText));
            return Encoding.UTF8.GetString(decrypted);
        }

        /// <summary>
        /// ECB模式解密
        /// </summary>
        /// <param name="cipherBytes"></param>
        /// <returns></returns>
        public static string Decrypt_ECB_Str(byte[] cipherBytes)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);

            // 原始代码
            //byte[] decrypted = sm4.sm4_crypt_ecb(ctx, Hex.Decode(cipherBytes));
            // 110对接需要如此处理
            byte[] decrypted = sm4.sm4_crypt_ecb(ctx, cipherBytes);

            return Encoding.UTF8.GetString(decrypted);
        }
        #endregion

        #region CBC模式加密

        /// <summary>
        /// CBC模式加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static byte[] Encrypt_CBC(string plainText)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_ENCRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Encoding.UTF8.GetBytes(plainText));

            return Hex.Encode(encrypted);
        }

        /// <summary>
        /// CBC模式加密
        /// </summary>
        /// <param name="plainBytes"></param>
        /// <returns></returns>
        public static byte[] Encrypt_CBC(byte[] plainBytes)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_ENCRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainBytes);

            return Hex.Encode(encrypted);
        }

        /// <summary>
        /// CBC模式加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string Encrypt_CBC_Str(string plainText)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_ENCRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Encoding.UTF8.GetBytes(plainText));

            return Encoding.UTF8.GetString(Hex.Encode(encrypted));
        }

        /// <summary>
        /// CBC模式加密
        /// </summary>
        /// <param name="plainBytes"></param>
        /// <returns></returns>
        public static string Encrypt_CBC_Str(byte[] plainBytes)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_ENCRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_enc(ctx, keyBytes);
            byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainBytes);

            return Encoding.UTF8.GetString(Hex.Encode(encrypted));
        }
        #endregion

        #region CBC模式解密
        /// <summary>
        /// CBC模式解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static byte[] Decrypt_CBC(string cipherText)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Hex.Decode(cipherText));
            return decrypted;
        }

        /// <summary>
        /// CBC模式解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static byte[] Decrypt_CBC(byte[] cipherBytes)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Hex.Decode(cipherBytes));
            return decrypted;
        }
        /// <summary>
        /// CBC模式解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static string Decrypt_CBC_Str(string cipherText)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Hex.Decode(cipherText));
            return Encoding.UTF8.GetString(decrypted);
        }

        /// <summary>
        /// CBC模式解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static string Decrypt_CBC_Str(byte[] cipherBytes)
        {
            SM4Context ctx = new SM4Context
            {
                isPadding = true,
                mode = SM4.SM4_DECRYPT
            };

            byte[] keyBytes;
            byte[] ivBytes;
            if (hexString)
            {
                keyBytes = Hex.Decode(secretKey);
                ivBytes = Hex.Decode(iv);
            }
            else
            {
                keyBytes = Encoding.UTF8.GetBytes(secretKey);
                ivBytes = Encoding.UTF8.GetBytes(iv);
            }

            SM4 sm4 = new SM4();
            sm4.sm4_setkey_dec(ctx, keyBytes);
            byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, Hex.Decode(cipherBytes));
            return Encoding.UTF8.GetString(decrypted);
        }

        #endregion

        #region ECB模式加密转Base64（110）

        /// <summary>
        /// json通过sm4加密转Base64
        /// </summary>
        /// <param name="secretK"></param>
        /// <param name="jsonStr"></param>
        /// <returns></returns>
        public static string Encrypt_ECB_Base64(string secretK, string jsonStr)
        {
            secretKey = secretK;
            // SM4加密
            byte[] buffer = Encrypt_ECB(jsonStr);
            // SM4转成Base64
            string strBase64 = Convert.ToBase64String(buffer, Base64FormattingOptions.None);
            return strBase64;
        }

        #endregion

        #region ECB模式解密转Json（110）

        /// <summary>
        /// base64通过sm4解密转json
        /// </summary>
        /// <param name="secretK"></param>
        /// <param name="base64"></param>
        /// <returns></returns>
        public static string Decrypt_ECB_Base64(string secretK, string base64)
        {
            secretKey = secretK;
            byte[] buffer = Convert.FromBase64String(base64);
            byte[] bufferEcb = Decrypt_ECB(buffer);
            string json = Encoding.UTF8.GetString(bufferEcb);
            return json;
        }

        #endregion
    }
}
