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

namespace Com.Bocom.OpenApi
{
    namespace Security
    {
        namespace Crypt
        {
            public class AESCryptor
            {
                /**
                 * @param sourceContent
                 * @param cryptKey
                 * @param charset
                 * @return
                 */
                public static string Encrypt(string sourceContent, string cryptKey, string charset)
                {
                    Console.WriteLine(cryptKey);
                    Console.WriteLine(cryptKey.Length);
                    KeyParameter kp = new KeyParameter(Convert.FromBase64String(cryptKey));
                    byte[] bytes;
                    bytes = Encoding.GetEncoding(charset).GetBytes(sourceContent);
                    CbcBlockCipher aes = new CbcBlockCipher(new AesEngine());
                    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new Pkcs7Padding());
                    cipher.Init(true, kp);
                    byte[] output = new byte[cipher.GetOutputSize(bytes.Length)];
                    int len = cipher.ProcessBytes(bytes, 0, bytes.Length, output, 0);
                    cipher.DoFinal(output, len);
                    return Convert.ToBase64String(output);
                }

                /**
                 * @param content
                 * @param aesKey
                 * @return
                 */
                public static byte[] Encrypt(byte[] content, string aesKey, string charset)
                {
                    KeyParameter kp = new KeyParameter(Convert.FromBase64String(aesKey));
                    CbcBlockCipher aes = new CbcBlockCipher(new AesEngine());
                    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new Pkcs7Padding());
                    cipher.Init(true, kp);
                    byte[] output = new byte[cipher.GetOutputSize(content.Length)];
                    int len = cipher.ProcessBytes(content, 0, content.Length, output, 0);
                    cipher.DoFinal(output, len);
                    return Encoding.GetEncoding(charset).GetBytes(Convert.ToBase64String(output));
                }

                /**
                 * @param encryptContent
                 * @param cryptKey
                 * @param charset
                 * @return
                 */
                public static string Decrypt(string encryptContent, string cryptKey, string charset)
                {
                    try
                    {
                        KeyParameter kp = new KeyParameter(Convert.FromBase64String(cryptKey));

                        Console.WriteLine("encryptContent : " + encryptContent);

                        byte[] bytes = Convert.FromBase64String(encryptContent);

                        CbcBlockCipher aes = new CbcBlockCipher(new AesEngine());

                        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new Pkcs7Padding());

                        cipher.Init(false, kp);

                        byte[] output = new byte[cipher.GetOutputSize(bytes.Length)];

                        int len = cipher.ProcessBytes(bytes, 0, bytes.Length, output, 0);

                        int len2;
                        len2 = cipher.DoFinal(output, len);

                        byte[] rawData = new byte[len + len2];
                        Array.Copy(output, 0, rawData, 0, rawData.Length);

                        string plainData = Encoding.UTF8.GetString(rawData, 0, rawData.Length);
                        return plainData;
                    }
                    catch (Exception e)
                    {
                        throw e;
                    }
                }

                /**
                 * @param content
                 * @param aesKey
                 * @param charset
                 * @return
                 */
                public static byte[] Decrypt(byte[] content, string aesKey, string charset)
                {
                    try
                    {
                        KeyParameter kp = new KeyParameter(Convert.FromBase64String(aesKey));

                        CbcBlockCipher aes = new CbcBlockCipher(new AesEngine());
                        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new Pkcs7Padding());
                        cipher.Init(false, kp);

                        byte[] output = new byte[cipher.GetOutputSize(content.Length)];
                        int len = cipher.ProcessBytes(content, 0, content.Length, output, 0);
                        int len2;
                        len2 = cipher.DoFinal(output, len);
                        byte[] rawData = new byte[len + len2];
                        rawData = (byte[]) output.Take(rawData.Length);
                        string plainData = Encoding.UTF8.GetString(rawData, 0, rawData.Length);
                        return Encoding.GetEncoding(charset).GetBytes(plainData);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("解密错误，错误信息为：" + e.Message);
                    }

                    return null;
                }

                /**
                 * @param in
                 * @param cryptKey
                 * @return
                 */
                public static byte[] EncryptFile(Stream fi, string cryptKey)
                {
                    KeyParameter kp = new KeyParameter(Convert.FromBase64String(cryptKey));
                    byte[] bytes = ToByteArray(fi);
                    CbcBlockCipher aes = new CbcBlockCipher(new AesEngine());
                    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new Pkcs7Padding());
                    cipher.Init(true, kp);
                    byte[] output = new byte[cipher.GetOutputSize(bytes.Length)];
                    int len = cipher.ProcessBytes(bytes, 0, bytes.Length, output, 0);
                    cipher.DoFinal(output, len);

                    fi.Close();

                    return output;
                }


                public static byte[] DecryptFile(Stream fi, string cryptKey)
                {
                    KeyParameter kp = new KeyParameter(Convert.FromBase64String(cryptKey));
                    byte[] bytes = ToByteArray(fi);

                    CbcBlockCipher aes = new CbcBlockCipher(new AesEngine());
                    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new Pkcs7Padding());
                    cipher.Init(false, kp);
                    byte[] output = new byte[cipher.GetOutputSize(bytes.Length)];
                    int len = cipher.ProcessBytes(bytes, 0, bytes.Length, output, 0);
                    int len2 = cipher.DoFinal(output, len);
                    byte[] rawData = new byte[len + len2];
                    Array.Copy(output, 0, rawData, 0, rawData.Length);
                    return rawData;
                }

                private static byte[] ToByteArray(Stream stream)
                {
                    byte[] bytes = new byte[stream.Length];
                    stream.Read(bytes, 0, bytes.Length);
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Close();
                    return bytes;
                }
            }
        }
    }
}