FastBcChaCha20Poly1305.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
  9. using BestHTTP.PlatformSupport.Memory;
  10. namespace BestHTTP.Connections.TLS.Crypto.Impl
  11. {
  12. public sealed class FastBcChaCha20Poly1305
  13. : TlsAeadCipherImpl
  14. {
  15. private static readonly byte[] Zeroes = new byte[15];
  16. private readonly FastChaCha7539Engine m_cipher = new FastChaCha7539Engine();
  17. private readonly FastPoly1305 m_mac = new FastPoly1305();
  18. private readonly bool m_isEncrypting;
  19. private int m_additionalDataLength;
  20. public FastBcChaCha20Poly1305(bool isEncrypting)
  21. {
  22. this.m_isEncrypting = isEncrypting;
  23. }
  24. public int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
  25. {
  26. if (m_isEncrypting)
  27. {
  28. int ciphertextLength = inputLength;
  29. m_cipher.ProcessBytes(input, inputOffset, inputLength, output, outputOffset);
  30. int outputLength = inputLength;
  31. if (ciphertextLength != outputLength)
  32. throw new InvalidOperationException();
  33. UpdateMac(output, outputOffset, ciphertextLength);
  34. byte[] lengths = BufferPool.Get(16, true);
  35. Pack.UInt64_To_LE((ulong)m_additionalDataLength, lengths, 0);
  36. Pack.UInt64_To_LE((ulong)ciphertextLength, lengths, 8);
  37. m_mac.BlockUpdate(lengths, 0, 16);
  38. BufferPool.Release(lengths);
  39. m_mac.DoFinal(output, outputOffset + ciphertextLength);
  40. return ciphertextLength + 16;
  41. }
  42. else
  43. {
  44. int ciphertextLength = inputLength - 16;
  45. UpdateMac(input, inputOffset, ciphertextLength);
  46. byte[] expectedMac = BufferPool.Get(16, true);
  47. Pack.UInt64_To_LE((ulong)m_additionalDataLength, expectedMac, 0);
  48. Pack.UInt64_To_LE((ulong)ciphertextLength, expectedMac, 8);
  49. m_mac.BlockUpdate(expectedMac, 0, 16);
  50. m_mac.DoFinal(expectedMac, 0);
  51. bool badMac = !TlsUtilities.ConstantTimeAreEqual(16, expectedMac, 0, input, inputOffset + ciphertextLength);
  52. BufferPool.Release(expectedMac);
  53. if (badMac)
  54. throw new TlsFatalAlert(AlertDescription.bad_record_mac);
  55. m_cipher.ProcessBytes(input, inputOffset, ciphertextLength, output, outputOffset);
  56. int outputLength = ciphertextLength;
  57. if (ciphertextLength != outputLength)
  58. throw new InvalidOperationException();
  59. return ciphertextLength;
  60. }
  61. }
  62. public int GetOutputSize(int inputLength)
  63. {
  64. return m_isEncrypting ? inputLength + 16 : inputLength - 16;
  65. }
  66. public void Init(byte[] nonce, int macSize, byte[] additionalData)
  67. {
  68. if (nonce == null || nonce.Length != 12 || macSize != 16)
  69. throw new TlsFatalAlert(AlertDescription.internal_error);
  70. m_cipher.Init(m_isEncrypting, new FastParametersWithIV(null, nonce));
  71. InitMac();
  72. if (additionalData == null)
  73. {
  74. this.m_additionalDataLength = 0;
  75. }
  76. else
  77. {
  78. this.m_additionalDataLength = additionalData.Length;
  79. UpdateMac(additionalData, 0, additionalData.Length);
  80. }
  81. }
  82. public void SetKey(byte[] key, int keyOff, int keyLen)
  83. {
  84. NoCopyKeyParameter cipherKey = new NoCopyKeyParameter(key, keyOff, keyLen);
  85. m_cipher.Init(m_isEncrypting, new FastParametersWithIV(cipherKey, Zeroes, 0, 12));
  86. }
  87. private void InitMac()
  88. {
  89. byte[] firstBlock = new byte[64];
  90. m_cipher.ProcessBytes(firstBlock, 0, 64, firstBlock, 0);
  91. m_mac.Init(new NoCopyKeyParameter(firstBlock, 0, 32));
  92. Array.Clear(firstBlock, 0, firstBlock.Length);
  93. }
  94. private void UpdateMac(byte[] buf, int off, int len)
  95. {
  96. m_mac.BlockUpdate(buf, off, len);
  97. int partial = len % 16;
  98. if (partial != 0)
  99. {
  100. m_mac.BlockUpdate(Zeroes, 0, 16 - partial);
  101. }
  102. }
  103. }
  104. }
  105. #endif