You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.7 KiB
132 lines
4.7 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
using System; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls; |
|
using BestHTTP.PlatformSupport.Memory; |
|
|
|
namespace BestHTTP.Connections.TLS.Crypto.Impl |
|
{ |
|
public sealed class FastBcChaCha20Poly1305 |
|
: TlsAeadCipherImpl |
|
{ |
|
private static readonly byte[] Zeroes = new byte[15]; |
|
|
|
private readonly FastChaCha7539Engine m_cipher = new FastChaCha7539Engine(); |
|
private readonly FastPoly1305 m_mac = new FastPoly1305(); |
|
|
|
private readonly bool m_isEncrypting; |
|
|
|
private int m_additionalDataLength; |
|
|
|
public FastBcChaCha20Poly1305(bool isEncrypting) |
|
{ |
|
this.m_isEncrypting = isEncrypting; |
|
} |
|
|
|
public int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) |
|
{ |
|
if (m_isEncrypting) |
|
{ |
|
int ciphertextLength = inputLength; |
|
|
|
m_cipher.ProcessBytes(input, inputOffset, inputLength, output, outputOffset); |
|
int outputLength = inputLength; |
|
|
|
if (ciphertextLength != outputLength) |
|
throw new InvalidOperationException(); |
|
|
|
UpdateMac(output, outputOffset, ciphertextLength); |
|
|
|
byte[] lengths = BufferPool.Get(16, true); |
|
Pack.UInt64_To_LE((ulong)m_additionalDataLength, lengths, 0); |
|
Pack.UInt64_To_LE((ulong)ciphertextLength, lengths, 8); |
|
m_mac.BlockUpdate(lengths, 0, 16); |
|
|
|
BufferPool.Release(lengths); |
|
|
|
m_mac.DoFinal(output, outputOffset + ciphertextLength); |
|
|
|
return ciphertextLength + 16; |
|
} |
|
else |
|
{ |
|
int ciphertextLength = inputLength - 16; |
|
|
|
UpdateMac(input, inputOffset, ciphertextLength); |
|
|
|
byte[] expectedMac = BufferPool.Get(16, true); |
|
Pack.UInt64_To_LE((ulong)m_additionalDataLength, expectedMac, 0); |
|
Pack.UInt64_To_LE((ulong)ciphertextLength, expectedMac, 8); |
|
m_mac.BlockUpdate(expectedMac, 0, 16); |
|
m_mac.DoFinal(expectedMac, 0); |
|
|
|
bool badMac = !TlsUtilities.ConstantTimeAreEqual(16, expectedMac, 0, input, inputOffset + ciphertextLength); |
|
BufferPool.Release(expectedMac); |
|
if (badMac) |
|
throw new TlsFatalAlert(AlertDescription.bad_record_mac); |
|
|
|
m_cipher.ProcessBytes(input, inputOffset, ciphertextLength, output, outputOffset); |
|
int outputLength = ciphertextLength; |
|
|
|
if (ciphertextLength != outputLength) |
|
throw new InvalidOperationException(); |
|
|
|
return ciphertextLength; |
|
} |
|
} |
|
|
|
public int GetOutputSize(int inputLength) |
|
{ |
|
return m_isEncrypting ? inputLength + 16 : inputLength - 16; |
|
} |
|
|
|
public void Init(byte[] nonce, int macSize, byte[] additionalData) |
|
{ |
|
if (nonce == null || nonce.Length != 12 || macSize != 16) |
|
throw new TlsFatalAlert(AlertDescription.internal_error); |
|
|
|
m_cipher.Init(m_isEncrypting, new FastParametersWithIV(null, nonce)); |
|
InitMac(); |
|
if (additionalData == null) |
|
{ |
|
this.m_additionalDataLength = 0; |
|
} |
|
else |
|
{ |
|
this.m_additionalDataLength = additionalData.Length; |
|
UpdateMac(additionalData, 0, additionalData.Length); |
|
} |
|
} |
|
|
|
public void SetKey(byte[] key, int keyOff, int keyLen) |
|
{ |
|
NoCopyKeyParameter cipherKey = new NoCopyKeyParameter(key, keyOff, keyLen); |
|
m_cipher.Init(m_isEncrypting, new FastParametersWithIV(cipherKey, Zeroes, 0, 12)); |
|
} |
|
|
|
private void InitMac() |
|
{ |
|
byte[] firstBlock = new byte[64]; |
|
m_cipher.ProcessBytes(firstBlock, 0, 64, firstBlock, 0); |
|
m_mac.Init(new NoCopyKeyParameter(firstBlock, 0, 32)); |
|
Array.Clear(firstBlock, 0, firstBlock.Length); |
|
} |
|
|
|
private void UpdateMac(byte[] buf, int off, int len) |
|
{ |
|
m_mac.BlockUpdate(buf, off, len); |
|
|
|
int partial = len % 16; |
|
if (partial != 0) |
|
{ |
|
m_mac.BlockUpdate(Zeroes, 0, 16 - partial); |
|
} |
|
} |
|
} |
|
} |
|
#endif
|
|
|