BcChaCha20Poly1305.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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.Engines;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  8. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl.BC
  9. {
  10. public sealed class BcChaCha20Poly1305
  11. : TlsAeadCipherImpl
  12. {
  13. private static readonly byte[] Zeroes = new byte[15];
  14. private readonly ChaCha7539Engine m_cipher = new ChaCha7539Engine();
  15. private readonly Poly1305 m_mac = new Poly1305();
  16. private readonly bool m_isEncrypting;
  17. private int m_additionalDataLength;
  18. public BcChaCha20Poly1305(bool isEncrypting)
  19. {
  20. this.m_isEncrypting = isEncrypting;
  21. }
  22. public int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
  23. {
  24. if (m_isEncrypting)
  25. {
  26. int ciphertextLength = inputLength;
  27. m_cipher.DoFinal(input, inputOffset, inputLength, output, outputOffset);
  28. int outputLength = inputLength;
  29. if (ciphertextLength != outputLength)
  30. throw new InvalidOperationException();
  31. UpdateMac(output, outputOffset, ciphertextLength);
  32. byte[] lengths = new byte[16];
  33. Pack.UInt64_To_LE((ulong)m_additionalDataLength, lengths, 0);
  34. Pack.UInt64_To_LE((ulong)ciphertextLength, lengths, 8);
  35. m_mac.BlockUpdate(lengths, 0, 16);
  36. m_mac.DoFinal(output, outputOffset + ciphertextLength);
  37. return ciphertextLength + 16;
  38. }
  39. else
  40. {
  41. int ciphertextLength = inputLength - 16;
  42. UpdateMac(input, inputOffset, ciphertextLength);
  43. byte[] expectedMac = new byte[16];
  44. Pack.UInt64_To_LE((ulong)m_additionalDataLength, expectedMac, 0);
  45. Pack.UInt64_To_LE((ulong)ciphertextLength, expectedMac, 8);
  46. m_mac.BlockUpdate(expectedMac, 0, 16);
  47. m_mac.DoFinal(expectedMac, 0);
  48. bool badMac = !TlsUtilities.ConstantTimeAreEqual(16, expectedMac, 0, input, inputOffset + ciphertextLength);
  49. if (badMac)
  50. throw new TlsFatalAlert(AlertDescription.bad_record_mac);
  51. m_cipher.DoFinal(input, inputOffset, ciphertextLength, output, outputOffset);
  52. int outputLength = ciphertextLength;
  53. if (ciphertextLength != outputLength)
  54. throw new InvalidOperationException();
  55. return ciphertextLength;
  56. }
  57. }
  58. public int GetOutputSize(int inputLength)
  59. {
  60. return m_isEncrypting ? inputLength + 16 : inputLength - 16;
  61. }
  62. public void Init(byte[] nonce, int macSize, byte[] additionalData)
  63. {
  64. if (nonce == null || nonce.Length != 12 || macSize != 16)
  65. throw new TlsFatalAlert(AlertDescription.internal_error);
  66. m_cipher.Init(m_isEncrypting, new ParametersWithIV(null, nonce));
  67. InitMac();
  68. if (additionalData == null)
  69. {
  70. this.m_additionalDataLength = 0;
  71. }
  72. else
  73. {
  74. this.m_additionalDataLength = additionalData.Length;
  75. UpdateMac(additionalData, 0, additionalData.Length);
  76. }
  77. }
  78. public void Reset()
  79. {
  80. m_cipher.Reset();
  81. m_mac.Reset();
  82. }
  83. public void SetKey(byte[] key, int keyOff, int keyLen)
  84. {
  85. KeyParameter cipherKey = new KeyParameter(key, keyOff, keyLen);
  86. m_cipher.Init(m_isEncrypting, new ParametersWithIV(cipherKey, Zeroes, 0, 12));
  87. }
  88. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  89. public void SetKey(ReadOnlySpan<byte> key)
  90. {
  91. KeyParameter cipherKey = new KeyParameter(key);
  92. m_cipher.Init(m_isEncrypting, new ParametersWithIV(cipherKey, Zeroes.AsSpan(0, 12)));
  93. }
  94. #endif
  95. private void InitMac()
  96. {
  97. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  98. Span<byte> firstBlock = stackalloc byte[64];
  99. m_cipher.ProcessBytes(firstBlock, firstBlock);
  100. m_mac.Init(new KeyParameter(firstBlock[..32]));
  101. firstBlock.Fill(0x00);
  102. #else
  103. byte[] firstBlock = new byte[64];
  104. m_cipher.ProcessBytes(firstBlock, 0, 64, firstBlock, 0);
  105. m_mac.Init(new KeyParameter(firstBlock, 0, 32));
  106. Array.Clear(firstBlock, 0, firstBlock.Length);
  107. #endif
  108. }
  109. private void UpdateMac(byte[] buf, int off, int len)
  110. {
  111. m_mac.BlockUpdate(buf, off, len);
  112. int partial = len % 16;
  113. if (partial != 0)
  114. {
  115. m_mac.BlockUpdate(Zeroes, 0, 16 - partial);
  116. }
  117. }
  118. }
  119. }
  120. #pragma warning restore
  121. #endif