context: 
  // Copyright(c) 2016 Si13n7 'Roy Schroedel' Developments(r)
  // This file is licensed under the MIT License
  
  #region '
  
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Text;
  
  namespace SilDev
  {
      /// <summary>Requirements:
      /// <para><see cref="SilDev.Convert"/>.cs</para>
      /// <para><see cref="SilDev.Log"/>.cs</para>
      /// <seealso cref="SilDev"/></summary>
      public static class Crypt
      {
          #region PRIVATE
  
          private static string BaseEncodeFilters(string input, string prefixMark, string suffixMark, uint lineLength)
          {
              string s = input;
              if (!string.IsNullOrEmpty(prefixMark) && !string.IsNullOrEmpty(prefixMark))
              {
                  string prefix = prefixMark;
                  string suffix = suffixMark;
                  if (lineLength > 0)
                  {
                      prefix = $"{prefix}{Environment.NewLine}";
                      suffix = $"{Environment.NewLine}{suffix}";
                  }
                  s = $"{prefix}{s}{suffix}";
              }
              if (lineLength > 1 & s.Length > lineLength)
              {
                  int i = 0;
                  s = string.Join(Environment.NewLine, s.ToLookup(c => Math.Floor(i++ / (double)lineLength)).Select(e => new string(e.ToArray())));
              }
              return s;
          }
  
          private static string BaseDecodeFilters(string input, string prefixMark, string suffixMark)
          {
              string s = input;
              if (!string.IsNullOrEmpty(prefixMark) && !string.IsNullOrEmpty(suffixMark))
              {
                  if (s.StartsWith(prefixMark))
                      s = s.Substring(prefixMark.Length);
                  if (s.EndsWith(suffixMark))
                      s = s.Substring(0, s.Length - suffixMark.Length);
              }
              if (s.Contains('\r') || s.Contains('\n'))
                  s = string.Concat(s.ToCharArray().Where(c => c != '\r' && c != '\n').ToArray());
              return s;
          }
  
          #endregion
  
          #region Base64
  
          public class Base64
          {
              public string PrefixMark = null;
              public string SuffixMark = null;
              public uint LineLength = 0;
  
              public string LastEncodedResult { get; private set; }
              public byte[] LastDecodedResult { get; private set; }
  
              public string EncodeByteArray(byte[] bytes, string prefixMark = null, string suffixMark = null, uint lineLength = 0)
              {
                  try
                  {
                      if (!string.IsNullOrEmpty(prefixMark) && !string.IsNullOrEmpty(suffixMark))
                      {
                          PrefixMark = prefixMark;
                          SuffixMark = suffixMark;
                      }
                      if (lineLength > 0)
                          LineLength = lineLength;
                      LastEncodedResult = System.Convert.ToBase64String(bytes);
                      LastEncodedResult = BaseEncodeFilters(LastEncodedResult, null, null, LineLength);
                      LastEncodedResult = BaseEncodeFilters(LastEncodedResult, PrefixMark, SuffixMark, (uint)(LineLength > 1 ? 1 : 0));
                  }
                  catch (Exception ex)
                  {
                      Log.Debug(ex);
                      LastEncodedResult = string.Empty;
                  }
                  return LastEncodedResult;
              }
  
              public byte[] DecodeByteArray(string code, string prefixMark = null, string suffixMark = null)
              {
                  try
                  {
                      if (!string.IsNullOrEmpty(prefixMark) && !string.IsNullOrEmpty(suffixMark))
                      {
                          PrefixMark = prefixMark;
                          SuffixMark = suffixMark;
                      }
                      code = BaseDecodeFilters(code, PrefixMark, SuffixMark);
                      LastDecodedResult = System.Convert.FromBase64String(code);
                  }
                  catch (Exception ex)
                  {
                      Log.Debug(ex);
                      LastDecodedResult = null;
                  }
                  return LastDecodedResult;
              }
  
              public string EncodeString(string text, string prefixMark = null, string suffixMark = null, uint lineLength = 0)
              {
                  try
                  {
                      byte[] ba = Encoding.UTF8.GetBytes(text);
                      return EncodeByteArray(ba, prefixMark, suffixMark, lineLength) ?? string.Empty;
                  }
                  catch (Exception ex)
                  {
                      Log.Debug(ex);
                      return string.Empty;
                  }
              }
  
              public string EncodeString(string text, uint lineLength) =>
                  EncodeString(text, null, null, lineLength);
  
              public string DecodeString(string code, string prefixMark = null, string suffixMark = null)
              {
                  try
                  {
                      byte[] ba = DecodeByteArray(code, prefixMark, suffixMark);
                      return Encoding.UTF8.GetString(ba) ?? string.Empty;
                  }
                  catch (Exception ex)
                  {
                      Log.Debug(ex);
                      return string.Empty;
                  }
              }
  
              public string EncodeFile(string path, string prefixMark = null, string suffixMark = null, uint lineLength = 0)
              {
                  try
                  {
                      if (!File.Exists(path))
                          throw new FileNotFoundException();
                      byte[] ba = null;
                      using (FileStream fs = new FileStream(path, FileMode.Open))
                      {
                          ba = new byte[fs.Length];
                          fs.Read(ba, 0, (int)fs.Length);
                      }
                      return EncodeByteArray(ba, prefixMark, suffixMark, lineLength);
                  }
                  catch (Exception ex)
                  {
                      Log.Debug(ex);
                      return string.Empty;
                  }
              }
  
              public string EncodeFile(string path, uint lineLength) =>
                  EncodeFile(path, null, null, lineLength);
  
              public byte[] DecodeFile(string code, string prefixMark = null, string suffixMark = null) =>
                  DecodeByteArray(code, prefixMark, suffixMark);
          }
  
          #endregion
  
          #region Base85
  
          public class Base85
          {
              private static uint[] p85 = 
              {
                  85 * 85 * 85 * 85,
                  85 * 85 * 85,
                  85 * 85,
                  85,
                  1
              };
  
              private static byte[] encodeBlock = new byte[5];
              private static byte[] decodeBlock = new byte[4];
  
              public string PrefixMark = "<~";
              public string SuffixMark = "~>";
              public uint LineLength = 0;
  
              public string LastEncodedResult { get; private set; }
              public byte[] LastDecodedResult { get; private set; }
  
              public string EncodeByteArray(byte[] bytes, string prefixMark = "<~", string suffixMark = "~>", uint lineLength = 0)
              {
                  try
                  {
                      if (prefixMark != "<~" && suffixMark != "~>")
                      {
                          PrefixMark = prefixMark;
                          SuffixMark = suffixMark;
                      }
                      if (lineLength > 0)
                          LineLength = lineLength;
                      StringBuilder sb = new StringBuilder();
                      uint t = 0;
                      int n = 0;
                      foreach (byte b in bytes)
                      {
                          if (n + 1 < decodeBlock.Length)
                          {
                              t |= (uint)(b << (24 - (n * 8)));
                              n++;
                              continue;
                          }
                          t |= b;
                          if (t == 0)
                              sb.Append((char)122);
                          else
                          {
                              for (int i = encodeBlock.Length - 1; i >= 0; i--)
                              {
                                  encodeBlock[i] = (byte)((t % 85) + 33);
                                  t /= 85;
                              }
                              for (int i = 0; i < encodeBlock.Length; i++)
                                  sb.Append((char)encodeBlock[i]);
                          }
                          t = 0;
                          n = 0;
                      }
                      if (n > 0)
                      {
                          for (int i = encodeBlock.Length - 1; i >= 0; i--)
                          {
                              encodeBlock[i] = (byte)((t % 85) + 33);
                              t /= 85;
                          }
                          for (int i = 0; i <= n; i++)
                              sb.Append((char)encodeBlock[i]);
                      }
                      LastEncodedResult = sb.ToString();
                      LastEncodedResult = BaseEncodeFilters(LastEncodedResult, null, null, LineLength);
                      LastEncodedResult = BaseEncodeFilters(LastEncodedResult, PrefixMark, SuffixMark, (uint)(LineLength > 1 ? 1 : 0));
                  }
                  catch (Exception ex)
                  {
                      Log.Debug(ex);
                      LastEncodedResult = string.Empty;
                  }
                  return LastEncodedResult;
              }
  
              public byte[] DecodeByteArray(string code, string prefixMark = "<~", string suffixMark = "~>")
              {
                  try
                  {
                      if (!string.IsNullOrEmpty(prefixMark) && !string.IsNullOrEmpty(suffixMark))
                      {
                          PrefixMark = prefixMark;
                          SuffixMark = suffixMark;
                      }
                      code = BaseDecodeFilters(code, PrefixMark, SuffixMark);
                      using (MemoryStream ms = new MemoryStream())
                      {
                          char[] ca = new char[] 
                          {
                              (char)0, (char)8, (char)9,
                              (char)10, (char)12, (char)13
                          };
                          int n = 0;
                          uint t = 0;
                          foreach (char c in code)
                          {
                              if (c == (char)122)
                              {
                                  if (n != 0)
                                      throw new ArgumentException("n");
                                  for (int i = 0; i < 4; i++)
                                      decodeBlock[i] = 0;
                                  ms.Write(decodeBlock, 0, decodeBlock.Length);
                                  continue;
                              }
                              if (ca.Contains(c))
                                  continue;
                              if (c < (char)33 || c > (char)117)
                                  throw new ArgumentOutOfRangeException("c");
                              t += (uint)((c - 33) * p85[n]);
                              n++;
                              if (n == encodeBlock.Length)
                              {
                                  for (int i = 0; i < decodeBlock.Length; i++)
                                      decodeBlock[i] = (byte)(t >> 24 - (i * 8));
                                  ms.Write(decodeBlock, 0, decodeBlock.Length);
                                  t = 0;
                                  n = 0;
                              }
                          }
                          if (n != 0)
                          {
                              if (n == 1)
                                  throw new NotSupportedException("n");
                              n--;
                              t += p85[n];
                              for (int i = 0; i < n; i++)
  
gt:                                 decodeBlock[i] = (byte)(t >> 24 - (i * 8));