GMac.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs
  7. {
  8. /// <summary>
  9. /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
  10. /// 800-38D.
  11. /// </summary>
  12. /// <remarks>
  13. /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
  14. /// is processed as additional authenticated data with the underlying GCM block cipher).
  15. /// </remarks>
  16. public class GMac
  17. : IMac
  18. {
  19. private readonly GcmBlockCipher cipher;
  20. private readonly int macSizeBits;
  21. /// <summary>
  22. /// Creates a GMAC based on the operation of a block cipher in GCM mode.
  23. /// </summary>
  24. /// <remarks>
  25. /// This will produce an authentication code the length of the block size of the cipher.
  26. /// </remarks>
  27. /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
  28. public GMac(GcmBlockCipher cipher)
  29. : this(cipher, 128)
  30. {
  31. }
  32. /// <summary>
  33. /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
  34. /// </summary>
  35. /// <remarks>
  36. /// This will produce an authentication code the length of the block size of the cipher.
  37. /// </remarks>
  38. /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
  39. /// <param name="macSizeBits">the mac size to generate, in bits. Must be a multiple of 8, between 32 and 128 (inclusive).
  40. /// Sizes less than 96 are not recommended, but are supported for specialized applications.</param>
  41. public GMac(GcmBlockCipher cipher, int macSizeBits)
  42. {
  43. this.cipher = cipher;
  44. this.macSizeBits = macSizeBits;
  45. }
  46. /// <summary>
  47. /// Initialises the GMAC - requires a <see cref="Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters.ParametersWithIV"/>
  48. /// providing a <see cref="Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters.KeyParameter"/> and a nonce.
  49. /// </summary>
  50. public void Init(ICipherParameters parameters)
  51. {
  52. if (parameters is ParametersWithIV param)
  53. {
  54. byte[] iv = param.GetIV();
  55. KeyParameter keyParam = (KeyParameter)param.Parameters;
  56. // GCM is always operated in encrypt mode to calculate MAC
  57. cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv));
  58. }
  59. else
  60. {
  61. throw new ArgumentException("GMAC requires ParametersWithIV");
  62. }
  63. }
  64. public string AlgorithmName
  65. {
  66. get { return cipher.UnderlyingCipher.AlgorithmName + "-GMAC"; }
  67. }
  68. public int GetMacSize()
  69. {
  70. return macSizeBits / 8;
  71. }
  72. public void Update(byte input)
  73. {
  74. cipher.ProcessAadByte(input);
  75. }
  76. public void BlockUpdate(byte[] input, int inOff, int len)
  77. {
  78. cipher.ProcessAadBytes(input, inOff, len);
  79. }
  80. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  81. public void BlockUpdate(ReadOnlySpan<byte> input)
  82. {
  83. cipher.ProcessAadBytes(input);
  84. }
  85. #endif
  86. public int DoFinal(byte[] output, int outOff)
  87. {
  88. try
  89. {
  90. return cipher.DoFinal(output, outOff);
  91. }
  92. catch (InvalidCipherTextException e)
  93. {
  94. // Impossible in encrypt mode
  95. throw new InvalidOperationException(e.ToString());
  96. }
  97. }
  98. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  99. public int DoFinal(Span<byte> output)
  100. {
  101. try
  102. {
  103. return cipher.DoFinal(output);
  104. }
  105. catch (InvalidCipherTextException e)
  106. {
  107. // Impossible in encrypt mode
  108. throw new InvalidOperationException(e.ToString());
  109. }
  110. }
  111. #endif
  112. public void Reset()
  113. {
  114. cipher.Reset();
  115. }
  116. }
  117. }
  118. #pragma warning restore
  119. #endif