using System.Security.Cryptography;

namespace Extensions {

  /// <summary>
  /// https://www.syncfusion.com/succinctly-free-ebooks/application-security-in-net-succinctly/comparing-byte-arrays
  /// </summary>
  public static class BytesExtensions {

    /// <summary>
    /// Insecure direct comparison implements the fundamental BAC requirement, but it also makes a variable number of comparisons based on the position of the first unequal byte pair, which leaks timing information that can help mount effective guessing attacks to uncover the data. These types of attacks are known as side-channel attacks (the side channel in this case is timing). You should never use direct comparison with sensitive or secret data.
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public static bool DirectComparison(byte[] a, byte[] b) {

      if (a.Length != b.Length)
        return false;

      for (int i = 0; i < a.Length; ++i) {
        if (a[i] != b[i])
          return false;
      }

      return true;
    }

    /// <summary>
    /// The AND comparison is similar to a direct comparison that keeps comparing byte pairs even after the result is determined to be false. It performs a fixed amount of work in every comparison, which protects against timing attacks. AND comparison is the BAC approach used by Microsoft within their internal CryptoUtil classes (System.Web.Security.Cryptography namespace—System.Web assembly and System.Web.Helpers namespace—System.Web.WebPages assembly).
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public static bool AndComparison(byte[] a, byte[] b) {

      bool f = a.Length == b.Length;

      for (int i = 0; i < a.Length && i < b.Length; ++i) {

        f &= a[i] == b[i];

      }

      return f;

    }

    /// <summary>
    /// XOR comparison exploits the fact that equal byte pairs XOR to zero and OR-ing all XOR-ed results together would only produce zero if all byte pairs are equal. The XOR approach might have a slight advantage over the AND approach because the XOR-OR combination is pure bit shifting, and is typically compiled into direct assembly equivalents, while Boolean AND combination can be compiled into conditional branching instructions, which might have different timings.
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public static bool XORCcomparison(this byte[] a, byte[] b) {
      int x = a.Length ^ b.Length;

      for (int i = 0; i < a.Length && i < b.Length; ++i) {
        x |= a[i] ^ b[i];
      }

      return x == 0;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public static bool DoubleHMAC(byte[] a, byte[] b) {
      byte[] aHMAC, bHMAC;

      //using var hmac = HMACFactories.HMACSHA1();

      //// key unpredictability not required
      //hmac.Key = Guid.NewGuid().ToByteArray();
      //aHMAC = hmac.ComputeHash(a);
      //bHMAC = hmac.ComputeHash(b);

      //return XORCcomparison(aHMAC, bHMAC) && XORCcomparison(a, b);
      return false;
    }

  }
}
