提交Unity 联机Pro

This commit is contained in:
PC-20230316NUNE\Administrator
2024-08-17 14:27:18 +08:00
parent f00193b000
commit 894100ae37
7448 changed files with 854473 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Collections;
using System.Collections.Generic;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.Logger;
namespace BestHTTP.Connections.TLS
{
public abstract class AbstractTls13Client : AbstractTlsClient, TlsAuthentication
{
protected static readonly int[] DefaultCipherSuites = new int[] {
/*
* TLS 1.3
*/
CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_AES_256_GCM_SHA384,
CipherSuite.TLS_AES_128_GCM_SHA256,
/*
* pre-TLS 1.3
*/
CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
};
protected HTTPRequest _request;
protected List<ServerName> _sniServerNames;
protected List<ProtocolName> _protocols;
protected LoggingContext Context { get; private set; }
protected AbstractTls13Client(HTTPRequest request, List<ServerName> sniServerNames, List<ProtocolName> protocols, TlsCrypto crypto)
: base(crypto)
{
this._request = request;
// get the request's logging context. The context has no reference to the request, so it won't keep it in memory.
this.Context = this._request.Context;
this._sniServerNames = sniServerNames;
this._protocols = protocols;
}
/// <summary>
/// TCPConnector has to know what protocol got negotiated
/// </summary>
public string GetNegotiatedApplicationProtocol() => base.m_context.SecurityParameters.ApplicationProtocol?.GetUtf8Decoding();
// (Abstract)TLSClient facing functions
protected override ProtocolVersion[] GetSupportedVersions() => ProtocolVersion.TLSv13.DownTo(ProtocolVersion.TLSv12);
protected override IList<ProtocolName> GetProtocolNames() => this._protocols;
protected override IList<ServerName> GetSniServerNames() => this._sniServerNames;
protected override int[] GetSupportedCipherSuites()
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(GetSupportedCipherSuites)}", this.Context);
return TlsUtilities.GetSupportedCipherSuites(Crypto, DefaultCipherSuites);
}
// TlsAuthentication implementation
public override TlsAuthentication GetAuthentication()
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(GetAuthentication)}", this.Context);
return this;
}
public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(GetClientCredentials)}", this.Context);
return null;
}
public virtual void NotifyServerCertificate(TlsServerCertificate serverCertificate)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyServerCertificate)}", this.Context);
}
public override void NotifyAlertReceived(short alertLevel, short alertDescription)
{
base.NotifyAlertReceived(alertLevel, alertDescription);
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyAlertReceived)}({alertLevel}, {alertDescription})", this.Context);
}
public override void NotifyAlertRaised(short alertLevel, short alertDescription, string message, Exception cause)
{
base.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyAlertRaised)}({alertLevel}, {alertDescription}, {message}, {cause?.StackTrace})", this.Context);
}
public override void NotifyHandshakeBeginning()
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyHandshakeBeginning)}", this.Context);
}
public override void NotifyHandshakeComplete()
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyHandshakeComplete)}", this.Context);
this._request = null;
}
public override void NotifyNewSessionTicket(NewSessionTicket newSessionTicket)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyNewSessionTicket)}", this.Context);
base.NotifyNewSessionTicket(newSessionTicket);
}
public override void NotifySecureRenegotiation(bool secureRenegotiation)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifySecureRenegotiation)}", this.Context);
base.NotifySecureRenegotiation(secureRenegotiation);
}
public override void NotifySelectedCipherSuite(int selectedCipherSuite)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifySelectedCipherSuite)}({selectedCipherSuite})", this.Context);
base.NotifySelectedCipherSuite(selectedCipherSuite);
}
public override void NotifySelectedPsk(TlsPsk selectedPsk)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifySelectedPsk)}({selectedPsk?.PrfAlgorithm})", this.Context);
base.NotifySelectedPsk(selectedPsk);
}
public override void NotifyServerVersion(ProtocolVersion serverVersion)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifyServerVersion)}({serverVersion})", this.Context);
base.NotifyServerVersion(serverVersion);
}
public override void NotifySessionID(byte[] sessionID)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifySessionID)}", this.Context);
base.NotifySessionID(sessionID);
}
public override void NotifySessionToResume(TlsSession session)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(NotifySessionToResume)}", this.Context);
base.NotifySessionToResume(session);
}
public override void ProcessServerExtensions(IDictionary<int, byte[]> serverExtensions)
{
HTTPManager.Logger.Information(nameof(AbstractTls13Client), $"{nameof(ProcessServerExtensions)}", this.Context);
base.ProcessServerExtensions(serverExtensions);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a656ab93e95c3174cb0afd2f26ef7da1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 129f7b1f27cbedb43b7948eaf7a4d423
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using BestHTTP.Connections.TLS.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl.BC;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.IO;
namespace BestHTTP.Connections.TLS.Crypto
{
public sealed class FastTlsCrypto : BcTlsCrypto
{
public FastTlsCrypto(SecureRandom entropySource)
: base(entropySource)
{
}
public override TlsCipher CreateCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, int macAlgorithm)
{
HTTPManager.Logger.Verbose(nameof(FastTlsCrypto), $"CreateCipher({encryptionAlgorithm}, {macAlgorithm})");
switch (encryptionAlgorithm)
{
case EncryptionAlgorithm.CHACHA20_POLY1305:
{
// NOTE: Ignores macAlgorithm
//return CreateChaCha20Poly1305(cryptoParams);
FastBcChaCha20Poly1305 encrypt = new FastBcChaCha20Poly1305(true);
FastBcChaCha20Poly1305 decrypt = new FastBcChaCha20Poly1305(false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 32, 16, TlsAeadCipher.AEAD_CHACHA20_POLY1305);
}
case EncryptionAlgorithm.AES_128_CBC:
case EncryptionAlgorithm.ARIA_128_CBC:
case EncryptionAlgorithm.CAMELLIA_128_CBC:
case EncryptionAlgorithm.SEED_CBC:
case EncryptionAlgorithm.SM4_CBC:
{
//return CreateCipher_Cbc(cryptoParams, encryptionAlgorithm, 16, macAlgorithm);
FastTlsBlockCipherImpl encrypt = new FastTlsBlockCipherImpl(CreateCbcBlockCipher(encryptionAlgorithm), true);
FastTlsBlockCipherImpl decrypt = new FastTlsBlockCipherImpl(CreateCbcBlockCipher(encryptionAlgorithm), false);
TlsHmac clientMac = CreateMac(cryptoParams, macAlgorithm);
TlsHmac serverMac = CreateMac(cryptoParams, macAlgorithm);
return new FastTlsBlockCipher(cryptoParams, encrypt, decrypt, clientMac, serverMac, 16);
}
case EncryptionAlgorithm.AES_256_CBC:
case EncryptionAlgorithm.ARIA_256_CBC:
case EncryptionAlgorithm.CAMELLIA_256_CBC:
{
//return CreateCipher_Cbc(cryptoParams, encryptionAlgorithm, 32, macAlgorithm);
FastTlsBlockCipherImpl encrypt = new FastTlsBlockCipherImpl(CreateCbcBlockCipher(encryptionAlgorithm), true);
FastTlsBlockCipherImpl decrypt = new FastTlsBlockCipherImpl(CreateCbcBlockCipher(encryptionAlgorithm), false);
TlsHmac clientMac = CreateMac(cryptoParams, macAlgorithm);
TlsHmac serverMac = CreateMac(cryptoParams, macAlgorithm);
return new FastTlsBlockCipher(cryptoParams, encrypt, decrypt, clientMac, serverMac, 32);
}
case EncryptionAlgorithm.AES_128_CCM:
{
// NOTE: Ignores macAlgorithm
//return CreateCipher_Aes_Ccm(cryptoParams, 16, 16);
FastTlsAeadCipherImpl encrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), true);
FastTlsAeadCipherImpl decrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 16, 16, TlsAeadCipher.AEAD_CCM);
}
case EncryptionAlgorithm.AES_128_CCM_8:
{
// NOTE: Ignores macAlgorithm
//return CreateCipher_Aes_Ccm(cryptoParams, 16, 8);
FastTlsAeadCipherImpl encrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), true);
FastTlsAeadCipherImpl decrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 16, 8, TlsAeadCipher.AEAD_CCM);
}
case EncryptionAlgorithm.AES_256_CCM:
{
// NOTE: Ignores macAlgorithm
//return CreateCipher_Aes_Ccm(cryptoParams, 32, 16);
FastTlsAeadCipherImpl encrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), true);
FastTlsAeadCipherImpl decrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 32, 16, TlsAeadCipher.AEAD_CCM);
}
case EncryptionAlgorithm.AES_256_CCM_8:
{
// NOTE: Ignores macAlgorithm
//return CreateCipher_Aes_Ccm(cryptoParams, 32, 8);
FastTlsAeadCipherImpl encrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), true);
FastTlsAeadCipherImpl decrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Ccm(), false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 32, 8, TlsAeadCipher.AEAD_CCM);
}
case EncryptionAlgorithm.AES_128_GCM:
{
// NOTE: Ignores macAlgorithm
//return CreateCipher_Aes_Gcm(cryptoParams, 16, 16);
FastTlsAeadCipherImpl encrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Gcm(), true);
FastTlsAeadCipherImpl decrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Gcm(), false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 16, 16, TlsAeadCipher.AEAD_GCM);
}
case EncryptionAlgorithm.AES_256_GCM:
{
// NOTE: Ignores macAlgorithm
//return CreateCipher_Aes_Gcm(cryptoParams, 32, 16);
FastTlsAeadCipherImpl encrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Gcm(), true);
FastTlsAeadCipherImpl decrypt = new FastTlsAeadCipherImpl(CreateAeadCipher_Aes_Gcm(), false);
return new FastTlsAeadCipher(cryptoParams, encrypt, decrypt, 32, 16, TlsAeadCipher.AEAD_GCM);
}
default:
return base.CreateCipher(cryptoParams, encryptionAlgorithm, macAlgorithm);
}
}
protected override IBlockCipher CreateAesEngine()
{
//return new AesEngine();
return new FastAesEngine();
}
protected override IAeadCipher CreateCcmMode(IBlockCipher engine)
{
return new FastCcmBlockCipher(engine);
}
protected override IAeadCipher CreateGcmMode(IBlockCipher engine)
{
// TODO Consider allowing custom configuration of multiplier
return new FastGcmBlockCipher(engine);
}
protected override IBlockCipher CreateCbcBlockCipher(IBlockCipher blockCipher)
{
return new FastCbcBlockCipher(blockCipher);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a2a6059d661c094db479c8d4e9ea6ef
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8a8a4ac374e70b84b87d66c99e9dcc90
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,150 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Runtime.CompilerServices;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
#if BESTHTTP_WITH_BURST
using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
#endif
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
#if BESTHTTP_WITH_BURST
[BurstCompile]
#endif
public sealed class BurstTables8kGcmMultiplier //: IGcmMultiplier
{
private byte[] H;
private GcmUtilities.FieldElement[][] T;
public void Init(byte[] H)
{
if (T == null)
{
T = new GcmUtilities.FieldElement[2][];
}
else if (Arrays.AreEqual(this.H, H))
{
return;
}
if (this.H == null)
this.H = Arrays.Clone(H);
else
{
if (this.H.Length != H.Length)
Array.Resize(ref this.H, H.Length);
Array.Copy(H, this.H, H.Length);
}
for (int i = 0; i < 2; ++i)
{
if (T[i] == null)
T[i] = new GcmUtilities.FieldElement[256];
GcmUtilities.FieldElement[] t = T[i];
// t[0] = 0
if (i == 0)
{
// t[1] = H.p^7
GcmUtilities.AsFieldElement(this.H, out t[1]);
GcmUtilities.MultiplyP7(ref t[1]);
}
else
{
// t[1] = T[i-1][1].p^8
GcmUtilities.MultiplyP8(ref T[i - 1][1], out t[1]);
}
for (int n = 1; n < 128; ++n)
{
// t[2.n] = t[n].p^-1
GcmUtilities.DivideP(ref t[n], out t[n << 1]);
// t[2.n + 1] = t[2.n] + t[1]
GcmUtilities.Xor(ref t[n << 1], ref t[1], out t[(n << 1) + 1]);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void MultiplyH(byte[] x)
{
fixed (byte* px = x)
fixed (GcmUtilities.FieldElement* pT0 = this.T[0])
fixed (GcmUtilities.FieldElement* pT1 = this.T[1])
MultiplyHImpl(px, pT0, pT1);
}
#if BESTHTTP_WITH_BURST
[BurstCompile]
#endif
private static unsafe void MultiplyHImpl(
#if BESTHTTP_WITH_BURST
[NoAlias]
#endif
byte* px,
#if BESTHTTP_WITH_BURST
[NoAlias]
#endif
GcmUtilities.FieldElement* pT0,
#if BESTHTTP_WITH_BURST
[NoAlias]
#endif
GcmUtilities.FieldElement* pT1)
{
int vPos = px[15];
int uPos = px[14];
ulong z1 = pT0[uPos].n1 ^ pT1[vPos].n1;
ulong z0 = pT0[uPos].n0 ^ pT1[vPos].n0;
for (int i = 12; i >= 0; i -= 2)
{
vPos = px[i + 1];
uPos = px[i];
ulong c = z1 << 48;
z1 = pT0[uPos].n1 ^ pT1[vPos].n1 ^ ((z1 >> 16) | (z0 << 48));
z0 = pT0[uPos].n0 ^ pT1[vPos].n0 ^ (z0 >> 16) ^ c ^ (c >> 1) ^ (c >> 2) ^ (c >> 7);
}
//GcmUtilities.AsBytes(z0, z1, x);
//UInt32_To_BE((uint)(n >> 32), bs, off);
uint n = (uint)(z0 >> 32);
px[0] = (byte)(n >> 24);
px[1] = (byte)(n >> 16);
px[2] = (byte)(n >> 8);
px[3] = (byte)(n);
//UInt32_To_BE((uint)(n), bs, off + 4);
n = (uint)(z0);
px[4] = (byte)(n >> 24);
px[5] = (byte)(n >> 16);
px[6] = (byte)(n >> 8);
px[7] = (byte)(n);
n = (uint)(z1 >> 32);
px[8] = (byte)(n >> 24);
px[9] = (byte)(n >> 16);
px[10] = (byte)(n >> 8);
px[11] = (byte)(n);
//UInt32_To_BE((uint)(n), bs, off + 4);
n = (uint)(z1);
px[12] = (byte)(n >> 24);
px[13] = (byte)(n >> 16);
px[14] = (byte)(n >> 8);
px[15] = (byte)(n);
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e88c42789588844893c08f62978218b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,938 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Diagnostics;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/**
* an implementation of the AES (Rijndael), from FIPS-197.
* <p>
* For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
*
* This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
*
* There are three levels of tradeoff of speed vs memory
* Because java has no preprocessor, they are written as three separate classes from which to choose
*
* The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
* and 4 for decryption.
*
* The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
* adding 12 rotate operations per round to compute the values contained in the other tables from
* the contents of the first.
*
* The slowest version uses no static tables at all and computes the values in each round.
* </p>
* <p>
* This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
* </p>
*/
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public sealed class FastAesEngine
: IBlockCipher
{
// The S box
private static readonly byte[] S =
{
99, 124, 119, 123, 242, 107, 111, 197,
48, 1, 103, 43, 254, 215, 171, 118,
202, 130, 201, 125, 250, 89, 71, 240,
173, 212, 162, 175, 156, 164, 114, 192,
183, 253, 147, 38, 54, 63, 247, 204,
52, 165, 229, 241, 113, 216, 49, 21,
4, 199, 35, 195, 24, 150, 5, 154,
7, 18, 128, 226, 235, 39, 178, 117,
9, 131, 44, 26, 27, 110, 90, 160,
82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91,
106, 203, 190, 57, 74, 76, 88, 207,
208, 239, 170, 251, 67, 77, 51, 133,
69, 249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56, 245,
188, 182, 218, 33, 16, 255, 243, 210,
205, 12, 19, 236, 95, 151, 68, 23,
196, 167, 126, 61, 100, 93, 25, 115,
96, 129, 79, 220, 34, 42, 144, 136,
70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92,
194, 211, 172, 98, 145, 149, 228, 121,
231, 200, 55, 109, 141, 213, 78, 169,
108, 86, 244, 234, 101, 122, 174, 8,
186, 120, 37, 46, 28, 166, 180, 198,
232, 221, 116, 31, 75, 189, 139, 138,
112, 62, 181, 102, 72, 3, 246, 14,
97, 53, 87, 185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217, 142, 148,
155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104,
65, 153, 45, 15, 176, 84, 187, 22,
};
// The inverse S-box
private static readonly byte[] Si =
{
82, 9, 106, 213, 48, 54, 165, 56,
191, 64, 163, 158, 129, 243, 215, 251,
124, 227, 57, 130, 155, 47, 255, 135,
52, 142, 67, 68, 196, 222, 233, 203,
84, 123, 148, 50, 166, 194, 35, 61,
238, 76, 149, 11, 66, 250, 195, 78,
8, 46, 161, 102, 40, 217, 36, 178,
118, 91, 162, 73, 109, 139, 209, 37,
114, 248, 246, 100, 134, 104, 152, 22,
212, 164, 92, 204, 93, 101, 182, 146,
108, 112, 72, 80, 253, 237, 185, 218,
94, 21, 70, 87, 167, 141, 157, 132,
144, 216, 171, 0, 140, 188, 211, 10,
247, 228, 88, 5, 184, 179, 69, 6,
208, 44, 30, 143, 202, 63, 15, 2,
193, 175, 189, 3, 1, 19, 138, 107,
58, 145, 17, 65, 79, 103, 220, 234,
151, 242, 207, 206, 240, 180, 230, 115,
150, 172, 116, 34, 231, 173, 53, 133,
226, 249, 55, 232, 28, 117, 223, 110,
71, 241, 26, 113, 29, 41, 197, 137,
111, 183, 98, 14, 170, 24, 190, 27,
252, 86, 62, 75, 198, 210, 121, 32,
154, 219, 192, 254, 120, 205, 90, 244,
31, 221, 168, 51, 136, 7, 199, 49,
177, 18, 16, 89, 39, 128, 236, 95,
96, 81, 127, 169, 25, 181, 74, 13,
45, 229, 122, 159, 147, 201, 156, 239,
160, 224, 59, 77, 174, 42, 245, 176,
200, 235, 187, 60, 131, 83, 153, 97,
23, 43, 4, 126, 186, 119, 214, 38,
225, 105, 20, 99, 85, 33, 12, 125,
};
// vector used in calculating key schedule (powers of x in GF(256))
private static readonly byte[] rcon =
{
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
};
// precomputation tables of calculations for rounds
private static readonly uint[] T0 =
{
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
0x3a16162c
};
private static readonly uint[] Tinv0 =
{
0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
0x4257b8d0
};
private static uint Shift(uint r, int shift)
{
return (r >> shift) | (r << (32 - shift));
}
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
private const uint m1 = 0x80808080;
private const uint m2 = 0x7f7f7f7f;
private const uint m3 = 0x0000001b;
private const uint m4 = 0xC0C0C0C0;
private const uint m5 = 0x3f3f3f3f;
private static uint FFmulX(uint x)
{
return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
}
private static uint FFmulX2(uint x)
{
uint t0 = (x & m5) << 2;
uint t1 = (x & m4);
t1 ^= (t1 >> 1);
return t0 ^ (t1 >> 2) ^ (t1 >> 5);
}
/*
The following defines provide alternative definitions of FFmulX that might
give improved performance if a fast 32-bit multiply is not available.
private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
private static final int m4 = 0x1b1b1b1b;
private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
*/
private static uint Inv_Mcol(uint x)
{
uint t0, t1;
t0 = x;
t1 = t0 ^ Shift(t0, 8);
t0 ^= FFmulX(t1);
t1 ^= FFmulX2(t0);
t0 ^= t1 ^ Shift(t1, 16);
return t0;
}
private static uint SubWord(uint x)
{
return (uint)S[x & 255]
| (((uint)S[(x >> 8) & 255]) << 8)
| (((uint)S[(x >> 16) & 255]) << 16)
| (((uint)S[(x >> 24) & 255]) << 24);
}
uint[][] W = null;
/**
* Calculate the necessary round keys
* The number of calculations depends on key size and block size
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
* This code is written assuming those are the only possible values
*/
private uint[][] GenerateWorkingKey(byte[] key, bool forEncryption)
{
int keyLen = key.Length;
if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
throw new ArgumentException("Key length not 128/192/256 bits.");
int KC = keyLen >> 2;
this.ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
if (W == null || W.Length < ROUNDS + 1)
{
W = new uint[ROUNDS + 1][]; // 4 words in a block
for (int i = 0; i <= ROUNDS; ++i)
{
W[i] = new uint[4];
}
}
else
{
for (int i = 0; i < W.Length; ++i)
Array.Clear(W[i], 0, W[i].Length);
}
switch (KC)
{
case 4:
{
uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
for (int i = 1; i <= 10; ++i)
{
uint u = SubWord(Shift(t3, 8)) ^ rcon[i - 1];
t0 ^= u; W[i][0] = t0;
t1 ^= t0; W[i][1] = t1;
t2 ^= t1; W[i][2] = t2;
t3 ^= t2; W[i][3] = t3;
}
break;
}
case 6:
{
uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
uint rcon = 1;
uint u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
t0 ^= u; W[1][2] = t0;
t1 ^= t0; W[1][3] = t1;
t2 ^= t1; W[2][0] = t2;
t3 ^= t2; W[2][1] = t3;
t4 ^= t3; W[2][2] = t4;
t5 ^= t4; W[2][3] = t5;
for (int i = 3; i < 12; i += 3)
{
u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
t0 ^= u; W[i][0] = t0;
t1 ^= t0; W[i][1] = t1;
t2 ^= t1; W[i][2] = t2;
t3 ^= t2; W[i][3] = t3;
t4 ^= t3; W[i + 1][0] = t4;
t5 ^= t4; W[i + 1][1] = t5;
u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
t0 ^= u; W[i + 1][2] = t0;
t1 ^= t0; W[i + 1][3] = t1;
t2 ^= t1; W[i + 2][0] = t2;
t3 ^= t2; W[i + 2][1] = t3;
t4 ^= t3; W[i + 2][2] = t4;
t5 ^= t4; W[i + 2][3] = t5;
}
u = SubWord(Shift(t5, 8)) ^ rcon;
t0 ^= u; W[12][0] = t0;
t1 ^= t0; W[12][1] = t1;
t2 ^= t1; W[12][2] = t2;
t3 ^= t2; W[12][3] = t3;
break;
}
case 8:
{
uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
uint t6 = Pack.LE_To_UInt32(key, 24); W[1][2] = t6;
uint t7 = Pack.LE_To_UInt32(key, 28); W[1][3] = t7;
uint u, rcon = 1;
for (int i = 2; i < 14; i += 2)
{
u = SubWord(Shift(t7, 8)) ^ rcon; rcon <<= 1;
t0 ^= u; W[i][0] = t0;
t1 ^= t0; W[i][1] = t1;
t2 ^= t1; W[i][2] = t2;
t3 ^= t2; W[i][3] = t3;
u = SubWord(t3);
t4 ^= u; W[i + 1][0] = t4;
t5 ^= t4; W[i + 1][1] = t5;
t6 ^= t5; W[i + 1][2] = t6;
t7 ^= t6; W[i + 1][3] = t7;
}
u = SubWord(Shift(t7, 8)) ^ rcon;
t0 ^= u; W[14][0] = t0;
t1 ^= t0; W[14][1] = t1;
t2 ^= t1; W[14][2] = t2;
t3 ^= t2; W[14][3] = t3;
break;
}
default:
{
throw new InvalidOperationException("Should never get here");
}
}
if (!forEncryption)
{
for (int j = 1; j < ROUNDS; j++)
{
uint[] w = W[j];
for (int i = 0; i < 4; i++)
{
w[i] = Inv_Mcol(w[i]);
}
}
}
return W;
}
private int ROUNDS;
private uint[][] WorkingKey;
private bool forEncryption;
private byte[] s;
private const int BLOCK_SIZE = 16;
/**
* default constructor - 128 bit block size.
*/
public FastAesEngine()
{
}
/**
* initialise an AES cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(bool forEncryption, ICipherParameters parameters)
{
if (!(parameters is KeyParameter keyParameter))
throw new ArgumentException("invalid parameter passed to AES init - "
+ BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(parameters));
WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
this.forEncryption = forEncryption;
this.s = /*Arrays.Clone*/(forEncryption ? S : Si);
}
public string AlgorithmName
{
get { return "AES"; }
}
public int GetBlockSize()
{
return BLOCK_SIZE;
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (WorkingKey == null)
throw new InvalidOperationException("AES engine not initialised");
Check.DataLength(input, inOff, 16, "input buffer too short");
Check.OutputLength(output, outOff, 16, "output buffer too short");
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
if (forEncryption)
{
EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff), WorkingKey);
}
else
{
DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff), WorkingKey);
}
#else
if (forEncryption)
{
EncryptBlock(input, inOff, output, outOff, WorkingKey);
}
else
{
DecryptBlock(input, inOff, output, outOff, WorkingKey);
}
#endif
return BLOCK_SIZE;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public unsafe int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
if (WorkingKey == null)
throw new InvalidOperationException("AES engine not initialised");
Check.DataLength(input, 16, "input buffer too short");
Check.OutputLength(output, 16, "output buffer too short");
if (forEncryption)
{
//EncryptBlock(input, output, WorkingKey);
uint C0 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input);
uint C1 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[4..]);
uint C2 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[8..]);
uint C3 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[12..]);
uint[] kw = WorkingKey[0];
uint t0 = C0 ^ kw[0];
uint t1 = C1 ^ kw[1];
uint t2 = C2 ^ kw[2];
uint r0, r1, r2, r3 = C3 ^ kw[3];
int r = 1;
uint tmp1, tmp2, tmp3;
uint shift1, shift2, shift3;
fixed (uint* pT0 = T0)
{
while (r < ROUNDS - 1)
{
kw = WorkingKey[r++];
fixed (uint* pkw = kw)
{
tmp1 = pT0[(t1 >> 8) & 255]; tmp2 = pT0[(t2 >> 16) & 255]; tmp3 = pT0[(r3 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r0 = pT0[t0 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[0];
tmp1 = pT0[(t2 >> 8) & 255]; tmp2 = pT0[(r3 >> 16) & 255]; tmp3 = pT0[(t0 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r1 = pT0[t1 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[1];
tmp1 = pT0[(r3 >> 8) & 255]; tmp2 = pT0[(t0 >> 16) & 255]; tmp3 = pT0[(t1 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r2 = pT0[t2 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[2];
tmp1 = pT0[(t0 >> 8) & 255]; tmp2 = pT0[(t1 >> 16) & 255]; tmp3 = pT0[(t2 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r3 = pT0[r3 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[3];
}
kw = WorkingKey[r++];
fixed (uint* pkw = kw)
{
tmp1 = pT0[(r1 >> 8) & 255]; tmp2 = pT0[(r2 >> 16) & 255]; tmp3 = pT0[(r3 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
t0 = pT0[r0 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[0];
tmp1 = pT0[(r2 >> 8) & 255]; tmp2 = pT0[(r3 >> 16) & 255]; tmp3 = pT0[(r0 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
t1 = pT0[r1 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[1];
tmp1 = pT0[(r3 >> 8) & 255]; tmp2 = pT0[(r0 >> 16) & 255]; tmp3 = pT0[(r1 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
t2 = pT0[r2 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[2];
tmp1 = pT0[(r0 >> 8) & 255]; tmp2 = pT0[(r1 >> 16) & 255]; tmp3 = pT0[(r2 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r3 = pT0[r3 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[3];
}
}
kw = WorkingKey[r++];
fixed (uint* pkw = kw)
{
tmp1 = pT0[(t1 >> 8) & 255]; tmp2 = pT0[(t2 >> 16) & 255]; tmp3 = pT0[(r3 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r0 = pT0[t0 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[0];
tmp1 = pT0[(t2 >> 8) & 255]; tmp2 = pT0[(r3 >> 16) & 255]; tmp3 = pT0[(t0 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r1 = pT0[t1 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[1];
tmp1 = pT0[(r3 >> 8) & 255]; tmp2 = pT0[(t0 >> 16) & 255]; tmp3 = pT0[(t1 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r2 = pT0[t2 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[2];
tmp1 = pT0[(t0 >> 8) & 255]; tmp2 = pT0[(t1 >> 16) & 255]; tmp3 = pT0[(t2 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r3 = pT0[r3 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[3];
}
}
// the final round's table is a simple function of S so we don't use a whole other four tables for it
kw = WorkingKey[r];
fixed (uint* pkw = kw)
fixed (byte* pS = S)
fixed (byte* ps = s)
{
C0 = (uint)pS[r0 & 255] ^ (((uint)pS[(r1 >> 8) & 255]) << 8) ^ (((uint)ps[(r2 >> 16) & 255]) << 16) ^ (((uint)ps[(r3 >> 24) & 255]) << 24) ^ pkw[0];
C1 = (uint)ps[r1 & 255] ^ (((uint)pS[(r2 >> 8) & 255]) << 8) ^ (((uint)pS[(r3 >> 16) & 255]) << 16) ^ (((uint)ps[(r0 >> 24) & 255]) << 24) ^ pkw[1];
C2 = (uint)ps[r2 & 255] ^ (((uint)pS[(r3 >> 8) & 255]) << 8) ^ (((uint)pS[(r0 >> 16) & 255]) << 16) ^ (((uint)pS[(r1 >> 24) & 255]) << 24) ^ pkw[2];
C3 = (uint)ps[r3 & 255] ^ (((uint)ps[(r0 >> 8) & 255]) << 8) ^ (((uint)ps[(r1 >> 16) & 255]) << 16) ^ (((uint)pS[(r2 >> 24) & 255]) << 24) ^ pkw[3];
}
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output, C0);
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output[4..], C1);
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output[8..], C2);
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output[12..], C3);
}
else
{
//DecryptBlock(input, output, WorkingKey);
uint C0 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input);
uint C1 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[4..]);
uint C2 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[8..]);
uint C3 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[12..]);
uint[] kw = WorkingKey[ROUNDS];
uint t0 = C0 ^ kw[0];
uint t1 = C1 ^ kw[1];
uint t2 = C2 ^ kw[2];
uint r0, r1, r2, r3 = C3 ^ kw[3];
int r = ROUNDS - 1;
uint tmp1, tmp2, tmp3;
uint shift1, shift2, shift3;
fixed (uint* pTinv0 = Tinv0)
{
while (r > 1)
{
kw = WorkingKey[r--];
fixed (uint* pkw = kw)
{
tmp1 = pTinv0[(r3 >> 8) & 255]; tmp2 = pTinv0[(t2 >> 16) & 255]; tmp3 = pTinv0[(t1 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r0 = pTinv0[t0 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[0];
tmp1 = pTinv0[(t0 >> 8) & 255]; tmp2 = pTinv0[(r3 >> 16) & 255]; tmp3 = pTinv0[(t2 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r1 = pTinv0[t1 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[1];
tmp1 = pTinv0[(t1 >> 8) & 255]; tmp2 = pTinv0[(t0 >> 16) & 255]; tmp3 = pTinv0[(r3 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r2 = pTinv0[t2 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[2];
tmp1 = pTinv0[(t2 >> 8) & 255]; tmp2 = pTinv0[(t1 >> 16) & 255]; tmp3 = pTinv0[(t0 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r3 = pTinv0[r3 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[3];
}
kw = WorkingKey[r--];
fixed (uint* pkw = kw)
{
tmp1 = pTinv0[(r3 >> 8) & 255]; tmp2 = pTinv0[(r2 >> 16) & 255]; tmp3 = pTinv0[(r1 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
t0 = pTinv0[r0 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[0];
tmp1 = pTinv0[(r0 >> 8) & 255]; tmp2 = pTinv0[(r3 >> 16) & 255]; tmp3 = pTinv0[(r2 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
t1 = pTinv0[r1 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[1];
tmp1 = pTinv0[(r1 >> 8) & 255]; tmp2 = pTinv0[(r0 >> 16) & 255]; tmp3 = pTinv0[(r3 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
t2 = pTinv0[r2 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[2];
tmp1 = pTinv0[(r2 >> 8) & 255]; tmp2 = pTinv0[(r1 >> 16) & 255]; tmp3 = pTinv0[(r0 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r3 = pTinv0[r3 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[3];
}
}
kw = WorkingKey[1];
fixed (uint* pkw = kw)
{
tmp1 = pTinv0[(r3 >> 8) & 255]; tmp2 = pTinv0[(t2 >> 16) & 255]; tmp3 = pTinv0[(t1 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r0 = pTinv0[t0 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[0];
tmp1 = pTinv0[(t0 >> 8) & 255]; tmp2 = pTinv0[(r3 >> 16) & 255]; tmp3 = pTinv0[(t2 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r1 = pTinv0[t1 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[1];
tmp1 = pTinv0[(t1 >> 8) & 255]; tmp2 = pTinv0[(t0 >> 16) & 255]; tmp3 = pTinv0[(r3 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r2 = pTinv0[t2 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[2];
tmp1 = pTinv0[(t2 >> 8) & 255]; tmp2 = pTinv0[(t1 >> 16) & 255]; tmp3 = pTinv0[(t0 >> 24) & 255];
shift1 = (tmp1 >> 24) | (tmp1 << 8); shift2 = (tmp2 >> 16) | (tmp2 << 16); shift3 = (tmp3 >> 8) | (tmp3 << 24);
r3 = pTinv0[r3 & 255] ^ shift1 ^ shift2 ^ shift3 ^ pkw[3];
}
}
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
kw = WorkingKey[0];
fixed (uint* pkw = kw)
fixed(byte* pSi = Si)
fixed (byte* ps = s)
{
C0 = (uint)pSi[r0 & 255] ^ (((uint)ps[(r3 >> 8) & 255]) << 8) ^ (((uint)ps[(r2 >> 16) & 255]) << 16) ^ (((uint)pSi[(r1 >> 24) & 255]) << 24) ^ pkw[0];
C1 = (uint)ps[r1 & 255] ^ (((uint)ps[(r0 >> 8) & 255]) << 8) ^ (((uint)pSi[(r3 >> 16) & 255]) << 16) ^ (((uint)ps[(r2 >> 24) & 255]) << 24) ^ pkw[1];
C2 = (uint)ps[r2 & 255] ^ (((uint)pSi[(r1 >> 8) & 255]) << 8) ^ (((uint)pSi[(r0 >> 16) & 255]) << 16) ^ (((uint)ps[(r3 >> 24) & 255]) << 24) ^ pkw[2];
C3 = (uint)pSi[r3 & 255] ^ (((uint)ps[(r2 >> 8) & 255]) << 8) ^ (((uint)ps[(r1 >> 16) & 255]) << 16) ^ (((uint)ps[(r0 >> 24) & 255]) << 24) ^ pkw[3];
}
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output, C0);
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output[4..], C1);
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output[8..], C2);
System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(output[12..], C3);
}
return BLOCK_SIZE;
}
#endif
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
{
uint C0 = Pack.LE_To_UInt32(input);
uint C1 = Pack.LE_To_UInt32(input[4..]);
uint C2 = Pack.LE_To_UInt32(input[8..]);
uint C3 = Pack.LE_To_UInt32(input[12..]);
uint[] kw = KW[0];
uint t0 = C0 ^ kw[0];
uint t1 = C1 ^ kw[1];
uint t2 = C2 ^ kw[2];
uint r0, r1, r2, r3 = C3 ^ kw[3];
int r = 1;
while (r < ROUNDS - 1)
{
kw = KW[r++];
r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
kw = KW[r++];
t0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
t1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(r0 >> 24) & 255], 8) ^ kw[1];
t2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ Shift(T0[(r1 >> 24) & 255], 8) ^ kw[2];
r3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ Shift(T0[(r2 >> 24) & 255], 8) ^ kw[3];
}
kw = KW[r++];
r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
// the final round's table is a simple function of S so we don't use a whole other four tables for it
kw = KW[r];
C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[0];
C1 = (uint)s[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[1];
C2 = (uint)s[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
C3 = (uint)s[r3 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
Pack.UInt32_To_LE(C0, output);
Pack.UInt32_To_LE(C1, output[4..]);
Pack.UInt32_To_LE(C2, output[8..]);
Pack.UInt32_To_LE(C3, output[12..]);
}
private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
{
uint C0 = Pack.LE_To_UInt32(input);
uint C1 = Pack.LE_To_UInt32(input[4..]);
uint C2 = Pack.LE_To_UInt32(input[8..]);
uint C3 = Pack.LE_To_UInt32(input[12..]);
uint[] kw = KW[ROUNDS];
uint t0 = C0 ^ kw[0];
uint t1 = C1 ^ kw[1];
uint t2 = C2 ^ kw[2];
uint r0, r1, r2, r3 = C3 ^ kw[3];
int r = ROUNDS - 1;
while (r > 1)
{
kw = KW[r--];
r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
kw = KW[r--];
t0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ Shift(Tinv0[(r1 >> 24) & 255], 8) ^ kw[0];
t1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(r2 >> 24) & 255], 8) ^ kw[1];
t2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ Shift(Tinv0[(r0 >> 24) & 255], 8) ^ kw[3];
}
kw = KW[1];
r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
kw = KW[0];
C0 = (uint)Si[r0 & 255] ^ (((uint)s[(r3 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
C1 = (uint)s[r1 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r2 >> 24) & 255]) << 24) ^ kw[1];
C2 = (uint)s[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[2];
C3 = (uint)Si[r3 & 255] ^ (((uint)s[(r2 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[3];
Pack.UInt32_To_LE(C0, output);
Pack.UInt32_To_LE(C1, output[4..]);
Pack.UInt32_To_LE(C2, output[8..]);
Pack.UInt32_To_LE(C3, output[12..]);
}
#else
private void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff, uint[][] KW)
{
FastAesEngineHelper.EncryptBlock(input, inOff, output, outOff, KW, ROUNDS, T0, S, s);
//uint C0 = Pack.LE_To_UInt32(input, inOff + 0);
//uint C1 = Pack.LE_To_UInt32(input, inOff + 4);
//uint C2 = Pack.LE_To_UInt32(input, inOff + 8);
//uint C3 = Pack.LE_To_UInt32(input, inOff + 12);
//
//uint[] kw = KW[0];
//uint t0 = C0 ^ kw[0];
//uint t1 = C1 ^ kw[1];
//uint t2 = C2 ^ kw[2];
//
//uint r0, r1, r2, r3 = C3 ^ kw[3];
//int r = 1;
//while (r < ROUNDS - 1)
//{
// kw = KW[r++];
// r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
// r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
// r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
// r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
// kw = KW[r++];
// t0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
// t1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(r0 >> 24) & 255], 8) ^ kw[1];
// t2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ Shift(T0[(r1 >> 24) & 255], 8) ^ kw[2];
// r3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ Shift(T0[(r2 >> 24) & 255], 8) ^ kw[3];
//}
//
//kw = KW[r++];
//r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
//r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
//r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
//r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
//
//// the final round's table is a simple function of S so we don't use a whole other four tables for it
//
//kw = KW[r];
//C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[0];
//C1 = (uint)s[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[1];
//C2 = (uint)s[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
//C3 = (uint)s[r3 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
//
//Pack.UInt32_To_LE(C0, output, outOff + 0);
//Pack.UInt32_To_LE(C1, output, outOff + 4);
//Pack.UInt32_To_LE(C2, output, outOff + 8);
//Pack.UInt32_To_LE(C3, output, outOff + 12);
}
private void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff, uint[][] KW)
{
uint C0 = Pack.LE_To_UInt32(input, inOff + 0);
uint C1 = Pack.LE_To_UInt32(input, inOff + 4);
uint C2 = Pack.LE_To_UInt32(input, inOff + 8);
uint C3 = Pack.LE_To_UInt32(input, inOff + 12);
uint[] kw = KW[ROUNDS];
uint t0 = C0 ^ kw[0];
uint t1 = C1 ^ kw[1];
uint t2 = C2 ^ kw[2];
uint r0, r1, r2, r3 = C3 ^ kw[3];
int r = ROUNDS - 1;
while (r > 1)
{
kw = KW[r--];
r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
kw = KW[r--];
t0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ Shift(Tinv0[(r1 >> 24) & 255], 8) ^ kw[0];
t1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(r2 >> 24) & 255], 8) ^ kw[1];
t2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ Shift(Tinv0[(r0 >> 24) & 255], 8) ^ kw[3];
}
kw = KW[1];
r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
kw = KW[0];
C0 = (uint)Si[r0 & 255] ^ (((uint)s[(r3 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
C1 = (uint)s[r1 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r2 >> 24) & 255]) << 24) ^ kw[1];
C2 = (uint)s[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[2];
C3 = (uint)Si[r3 & 255] ^ (((uint)s[(r2 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[3];
Pack.UInt32_To_LE(C0, output, outOff + 0);
Pack.UInt32_To_LE(C1, output, outOff + 4);
Pack.UInt32_To_LE(C2, output, outOff + 8);
Pack.UInt32_To_LE(C3, output, outOff + 12);
}
#endif
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04025dfce7b22d142b61813959b98226
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,195 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
internal static class FastAesEngineHelper
{
public unsafe static void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff, uint[][] KW, int ROUNDS, uint[] T0, byte[] S, byte[] s)
{
uint C0 = Pack.LE_To_UInt32(input, inOff + 0);
uint C1 = Pack.LE_To_UInt32(input, inOff + 4);
uint C2 = Pack.LE_To_UInt32(input, inOff + 8);
uint C3 = Pack.LE_To_UInt32(input, inOff + 12);
uint[] kw = KW[0];
uint t0 = C0 ^ kw[0];
uint t1 = C1 ^ kw[1];
uint t2 = C2 ^ kw[2];
uint r0, r1, r2, r3 = C3 ^ kw[3];
int r = 1;
byte idx;
uint tmp1, tmp2, tmp3;
fixed (uint* pT0 = T0)
{
while (r < ROUNDS - 1)
{
kw = KW[r++];
fixed (uint* pkw = kw)
{
idx = (byte)(t1 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(t2 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(r3 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r0 = pT0[t0 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[0];
idx = (byte)(t2 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(r3 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(t0 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r1 = pT0[t1 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[1];
idx = (byte)(r3 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(t0 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(t1 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r2 = pT0[t2 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[2];
idx = (byte)(t0 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(t1 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(t2 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r3 = pT0[r3 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[3];
}
kw = KW[r++];
fixed (uint* pkw = kw)
{
idx = (byte)(r1 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(r2 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(r3 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
t0 = pT0[r0 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[0];
idx = (byte)(r2 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(r3 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(r0 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
t1 = pT0[r1 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[1];
idx = (byte)(r3 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(r0 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(r1 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
t2 = pT0[r2 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[2];
idx = (byte)(r0 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(r1 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(r2 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r3 = pT0[r3 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[3];
}
}
kw = KW[r++];
fixed (uint* pkw = kw)
{
idx = (byte)(t1 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(t2 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(r3 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r0 = pT0[t0 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[0];
idx = (byte)(t2 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(r3 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(t0 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r1 = pT0[t1 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[1];
idx = (byte)(r3 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(t0 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(t1 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r2 = pT0[t2 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[2];
idx = (byte)(t0 >> 8);
tmp1 = (pT0[idx] >> 24) | (pT0[idx] << 8);
idx = (byte)(t1 >> 16);
tmp2 = (pT0[idx] >> 16) | (pT0[idx] << 16);
idx = (byte)(t2 >> 24);
tmp3 = (pT0[idx] >> 8) | (pT0[idx] << 24);
r3 = pT0[r3 & 255] ^ tmp1 ^ tmp2 ^ tmp3 ^ pkw[3];
}
// the final round's table is a simple function of S so we don't use a whole other four tables for it
kw = KW[r];
fixed (byte* pS = S, ps = s)
fixed (uint* pkw = kw)
{
C0 = (uint)pS[(byte)r0] ^ (((uint)pS[(byte)(r1 >> 8)]) << 8) ^ (((uint)ps[(byte)(r2 >> 16)]) << 16) ^ (((uint)ps[(byte)(r3 >> 24)]) << 24) ^ pkw[0];
C1 = (uint)ps[(byte)r1] ^ (((uint)pS[(byte)(r2 >> 8)]) << 8) ^ (((uint)pS[(byte)(r3 >> 16)]) << 16) ^ (((uint)ps[(byte)(r0 >> 24)]) << 24) ^ pkw[1];
C2 = (uint)ps[(byte)r2] ^ (((uint)pS[(byte)(r3 >> 8)]) << 8) ^ (((uint)pS[(byte)(r0 >> 16)]) << 16) ^ (((uint)pS[(byte)(r1 >> 24)]) << 24) ^ pkw[2];
C3 = (uint)ps[(byte)r3] ^ (((uint)ps[(byte)(r0 >> 8)]) << 8) ^ (((uint)ps[(byte)(r1 >> 16)]) << 16) ^ (((uint)pS[(byte)(r2 >> 24)]) << 24) ^ pkw[3];
}
}
Pack.UInt32_To_LE(C0, output, outOff + 0);
Pack.UInt32_To_LE(C1, output, outOff + 4);
Pack.UInt32_To_LE(C2, output, outOff + 8);
Pack.UInt32_To_LE(C3, output, outOff + 12);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f41ac81f5b4391419ba276b4bb78044
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,189 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
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;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
unsafe
#endif
public int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
{
if (m_isEncrypting)
{
int ciphertextLength = inputLength;
m_cipher.DoFinal(input, inputOffset, inputLength, output, outputOffset);
int outputLength = inputLength;
if (ciphertextLength != outputLength)
throw new InvalidOperationException();
UpdateMac(output, outputOffset, ciphertextLength);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
Span<byte> lengths = stackalloc byte[16];
Pack.UInt64_To_LE((ulong)m_additionalDataLength, lengths);
Pack.UInt64_To_LE((ulong)ciphertextLength, lengths[8..]);
m_mac.BlockUpdate(lengths);
m_mac.DoFinal(output.AsSpan(outputOffset + ciphertextLength));
#else
byte[] lengths = BufferPool.Get(16, true);
using (var _ = new PooledBuffer(lengths))
{
Pack.UInt64_To_LE((ulong)m_additionalDataLength, lengths, 0);
Pack.UInt64_To_LE((ulong)ciphertextLength, lengths, 8);
m_mac.BlockUpdate(lengths, 0, 16);
m_mac.DoFinal(output, outputOffset + ciphertextLength);
}
#endif
return ciphertextLength + 16;
}
else
{
int ciphertextLength = inputLength - 16;
UpdateMac(input, inputOffset, ciphertextLength);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
Span<byte> expectedMac = stackalloc byte[16];
Pack.UInt64_To_LE((ulong)m_additionalDataLength, expectedMac);
Pack.UInt64_To_LE((ulong)ciphertextLength, expectedMac[8..]);
m_mac.BlockUpdate(expectedMac);
m_mac.DoFinal(expectedMac);
bool badMac = !TlsUtilities.ConstantTimeAreEqual(16, expectedMac, 0, input, inputOffset + ciphertextLength);
if (badMac)
throw new TlsFatalAlert(AlertDescription.bad_record_mac);
#else
byte[] expectedMac = BufferPool.Get(16, true);
using (var _ = new PooledBuffer(expectedMac))
{
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);
if (badMac)
throw new TlsFatalAlert(AlertDescription.bad_record_mac);
}
#endif
m_cipher.DoFinal(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 ParametersWithIV(null, nonce));
InitMac();
if (additionalData == null)
{
this.m_additionalDataLength = 0;
}
else
{
this.m_additionalDataLength = additionalData.Length;
UpdateMac(additionalData, 0, additionalData.Length);
}
}
public void Reset()
{
m_cipher.Reset();
m_mac.Reset();
}
public void SetKey(byte[] key, int keyOff, int keyLen)
{
KeyParameter cipherKey = new KeyParameter(key, keyOff, keyLen);
m_cipher.Init(m_isEncrypting, new ParametersWithIV(cipherKey, Zeroes, 0, 12));
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public void SetKey(ReadOnlySpan<byte> key)
{
KeyParameter cipherKey = new KeyParameter(key);
m_cipher.Init(m_isEncrypting, new ParametersWithIV(cipherKey, Zeroes[..12]));
}
#endif
byte[] firstBlock = new byte[64];
private void InitMac()
{
m_cipher.ProcessBytes(firstBlock, 0, 64, firstBlock, 0);
m_mac.Init(new KeyParameter(firstBlock, 0, 32));
Array.Clear(firstBlock, 0, firstBlock.Length);
}
private void UpdateMac(byte[] buf, int off, int len)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
m_mac.BlockUpdate(buf.AsSpan(off, len));
#else
m_mac.BlockUpdate(buf, off, len);
#endif
int partial = len % 16;
if (partial != 0)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
m_mac.BlockUpdate(Zeroes.AsSpan(0, 16 - partial));
#else
m_mac.BlockUpdate(Zeroes, 0, 16 - partial);
#endif
}
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8147dce9f66d3aa42acf242bd200aa46
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,229 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using BestHTTP.Connections.TLS.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
namespace BestHTTP.Connections.TLS.Crypto
{
/**
* implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
*/
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public sealed class FastCbcBlockCipher
: IBlockCipherMode
{
private byte[] IV, cbcV, cbcNextV;
private int blockSize;
private IBlockCipher cipher;
private bool encrypting;
/**
* Basic constructor.
*
* @param cipher the block cipher to be used as the basis of chaining.
*/
public FastCbcBlockCipher(
IBlockCipher cipher)
{
this.cipher = cipher;
this.blockSize = cipher.GetBlockSize();
this.IV = new byte[blockSize];
this.cbcV = new byte[blockSize];
this.cbcNextV = new byte[blockSize];
}
/**
* return the underlying block cipher that we are wrapping.
*
* @return the underlying block cipher that we are wrapping.
*/
public IBlockCipher UnderlyingCipher => cipher;
/**
* Initialise the cipher and, possibly, the initialisation vector (IV).
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
*
* @param forEncryption if true the cipher is initialised for
* encryption, if false for decryption.
* @param param the key and other data required by the cipher.
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
public void Init(bool forEncryption, ICipherParameters parameters)
{
bool oldEncrypting = this.encrypting;
this.encrypting = forEncryption;
if (parameters is ParametersWithIV ivParam)
{
byte[] iv = ivParam.GetIV();
if (iv.Length != blockSize)
throw new ArgumentException("initialisation vector must be the same length as block size");
Array.Copy(iv, 0, IV, 0, iv.Length);
parameters = ivParam.Parameters;
}
Reset();
// if null it's an IV changed only.
if (parameters != null)
{
cipher.Init(encrypting, parameters);
}
else if (oldEncrypting != encrypting)
{
throw new ArgumentException("cannot change encrypting state without providing key.");
}
}
/**
* return the algorithm name and mode.
*
* @return the name of the underlying algorithm followed by "/CBC".
*/
public string AlgorithmName
{
get { return cipher.AlgorithmName + "/CBC"; }
}
public bool IsPartialBlockOkay
{
get { return false; }
}
/**
* return the block size of the underlying cipher.
*
* @return the block size of the underlying cipher.
*/
public int GetBlockSize()
{
return cipher.GetBlockSize();
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return encrypting
? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
: DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
#else
return encrypting
? EncryptBlock(input, inOff, output, outOff)
: DecryptBlock(input, inOff, output, outOff);
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
return encrypting
? EncryptBlock(input, output)
: DecryptBlock(input, output);
}
#endif
/**
* reset the chaining vector back to the IV and reset the underlying
* cipher.
*/
public void Reset()
{
Array.Copy(IV, 0, cbcV, 0, IV.Length);
Array.Clear(cbcNextV, 0, cbcNextV.Length);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
Check.DataLength(input, blockSize, "input buffer too short");
Check.OutputLength(output, blockSize, "output buffer too short");
for (int i = 0; i < blockSize; i++)
{
cbcV[i] ^= input[i];
}
int length = cipher.ProcessBlock(cbcV, output);
output[..blockSize].CopyTo(cbcV);
return length;
}
private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
Check.DataLength(input, blockSize, "input buffer too short");
Check.OutputLength(output, blockSize, "output buffer too short");
input[..blockSize].CopyTo(cbcNextV);
int length = cipher.ProcessBlock(input, output);
for (int i = 0; i < blockSize; i++)
{
output[i] ^= cbcV[i];
}
byte[] tmp = cbcV;
cbcV = cbcNextV;
cbcNextV = tmp;
return length;
}
#else
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
Check.DataLength(input, inOff, blockSize, "input buffer too short");
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
for (int i = 0; i < blockSize; i++)
{
cbcV[i] ^= input[inOff + i];
}
int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
return length;
}
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
Check.DataLength(input, inOff, blockSize, "input buffer too short");
Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
Array.Copy(input, inOff, cbcNextV, 0, blockSize);
int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
for (int i = 0; i < blockSize; i++)
{
outBytes[outOff + i] ^= cbcV[i];
}
byte[] tmp = cbcV;
cbcV = cbcNextV;
cbcNextV = tmp;
return length;
}
#endif
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 885849ed4738c9c4197fbee14f00dd5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,661 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.IO;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/**
* Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
* NIST Special Publication 800-38C.
* <p>
* <b>Note</b>: this mode is a packet mode - it needs all the data up front.
* </p>
*/
public class FastCcmBlockCipher
: IAeadBlockCipher
{
private static readonly int BlockSize = 16;
private readonly IBlockCipher cipher;
private readonly byte[] macBlock;
private bool forEncryption;
private byte[] nonce;
private byte[] initialAssociatedText;
private int macSize;
private ICipherParameters keyParam;
private readonly MemoryStream associatedText = new MemoryStream();
private readonly MemoryStream data = new MemoryStream();
/**
* Basic constructor.
*
* @param cipher the block cipher to be used.
*/
public FastCcmBlockCipher(
IBlockCipher cipher)
{
this.cipher = cipher;
this.macBlock = new byte[BlockSize];
if (cipher.GetBlockSize() != BlockSize)
throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
}
/**
* return the underlying block cipher that we are wrapping.
*
* @return the underlying block cipher that we are wrapping.
*/
public virtual IBlockCipher UnderlyingCipher => cipher;
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
ICipherParameters cipherParameters;
if (parameters is AeadParameters aeadParameters)
{
nonce = aeadParameters.GetNonce();
initialAssociatedText = aeadParameters.GetAssociatedText();
macSize = GetMacSize(forEncryption, aeadParameters.MacSize);
cipherParameters = aeadParameters.Key;
}
else if (parameters is ParametersWithIV parametersWithIV)
{
nonce = parametersWithIV.GetIV();
initialAssociatedText = null;
macSize = GetMacSize(forEncryption, 64);
cipherParameters = parametersWithIV.Parameters;
}
else
{
throw new ArgumentException("invalid parameters passed to CCM");
}
// NOTE: Very basic support for key re-use, but no performance gain from it
if (cipherParameters != null)
{
keyParam = cipherParameters;
}
if (nonce == null || nonce.Length < 7 || nonce.Length > 13)
throw new ArgumentException("nonce must have length from 7 to 13 octets");
Reset();
}
public virtual string AlgorithmName => cipher.AlgorithmName + "/CCM";
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
}
public virtual void ProcessAadByte(byte input)
{
associatedText.WriteByte(input);
}
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
// TODO: Process AAD online
associatedText.Write(inBytes, inOff, len);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
{
// TODO: Process AAD online
associatedText.Write(input);
}
#endif
public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
{
data.WriteByte(input);
return 0;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual int ProcessByte(byte input, Span<byte> output)
{
data.WriteByte(input);
return 0;
}
#endif
public virtual int ProcessBytes(byte[] inBytes, int inOff, int inLen, byte[] outBytes, int outOff)
{
Check.DataLength(inBytes, inOff, inLen, "input buffer too short");
data.Write(inBytes, inOff, inLen);
return 0;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
{
data.Write(input);
return 0;
}
#endif
public virtual int DoFinal(byte[] outBytes, int outOff)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return DoFinal(outBytes.AsSpan(outOff));
#else
byte[] input = data.GetBuffer();
int inLen = Convert.ToInt32(data.Length);
int len = ProcessPacket(input, 0, inLen, outBytes, outOff);
Reset();
return len;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual int DoFinal(Span<byte> output)
{
byte[] input = data.GetBuffer();
int inLen = Convert.ToInt32(data.Length);
int len = ProcessPacket(input.AsSpan(0, inLen), output);
Reset();
return len;
}
#endif
public virtual void Reset()
{
associatedText.SetLength(0);
data.SetLength(0);
}
/**
* Returns a byte array containing the mac calculated as part of the
* last encrypt or decrypt operation.
*
* @return the last mac calculated.
*/
public virtual byte[] GetMac()
{
return Arrays.CopyOfRange(macBlock, 0, macSize);
}
public virtual int GetUpdateOutputSize(int len)
{
return 0;
}
public virtual int GetOutputSize(int len)
{
int totalData = Convert.ToInt32(data.Length) + len;
if (forEncryption)
{
return totalData + macSize;
}
return totalData < macSize ? 0 : totalData - macSize;
}
/**
* Process a packet of data for either CCM decryption or encryption.
*
* @param in data for processing.
* @param inOff offset at which data starts in the input array.
* @param inLen length of the data in the input array.
* @return a byte array containing the processed input..
* @throws IllegalStateException if the cipher is not appropriately set up.
* @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
*/
public virtual byte[] ProcessPacket(byte[] input, int inOff, int inLen)
{
byte[] output;
if (forEncryption)
{
output = new byte[inLen + macSize];
}
else
{
if (inLen < macSize)
throw new InvalidCipherTextException("data too short");
output = new byte[inLen - macSize];
}
ProcessPacket(input, inOff, inLen, output, 0);
return output;
}
/**
* Process a packet of data for either CCM decryption or encryption.
*
* @param in data for processing.
* @param inOff offset at which data starts in the input array.
* @param inLen length of the data in the input array.
* @param output output array.
* @param outOff offset into output array to start putting processed bytes.
* @return the number of bytes added to output.
* @throws IllegalStateException if the cipher is not appropriately set up.
* @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
* @throws DataLengthException if output buffer too short.
*/
public virtual int ProcessPacket(byte[] input, int inOff, int inLen, byte[] output, int outOff)
{
// TODO: handle null keyParam (e.g. via RepeatedKeySpec)
// Need to keep the CTR and CBC Mac parts around and reset
if (keyParam == null)
throw new InvalidOperationException("CCM cipher unitialized.");
int n = nonce.Length;
int q = 15 - n;
if (q < 4)
{
int limitLen = 1 << (8 * q);
if (inLen >= limitLen)
throw new InvalidOperationException("CCM packet too large for choice of q.");
}
byte[] iv = new byte[BlockSize];
iv[0] = (byte)((q - 1) & 0x7);
nonce.CopyTo(iv, 1);
IBlockCipher ctrCipher = new FastSicBlockCipher(cipher);
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
int outputLen;
int inIndex = inOff;
int outIndex = outOff;
if (forEncryption)
{
outputLen = inLen + macSize;
Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
CalculateMac(input, inOff, inLen, macBlock);
byte[] encMac = new byte[BlockSize];
ctrCipher.ProcessBlock(macBlock, 0, encMac, 0); // S0
while (inIndex < (inOff + inLen - BlockSize)) // S1...
{
ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
outIndex += BlockSize;
inIndex += BlockSize;
}
byte[] block = new byte[BlockSize];
Array.Copy(input, inIndex, block, 0, inLen + inOff - inIndex);
ctrCipher.ProcessBlock(block, 0, block, 0);
Array.Copy(block, 0, output, outIndex, inLen + inOff - inIndex);
Array.Copy(encMac, 0, output, outOff + inLen, macSize);
}
else
{
if (inLen < macSize)
throw new InvalidCipherTextException("data too short");
outputLen = inLen - macSize;
Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
Array.Copy(input, inOff + outputLen, macBlock, 0, macSize);
ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
for (int i = macSize; i != macBlock.Length; i++)
{
macBlock[i] = 0;
}
while (inIndex < (inOff + outputLen - BlockSize))
{
ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
outIndex += BlockSize;
inIndex += BlockSize;
}
byte[] block = new byte[BlockSize];
Array.Copy(input, inIndex, block, 0, outputLen - (inIndex - inOff));
ctrCipher.ProcessBlock(block, 0, block, 0);
Array.Copy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
byte[] calculatedMacBlock = new byte[BlockSize];
CalculateMac(output, outOff, outputLen, calculatedMacBlock);
if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
throw new InvalidCipherTextException("mac check in CCM failed");
}
return outputLen;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual int ProcessPacket(ReadOnlySpan<byte> input, Span<byte> output)
{
int inLen = input.Length;
// TODO: handle null keyParam (e.g. via RepeatedKeySpec)
// Need to keep the CTR and CBC Mac parts around and reset
if (keyParam == null)
throw new InvalidOperationException("CCM cipher unitialized.");
int n = nonce.Length;
int q = 15 - n;
if (q < 4)
{
int limitLen = 1 << (8 * q);
if (inLen >= limitLen)
throw new InvalidOperationException("CCM packet too large for choice of q.");
}
byte[] iv = new byte[BlockSize];
iv[0] = (byte)((q - 1) & 0x7);
nonce.CopyTo(iv, 1);
IBlockCipher ctrCipher = new SicBlockCipher(cipher);
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
int outputLen;
int index = 0;
Span<byte> block = stackalloc byte[BlockSize];
if (forEncryption)
{
outputLen = inLen + macSize;
Check.OutputLength(output, outputLen, "output buffer too short");
CalculateMac(input, macBlock);
byte[] encMac = new byte[BlockSize];
ctrCipher.ProcessBlock(macBlock, encMac); // S0
while (index < (inLen - BlockSize)) // S1...
{
ctrCipher.ProcessBlock(input[index..], output[index..]);
index += BlockSize;
}
input[index..].CopyTo(block);
ctrCipher.ProcessBlock(block, block);
block[..(inLen - index)].CopyTo(output[index..]);
encMac.AsSpan(0, macSize).CopyTo(output[inLen..]);
}
else
{
if (inLen < macSize)
throw new InvalidCipherTextException("data too short");
outputLen = inLen - macSize;
Check.OutputLength(output, outputLen, "output buffer too short");
input[outputLen..].CopyTo(macBlock);
ctrCipher.ProcessBlock(macBlock, macBlock);
for (int i = macSize; i != macBlock.Length; i++)
{
macBlock[i] = 0;
}
while (index < (outputLen - BlockSize))
{
ctrCipher.ProcessBlock(input[index..], output[index..]);
index += BlockSize;
}
input[index..outputLen].CopyTo(block);
ctrCipher.ProcessBlock(block, block);
block[..(outputLen - index)].CopyTo(output[index..]);
Span<byte> calculatedMacBlock = stackalloc byte[BlockSize];
CalculateMac(output[..outputLen], calculatedMacBlock);
if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
throw new InvalidCipherTextException("mac check in CCM failed");
}
return outputLen;
}
#endif
private int CalculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return CalculateMac(data.AsSpan(dataOff, dataLen), macBlock);
#else
IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
cMac.Init(keyParam);
//
// build b0
//
byte[] b0 = new byte[16];
if (HasAssociatedText())
{
b0[0] |= 0x40;
}
b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
Array.Copy(nonce, 0, b0, 1, nonce.Length);
int q = dataLen;
int count = 1;
while (q > 0)
{
b0[b0.Length - count] = (byte)(q & 0xff);
q >>= 8;
count++;
}
cMac.BlockUpdate(b0, 0, b0.Length);
//
// process associated text
//
if (HasAssociatedText())
{
int extra;
int textLength = GetAssociatedTextLength();
if (textLength < ((1 << 16) - (1 << 8)))
{
cMac.Update((byte)(textLength >> 8));
cMac.Update((byte)textLength);
extra = 2;
}
else // can't go any higher than 2^32
{
cMac.Update((byte)0xff);
cMac.Update((byte)0xfe);
cMac.Update((byte)(textLength >> 24));
cMac.Update((byte)(textLength >> 16));
cMac.Update((byte)(textLength >> 8));
cMac.Update((byte)textLength);
extra = 6;
}
if (initialAssociatedText != null)
{
cMac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
}
if (associatedText.Length > 0)
{
byte[] input = associatedText.GetBuffer();
int len = Convert.ToInt32(associatedText.Length);
cMac.BlockUpdate(input, 0, len);
}
extra = (extra + textLength) % 16;
if (extra != 0)
{
for (int i = extra; i < 16; ++i)
{
cMac.Update((byte)0x00);
}
}
}
//
// add the text
//
cMac.BlockUpdate(data, dataOff, dataLen);
return cMac.DoFinal(macBlock, 0);
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
private int CalculateMac(ReadOnlySpan<byte> data, Span<byte> macBlock)
{
IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
cMac.Init(keyParam);
//
// build b0
//
byte[] b0 = new byte[16];
if (HasAssociatedText())
{
b0[0] |= 0x40;
}
b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
Array.Copy(nonce, 0, b0, 1, nonce.Length);
int q = data.Length;
int count = 1;
while (q > 0)
{
b0[b0.Length - count] = (byte)(q & 0xff);
q >>= 8;
count++;
}
cMac.BlockUpdate(b0, 0, b0.Length);
//
// process associated text
//
if (HasAssociatedText())
{
int extra;
int textLength = GetAssociatedTextLength();
if (textLength < ((1 << 16) - (1 << 8)))
{
cMac.Update((byte)(textLength >> 8));
cMac.Update((byte)textLength);
extra = 2;
}
else // can't go any higher than 2^32
{
cMac.Update((byte)0xff);
cMac.Update((byte)0xfe);
cMac.Update((byte)(textLength >> 24));
cMac.Update((byte)(textLength >> 16));
cMac.Update((byte)(textLength >> 8));
cMac.Update((byte)textLength);
extra = 6;
}
if (initialAssociatedText != null)
{
cMac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
}
if (associatedText.Length > 0)
{
byte[] input = associatedText.GetBuffer();
int len = Convert.ToInt32(associatedText.Length);
cMac.BlockUpdate(input, 0, len);
}
extra = (extra + textLength) % 16;
if (extra != 0)
{
for (int i = extra; i < 16; ++i)
{
cMac.Update((byte)0x00);
}
}
}
//
// add the text
//
cMac.BlockUpdate(data);
return cMac.DoFinal(macBlock);
}
#endif
private int GetMacSize(bool forEncryption, int requestedMacBits)
{
if (forEncryption && (requestedMacBits < 32 || requestedMacBits > 128 || 0 != (requestedMacBits & 15)))
throw new ArgumentException("tag length in octets must be one of {4,6,8,10,12,14,16}");
return requestedMacBits >> 3;
}
private int GetAssociatedTextLength()
{
return Convert.ToInt32(associatedText.Length) +
(initialAssociatedText == null ? 0 : initialAssociatedText.Length);
}
private bool HasAssociatedText()
{
return GetAssociatedTextLength() > 0;
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 017b9fa6887917045ac682f80707a9ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,531 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Runtime.CompilerServices;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/// <summary>
/// Implementation of Daniel J. Bernstein's ChaCha stream cipher.
/// </summary>
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public sealed class FastChaCha7539Engine
: FastSalsa20Engine
{
/// <summary>
/// Creates a 20 rounds ChaCha engine.
/// </summary>
public FastChaCha7539Engine()
: base()
{
}
public override string AlgorithmName
{
get { return "ChaCha7539"; }
}
protected override int NonceSize
{
get { return 12; }
}
protected override void AdvanceCounter()
{
if (++engineState[12] == 0)
throw new InvalidOperationException("attempt to increase counter past 2^32.");
}
protected override void ResetCounter()
{
engineState[12] = 0;
}
protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
{
if (keyBytes != null)
{
if (keyBytes.Length != 32)
throw new ArgumentException(AlgorithmName + " requires 256 bit key");
PackTauOrSigma(keyBytes.Length, engineState, 0);
// Key
Pack.LE_To_UInt32(keyBytes, 0, engineState, 4, 8);
}
// IV
Pack.LE_To_UInt32(ivBytes, 0, engineState, 13, 3);
}
protected override void GenerateKeyStream(byte[] output)
{
FastChaChaEngineHelper.ChachaCore(rounds, engineState, output);
}
internal void DoFinal(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if (index != 0)
throw new InvalidOperationException(AlgorithmName + " not in block-aligned state");
Check.DataLength(inBuf, inOff, inLen, "input buffer too short");
Check.OutputLength(outBuf, outOff, inLen, "output buffer too short");
while (inLen >= 128)
{
#if BESTHTTP_WITH_BURST
FastChaCha7539EngineHelper.ProcessBlocks2(inBuf.AsSpan(inOff), outBuf.AsSpan(outOff), engineState, rounds, keyStream);
#elif NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
//ProcessBlocks2(inBuf.AsSpan(inOff), outBuf.AsSpan(outOff));
var input = inBuf.AsSpan(inOff);
var output = outBuf.AsSpan(outOff);
ImplProcessBlock(inBuf.AsSpan(inOff), outBuf.AsSpan(outOff));
ImplProcessBlock(input[64..], output[64..]);
#else
ProcessBlocks2(inBuf, inOff, outBuf, outOff);
#endif
inOff += 128;
inLen -= 128;
outOff += 128;
}
if (inLen >= 64)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
ImplProcessBlock(inBuf.AsSpan(inOff), outBuf.AsSpan(outOff));
#else
ImplProcessBlock(inBuf, inOff, outBuf, outOff);
#endif
inOff += 64;
inLen -= 64;
outOff += 64;
}
if (inLen > 0)
{
GenerateKeyStream(keyStream);
//AdvanceCounter();
if (++engineState[12] == 0)
throw new InvalidOperationException("attempt to increase counter past 2^32.");
for (int i = 0; i < inLen; ++i)
{
outBuf[outOff + i] = (byte)(inBuf[i + inOff] ^ keyStream[i]);
}
}
engineState[12] = 0;
// TODO Prevent re-use if encrypting
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
internal void ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if (LimitExceeded(64U))
throw new MaxBytesExceededException("2^38 byte limit per IV would be exceeded; Change IV");
UnityEngine.Debug.Assert(index == 0);
ImplProcessBlock(input, output);
}
internal void ProcessBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if (LimitExceeded(128U))
throw new MaxBytesExceededException("2^38 byte limit per IV would be exceeded; Change IV");
UnityEngine.Debug.Assert(index == 0);
#if NETCOREAPP3_0_OR_GREATER
if (Avx2.IsSupported)
{
ImplProcessBlocks2_X86_Avx2(rounds, engineState, input, output);
return;
}
if (Sse2.IsSupported)
{
ImplProcessBlocks2_X86_Sse2(rounds, engineState, input, output);
return;
}
#endif
{
ImplProcessBlock(input, output);
ImplProcessBlock(input[64..], output[64..]);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ImplProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
FastChaChaEngineHelper.ChachaCore(rounds, engineState, keyStream);
//AdvanceCounter();
if (++engineState[12] == 0)
throw new InvalidOperationException("attempt to increase counter past 2^32.");
FastChaChaEngineHelper.ImplProcessBlock(input, output, keyStream);
}
#else
internal void ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if (LimitExceeded(64U))
throw new MaxBytesExceededException("2^38 byte limit per IV would be exceeded; Change IV");
UnityEngine.Debug.Assert(index == 0);
ImplProcessBlock(inBytes, inOff, outBytes, outOff);
}
internal void ProcessBlocks2(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
if (LimitExceeded(128U))
throw new MaxBytesExceededException("2^38 byte limit per IV would be exceeded; Change IV");
UnityEngine.Debug.Assert(index == 0);
{
ImplProcessBlock(inBytes, inOff, outBytes, outOff);
ImplProcessBlock(inBytes, inOff + 64, outBytes, outOff + 64);
}
}
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
internal void ImplProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
{
ChaChaEngine.ChachaCore(rounds, engineState, keyStream);
AdvanceCounter();
for (int i = 0; i < 64; ++i)
{
outBuf[outOff + i] = (byte)(keyStream[i] ^ inBuf[inOff + i]);
}
}
#endif
#if NETCOREAPP3_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void ImplProcessBlocks2_X86_Avx2(int rounds, uint[] state, ReadOnlySpan<byte> input,
Span<byte> output)
{
if (!Avx2.IsSupported)
throw new PlatformNotSupportedException();
Debug.Assert(rounds % 2 == 0);
Debug.Assert(state.Length >= 16);
Debug.Assert(input.Length >= 128);
Debug.Assert(output.Length >= 128);
var t0 = Load128_UInt32(state.AsSpan());
var t1 = Load128_UInt32(state.AsSpan(4));
var t2 = Load128_UInt32(state.AsSpan(8));
var t3 = Load128_UInt32(state.AsSpan(12));
++state[12];
var t4 = Load128_UInt32(state.AsSpan(12));
++state[12];
var x0 = Vector256.Create(t0, t0);
var x1 = Vector256.Create(t1, t1);
var x2 = Vector256.Create(t2, t2);
var x3 = Vector256.Create(t3, t4);
var v0 = x0;
var v1 = x1;
var v2 = x2;
var v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Avx2.Add(v0, v1);
v3 = Avx2.Xor(v3, v0);
v3 = Avx2.Xor(Avx2.ShiftLeftLogical(v3, 16), Avx2.ShiftRightLogical(v3, 16));
v2 = Avx2.Add(v2, v3);
v1 = Avx2.Xor(v1, v2);
v1 = Avx2.Xor(Avx2.ShiftLeftLogical(v1, 12), Avx2.ShiftRightLogical(v1, 20));
v0 = Avx2.Add(v0, v1);
v3 = Avx2.Xor(v3, v0);
v3 = Avx2.Xor(Avx2.ShiftLeftLogical(v3, 8), Avx2.ShiftRightLogical(v3, 24));
v2 = Avx2.Add(v2, v3);
v1 = Avx2.Xor(v1, v2);
v1 = Avx2.Xor(Avx2.ShiftLeftLogical(v1, 7), Avx2.ShiftRightLogical(v1, 25));
v1 = Avx2.Shuffle(v1, 0x39);
v2 = Avx2.Shuffle(v2, 0x4E);
v3 = Avx2.Shuffle(v3, 0x93);
v0 = Avx2.Add(v0, v1);
v3 = Avx2.Xor(v3, v0);
v3 = Avx2.Xor(Avx2.ShiftLeftLogical(v3, 16), Avx2.ShiftRightLogical(v3, 16));
v2 = Avx2.Add(v2, v3);
v1 = Avx2.Xor(v1, v2);
v1 = Avx2.Xor(Avx2.ShiftLeftLogical(v1, 12), Avx2.ShiftRightLogical(v1, 20));
v0 = Avx2.Add(v0, v1);
v3 = Avx2.Xor(v3, v0);
v3 = Avx2.Xor(Avx2.ShiftLeftLogical(v3, 8), Avx2.ShiftRightLogical(v3, 24));
v2 = Avx2.Add(v2, v3);
v1 = Avx2.Xor(v1, v2);
v1 = Avx2.Xor(Avx2.ShiftLeftLogical(v1, 7), Avx2.ShiftRightLogical(v1, 25));
v1 = Avx2.Shuffle(v1, 0x93);
v2 = Avx2.Shuffle(v2, 0x4E);
v3 = Avx2.Shuffle(v3, 0x39);
}
v0 = Avx2.Add(v0, x0);
v1 = Avx2.Add(v1, x1);
v2 = Avx2.Add(v2, x2);
v3 = Avx2.Add(v3, x3);
var n0 = Avx2.Permute2x128(v0, v1, 0x20).AsByte();
var n1 = Avx2.Permute2x128(v2, v3, 0x20).AsByte();
var n2 = Avx2.Permute2x128(v0, v1, 0x31).AsByte();
var n3 = Avx2.Permute2x128(v2, v3, 0x31).AsByte();
n0 = Avx2.Xor(n0, Load256_Byte(input));
n1 = Avx2.Xor(n1, Load256_Byte(input[0x20..]));
n2 = Avx2.Xor(n2, Load256_Byte(input[0x40..]));
n3 = Avx2.Xor(n3, Load256_Byte(input[0x60..]));
Store256_Byte(n0, output);
Store256_Byte(n1, output[0x20..]);
Store256_Byte(n2, output[0x40..]);
Store256_Byte(n3, output[0x60..]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void ImplProcessBlocks2_X86_Sse2(int rounds, uint[] state, ReadOnlySpan<byte> input,
Span<byte> output)
{
if (!Sse2.IsSupported)
throw new PlatformNotSupportedException();
Debug.Assert(rounds % 2 == 0);
Debug.Assert(state.Length >= 16);
Debug.Assert(input.Length >= 128);
Debug.Assert(output.Length >= 128);
var x0 = Load128_UInt32(state.AsSpan());
var x1 = Load128_UInt32(state.AsSpan(4));
var x2 = Load128_UInt32(state.AsSpan(8));
var x3 = Load128_UInt32(state.AsSpan(12));
++state[12];
var v0 = x0;
var v1 = x1;
var v2 = x2;
var v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 16), Sse2.ShiftRightLogical(v3, 16));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 12), Sse2.ShiftRightLogical(v1, 20));
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 8), Sse2.ShiftRightLogical(v3, 24));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 7), Sse2.ShiftRightLogical(v1, 25));
v1 = Sse2.Shuffle(v1, 0x39);
v2 = Sse2.Shuffle(v2, 0x4E);
v3 = Sse2.Shuffle(v3, 0x93);
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 16), Sse2.ShiftRightLogical(v3, 16));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 12), Sse2.ShiftRightLogical(v1, 20));
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 8), Sse2.ShiftRightLogical(v3, 24));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 7), Sse2.ShiftRightLogical(v1, 25));
v1 = Sse2.Shuffle(v1, 0x93);
v2 = Sse2.Shuffle(v2, 0x4E);
v3 = Sse2.Shuffle(v3, 0x39);
}
v0 = Sse2.Add(v0, x0);
v1 = Sse2.Add(v1, x1);
v2 = Sse2.Add(v2, x2);
v3 = Sse2.Add(v3, x3);
var n0 = Load128_Byte(input);
var n1 = Load128_Byte(input[0x10..]);
var n2 = Load128_Byte(input[0x20..]);
var n3 = Load128_Byte(input[0x30..]);
n0 = Sse2.Xor(n0, v0.AsByte());
n1 = Sse2.Xor(n1, v1.AsByte());
n2 = Sse2.Xor(n2, v2.AsByte());
n3 = Sse2.Xor(n3, v3.AsByte());
Store128_Byte(n0, output);
Store128_Byte(n1, output[0x10..]);
Store128_Byte(n2, output[0x20..]);
Store128_Byte(n3, output[0x30..]);
x3 = Load128_UInt32(state.AsSpan(12));
++state[12];
v0 = x0;
v1 = x1;
v2 = x2;
v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 16), Sse2.ShiftRightLogical(v3, 16));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 12), Sse2.ShiftRightLogical(v1, 20));
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 8), Sse2.ShiftRightLogical(v3, 24));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 7), Sse2.ShiftRightLogical(v1, 25));
v1 = Sse2.Shuffle(v1, 0x39);
v2 = Sse2.Shuffle(v2, 0x4E);
v3 = Sse2.Shuffle(v3, 0x93);
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 16), Sse2.ShiftRightLogical(v3, 16));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 12), Sse2.ShiftRightLogical(v1, 20));
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 8), Sse2.ShiftRightLogical(v3, 24));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 7), Sse2.ShiftRightLogical(v1, 25));
v1 = Sse2.Shuffle(v1, 0x93);
v2 = Sse2.Shuffle(v2, 0x4E);
v3 = Sse2.Shuffle(v3, 0x39);
}
v0 = Sse2.Add(v0, x0);
v1 = Sse2.Add(v1, x1);
v2 = Sse2.Add(v2, x2);
v3 = Sse2.Add(v3, x3);
n0 = Load128_Byte(input[0x40..]);
n1 = Load128_Byte(input[0x50..]);
n2 = Load128_Byte(input[0x60..]);
n3 = Load128_Byte(input[0x70..]);
n0 = Sse2.Xor(n0, v0.AsByte());
n1 = Sse2.Xor(n1, v1.AsByte());
n2 = Sse2.Xor(n2, v2.AsByte());
n3 = Sse2.Xor(n3, v3.AsByte());
Store128_Byte(n0, output[0x40..]);
Store128_Byte(n1, output[0x50..]);
Store128_Byte(n2, output[0x60..]);
Store128_Byte(n3, output[0x70..]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> Load128_Byte(ReadOnlySpan<byte> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
return MemoryMarshal.Read<Vector128<byte>>(t);
return Vector128.Create(
BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
).AsByte();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<uint> Load128_UInt32(ReadOnlySpan<uint> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
return MemoryMarshal.Read<Vector128<uint>>(MemoryMarshal.AsBytes(t));
return Vector128.Create(t[0], t[1], t[2], t[3]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector256<byte> Load256_Byte(ReadOnlySpan<byte> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
return MemoryMarshal.Read<Vector256<byte>>(t);
return Vector256.Create(
BinaryPrimitives.ReadUInt64LittleEndian(t[ 0.. 8]),
BinaryPrimitives.ReadUInt64LittleEndian(t[ 8..16]),
BinaryPrimitives.ReadUInt64LittleEndian(t[16..24]),
BinaryPrimitives.ReadUInt64LittleEndian(t[24..32])
).AsByte();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Store128_Byte(Vector128<byte> s, Span<byte> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
{
MemoryMarshal.Write(t, ref s);
return;
}
var u = s.AsUInt64();
BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Store256_Byte(Vector256<byte> s, Span<byte> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
{
MemoryMarshal.Write(t, ref s);
return;
}
var u = s.AsUInt64();
BinaryPrimitives.WriteUInt64LittleEndian(t[ 0.. 8], u.GetElement(0));
BinaryPrimitives.WriteUInt64LittleEndian(t[ 8..16], u.GetElement(1));
BinaryPrimitives.WriteUInt64LittleEndian(t[16..24], u.GetElement(2));
BinaryPrimitives.WriteUInt64LittleEndian(t[24..32], u.GetElement(3));
}
#endif
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 265fa53fa94a97e4fb0c6ab738d53f4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,484 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) && BESTHTTP_WITH_BURST
using System;
using System.Runtime.CompilerServices;
using Unity.Burst;
using Unity.Burst.Intrinsics;
using static Unity.Burst.Intrinsics.X86;
using static Unity.Burst.Intrinsics.Arm;
// https://github.com/sschoener/burst-simd-exercises/blob/main/Assets/Examples/2-sum-small-numbers-sse3/SumSmallNumbers_SSE3.cs
// https://github.com/jratcliff63367/sse2neon/blob/master/SSE2NEON.h#L789
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
[BurstCompile]
public unsafe static class FastChaCha7539EngineHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ProcessBlocks2(ReadOnlySpan<byte> input, Span<byte> output, uint[] state, int rounds, byte[] keyStream)
{
fixed (byte* pinput = input)
fixed (byte* poutput = output)
fixed (uint* pstate = state)
fixed(byte* pkeyStream = keyStream)
ProcessBlocks2Impl(pinput, input.Length, poutput, output.Length, pstate, state.Length, rounds, pkeyStream);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[BurstCompile(CompileSynchronously = true)]
private static void ProcessBlocks2Impl([NoAlias] byte* input, int inputLen, [NoAlias] byte* output, int outLen, [NoAlias] uint* state, int stateLen, int rounds, [NoAlias] byte* keyStream)
{
if (Avx2.IsAvx2Supported)
{
var t0 = new v128(state[0], state[1], state[2], state[3]); //Load128_UInt32(state.AsSpan());
var t1 = new v128(state[4], state[5], state[6], state[7]); //Load128_UInt32(state.AsSpan(4));
var t2 = new v128(state[8], state[9], state[10], state[11]); //Load128_UInt32(state.AsSpan(8));
var t3 = new v128(state[12], state[13], state[14], state[15]); //Load128_UInt32(state.AsSpan(12));
++state[12];
var t4 = new v128(state[12], state[13], state[14], state[15]); //Load128_UInt32(state.AsSpan(12));
++state[12];
var x0 = new v256(t0, t0); //Vector256.Create(t0, t0);
var x1 = new v256(t1, t1); //Vector256.Create(t1, t1);
var x2 = new v256(t2, t2); //Vector256.Create(t2, t2);
var x3 = new v256(t3, t4); //Vector256.Create(t3, t4);
var v0 = x0;
var v1 = x1;
var v2 = x2;
var v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Avx2.mm256_add_epi32(v0, v1);
v3 = Avx2.mm256_xor_si256(v3, v0);
v3 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v3, 16), Avx2.mm256_srli_epi32(v3, 16));
v2 = Avx2.mm256_add_epi32(v2, v3);
v1 = Avx2.mm256_xor_si256(v1, v2);
v1 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v1, 12), Avx2.mm256_srli_epi32(v1, 20));
v0 = Avx2.mm256_add_epi32(v0, v1);
v3 = Avx2.mm256_xor_si256(v3, v0);
v3 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v3, 8), Avx2.mm256_srli_epi32(v3, 24));
v2 = Avx2.mm256_add_epi32(v2, v3);
v1 = Avx2.mm256_xor_si256(v1, v2);
v1 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v1, 7), Avx2.mm256_srli_epi32(v1, 25));
v1 = Avx2.mm256_shuffle_epi32(v1, 0x39);
v2 = Avx2.mm256_shuffle_epi32(v2, 0x4E);
v3 = Avx2.mm256_shuffle_epi32(v3, 0x93);
v0 = Avx2.mm256_add_epi32(v0, v1);
v3 = Avx2.mm256_xor_si256(v3, v0);
v3 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v3, 16), Avx2.mm256_srli_epi32(v3, 16));
v2 = Avx2.mm256_add_epi32(v2, v3);
v1 = Avx2.mm256_xor_si256(v1, v2);
v1 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v1, 12), Avx2.mm256_srli_epi32(v1, 20));
v0 = Avx2.mm256_add_epi32(v0, v1);
v3 = Avx2.mm256_xor_si256(v3, v0);
v3 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v3, 8), Avx2.mm256_srli_epi32(v3, 24));
v2 = Avx2.mm256_add_epi32(v2, v3);
v1 = Avx2.mm256_xor_si256(v1, v2);
v1 = Avx2.mm256_xor_si256(Avx2.mm256_slli_epi32(v1, 7), Avx2.mm256_srli_epi32(v1, 25));
v1 = Avx2.mm256_shuffle_epi32(v1, 0x93);
v2 = Avx2.mm256_shuffle_epi32(v2, 0x4E);
v3 = Avx2.mm256_shuffle_epi32(v3, 0x39);
}
v0 = Avx2.mm256_add_epi32(v0, x0);
v1 = Avx2.mm256_add_epi32(v1, x1);
v2 = Avx2.mm256_add_epi32(v2, x2);
v3 = Avx2.mm256_add_epi32(v3, x3);
var n0 = Avx2.mm256_permute2x128_si256(v0, v1, 0x20);
var n1 = Avx2.mm256_permute2x128_si256(v2, v3, 0x20);
var n2 = Avx2.mm256_permute2x128_si256(v0, v1, 0x31);
var n3 = Avx2.mm256_permute2x128_si256(v2, v3, 0x31);
ulong* uInput = (ulong*)input;
n0 = Avx2.mm256_xor_si256(n0, new v256(uInput[0], uInput[1], uInput[2], uInput[3])); // Load256_Byte(input)
n1 = Avx2.mm256_xor_si256(n1, new v256(uInput[4], uInput[5], uInput[6], uInput[7])); // Load256_Byte(input[0x20..])
n2 = Avx2.mm256_xor_si256(n2, new v256(uInput[8], uInput[9], uInput[10], uInput[11])); // Load256_Byte(input[0x40..])
n3 = Avx2.mm256_xor_si256(n3, new v256(uInput[12], uInput[13], uInput[14], uInput[15])); // Load256_Byte(input[0x60..])
ulong* uOutput = (ulong*)output;
uOutput[0] = n0.ULong0; uOutput[1] = n0.ULong1; uOutput[2] = n0.ULong2; uOutput[3] = n0.ULong3; //Store256_Byte(n0, output);
uOutput[4] = n1.ULong0; uOutput[5] = n1.ULong1; uOutput[6] = n1.ULong2; uOutput[7] = n1.ULong3; //Store256_Byte(n1, output[0x20..]);
uOutput[8] = n2.ULong0; uOutput[9] = n2.ULong1; uOutput[10] = n2.ULong2; uOutput[11] = n2.ULong3; //Store256_Byte(n2, output[0x40..]);
uOutput[12] = n3.ULong0; uOutput[13] = n3.ULong1; uOutput[14] = n3.ULong2; uOutput[15] = n3.ULong3; //Store256_Byte(n3, output[0x60..]);
}
else if (Sse2.IsSse2Supported)
{
var x0 = Sse2.loadu_si128(state); //new v128(state[0], state[1], state[2], state[3]); //Load128_UInt32(state.AsSpan());
var x1 = Sse2.loadu_si128(state + 4); //new v128(state[4], state[5], state[6], state[7]); //Load128_UInt32(state.AsSpan(4));
var x2 = Sse2.loadu_si128(state + 8); //new v128(state[8], state[9], state[10], state[11]); //Load128_UInt32(state.AsSpan(8));
var x3 = Sse2.loadu_si128(state + 12); //new v128(state[12], state[13], state[14], state[15]); //Load128_UInt32(state.AsSpan(12));
++state[12];
var v0 = x0;
var v1 = x1;
var v2 = x2;
var v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 16), Sse2.srli_epi32(v3, 16));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 12), Sse2.srli_epi32(v1, 20));
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 8), Sse2.srli_epi32(v3, 24));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 7), Sse2.srli_epi32(v1, 25));
v1 = Sse2.shuffle_epi32(v1, 0x39);
v2 = Sse2.shuffle_epi32(v2, 0x4E);
v3 = Sse2.shuffle_epi32(v3, 0x93);
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 16), Sse2.srli_epi32(v3, 16));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 12), Sse2.srli_epi32(v1, 20));
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 8), Sse2.srli_epi32(v3, 24));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 7), Sse2.srli_epi32(v1, 25));
v1 = Sse2.shuffle_epi32(v1, 0x93);
v2 = Sse2.shuffle_epi32(v2, 0x4E);
v3 = Sse2.shuffle_epi32(v3, 0x39);
}
v0 = Sse2.add_epi32(v0, x0);
v1 = Sse2.add_epi32(v1, x1);
v2 = Sse2.add_epi32(v2, x2);
v3 = Sse2.add_epi32(v3, x3);
var n0 = Sse2.loadu_si128(input + 0x00); //Load128_Byte(input);
var n1 = Sse2.loadu_si128(input + 0x10); //Load128_Byte(input[0x10..]);
var n2 = Sse2.loadu_si128(input + 0x20); //Load128_Byte(input[0x20..]);
var n3 = Sse2.loadu_si128(input + 0x30); //Load128_Byte(input[0x30..]);
n0 = Sse2.xor_si128(n0, v0);
n1 = Sse2.xor_si128(n1, v1);
n2 = Sse2.xor_si128(n2, v2);
n3 = Sse2.xor_si128(n3, v3);
Sse2.storeu_si128(output + 0x00, n0); //Store128_Byte(n0, output);
Sse2.storeu_si128(output + 0x10, n1); //Store128_Byte(n1, output[0x10..]);
Sse2.storeu_si128(output + 0x20, n2); //Store128_Byte(n2, output[0x20..]);
Sse2.storeu_si128(output + 0x30, n3); //Store128_Byte(n3, output[0x30..]);
x3 = Sse2.loadu_si128(state + 12); // Load128_UInt32(state.AsSpan(12));
++state[12];
v0 = x0;
v1 = x1;
v2 = x2;
v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 16), Sse2.srli_epi32(v3, 16));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 12), Sse2.srli_epi32(v1, 20));
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 8), Sse2.srli_epi32(v3, 24));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 7), Sse2.srli_epi32(v1, 25));
v1 = Sse2.shuffle_epi32(v1, 0x39);
v2 = Sse2.shuffle_epi32(v2, 0x4E);
v3 = Sse2.shuffle_epi32(v3, 0x93);
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 16), Sse2.srli_epi32(v3, 16));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 12), Sse2.srli_epi32(v1, 20));
v0 = Sse2.add_epi32(v0, v1);
v3 = Sse2.xor_si128(v3, v0);
v3 = Sse2.xor_si128(Sse2.slli_epi32(v3, 8), Sse2.srli_epi32(v3, 24));
v2 = Sse2.add_epi32(v2, v3);
v1 = Sse2.xor_si128(v1, v2);
v1 = Sse2.xor_si128(Sse2.slli_epi32(v1, 7), Sse2.srli_epi32(v1, 25));
v1 = Sse2.shuffle_epi32(v1, 0x93);
v2 = Sse2.shuffle_epi32(v2, 0x4E);
v3 = Sse2.shuffle_epi32(v3, 0x39);
}
v0 = Sse2.add_epi32(v0, x0);
v1 = Sse2.add_epi32(v1, x1);
v2 = Sse2.add_epi32(v2, x2);
v3 = Sse2.add_epi32(v3, x3);
n0 = Sse2.loadu_si128(input + 0x40); //Load128_Byte(input[0x40..]);
n1 = Sse2.loadu_si128(input + 0x50); //Load128_Byte(input[0x50..]);
n2 = Sse2.loadu_si128(input + 0x60); //Load128_Byte(input[0x60..]);
n3 = Sse2.loadu_si128(input + 0x70); //Load128_Byte(input[0x70..]);
n0 = Sse2.xor_si128(n0, v0);
n1 = Sse2.xor_si128(n1, v1);
n2 = Sse2.xor_si128(n2, v2);
n3 = Sse2.xor_si128(n3, v3);
Sse2.storeu_si128(output + 0x40, n0); //Store128_Byte(n0, output[0x40..]);
Sse2.storeu_si128(output + 0x50, n1); //Store128_Byte(n1, output[0x50..]);
Sse2.storeu_si128(output + 0x60, n2); //Store128_Byte(n2, output[0x60..]);
Sse2.storeu_si128(output + 0x70, n3); //Store128_Byte(n3, output[0x70..]);
}
else if (Neon.IsNeonSupported)
{
var x0 = Neon.vld1q_u32(state); //new v128(state[0], state[1], state[2], state[3]); //Load128_UInt32(state.AsSpan());
var x1 = Neon.vld1q_u32(state + 4); //new v128(state[4], state[5], state[6], state[7]); //Load128_UInt32(state.AsSpan(4));
var x2 = Neon.vld1q_u32(state + 8); //new v128(state[8], state[9], state[10], state[11]); //Load128_UInt32(state.AsSpan(8));
var x3 = Neon.vld1q_u32(state + 12);
++state[12];
var v0 = x0;
var v1 = x1;
var v2 = x2;
var v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 16), Neon.vshrq_n_u32(v3, 16));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 12), Neon.vshrq_n_u32(v1, 20));
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 8), Neon.vshrq_n_u32(v3, 24));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 7), Neon.vshrq_n_u32(v1, 25));
///*v1 = */Neon_shuffle_epi32(v1, 0x39, out v1);
v128 ret;
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v1, (0x39) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x39) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x39) >> 4) & 0x3), ret, 2);
v1 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x39) >> 6) & 0x3), ret, 3);
///*v2 = */Neon_shuffle_epi32(v2, 0x4E, out v2);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v2, (0x4E) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 4) & 0x3), ret, 2);
v2 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 6) & 0x3), ret, 3);
///*v3 = */Neon_shuffle_epi32(v3, 0x93, out v3);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v3, (0x93) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x93) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x93) >> 4) & 0x3), ret, 2);
v3 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x93) >> 6) & 0x3), ret, 3);
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 16), Neon.vshrq_n_u32(v3, 16));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 12), Neon.vshrq_n_u32(v1, 20));
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 8), Neon.vshrq_n_u32(v3, 24));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 7), Neon.vshrq_n_u32(v1, 25));
///*v1 = */Neon_shuffle_epi32(v1, 0x93, out v1);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v1, (0x93) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x93) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x93) >> 4) & 0x3), ret, 2);
v1 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x93) >> 6) & 0x3), ret, 3);
///*v2 = */Neon_shuffle_epi32(v2, 0x4E, out v2);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v2, (0x4E) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 4) & 0x3), ret, 2);
v2 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 6) & 0x3), ret, 3);
///*v3 = */Neon_shuffle_epi32(v3, 0x39, out v3);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v3, (0x39) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x39) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x39) >> 4) & 0x3), ret, 2);
v3 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x39) >> 6) & 0x3), ret, 3);
}
v0 = Neon.vaddq_u32(v0, x0);
v1 = Neon.vaddq_u32(v1, x1);
v2 = Neon.vaddq_u32(v2, x2);
v3 = Neon.vaddq_u32(v3, x3);
var n0 = Neon.vld1q_u32((uint*)(input + 0x00)); //Load128_Byte(input);
var n1 = Neon.vld1q_u32((uint*)(input + 0x10)); //Load128_Byte(input[0x10..]);
var n2 = Neon.vld1q_u32((uint*)(input + 0x20)); //Load128_Byte(input[0x20..]);
var n3 = Neon.vld1q_u32((uint*)(input + 0x30)); //Load128_Byte(input[0x30..]);
n0 = Neon.veorq_u32(n0, v0);
n1 = Neon.veorq_u32(n1, v1);
n2 = Neon.veorq_u32(n2, v2);
n3 = Neon.veorq_u32(n3, v3);
Neon.vst1q_u32((uint*)(output + 0x00), n0); //Store128_Byte(n0, output);
Neon.vst1q_u32((uint*)(output + 0x10), n1); //Store128_Byte(n1, output[0x10..]);
Neon.vst1q_u32((uint*)(output + 0x20), n2); //Store128_Byte(n2, output[0x20..]);
Neon.vst1q_u32((uint*)(output + 0x30), n3); //Store128_Byte(n3, output[0x30..]);
x3 = Neon.vld1q_u32(state + 12); // Load128_UInt32(state.AsSpan(12));
++state[12];
v0 = x0;
v1 = x1;
v2 = x2;
v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 16), Neon.vshrq_n_u32(v3, 16));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 12), Neon.vshrq_n_u32(v1, 20));
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 8), Neon.vshrq_n_u32(v3, 24));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 7), Neon.vshrq_n_u32(v1, 25));
///*v1 = */Neon_shuffle_epi32(v1, 0x39, out v1);
v128 ret;
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v1, (0x39) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x39) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x39) >> 4) & 0x3), ret, 2);
v1 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x39) >> 6) & 0x3), ret, 3);
///*v2 = */Neon_shuffle_epi32(v2, 0x4E, out v2);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v2, (0x4E) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 4) & 0x3), ret, 2);
v2 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 6) & 0x3), ret, 3);
///*v3 = */Neon_shuffle_epi32(v3, 0x93, out v3);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v3, (0x93) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x93) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x93) >> 4) & 0x3), ret, 2);
v3 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x93) >> 6) & 0x3), ret, 3);
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 16), Neon.vshrq_n_u32(v3, 16));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 12), Neon.vshrq_n_u32(v1, 20));
v0 = Neon.vaddq_u32(v0, v1);
v3 = Neon.veorq_u32(v3, v0);
v3 = Neon.veorq_u32(Neon.vshlq_n_u32(v3, 8), Neon.vshrq_n_u32(v3, 24));
v2 = Neon.vaddq_u32(v2, v3);
v1 = Neon.veorq_u32(v1, v2);
v1 = Neon.veorq_u32(Neon.vshlq_n_u32(v1, 7), Neon.vshrq_n_u32(v1, 25));
///*v1 = */Neon_shuffle_epi32(v1, 0x93, out v1);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v1, (0x93) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x93) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x93) >> 4) & 0x3), ret, 2);
v1 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v1, ((0x93) >> 6) & 0x3), ret, 3);
///*v2 = */Neon_shuffle_epi32(v2, 0x4E, out v2);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v2, (0x4E) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 4) & 0x3), ret, 2);
v2 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v2, ((0x4E) >> 6) & 0x3), ret, 3);
///*v3 = */Neon_shuffle_epi32(v3, 0x39, out v3);
ret = Neon.vmovq_n_u32(Neon.vgetq_lane_u32(v3, (0x39) & 0x3));
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x39) >> 2) & 0x3), ret, 1);
ret = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x39) >> 4) & 0x3), ret, 2);
v3 = Neon.vsetq_lane_u32(Neon.vgetq_lane_u32(v3, ((0x39) >> 6) & 0x3), ret, 3);
}
v0 = Neon.vaddq_u32(v0, x0);
v1 = Neon.vaddq_u32(v1, x1);
v2 = Neon.vaddq_u32(v2, x2);
v3 = Neon.vaddq_u32(v3, x3);
n0 = Neon.vld1q_u32((uint*)(input + 0x40)); //Load128_Byte(input[0x40..]);
n1 = Neon.vld1q_u32((uint*)(input + 0x50)); //Load128_Byte(input[0x50..]);
n2 = Neon.vld1q_u32((uint*)(input + 0x60)); //Load128_Byte(input[0x60..]);
n3 = Neon.vld1q_u32((uint*)(input + 0x70)); //Load128_Byte(input[0x70..]);
n0 = Neon.veorq_u32(n0, v0);
n1 = Neon.veorq_u32(n1, v1);
n2 = Neon.veorq_u32(n2, v2);
n3 = Neon.veorq_u32(n3, v3);
Neon.vst1q_u32((uint*)(output + 0x40), n0); //Store128_Byte(n0, output[0x40..]);
Neon.vst1q_u32((uint*)(output + 0x50), n1); //Store128_Byte(n1, output[0x50..]);
Neon.vst1q_u32((uint*)(output + 0x60), n2); //Store128_Byte(n2, output[0x60..]);
Neon.vst1q_u32((uint*)(output + 0x70), n3); //Store128_Byte(n3, output[0x70..]);
}
else
{
// Inlined to two ImplProcessBlock calls:
//ImplProcessBlock(input, output);
//ImplProcessBlock(input[64..], output[64..]);
FastChaChaEngineHelper.ChachaCoreImpl(rounds, state, keyStream);
++state[12];
ulong* pulinput = (ulong*)input;
ulong* puloutput = (ulong*)output;
ulong* pulkeyStream = (ulong*)keyStream;
puloutput[0] = pulkeyStream[0] ^ pulinput[0];
puloutput[1] = pulkeyStream[1] ^ pulinput[1];
puloutput[2] = pulkeyStream[2] ^ pulinput[2];
puloutput[3] = pulkeyStream[3] ^ pulinput[3];
puloutput[4] = pulkeyStream[4] ^ pulinput[4];
puloutput[5] = pulkeyStream[5] ^ pulinput[5];
puloutput[6] = pulkeyStream[6] ^ pulinput[6];
puloutput[7] = pulkeyStream[7] ^ pulinput[7];
FastChaChaEngineHelper.ChachaCoreImpl(rounds, state, keyStream);
++state[12];
pulinput = (ulong*)&input[64];
puloutput = (ulong*)&output[64];
puloutput[0] = pulkeyStream[0] ^ pulinput[0];
puloutput[1] = pulkeyStream[1] ^ pulinput[1];
puloutput[2] = pulkeyStream[2] ^ pulinput[2];
puloutput[3] = pulkeyStream[3] ^ pulinput[3];
puloutput[4] = pulkeyStream[4] ^ pulinput[4];
puloutput[5] = pulkeyStream[5] ^ pulinput[5];
puloutput[6] = pulkeyStream[6] ^ pulinput[6];
puloutput[7] = pulkeyStream[7] ^ pulinput[7];
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f659fd4b1e907e64c82229d4a0b83341
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,249 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Diagnostics;
#if NETCOREAPP3_0_OR_GREATER
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#endif
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/// <summary>
/// Implementation of Daniel J. Bernstein's ChaCha stream cipher.
/// </summary>
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public sealed class FastChaChaEngine
: FastSalsa20Engine
{
/// <summary>
/// Creates a 20 rounds ChaCha engine.
/// </summary>
public FastChaChaEngine()
{
}
/// <summary>
/// Creates a ChaCha engine with a specific number of rounds.
/// </summary>
/// <param name="rounds">the number of rounds (must be an even number).</param>
public FastChaChaEngine(int rounds)
: base(rounds)
{
}
public override string AlgorithmName
{
get { return "ChaCha" + rounds; }
}
protected override void AdvanceCounter()
{
if (++engineState[12] == 0)
{
++engineState[13];
}
}
protected override void ResetCounter()
{
engineState[12] = engineState[13] = 0;
}
protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
{
if (keyBytes != null)
{
if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
PackTauOrSigma(keyBytes.Length, engineState, 0);
// Key
Pack.LE_To_UInt32(keyBytes, 0, engineState, 4, 4);
Pack.LE_To_UInt32(keyBytes, keyBytes.Length - 16, engineState, 8, 4);
}
// IV
Pack.LE_To_UInt32(ivBytes, 0, engineState, 14, 2);
}
protected override void GenerateKeyStream(byte[] output)
{
//ChachaCore(rounds, engineState, output);
FastChaChaEngineHelper.ChachaCore(rounds, engineState, output);
}
internal static void ChachaCore(int rounds, uint[] input, byte[] output)
{
Debug.Assert(rounds % 2 == 0);
Debug.Assert(input.Length >= 16);
Debug.Assert(output.Length >= 64);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported)
{
var x0 = Load128_UInt32(input.AsSpan());
var x1 = Load128_UInt32(input.AsSpan(4));
var x2 = Load128_UInt32(input.AsSpan(8));
var x3 = Load128_UInt32(input.AsSpan(12));
var v0 = x0;
var v1 = x1;
var v2 = x2;
var v3 = x3;
for (int i = rounds; i > 0; i -= 2)
{
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 16), Sse2.ShiftRightLogical(v3, 16));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 12), Sse2.ShiftRightLogical(v1, 20));
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 8), Sse2.ShiftRightLogical(v3, 24));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 7), Sse2.ShiftRightLogical(v1, 25));
v1 = Sse2.Shuffle(v1, 0x39);
v2 = Sse2.Shuffle(v2, 0x4E);
v3 = Sse2.Shuffle(v3, 0x93);
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 16), Sse2.ShiftRightLogical(v3, 16));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 12), Sse2.ShiftRightLogical(v1, 20));
v0 = Sse2.Add(v0, v1);
v3 = Sse2.Xor(v3, v0);
v3 = Sse2.Xor(Sse2.ShiftLeftLogical(v3, 8), Sse2.ShiftRightLogical(v3, 24));
v2 = Sse2.Add(v2, v3);
v1 = Sse2.Xor(v1, v2);
v1 = Sse2.Xor(Sse2.ShiftLeftLogical(v1, 7), Sse2.ShiftRightLogical(v1, 25));
v1 = Sse2.Shuffle(v1, 0x93);
v2 = Sse2.Shuffle(v2, 0x4E);
v3 = Sse2.Shuffle(v3, 0x39);
}
v0 = Sse2.Add(v0, x0);
v1 = Sse2.Add(v1, x1);
v2 = Sse2.Add(v2, x2);
v3 = Sse2.Add(v3, x3);
Store128_UInt32(v0, output.AsSpan());
Store128_UInt32(v1, output.AsSpan(0x10));
Store128_UInt32(v2, output.AsSpan(0x20));
Store128_UInt32(v3, output.AsSpan(0x30));
return;
}
#endif
{
uint x00 = input[0], x01 = input[1], x02 = input[2], x03 = input[3];
uint x04 = input[4], x05 = input[5], x06 = input[6], x07 = input[7];
uint x08 = input[8], x09 = input[9], x10 = input[10], x11 = input[11];
uint x12 = input[12], x13 = input[13], x14 = input[14], x15 = input[15];
for (int i = rounds; i > 0; i -= 2)
{
x00 += x04; x12 = Integers.RotateLeft(x12 ^ x00, 16);
x01 += x05; x13 = Integers.RotateLeft(x13 ^ x01, 16);
x02 += x06; x14 = Integers.RotateLeft(x14 ^ x02, 16);
x03 += x07; x15 = Integers.RotateLeft(x15 ^ x03, 16);
x08 += x12; x04 = Integers.RotateLeft(x04 ^ x08, 12);
x09 += x13; x05 = Integers.RotateLeft(x05 ^ x09, 12);
x10 += x14; x06 = Integers.RotateLeft(x06 ^ x10, 12);
x11 += x15; x07 = Integers.RotateLeft(x07 ^ x11, 12);
x00 += x04; x12 = Integers.RotateLeft(x12 ^ x00, 8);
x01 += x05; x13 = Integers.RotateLeft(x13 ^ x01, 8);
x02 += x06; x14 = Integers.RotateLeft(x14 ^ x02, 8);
x03 += x07; x15 = Integers.RotateLeft(x15 ^ x03, 8);
x08 += x12; x04 = Integers.RotateLeft(x04 ^ x08, 7);
x09 += x13; x05 = Integers.RotateLeft(x05 ^ x09, 7);
x10 += x14; x06 = Integers.RotateLeft(x06 ^ x10, 7);
x11 += x15; x07 = Integers.RotateLeft(x07 ^ x11, 7);
x00 += x05; x15 = Integers.RotateLeft(x15 ^ x00, 16);
x01 += x06; x12 = Integers.RotateLeft(x12 ^ x01, 16);
x02 += x07; x13 = Integers.RotateLeft(x13 ^ x02, 16);
x03 += x04; x14 = Integers.RotateLeft(x14 ^ x03, 16);
x10 += x15; x05 = Integers.RotateLeft(x05 ^ x10, 12);
x11 += x12; x06 = Integers.RotateLeft(x06 ^ x11, 12);
x08 += x13; x07 = Integers.RotateLeft(x07 ^ x08, 12);
x09 += x14; x04 = Integers.RotateLeft(x04 ^ x09, 12);
x00 += x05; x15 = Integers.RotateLeft(x15 ^ x00, 8);
x01 += x06; x12 = Integers.RotateLeft(x12 ^ x01, 8);
x02 += x07; x13 = Integers.RotateLeft(x13 ^ x02, 8);
x03 += x04; x14 = Integers.RotateLeft(x14 ^ x03, 8);
x10 += x15; x05 = Integers.RotateLeft(x05 ^ x10, 7);
x11 += x12; x06 = Integers.RotateLeft(x06 ^ x11, 7);
x08 += x13; x07 = Integers.RotateLeft(x07 ^ x08, 7);
x09 += x14; x04 = Integers.RotateLeft(x04 ^ x09, 7);
}
Pack.UInt32_To_LE(x00 + input[0], output, 0);
Pack.UInt32_To_LE(x01 + input[1], output, 4);
Pack.UInt32_To_LE(x02 + input[2], output, 8);
Pack.UInt32_To_LE(x03 + input[3], output, 12);
Pack.UInt32_To_LE(x04 + input[4], output, 16);
Pack.UInt32_To_LE(x05 + input[5], output, 20);
Pack.UInt32_To_LE(x06 + input[6], output, 24);
Pack.UInt32_To_LE(x07 + input[7], output, 28);
Pack.UInt32_To_LE(x08 + input[8], output, 32);
Pack.UInt32_To_LE(x09 + input[9], output, 36);
Pack.UInt32_To_LE(x10 + input[10], output, 40);
Pack.UInt32_To_LE(x11 + input[11], output, 44);
Pack.UInt32_To_LE(x12 + input[12], output, 48);
Pack.UInt32_To_LE(x13 + input[13], output, 52);
Pack.UInt32_To_LE(x14 + input[14], output, 56);
Pack.UInt32_To_LE(x15 + input[15], output, 60);
}
}
#if NETCOREAPP3_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<uint> Load128_UInt32(ReadOnlySpan<uint> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
return MemoryMarshal.Read<Vector128<uint>>(MemoryMarshal.AsBytes(t));
return Vector128.Create(t[0], t[1], t[2], t[3]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Store128_UInt32(Vector128<uint> s, Span<byte> t)
{
if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
{
MemoryMarshal.Write(t, ref s);
return;
}
var u = s.AsUInt64();
BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
}
#endif
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: da7d76cfa0d2599459593226dc3959aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,124 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Runtime.CompilerServices;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
#if BESTHTTP_WITH_BURST
using Unity.Burst;
#endif
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
#if BESTHTTP_WITH_BURST
[Unity.Burst.BurstCompile]
#endif
internal static class FastChaChaEngineHelper
{
internal unsafe static void ChachaCore(int rounds, uint[] input, byte[] output)
{
fixed (uint* pinput = input)
fixed (byte* poutput = output)
ChachaCoreImpl(rounds, pinput, poutput);
}
#if BESTHTTP_WITH_BURST
[Unity.Burst.BurstCompile]
[Unity.Burst.CompilerServices.SkipLocalsInit]
#endif
internal unsafe static void ChachaCoreImpl(int rounds,
#if BESTHTTP_WITH_BURST
[NoAlias]
#endif
uint* input,
#if BESTHTTP_WITH_BURST
[NoAlias]
#endif
byte* output)
{
uint* x = stackalloc uint[16];
for (int i = 0; i < 16; i++)
x[i] = input[i];
uint tmp = 0;
for (int i = rounds; i > 0; i -= 2)
{
x[00] += x[04]; tmp = x[12] ^ x[00]; x[12] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[12] ^ x[00], 16);
x[01] += x[05]; tmp = x[13] ^ x[01]; x[13] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[13] ^ x[01], 16);
x[02] += x[06]; tmp = x[14] ^ x[02]; x[14] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[14] ^ x[02], 16);
x[03] += x[07]; tmp = x[15] ^ x[03]; x[15] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[15] ^ x[03], 16);
x[08] += x[12]; tmp = x[04] ^ x[08]; x[04] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[04] ^ x[08], 12);
x[09] += x[13]; tmp = x[05] ^ x[09]; x[05] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[05] ^ x[09], 12);
x[10] += x[14]; tmp = x[06] ^ x[10]; x[06] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[06] ^ x[10], 12);
x[11] += x[15]; tmp = x[07] ^ x[11]; x[07] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[07] ^ x[11], 12);
x[00] += x[04]; tmp = x[12] ^ x[00]; x[12] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[12] ^ x[00], 8);
x[01] += x[05]; tmp = x[13] ^ x[01]; x[13] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[13] ^ x[01], 8);
x[02] += x[06]; tmp = x[14] ^ x[02]; x[14] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[14] ^ x[02], 8);
x[03] += x[07]; tmp = x[15] ^ x[03]; x[15] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[15] ^ x[03], 8);
x[08] += x[12]; tmp = x[04] ^ x[08]; x[04] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[04] ^ x[08], 7);
x[09] += x[13]; tmp = x[05] ^ x[09]; x[05] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[05] ^ x[09], 7);
x[10] += x[14]; tmp = x[06] ^ x[10]; x[06] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[06] ^ x[10], 7);
x[11] += x[15]; tmp = x[07] ^ x[11]; x[07] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[07] ^ x[11], 7);
x[00] += x[05]; tmp = x[15] ^ x[00]; x[15] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[15] ^ x[00], 16);
x[01] += x[06]; tmp = x[12] ^ x[01]; x[12] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[12] ^ x[01], 16);
x[02] += x[07]; tmp = x[13] ^ x[02]; x[13] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[13] ^ x[02], 16);
x[03] += x[04]; tmp = x[14] ^ x[03]; x[14] = (tmp << 16) | (tmp >> -16); // Integers.RotateLeft(x[14] ^ x[03], 16);
x[10] += x[15]; tmp = x[05] ^ x[10]; x[05] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[05] ^ x[10], 12);
x[11] += x[12]; tmp = x[06] ^ x[11]; x[06] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[06] ^ x[11], 12);
x[08] += x[13]; tmp = x[07] ^ x[08]; x[07] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[07] ^ x[08], 12);
x[09] += x[14]; tmp = x[04] ^ x[09]; x[04] = (tmp << 12) | (tmp >> -12); // Integers.RotateLeft(x[04] ^ x[09], 12);
x[00] += x[05]; tmp = x[15] ^ x[00]; x[15] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[15] ^ x[00], 8);
x[01] += x[06]; tmp = x[12] ^ x[01]; x[12] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[12] ^ x[01], 8);
x[02] += x[07]; tmp = x[13] ^ x[02]; x[13] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[13] ^ x[02], 8);
x[03] += x[04]; tmp = x[14] ^ x[03]; x[14] = (tmp << 8) | (tmp >> -8); // Integers.RotateLeft(x[14] ^ x[03], 8);
x[10] += x[15]; tmp = x[05] ^ x[10]; x[05] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[05] ^ x[10], 7);
x[11] += x[12]; tmp = x[06] ^ x[11]; x[06] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[06] ^ x[11], 7);
x[08] += x[13]; tmp = x[07] ^ x[08]; x[07] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[07] ^ x[08], 7);
x[09] += x[14]; tmp = x[04] ^ x[09]; x[04] = (tmp << 7) | (tmp >> -7); // Integers.RotateLeft(x[04] ^ x[09], 7);
}
for (int i = 0; i < 16; i++)
{
uint n = x[i] + input[i];
output[(i * 4)] = (byte)n;
output[(i * 4) + 1] = (byte)(n >> 8);
output[(i * 4) + 2] = (byte)(n >> 16);
output[(i * 4) + 3] = (byte)(n >> 24);
}
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void ImplProcessBlock(ReadOnlySpan<byte> input, Span<byte> output, byte[] keyStream)
{
fixed (byte* pinput = input)
fixed (byte* poutput = output)
fixed (byte* pkeyStream = keyStream)
{
ulong* pulinput = (ulong*)pinput;
ulong* puloutput = (ulong*)poutput;
ulong* pulkeyStream = (ulong*)pkeyStream;
puloutput[0] = pulkeyStream[0] ^ pulinput[0];
puloutput[1] = pulkeyStream[1] ^ pulinput[1];
puloutput[2] = pulkeyStream[2] ^ pulinput[2];
puloutput[3] = pulkeyStream[3] ^ pulinput[3];
puloutput[4] = pulkeyStream[4] ^ pulinput[4];
puloutput[5] = pulkeyStream[5] ^ pulinput[5];
puloutput[6] = pulkeyStream[6] ^ pulinput[6];
puloutput[7] = pulkeyStream[7] ^ pulinput[7];
}
}
#endif
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be2ccde693e75344ca2f2e8f707edec4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aee2eea618479f042ac5f8d3339f3005
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) && BESTHTTP_WITH_BURST
using System;
using static Unity.Burst.Intrinsics.X86.Sse2;
using static Unity.Burst.Intrinsics.Arm.Neon;
using System.Runtime.CompilerServices;
using Unity.Burst;
// https://github.com/sschoener/burst-simd-exercises/blob/main/Assets/Examples/2-sum-small-numbers-sse3/SumSmallNumbers_SSE3.cs
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
[BurstCompile]
internal sealed unsafe class FastGcmBlockCipherHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output, Span<byte> ctrBlock, Span<byte> S, int BlockSize)
{
fixed (byte* pInput = input)
fixed (byte* pOutput = output)
fixed (byte* pctrBlock = ctrBlock)
fixed (byte* pS = S) {
DecryptBlock_Impl(pInput, input.Length, pOutput, output.Length, pctrBlock, pS, BlockSize);
}
}
[BurstCompile(CompileSynchronously = true)]
private unsafe static void DecryptBlock_Impl([NoAlias] byte* pinput, int inLen, [NoAlias] byte* poutput, int outLen, [NoAlias] byte* pctrBlock, [NoAlias] byte* pS, int BlockSize)
{
if (IsSse2Supported)
{
var vInput = loadu_si128(pinput);
var vCtrBlock = loadu_si128(pctrBlock);
var vS = loadu_si128(pS);
vS = xor_si128(vS, vInput);
vCtrBlock = xor_si128(vInput, vCtrBlock);
storeu_si128(pS, vS);
storeu_si128(poutput, vCtrBlock);
}
else if (IsNeonSupported)
{
var vInput = vld1q_u8(pinput);
var vCtrBlock = vld1q_u8(pctrBlock);
var vS = vld1q_u8(pS);
vS = veorq_u8(vS, vInput);
vCtrBlock = veorq_u8(vInput, vCtrBlock);
vst1q_u8(pS, vS);
vst1q_u8(poutput, vCtrBlock);
}
else
{
Unity.Burst.CompilerServices.Hint.Assume(BlockSize == 16);
for (int i = 0; i < BlockSize; i += 4)
{
byte c0 = pinput[i + 0];
byte c1 = pinput[i + 1];
byte c2 = pinput[i + 2];
byte c3 = pinput[i + 3];
pS[i + 0] ^= c0;
pS[i + 1] ^= c1;
pS[i + 2] ^= c2;
pS[i + 3] ^= c3;
poutput[i + 0] = (byte)(c0 ^ pctrBlock[i + 0]);
poutput[i + 1] = (byte)(c1 ^ pctrBlock[i + 1]);
poutput[i + 2] = (byte)(c2 ^ pctrBlock[i + 2]);
poutput[i + 3] = (byte)(c3 ^ pctrBlock[i + 3]);
}
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bc09b804bfd7824c90f995674bdad11
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,438 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Runtime.CompilerServices;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/// <summary>
/// Poly1305 message authentication code, designed by D. J. Bernstein.
/// </summary>
/// <remarks>
/// Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key
/// consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106
/// effective key bits) used in the authenticator.
///
/// The polynomial calculation in this implementation is adapted from the public domain <a
/// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation
/// by Andrew M (@floodyberry).
/// </remarks>
/// <seealso cref="BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/>
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public sealed class FastPoly1305 : IMac
{
private const int BlockSize = 16;
private readonly IBlockCipher cipher;
// Initialised state
/** Polynomial key */
private uint r0, r1, r2, r3, r4;
/** Precomputed 5 * r[1..4] */
private uint s1, s2, s3, s4;
/** Encrypted nonce */
private uint k0, k1, k2, k3;
// Accumulating state
/** Current block of buffered input */
private byte[] currentBlock = new byte[BlockSize];
/** Current offset in input buffer */
private int currentBlockOffset = 0;
/** Polynomial accumulator */
private uint h0, h1, h2, h3, h4;
/**
* Constructs a Poly1305 MAC, where the key passed to init() will be used directly.
*/
public FastPoly1305()
{
this.cipher = null;
}
/**
* Constructs a Poly1305 MAC, using a 128 bit block cipher.
*/
public FastPoly1305(IBlockCipher cipher)
{
if (cipher.GetBlockSize() != BlockSize)
{
throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
}
this.cipher = cipher;
}
/// <summary>
/// Initialises the Poly1305 MAC.
/// </summary>
/// <param name="parameters">a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with
/// a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}.</param>
public void Init(ICipherParameters parameters)
{
byte[] nonce = null;
if (cipher != null)
{
if (!(parameters is ParametersWithIV))
throw new ArgumentException("Poly1305 requires an IV when used with a block cipher.", "parameters");
ParametersWithIV ivParams = (ParametersWithIV)parameters;
nonce = ivParams.GetIV();
parameters = ivParams.Parameters;
}
if (!(parameters is KeyParameter))
throw new ArgumentException("Poly1305 requires a key.");
KeyParameter keyParams = (KeyParameter)parameters;
SetKey(keyParams.GetKey(), nonce);
Reset();
}
private void SetKey(byte[] key, byte[] nonce)
{
if (key.Length != 32)
throw new ArgumentException("Poly1305 key must be 256 bits.");
if (cipher != null && (nonce == null || nonce.Length != BlockSize))
throw new ArgumentException("Poly1305 requires a 128 bit IV.");
// Extract r portion of key (and "clamp" the values)
uint t0 = Pack.LE_To_UInt32(key, 0);
uint t1 = Pack.LE_To_UInt32(key, 4);
uint t2 = Pack.LE_To_UInt32(key, 8);
uint t3 = Pack.LE_To_UInt32(key, 12);
// NOTE: The masks perform the key "clamping" implicitly
r0 = t0 & 0x03FFFFFFU;
r1 = ((t0 >> 26) | (t1 << 6)) & 0x03FFFF03U;
r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU;
r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU;
r4 = (t3 >> 8) & 0x000FFFFFU;
// Precompute multipliers
s1 = r1 * 5;
s2 = r2 * 5;
s3 = r3 * 5;
s4 = r4 * 5;
byte[] kBytes;
int kOff;
if (cipher == null)
{
kBytes = key;
kOff = BlockSize;
}
else
{
// Compute encrypted nonce
kBytes = new byte[BlockSize];
kOff = 0;
cipher.Init(true, new KeyParameter(key, BlockSize, BlockSize));
cipher.ProcessBlock(nonce, 0, kBytes, 0);
}
k0 = Pack.LE_To_UInt32(kBytes, kOff + 0);
k1 = Pack.LE_To_UInt32(kBytes, kOff + 4);
k2 = Pack.LE_To_UInt32(kBytes, kOff + 8);
k3 = Pack.LE_To_UInt32(kBytes, kOff + 12);
}
public string AlgorithmName
{
get { return cipher == null ? "Poly1305" : "Poly1305-" + cipher.AlgorithmName; }
}
public int GetMacSize()
{
return BlockSize;
}
public void Update(byte input)
{
currentBlock[currentBlockOffset++] = input;
if (currentBlockOffset == BlockSize)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
ProcessBlock(currentBlock);
#else
ProcessBlock(currentBlock, 0);
#endif
currentBlockOffset = 0;
}
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void BlockUpdate(byte[] input, int inOff, int len)
{
Check.DataLength(input, inOff, len, "input buffer too short");
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
BlockUpdate(input.AsSpan(inOff, len));
#else
int available = BlockSize - currentBlockOffset;
if (len < available)
{
Array.Copy(input, inOff, currentBlock, currentBlockOffset, len);
currentBlockOffset += len;
return;
}
int pos = 0;
if (currentBlockOffset > 0)
{
Array.Copy(input, inOff, currentBlock, currentBlockOffset, available);
pos = available;
ProcessBlock(currentBlock, 0);
}
int remaining;
while ((remaining = len - pos) >= BlockSize)
{
ProcessBlock(input, inOff + pos);
pos += BlockSize;
}
Array.Copy(input, inOff + pos, currentBlock, 0, remaining);
currentBlockOffset = remaining;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if !UNITY_ANDROID || UNITY_EDITOR
unsafe
#endif
public void BlockUpdate(ReadOnlySpan<byte> input)
{
int available = BlockSize - currentBlockOffset;
if (input.Length < available)
{
input.CopyTo(currentBlock.AsSpan(currentBlockOffset));
currentBlockOffset += input.Length;
return;
}
int pos = 0;
if (currentBlockOffset > 0)
{
input[..available].CopyTo(currentBlock.AsSpan(currentBlockOffset));
pos = available;
ProcessBlock(currentBlock);
}
int remaining;
while ((remaining = input.Length - pos) >= BlockSize)
{
#if UNITY_ANDROID && !UNITY_EDITOR
uint t0 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[pos..]);
uint t1 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[(pos + 4)..]);
uint t2 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[(pos + 8)..]);
uint t3 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(input[(pos + 12)..]);
#else
uint t0 = 0;
uint t1 = 0;
uint t2 = 0;
uint t3 = 0;
fixed (byte* pblock = &input[pos])
{
uint* publock = (uint*)pblock;
t0 = publock[0];
t1 = publock[1];
t2 = publock[2];
t3 = publock[3];
}
#endif
h0 += t0 & 0x3ffffffU;
h1 += ((t1 << 6) | (t0 >> 26)) & 0x3ffffffU;
h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU;
h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU;
h4 += (1 << 24) | (t3 >> 8);
ulong tp0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1;
ulong tp1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2;
ulong tp2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3;
ulong tp3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4;
ulong tp4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0;
h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26);
h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26);
h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26);
h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26);
h4 = (uint)tp4 & 0x3ffffff;
h0 += (uint)(tp4 >> 26) * 5;
h1 += h0 >> 26; h0 &= 0x3ffffff;
pos += BlockSize;
}
input[pos..].CopyTo(currentBlock);
currentBlockOffset = remaining;
}
#endif
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessBlock(ReadOnlySpan<byte> block)
{
uint t0 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(block);
uint t1 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(block[4..]);
uint t2 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(block[8..]);
uint t3 = System.Buffers.Binary.BinaryPrimitives.ReadUInt32LittleEndian(block[12..]);
#else
private void ProcessBlock(byte[] buf, int off)
{
uint t0 = Pack.LE_To_UInt32(buf, off + 0);
uint t1 = Pack.LE_To_UInt32(buf, off + 4);
uint t2 = Pack.LE_To_UInt32(buf, off + 8);
uint t3 = Pack.LE_To_UInt32(buf, off + 12);
#endif
h0 += t0 & 0x3ffffffU;
h1 += ((t1 << 6) | (t0 >> 26)) & 0x3ffffffU;
h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU;
h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU;
h4 += (1 << 24) | (t3 >> 8);
ulong tp0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1;
ulong tp1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2;
ulong tp2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3;
ulong tp3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4;
ulong tp4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0;
h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26);
h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26);
h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26);
h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26);
h4 = (uint)tp4 & 0x3ffffff;
h0 += (uint)(tp4 >> 26) * 5;
h1 += h0 >> 26; h0 &= 0x3ffffff;
}
public int DoFinal(byte[] output, int outOff)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return DoFinal(output.AsSpan(outOff));
#else
Check.OutputLength(output, outOff, BlockSize, "output buffer is too short.");
if (currentBlockOffset > 0)
{
// Process padded block
if (currentBlockOffset < BlockSize)
{
currentBlock[currentBlockOffset++] = 1;
while (currentBlockOffset < BlockSize)
{
currentBlock[currentBlockOffset++] = 0;
}
h4 -= (1 << 24);
}
ProcessBlock(currentBlock, 0);
}
UnityEngine.Debug.Assert(h4 >> 26 == 0);
//h0 += (h4 >> 26) * 5U + 5U; h4 &= 0x3ffffff;
h0 += 5U;
h1 += h0 >> 26; h0 &= 0x3ffffff;
h2 += h1 >> 26; h1 &= 0x3ffffff;
h3 += h2 >> 26; h2 &= 0x3ffffff;
h4 += h3 >> 26; h3 &= 0x3ffffff;
long c = ((int)(h4 >> 26) - 1) * 5;
c += (long)k0 + ((h0) | (h1 << 26));
Pack.UInt32_To_LE((uint)c, output, outOff); c >>= 32;
c += (long)k1 + ((h1 >> 6) | (h2 << 20));
Pack.UInt32_To_LE((uint)c, output, outOff + 4); c >>= 32;
c += (long)k2 + ((h2 >> 12) | (h3 << 14));
Pack.UInt32_To_LE((uint)c, output, outOff + 8); c >>= 32;
c += (long)k3 + ((h3 >> 18) | (h4 << 8));
Pack.UInt32_To_LE((uint)c, output, outOff + 12);
Reset();
return BlockSize;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public int DoFinal(Span<byte> output)
{
Check.OutputLength(output, BlockSize, "output buffer is too short.");
if (currentBlockOffset > 0)
{
// Process padded block
if (currentBlockOffset < BlockSize)
{
currentBlock[currentBlockOffset++] = 1;
while (currentBlockOffset < BlockSize)
{
currentBlock[currentBlockOffset++] = 0;
}
h4 -= (1 << 24);
}
ProcessBlock(currentBlock);
}
UnityEngine.Debug.Assert(h4 >> 26 == 0);
//h0 += (h4 >> 26) * 5U + 5U; h4 &= 0x3ffffff;
h0 += 5U;
h1 += h0 >> 26; h0 &= 0x3ffffff;
h2 += h1 >> 26; h1 &= 0x3ffffff;
h3 += h2 >> 26; h2 &= 0x3ffffff;
h4 += h3 >> 26; h3 &= 0x3ffffff;
long c = ((int)(h4 >> 26) - 1) * 5;
c += (long)k0 + ((h0) | (h1 << 26));
Pack.UInt32_To_LE((uint)c, output); c >>= 32;
c += (long)k1 + ((h1 >> 6) | (h2 << 20));
Pack.UInt32_To_LE((uint)c, output[4..]); c >>= 32;
c += (long)k2 + ((h2 >> 12) | (h3 << 14));
Pack.UInt32_To_LE((uint)c, output[8..]); c >>= 32;
c += (long)k3 + ((h3 >> 18) | (h4 << 8));
Pack.UInt32_To_LE((uint)c, output[12..]);
Reset();
return BlockSize;
}
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
currentBlockOffset = 0;
h0 = h1 = h2 = h3 = h4 = 0;
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 37a51744d555ed842b5a324a257460ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,560 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#endif
#if NETCOREAPP3_0_OR_GREATER
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#endif
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/// <summary>
/// Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
/// </summary>
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public class FastSalsa20Engine
: IStreamCipher
{
public static readonly int DEFAULT_ROUNDS = 20;
/** Constants */
private const int StateSize = 16; // 16, 32 bit ints = 64 bytes
private readonly static uint[] TAU_SIGMA = Pack.LE_To_UInt32(Strings.ToAsciiByteArray("expand 16-byte k" + "expand 32-byte k"), 0, 8);
internal void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
{
int tsOff = (keyLength - 16) / 4;
state[stateOffset] = TAU_SIGMA[tsOff];
state[stateOffset + 1] = TAU_SIGMA[tsOff + 1];
state[stateOffset + 2] = TAU_SIGMA[tsOff + 2];
state[stateOffset + 3] = TAU_SIGMA[tsOff + 3];
}
protected int rounds;
/*
* variables to hold the state of the engine
* during encryption and decryption
*/
internal int index = 0;
internal uint[] engineState = new uint[StateSize]; // state
internal uint[] x = new uint[StateSize]; // internal buffer
internal byte[] keyStream = new byte[StateSize * 4]; // expanded state, 64 bytes
internal bool initialised = false;
/*
* internal counter
*/
private uint cW0, cW1, cW2;
/// <summary>
/// Creates a 20 round Salsa20 engine.
/// </summary>
public FastSalsa20Engine()
: this(DEFAULT_ROUNDS)
{
}
/// <summary>
/// Creates a Salsa20 engine with a specific number of rounds.
/// </summary>
/// <param name="rounds">the number of rounds (must be an even number).</param>
public FastSalsa20Engine(int rounds)
{
if (rounds <= 0 || (rounds & 1) != 0)
{
throw new ArgumentException("'rounds' must be a positive, even number");
}
this.rounds = rounds;
}
public virtual void Init(
bool forEncryption,
ICipherParameters parameters)
{
/*
* Salsa20 encryption and decryption is completely
* symmetrical, so the 'forEncryption' is
* irrelevant. (Like 90% of stream ciphers)
*/
ParametersWithIV ivParams = parameters as ParametersWithIV;
if (ivParams == null)
throw new ArgumentException(AlgorithmName + " Init requires an IV", "parameters");
byte[] iv = ivParams.GetIV();
if (iv == null || iv.Length != NonceSize)
throw new ArgumentException(AlgorithmName + " requires exactly " + NonceSize + " bytes of IV");
ICipherParameters keyParam = ivParams.Parameters;
if (keyParam == null)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " KeyParameter can not be null for first initialisation");
SetKey(null, iv);
}
else if (keyParam is KeyParameter)
{
SetKey(((KeyParameter)keyParam).GetKey(), iv);
}
else
{
throw new ArgumentException(AlgorithmName + " Init parameters must contain a KeyParameter (or null for re-init)");
}
Reset();
initialised = true;
}
protected virtual int NonceSize
{
get { return 8; }
}
public virtual string AlgorithmName
{
get
{
string name = "Salsa20";
if (rounds != DEFAULT_ROUNDS)
{
name += "/" + rounds;
}
return name;
}
}
public virtual byte ReturnByte(
byte input)
{
if (LimitExceeded())
{
throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV");
}
if (index == 0)
{
GenerateKeyStream(keyStream);
AdvanceCounter();
}
byte output = (byte)(keyStream[index] ^ input);
index = (index + 1) & 63;
return output;
}
protected virtual void AdvanceCounter()
{
if (++engineState[8] == 0)
{
++engineState[9];
}
}
public unsafe virtual void ProcessBytes(
byte[] inBytes,
int inOff,
int len,
byte[] outBytes,
int outOff)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
Check.DataLength(inBytes, inOff, len, "input buffer too short");
Check.OutputLength(outBytes, outOff, len, "output buffer too short");
if (LimitExceeded((uint)len))
throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
for (int i = 0; i < len; i++)
{
if (index == 0)
{
GenerateKeyStream(keyStream);
AdvanceCounter();
if (len - i >= 64)
{
fixed (byte* pbout = outBytes)
fixed (byte* pbin = inBytes)
fixed (byte* pbkey = keyStream)
{
#if BESTHTTP_WITH_BURST
FastSalsa20EngineHelper.ProcessBytes(pbout, outOff, pbin, inOff, pbkey);
#else
ulong* pulOut = (ulong*)&pbout[outOff];
ulong* pulIn = (ulong*)&pbin[inOff];
ulong* pulKeyStream = (ulong*)pbkey;
pulOut[0] = pulKeyStream[0] ^ pulIn[0];
pulOut[1] = pulKeyStream[1] ^ pulIn[1];
pulOut[2] = pulKeyStream[2] ^ pulIn[2];
pulOut[3] = pulKeyStream[3] ^ pulIn[3];
#endif
}
i += 63;
index = 0;
continue;
}
}
outBytes[i + outOff] = (byte)(keyStream[index] ^ inBytes[i + inOff]);
index = (index + 1) & 63;
}
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
Check.OutputLength(output, input.Length, "output buffer too short");
if (LimitExceeded((uint)input.Length))
throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
for (int i = 0; i < input.Length; i++)
{
if (index == 0)
{
GenerateKeyStream(keyStream);
AdvanceCounter();
if (input.Length - i >= 64)
{
Span<ulong> lOutput = MemoryMarshal.Cast<byte, ulong>(output.Slice(i));
ReadOnlySpan<ulong> lKeyStream = MemoryMarshal.Cast<byte, ulong>(keyStream);
ReadOnlySpan<ulong> lInput = MemoryMarshal.Cast<byte, ulong>(input.Slice(i));
lOutput[0] = lKeyStream[0] ^ lInput[0];
lOutput[1] = lKeyStream[1] ^ lInput[1];
lOutput[2] = lKeyStream[2] ^ lInput[2];
lOutput[3] = lKeyStream[3] ^ lInput[3];
i += 63;
index = 0;
continue;
}
}
output[i] = (byte)(keyStream[index++] ^ input[i]);
index &= 63;
}
}
#endif
public virtual void Reset()
{
index = 0;
ResetLimitCounter();
ResetCounter();
}
protected virtual void ResetCounter()
{
engineState[8] = engineState[9] = 0;
}
protected virtual void SetKey(byte[] keyBytes, byte[] ivBytes)
{
if (keyBytes != null)
{
if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
int tsOff = (keyBytes.Length - 16) / 4;
engineState[0] = TAU_SIGMA[tsOff];
engineState[5] = TAU_SIGMA[tsOff + 1];
engineState[10] = TAU_SIGMA[tsOff + 2];
engineState[15] = TAU_SIGMA[tsOff + 3];
// Key
Pack.LE_To_UInt32(keyBytes, 0, engineState, 1, 4);
Pack.LE_To_UInt32(keyBytes, keyBytes.Length - 16, engineState, 11, 4);
}
// IV
Pack.LE_To_UInt32(ivBytes, 0, engineState, 6, 2);
}
protected virtual void GenerateKeyStream(byte[] output)
{
SalsaCore(rounds, engineState, x);
Pack.UInt32_To_LE(x, output, 0);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
internal static void SalsaCore(int rounds, ReadOnlySpan<uint> input, Span<uint> output)
{
if (input.Length < 16)
throw new ArgumentException();
if (output.Length < 16)
throw new ArgumentException();
if (rounds % 2 != 0)
throw new ArgumentException("Number of rounds must be even");
#if NETCOREAPP3_0_OR_GREATER
if (Sse41.IsSupported && BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<short>>() == 16)
{
Vector128<uint> b0, b1, b2, b3;
{
var I = MemoryMarshal.AsBytes(input[..16]);
var t0 = MemoryMarshal.Read<Vector128<short>>(I[0x00..0x10]);
var t1 = MemoryMarshal.Read<Vector128<short>>(I[0x10..0x20]);
var t2 = MemoryMarshal.Read<Vector128<short>>(I[0x20..0x30]);
var t3 = MemoryMarshal.Read<Vector128<short>>(I[0x30..0x40]);
var u0 = Sse41.Blend(t0, t2, 0xF0);
var u1 = Sse41.Blend(t1, t3, 0xC3);
var u2 = Sse41.Blend(t0, t2, 0x0F);
var u3 = Sse41.Blend(t1, t3, 0x3C);
b0 = Sse41.Blend(u0, u1, 0xCC).AsUInt32();
b1 = Sse41.Blend(u0, u1, 0x33).AsUInt32();
b2 = Sse41.Blend(u2, u3, 0xCC).AsUInt32();
b3 = Sse41.Blend(u2, u3, 0x33).AsUInt32();
}
var c0 = b0;
var c1 = b1;
var c2 = b2;
var c3 = b3;
for (int i = rounds; i > 0; i -= 2)
{
QuarterRound_Sse2(ref c0, ref c3, ref c2, ref c1);
QuarterRound_Sse2(ref c0, ref c1, ref c2, ref c3);
}
b0 = Sse2.Add(b0, c0);
b1 = Sse2.Add(b1, c1);
b2 = Sse2.Add(b2, c2);
b3 = Sse2.Add(b3, c3);
{
var t0 = b0.AsUInt16();
var t1 = b1.AsUInt16();
var t2 = b2.AsUInt16();
var t3 = b3.AsUInt16();
var u0 = Sse41.Blend(t0, t1, 0xCC);
var u1 = Sse41.Blend(t0, t1, 0x33);
var u2 = Sse41.Blend(t2, t3, 0xCC);
var u3 = Sse41.Blend(t2, t3, 0x33);
var v0 = Sse41.Blend(u0, u2, 0xF0);
var v1 = Sse41.Blend(u1, u3, 0xC3);
var v2 = Sse41.Blend(u0, u2, 0x0F);
var v3 = Sse41.Blend(u1, u3, 0x3C);
var X = MemoryMarshal.AsBytes(output[..16]);
MemoryMarshal.Write(X[0x00..0x10], ref v0);
MemoryMarshal.Write(X[0x10..0x20], ref v1);
MemoryMarshal.Write(X[0x20..0x30], ref v2);
MemoryMarshal.Write(X[0x30..0x40], ref v3);
}
return;
}
#endif
uint x00 = input[ 0];
uint x01 = input[ 1];
uint x02 = input[ 2];
uint x03 = input[ 3];
uint x04 = input[ 4];
uint x05 = input[ 5];
uint x06 = input[ 6];
uint x07 = input[ 7];
uint x08 = input[ 8];
uint x09 = input[ 9];
uint x10 = input[10];
uint x11 = input[11];
uint x12 = input[12];
uint x13 = input[13];
uint x14 = input[14];
uint x15 = input[15];
for (int i = rounds; i > 0; i -= 2)
{
QuarterRound(ref x00, ref x04, ref x08, ref x12);
QuarterRound(ref x05, ref x09, ref x13, ref x01);
QuarterRound(ref x10, ref x14, ref x02, ref x06);
QuarterRound(ref x15, ref x03, ref x07, ref x11);
QuarterRound(ref x00, ref x01, ref x02, ref x03);
QuarterRound(ref x05, ref x06, ref x07, ref x04);
QuarterRound(ref x10, ref x11, ref x08, ref x09);
QuarterRound(ref x15, ref x12, ref x13, ref x14);
}
output[ 0] = x00 + input[ 0];
output[ 1] = x01 + input[ 1];
output[ 2] = x02 + input[ 2];
output[ 3] = x03 + input[ 3];
output[ 4] = x04 + input[ 4];
output[ 5] = x05 + input[ 5];
output[ 6] = x06 + input[ 6];
output[ 7] = x07 + input[ 7];
output[ 8] = x08 + input[ 8];
output[ 9] = x09 + input[ 9];
output[10] = x10 + input[10];
output[11] = x11 + input[11];
output[12] = x12 + input[12];
output[13] = x13 + input[13];
output[14] = x14 + input[14];
output[15] = x15 + input[15];
}
#else
internal static void SalsaCore(int rounds, uint[] input, uint[] output)
{
if (input.Length < 16)
throw new ArgumentException();
if (output.Length < 16)
throw new ArgumentException();
if (rounds % 2 != 0)
throw new ArgumentException("Number of rounds must be even");
uint x00 = input[0];
uint x01 = input[1];
uint x02 = input[2];
uint x03 = input[3];
uint x04 = input[4];
uint x05 = input[5];
uint x06 = input[6];
uint x07 = input[7];
uint x08 = input[8];
uint x09 = input[9];
uint x10 = input[10];
uint x11 = input[11];
uint x12 = input[12];
uint x13 = input[13];
uint x14 = input[14];
uint x15 = input[15];
for (int i = rounds; i > 0; i -= 2)
{
QuarterRound(ref x00, ref x04, ref x08, ref x12);
QuarterRound(ref x05, ref x09, ref x13, ref x01);
QuarterRound(ref x10, ref x14, ref x02, ref x06);
QuarterRound(ref x15, ref x03, ref x07, ref x11);
QuarterRound(ref x00, ref x01, ref x02, ref x03);
QuarterRound(ref x05, ref x06, ref x07, ref x04);
QuarterRound(ref x10, ref x11, ref x08, ref x09);
QuarterRound(ref x15, ref x12, ref x13, ref x14);
}
output[ 0] = x00 + input[ 0];
output[ 1] = x01 + input[ 1];
output[ 2] = x02 + input[ 2];
output[ 3] = x03 + input[ 3];
output[ 4] = x04 + input[ 4];
output[ 5] = x05 + input[ 5];
output[ 6] = x06 + input[ 6];
output[ 7] = x07 + input[ 7];
output[ 8] = x08 + input[ 8];
output[ 9] = x09 + input[ 9];
output[10] = x10 + input[10];
output[11] = x11 + input[11];
output[12] = x12 + input[12];
output[13] = x13 + input[13];
output[14] = x14 + input[14];
output[15] = x15 + input[15];
}
#endif
internal void ResetLimitCounter()
{
cW0 = 0;
cW1 = 0;
cW2 = 0;
}
internal bool LimitExceeded()
{
if (++cW0 == 0)
{
if (++cW1 == 0)
{
return (++cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
}
}
return false;
}
/*
* this relies on the fact len will always be positive.
*/
internal bool LimitExceeded(
uint len)
{
uint old = cW0;
cW0 += len;
if (cW0 < old)
{
if (++cW1 == 0)
{
return (++cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
}
}
return false;
}
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private static void QuarterRound(ref uint a, ref uint b, ref uint c, ref uint d)
{
b ^= Integers.RotateLeft(a + d, 7);
c ^= Integers.RotateLeft(b + a, 9);
d ^= Integers.RotateLeft(c + b, 13);
a ^= Integers.RotateLeft(d + c, 18);
}
#if NETCOREAPP3_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void QuarterRound_Sse2(ref Vector128<uint> a, ref Vector128<uint> b, ref Vector128<uint> c,
ref Vector128<uint> d)
{
b = Sse2.Xor(b, Rotate_Sse2(Sse2.Add(a, d), 7));
c = Sse2.Xor(c, Rotate_Sse2(Sse2.Add(b, a), 9));
d = Sse2.Xor(d, Rotate_Sse2(Sse2.Add(c, b), 13));
a = Sse2.Xor(a, Rotate_Sse2(Sse2.Add(d, c), 18));
b = Sse2.Shuffle(b, 0x93);
c = Sse2.Shuffle(c, 0x4E);
d = Sse2.Shuffle(d, 0x39);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<uint> Rotate_Sse2(Vector128<uint> x, byte sl)
{
byte sr = (byte)(32 - sl);
return Sse2.Xor(Sse2.ShiftLeftLogical(x, sl), Sse2.ShiftRightLogical(x, sr));
}
#endif
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d00c50c4ba4b7eb469b4940b7174779c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
#if BESTHTTP_WITH_BURST
[Unity.Burst.BurstCompile]
#endif
internal static class FastSalsa20EngineHelper
{
#if BESTHTTP_WITH_BURST
[Unity.Burst.BurstCompile]
public unsafe static void ProcessBytes([Unity.Burst.NoAlias] byte* outBytes, int outOff, [Unity.Burst.NoAlias] byte* inBytes, int inOff, [Unity.Burst.NoAlias] byte* keyStream)
{
//for (int i = 0; i < 64; ++i)
// outBytes[idx + i + outOff] = (byte)(keyStream[i] ^ inBytes[idx + i + inOff]);
ulong* pulOut = (ulong*)&outBytes[outOff];
ulong* pulIn = (ulong*)&inBytes[inOff];
ulong* pulKeyStream = (ulong*)keyStream;
pulOut[0] = pulKeyStream[0] ^ pulIn[0];
pulOut[1] = pulKeyStream[1] ^ pulIn[1];
pulOut[2] = pulKeyStream[2] ^ pulIn[2];
pulOut[3] = pulKeyStream[3] ^ pulIn[3];
}
#endif
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 07c49c8cf55d75e4fa1d12af126757d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,141 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/**
* Implements the Segmented Integer Counter (SIC) mode on top of a simple
* block cipher.
*/
public class FastSicBlockCipher
: IBlockCipherMode
{
private readonly IBlockCipher cipher;
private readonly int blockSize;
private readonly byte[] counter;
private readonly byte[] counterOut;
private byte[] IV;
/**
* Basic constructor.
*
* @param c the block cipher to be used.
*/
public FastSicBlockCipher(IBlockCipher cipher)
{
this.cipher = cipher;
this.blockSize = cipher.GetBlockSize();
this.counter = new byte[blockSize];
this.counterOut = new byte[blockSize];
this.IV = new byte[blockSize];
}
/**
* return the underlying block cipher that we are wrapping.
*
* @return the underlying block cipher that we are wrapping.
*/
public IBlockCipher UnderlyingCipher => cipher;
public virtual void Init(
bool forEncryption, //ignored by this CTR mode
ICipherParameters parameters)
{
ParametersWithIV ivParam = parameters as ParametersWithIV;
if (ivParam == null)
throw new ArgumentException("CTR/SIC mode requires ParametersWithIV", "parameters");
this.IV = Arrays.Clone(ivParam.GetIV());
if (blockSize < IV.Length)
throw new ArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes.");
int maxCounterSize = System.Math.Min(8, blockSize / 2);
if (blockSize - IV.Length > maxCounterSize)
throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
// if null it's an IV changed only.
if (ivParam.Parameters != null)
{
cipher.Init(true, ivParam.Parameters);
}
Reset();
}
public virtual string AlgorithmName
{
get { return cipher.AlgorithmName + "/SIC"; }
}
public virtual bool IsPartialBlockOkay
{
get { return true; }
}
public virtual int GetBlockSize()
{
return cipher.GetBlockSize();
}
public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
cipher.ProcessBlock(counter, 0, counterOut, 0);
//
// XOR the counterOut with the plaintext producing the cipher text
//
for (int i = 0; i < counterOut.Length; i++)
{
output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
}
// Increment the counter
int j = counter.Length;
while (--j >= 0 && ++counter[j] == 0)
{
}
return counter.Length;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
cipher.ProcessBlock(counter, 0, counterOut, 0);
//
// XOR the counterOut with the plaintext producing the cipher text
//
for (int i = 0; i < counterOut.Length; i++)
{
output[i] = (byte)(counterOut[i] ^ input[i]);
}
// Increment the counter
int j = counter.Length;
while (--j >= 0 && ++counter[j] == 0)
{
}
return counter.Length;
}
#endif
public virtual void Reset()
{
Arrays.Fill(counter, (byte)0);
Array.Copy(IV, 0, counter, 0, IV.Length);
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f774e66db9dd3d54ba629d80531016f2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,499 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.IO;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.PlatformSupport.Memory;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/// <summary>A generic TLS 1.2 AEAD cipher.</summary>
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
public sealed class FastTlsAeadCipher
: TlsCipher
{
public const int AEAD_CCM = 1;
public const int AEAD_CHACHA20_POLY1305 = 2;
public const int AEAD_GCM = 3;
private const int NONCE_RFC5288 = 1;
private const int NONCE_RFC7905 = 2;
private readonly TlsCryptoParameters m_cryptoParams;
private readonly int m_keySize;
private readonly int m_macSize;
private readonly int m_fixed_iv_length;
private readonly int m_record_iv_length;
private readonly TlsAeadCipherImpl m_decryptCipher, m_encryptCipher;
private readonly byte[] m_decryptNonce, m_encryptNonce;
private readonly bool m_isTlsV13;
private readonly int m_nonceMode;
/// <exception cref="IOException"/>
public FastTlsAeadCipher(TlsCryptoParameters cryptoParams, TlsAeadCipherImpl encryptCipher,
TlsAeadCipherImpl decryptCipher, int keySize, int macSize, int aeadType)
{
SecurityParameters securityParameters = cryptoParams.SecurityParameters;
ProtocolVersion negotiatedVersion = securityParameters.NegotiatedVersion;
if (!TlsImplUtilities.IsTlsV12(negotiatedVersion))
throw new TlsFatalAlert(AlertDescription.internal_error);
this.m_isTlsV13 = TlsImplUtilities.IsTlsV13(negotiatedVersion);
this.m_nonceMode = GetNonceMode(m_isTlsV13, aeadType);
switch (m_nonceMode)
{
case NONCE_RFC5288:
this.m_fixed_iv_length = 4;
this.m_record_iv_length = 8;
break;
case NONCE_RFC7905:
this.m_fixed_iv_length = 12;
this.m_record_iv_length = 0;
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
this.m_cryptoParams = cryptoParams;
this.m_keySize = keySize;
this.m_macSize = macSize;
this.m_decryptCipher = decryptCipher;
this.m_encryptCipher = encryptCipher;
this.m_decryptNonce = new byte[m_fixed_iv_length];
this.m_encryptNonce = new byte[m_fixed_iv_length];
bool isServer = cryptoParams.IsServer;
if (m_isTlsV13)
{
RekeyCipher(securityParameters, decryptCipher, m_decryptNonce, !isServer);
RekeyCipher(securityParameters, encryptCipher, m_encryptNonce, isServer);
return;
}
int keyBlockSize = (2 * keySize) + (2 * m_fixed_iv_length);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
Span<byte> keyBlock = keyBlockSize <= 512
? stackalloc byte[keyBlockSize]
: new byte[keyBlockSize];
TlsImplUtilities.CalculateKeyBlock(cryptoParams, keyBlock);
if (isServer)
{
decryptCipher.SetKey(keyBlock[..keySize]); keyBlock = keyBlock[keySize..];
encryptCipher.SetKey(keyBlock[..keySize]); keyBlock = keyBlock[keySize..];
keyBlock[..m_fixed_iv_length].CopyTo(m_decryptNonce); keyBlock = keyBlock[m_fixed_iv_length..];
keyBlock[..m_fixed_iv_length].CopyTo(m_encryptNonce); keyBlock = keyBlock[m_fixed_iv_length..];
}
else
{
encryptCipher.SetKey(keyBlock[..keySize]); keyBlock = keyBlock[keySize..];
decryptCipher.SetKey(keyBlock[..keySize]); keyBlock = keyBlock[keySize..];
keyBlock[..m_fixed_iv_length].CopyTo(m_encryptNonce); keyBlock = keyBlock[m_fixed_iv_length..];
keyBlock[..m_fixed_iv_length].CopyTo(m_decryptNonce); keyBlock = keyBlock[m_fixed_iv_length..];
}
if (!keyBlock.IsEmpty)
throw new TlsFatalAlert(AlertDescription.internal_error);
#else
byte[] keyBlock = TlsImplUtilities.CalculateKeyBlock(cryptoParams, keyBlockSize);
int pos = 0;
if (isServer)
{
decryptCipher.SetKey(keyBlock, pos, keySize); pos += keySize;
encryptCipher.SetKey(keyBlock, pos, keySize); pos += keySize;
Array.Copy(keyBlock, pos, m_decryptNonce, 0, m_fixed_iv_length); pos += m_fixed_iv_length;
Array.Copy(keyBlock, pos, m_encryptNonce, 0, m_fixed_iv_length); pos += m_fixed_iv_length;
}
else
{
encryptCipher.SetKey(keyBlock, pos, keySize); pos += keySize;
decryptCipher.SetKey(keyBlock, pos, keySize); pos += keySize;
Array.Copy(keyBlock, pos, m_encryptNonce, 0, m_fixed_iv_length); pos += m_fixed_iv_length;
Array.Copy(keyBlock, pos, m_decryptNonce, 0, m_fixed_iv_length); pos += m_fixed_iv_length;
}
if (pos != keyBlockSize)
throw new TlsFatalAlert(AlertDescription.internal_error);
#endif
int nonceLength = m_fixed_iv_length + m_record_iv_length;
// NOTE: Ensure dummy nonce is not part of the generated sequence(s)
byte[] dummyNonce = new byte[nonceLength];
dummyNonce[0] = (byte)~m_encryptNonce[0];
dummyNonce[1] = (byte)~m_decryptNonce[1];
encryptCipher.Init(dummyNonce, macSize, null);
decryptCipher.Init(dummyNonce, macSize, null);
}
public int GetCiphertextDecodeLimit(int plaintextLimit)
{
return plaintextLimit + m_macSize + m_record_iv_length + (m_isTlsV13 ? 1 : 0);
}
public int GetCiphertextEncodeLimit(int plaintextLength, int plaintextLimit)
{
int innerPlaintextLimit = plaintextLength;
if (m_isTlsV13)
{
// TODO[tls13] Add support for padding
int maxPadding = 0;
innerPlaintextLimit = 1 + System.Math.Min(plaintextLimit, plaintextLength + maxPadding);
}
return innerPlaintextLimit + m_macSize + m_record_iv_length;
}
public int GetPlaintextLimit(int ciphertextLimit)
{
return ciphertextLimit - m_macSize - m_record_iv_length - (m_isTlsV13 ? 1 : 0);
}
public TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, byte[] plaintext, int plaintextOffset, int plaintextLength)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return EncodePlaintext(seqNo, contentType, recordVersion, headerAllocation,
plaintext.AsSpan(plaintextOffset, plaintextLength));
#else
byte[] nonce = new byte[m_encryptNonce.Length + m_record_iv_length];
switch (m_nonceMode)
{
case NONCE_RFC5288:
Array.Copy(m_encryptNonce, 0, nonce, 0, m_encryptNonce.Length);
// RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
TlsUtilities.WriteUint64(seqNo, nonce, m_encryptNonce.Length);
break;
case NONCE_RFC7905:
TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
for (int i = 0; i < m_encryptNonce.Length; ++i)
{
nonce[i] ^= m_encryptNonce[i];
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
int extraLength = m_isTlsV13 ? 1 : 0;
// TODO[tls13] If we support adding padding to TLSInnerPlaintext, this will need review
int encryptionLength = m_encryptCipher.GetOutputSize(plaintextLength + extraLength);
int ciphertextLength = m_record_iv_length + encryptionLength;
byte[] output = BufferPool.Get(headerAllocation + ciphertextLength, true); //new byte[headerAllocation + ciphertextLength];
int outputPos = headerAllocation;
if (m_record_iv_length != 0)
{
Array.Copy(nonce, nonce.Length - m_record_iv_length, output, outputPos, m_record_iv_length);
outputPos += m_record_iv_length;
}
short recordType = m_isTlsV13 ? ContentType.application_data : contentType;
byte[] additionalData = GetAdditionalData(seqNo, recordType, recordVersion, ciphertextLength,
plaintextLength);
try
{
Array.Copy(plaintext, plaintextOffset, output, outputPos, plaintextLength);
if (m_isTlsV13)
{
output[outputPos + plaintextLength] = (byte)contentType;
}
m_encryptCipher.Init(nonce, m_macSize, additionalData);
outputPos += m_encryptCipher.DoFinal(output, outputPos, plaintextLength + extraLength, output,
outputPos);
}
catch (IOException e)
{
throw e;
}
catch (Exception e)
{
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
if (outputPos != headerAllocation + ciphertextLength)
{
// NOTE: The additional data mechanism for AEAD ciphers requires exact output size prediction.
throw new TlsFatalAlert(AlertDescription.internal_error);
}
return new TlsEncodeResult(output, 0, outputPos, recordType, true);
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, ReadOnlySpan<byte> plaintext)
{
byte[] nonce = new byte[m_encryptNonce.Length + m_record_iv_length];
switch (m_nonceMode)
{
case NONCE_RFC5288:
Array.Copy(m_encryptNonce, 0, nonce, 0, m_encryptNonce.Length);
// RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
TlsUtilities.WriteUint64(seqNo, nonce, m_encryptNonce.Length);
break;
case NONCE_RFC7905:
TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
for (int i = 0; i < m_encryptNonce.Length; ++i)
{
nonce[i] ^= m_encryptNonce[i];
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
int extraLength = m_isTlsV13 ? 1 : 0;
// TODO[tls13] If we support adding padding to TLSInnerPlaintext, this will need review
int encryptionLength = m_encryptCipher.GetOutputSize(plaintext.Length + extraLength);
int ciphertextLength = m_record_iv_length + encryptionLength;
byte[] output = new byte[headerAllocation + ciphertextLength];
int outputPos = headerAllocation;
if (m_record_iv_length != 0)
{
Array.Copy(nonce, nonce.Length - m_record_iv_length, output, outputPos, m_record_iv_length);
outputPos += m_record_iv_length;
}
short recordType = m_isTlsV13 ? ContentType.application_data : contentType;
byte[] additionalData = GetAdditionalData(seqNo, recordType, recordVersion, ciphertextLength,
plaintext.Length);
try
{
plaintext.CopyTo(output.AsSpan(outputPos));
if (m_isTlsV13)
{
output[outputPos + plaintext.Length] = (byte)contentType;
}
m_encryptCipher.Init(nonce, m_macSize, additionalData);
outputPos += m_encryptCipher.DoFinal(output, outputPos, plaintext.Length + extraLength, output,
outputPos);
}
catch (IOException e)
{
throw e;
}
catch (Exception e)
{
throw new TlsFatalAlert(AlertDescription.internal_error, e);
}
if (outputPos != output.Length)
{
// NOTE: The additional data mechanism for AEAD ciphers requires exact output size prediction.
throw new TlsFatalAlert(AlertDescription.internal_error);
}
return new TlsEncodeResult(output, 0, output.Length, recordType);
}
#endif
public TlsDecodeResult DecodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion,
byte[] ciphertext, int ciphertextOffset, int ciphertextLength)
{
if (GetPlaintextLimit(ciphertextLength) < 0)
throw new TlsFatalAlert(AlertDescription.decode_error);
byte[] nonce = new byte[m_decryptNonce.Length + m_record_iv_length];
switch (m_nonceMode)
{
case NONCE_RFC5288:
Array.Copy(m_decryptNonce, 0, nonce, 0, m_decryptNonce.Length);
Array.Copy(ciphertext, ciphertextOffset, nonce, nonce.Length - m_record_iv_length,
m_record_iv_length);
break;
case NONCE_RFC7905:
TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
for (int i = 0; i < m_decryptNonce.Length; ++i)
{
nonce[i] ^= m_decryptNonce[i];
}
break;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
int encryptionOffset = ciphertextOffset + m_record_iv_length;
int encryptionLength = ciphertextLength - m_record_iv_length;
int plaintextLength = m_decryptCipher.GetOutputSize(encryptionLength);
byte[] additionalData = GetAdditionalData(seqNo, recordType, recordVersion, ciphertextLength,
plaintextLength);
int outputPos;
try
{
m_decryptCipher.Init(nonce, m_macSize, additionalData);
outputPos = m_decryptCipher.DoFinal(ciphertext, encryptionOffset, encryptionLength, ciphertext,
encryptionOffset);
}
catch (IOException e)
{
throw e;
}
catch (Exception e)
{
throw new TlsFatalAlert(AlertDescription.bad_record_mac, e);
}
if (outputPos != plaintextLength)
{
// NOTE: The additional data mechanism for AEAD ciphers requires exact output size prediction.
throw new TlsFatalAlert(AlertDescription.internal_error);
}
short contentType = recordType;
if (m_isTlsV13)
{
// Strip padding and read true content type from TLSInnerPlaintext
int pos = plaintextLength;
for (; ; )
{
if (--pos < 0)
throw new TlsFatalAlert(AlertDescription.unexpected_message);
byte octet = ciphertext[encryptionOffset + pos];
if (0 != octet)
{
contentType = (short)(octet & 0xFF);
plaintextLength = pos;
break;
}
}
}
return new TlsDecodeResult(ciphertext, encryptionOffset, plaintextLength, contentType);
}
public void RekeyDecoder()
{
RekeyCipher(m_cryptoParams.SecurityParameters, m_decryptCipher, m_decryptNonce, !m_cryptoParams.IsServer);
}
public void RekeyEncoder()
{
RekeyCipher(m_cryptoParams.SecurityParameters, m_encryptCipher, m_encryptNonce, m_cryptoParams.IsServer);
}
public bool UsesOpaqueRecordType
{
get { return m_isTlsV13; }
}
private byte[] GetAdditionalData(long seqNo, short recordType, ProtocolVersion recordVersion,
int ciphertextLength, int plaintextLength)
{
if (m_isTlsV13)
{
/*
* TLSCiphertext.opaque_type || TLSCiphertext.legacy_record_version || TLSCiphertext.length
*/
byte[] additional_data = new byte[5];
TlsUtilities.WriteUint8(recordType, additional_data, 0);
TlsUtilities.WriteVersion(recordVersion, additional_data, 1);
TlsUtilities.WriteUint16(ciphertextLength, additional_data, 3);
return additional_data;
}
else
{
/*
* seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length
*/
byte[] additional_data = new byte[13];
TlsUtilities.WriteUint64(seqNo, additional_data, 0);
TlsUtilities.WriteUint8(recordType, additional_data, 8);
TlsUtilities.WriteVersion(recordVersion, additional_data, 9);
TlsUtilities.WriteUint16(plaintextLength, additional_data, 11);
return additional_data;
}
}
private void RekeyCipher(SecurityParameters securityParameters, TlsAeadCipherImpl cipher,
byte[] nonce, bool serverSecret)
{
if (!m_isTlsV13)
throw new TlsFatalAlert(AlertDescription.internal_error);
TlsSecret secret = serverSecret
? securityParameters.TrafficSecretServer
: securityParameters.TrafficSecretClient;
// TODO[tls13] For early data, have to disable server->client
if (null == secret)
throw new TlsFatalAlert(AlertDescription.internal_error);
Setup13Cipher(cipher, nonce, secret, securityParameters.PrfCryptoHashAlgorithm);
}
private void Setup13Cipher(TlsAeadCipherImpl cipher, byte[] nonce, TlsSecret secret,
int cryptoHashAlgorithm)
{
byte[] key = TlsCryptoUtilities.HkdfExpandLabel(secret, cryptoHashAlgorithm, "key",
TlsUtilities.EmptyBytes, m_keySize).Extract();
byte[] iv = TlsCryptoUtilities.HkdfExpandLabel(secret, cryptoHashAlgorithm, "iv", TlsUtilities.EmptyBytes,
m_fixed_iv_length).Extract();
cipher.SetKey(key, 0, m_keySize);
Array.Copy(iv, 0, nonce, 0, m_fixed_iv_length);
// NOTE: Ensure dummy nonce is not part of the generated sequence(s)
iv[0] ^= 0x80;
cipher.Init(iv, m_macSize, null);
}
private static int GetNonceMode(bool isTLSv13, int aeadType)
{
switch (aeadType)
{
case AEAD_CCM:
case AEAD_GCM:
return isTLSv13 ? NONCE_RFC7905 : NONCE_RFC5288;
case AEAD_CHACHA20_POLY1305:
return NONCE_RFC7905;
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a70fdf89e60be4541bbe5027ef19b3c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,205 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using BestHTTP.PlatformSupport.Memory;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
//public sealed class NoCopyKeyParameter
// : ICipherParameters
//{
// private readonly byte[] key;
//
// public NoCopyKeyParameter(byte[] key)
// :this(key, 0, key.Length)
// {
// }
//
// public NoCopyKeyParameter(
// byte[] key,
// int keyOff,
// int keyLen)
// {
// if (key == null)
// throw new ArgumentNullException("key");
// if (keyOff < 0 || keyOff > key.Length)
// throw new ArgumentOutOfRangeException("keyOff");
// if (keyLen < 0 || keyLen > (key.Length - keyOff))
// throw new ArgumentOutOfRangeException("keyLen");
//
// this.key = new byte[keyLen];
// Array.Copy(key, keyOff, this.key, 0, keyLen);
// }
//
// public byte[] GetKey()
// {
// return key;// (byte[])key.Clone();
// }
//}
//
//public sealed class FastAeadParameters
// : ICipherParameters
//{
// private readonly byte[] associatedText;
// private readonly byte[] nonce;
// private readonly NoCopyKeyParameter key;
// private readonly int macSize;
//
// /**
// * Base constructor.
// *
// * @param key key to be used by underlying cipher
// * @param macSize macSize in bits
// * @param nonce nonce to be used
// */
// public FastAeadParameters(NoCopyKeyParameter key, int macSize, byte[] nonce)
// : this(key, macSize, nonce, null)
// {
// }
//
// /**
// * Base constructor.
// *
// * @param key key to be used by underlying cipher
// * @param macSize macSize in bits
// * @param nonce nonce to be used
// * @param associatedText associated text, if any
// */
// public FastAeadParameters(
// NoCopyKeyParameter key,
// int macSize,
// byte[] nonce,
// byte[] associatedText)
// {
// this.key = key;
// this.nonce = nonce;
// this.macSize = macSize;
// this.associatedText = associatedText;
// }
//
// public NoCopyKeyParameter Key
// {
// get { return key; }
// }
//
// public int MacSize
// {
// get { return macSize; }
// }
//
// public byte[] GetAssociatedText()
// {
// return associatedText;
// }
//
// public byte[] GetNonce()
// {
// return nonce;
// }
//}
//
//public sealed class FastParametersWithIV
// : ICipherParameters
//{
// private readonly ICipherParameters parameters;
// private readonly byte[] iv;
//
// public FastParametersWithIV(ICipherParameters parameters,
// byte[] iv)
// : this(parameters, iv, 0, iv.Length)
// {
// }
//
// public FastParametersWithIV(ICipherParameters parameters,
// byte[] iv, int ivOff, int ivLen)
// {
// // NOTE: 'parameters' may be null to imply key re-use
// if (iv == null)
// throw new ArgumentNullException("iv");
//
// this.parameters = parameters;
// this.iv = Arrays.CopyOfRange(iv, ivOff, ivOff + ivLen);
// }
//
// public byte[] GetIV()
// {
// return iv; // (byte[])iv.Clone();
// }
//
// public ICipherParameters Parameters
// {
// get { return parameters; }
// }
//}
internal sealed class FastTlsAeadCipherImpl
: TlsAeadCipherImpl
{
private readonly bool m_isEncrypting;
private readonly IAeadCipher m_cipher;
private KeyParameter key;
internal FastTlsAeadCipherImpl(IAeadCipher cipher, bool isEncrypting)
{
this.m_cipher = cipher;
this.m_isEncrypting = isEncrypting;
}
public void SetKey(byte[] key, int keyOff, int keyLen)
{
this.key = new KeyParameter(key, keyOff, keyLen);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public void SetKey(ReadOnlySpan<byte> key)
{
this.key = new KeyParameter(key);
}
#endif
public void Init(byte[] nonce, int macSize, byte[] additionalData)
{
m_cipher.Init(m_isEncrypting, new AeadParameters(key, macSize * 8, nonce, additionalData));
}
public int GetOutputSize(int inputLength)
{
return m_cipher.GetOutputSize(inputLength);
}
public int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
int len = m_cipher.ProcessBytes(input.AsSpan(inputOffset, inputLength), Spans.FromNullable(output, outputOffset));
#else
int len = m_cipher.ProcessBytes(input, inputOffset, inputLength, output, outputOffset);
#endif
try
{
len += m_cipher.DoFinal(output, outputOffset + len);
}
catch (InvalidCipherTextException e)
{
throw new TlsFatalAlert(AlertDescription.bad_record_mac, e);
}
return len;
}
public void Reset()
{
m_cipher.Reset();
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6918471f7390c92418f038c9d91d42fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,535 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.IO;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
/// <summary>A generic TLS 1.0-1.2 block cipher. This can be used for AES or 3DES for example.</summary>
public class FastTlsBlockCipher
: TlsCipher
{
protected readonly TlsCryptoParameters m_cryptoParams;
protected readonly byte[] m_randomData;
protected readonly bool m_encryptThenMac;
protected readonly bool m_useExplicitIV;
protected readonly bool m_acceptExtraPadding;
protected readonly bool m_useExtraPadding;
protected readonly TlsBlockCipherImpl m_decryptCipher, m_encryptCipher;
protected readonly TlsSuiteMac m_readMac, m_writeMac;
/// <exception cref="IOException"/>
public FastTlsBlockCipher(TlsCryptoParameters cryptoParams, TlsBlockCipherImpl encryptCipher,
TlsBlockCipherImpl decryptCipher, TlsHmac clientMac, TlsHmac serverMac, int cipherKeySize)
{
SecurityParameters securityParameters = cryptoParams.SecurityParameters;
ProtocolVersion negotiatedVersion = securityParameters.NegotiatedVersion;
if (TlsImplUtilities.IsTlsV13(negotiatedVersion))
throw new TlsFatalAlert(AlertDescription.internal_error);
this.m_cryptoParams = cryptoParams;
this.m_randomData = cryptoParams.NonceGenerator.GenerateNonce(256);
this.m_encryptThenMac = securityParameters.IsEncryptThenMac;
this.m_useExplicitIV = TlsImplUtilities.IsTlsV11(negotiatedVersion);
this.m_acceptExtraPadding = !negotiatedVersion.IsSsl;
/*
* Don't use variable-length padding with truncated MACs.
*
* See "Tag Size Does Matter: Attacks and Proofs for the TLS Record Protocol", Paterson,
* Ristenpart, Shrimpton.
*
* TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
*/
this.m_useExtraPadding = securityParameters.IsExtendedPadding
&& ProtocolVersion.TLSv10.IsEqualOrEarlierVersionOf(negotiatedVersion)
&& (m_encryptThenMac || !securityParameters.IsTruncatedHmac);
this.m_encryptCipher = encryptCipher;
this.m_decryptCipher = decryptCipher;
TlsBlockCipherImpl clientCipher, serverCipher;
if (cryptoParams.IsServer)
{
clientCipher = decryptCipher;
serverCipher = encryptCipher;
}
else
{
clientCipher = encryptCipher;
serverCipher = decryptCipher;
}
int keyBlockSize = (2 * cipherKeySize) + clientMac.MacLength + serverMac.MacLength;
// From TLS 1.1 onwards, block ciphers don't need IVs from the key_block
if (!m_useExplicitIV)
{
keyBlockSize += clientCipher.GetBlockSize() + serverCipher.GetBlockSize();
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
Span<byte> keyBlock = keyBlockSize <= 512
? stackalloc byte[keyBlockSize]
: new byte[keyBlockSize];
TlsImplUtilities.CalculateKeyBlock(cryptoParams, keyBlock);
clientMac.SetKey(keyBlock[..clientMac.MacLength]); keyBlock = keyBlock[clientMac.MacLength..];
serverMac.SetKey(keyBlock[..serverMac.MacLength]); keyBlock = keyBlock[serverMac.MacLength..];
clientCipher.SetKey(keyBlock[..cipherKeySize]); keyBlock = keyBlock[cipherKeySize..];
serverCipher.SetKey(keyBlock[..cipherKeySize]); keyBlock = keyBlock[cipherKeySize..];
int clientIVLength = clientCipher.GetBlockSize();
int serverIVLength = serverCipher.GetBlockSize();
if (m_useExplicitIV)
{
clientCipher.Init(clientIVLength <= 64 ? stackalloc byte[clientIVLength] : new byte[clientIVLength]);
serverCipher.Init(serverIVLength <= 64 ? stackalloc byte[serverIVLength] : new byte[serverIVLength]);
}
else
{
clientCipher.Init(keyBlock[..clientIVLength]); keyBlock = keyBlock[clientIVLength..];
serverCipher.Init(keyBlock[..serverIVLength]); keyBlock = keyBlock[serverIVLength..];
}
if (!keyBlock.IsEmpty)
throw new TlsFatalAlert(AlertDescription.internal_error);
#else
byte[] keyBlock = TlsImplUtilities.CalculateKeyBlock(cryptoParams, keyBlockSize);
int pos = 0;
clientMac.SetKey(keyBlock, pos, clientMac.MacLength);
pos += clientMac.MacLength;
serverMac.SetKey(keyBlock, pos, serverMac.MacLength);
pos += serverMac.MacLength;
clientCipher.SetKey(keyBlock, pos, cipherKeySize);
pos += cipherKeySize;
serverCipher.SetKey(keyBlock, pos, cipherKeySize);
pos += cipherKeySize;
int clientIVLength = clientCipher.GetBlockSize();
int serverIVLength = serverCipher.GetBlockSize();
if (m_useExplicitIV)
{
clientCipher.Init(new byte[clientIVLength], 0, clientIVLength);
serverCipher.Init(new byte[serverIVLength], 0, serverIVLength);
}
else
{
clientCipher.Init(keyBlock, pos, clientIVLength);
pos += clientIVLength;
serverCipher.Init(keyBlock, pos, serverIVLength);
pos += serverIVLength;
}
if (pos != keyBlockSize)
throw new TlsFatalAlert(AlertDescription.internal_error);
#endif
if (cryptoParams.IsServer)
{
this.m_writeMac = new TlsSuiteHmac(cryptoParams, serverMac);
this.m_readMac = new TlsSuiteHmac(cryptoParams, clientMac);
}
else
{
this.m_writeMac = new TlsSuiteHmac(cryptoParams, clientMac);
this.m_readMac = new TlsSuiteHmac(cryptoParams, serverMac);
}
}
public virtual int GetCiphertextDecodeLimit(int plaintextLimit)
{
int blockSize = m_decryptCipher.GetBlockSize();
int macSize = m_readMac.Size;
int maxPadding = 256;
return GetCiphertextLength(blockSize, macSize, maxPadding, plaintextLimit);
}
public virtual int GetCiphertextEncodeLimit(int plaintextLength, int plaintextLimit)
{
int blockSize = m_encryptCipher.GetBlockSize();
int macSize = m_writeMac.Size;
int maxPadding = m_useExtraPadding ? 256 : blockSize;
return GetCiphertextLength(blockSize, macSize, maxPadding, plaintextLength);
}
public virtual int GetPlaintextLimit(int ciphertextLimit)
{
int blockSize = m_encryptCipher.GetBlockSize();
int macSize = m_writeMac.Size;
int plaintextLimit = ciphertextLimit;
// Leave room for the MAC, and require block-alignment
if (m_encryptThenMac)
{
plaintextLimit -= macSize;
plaintextLimit -= plaintextLimit % blockSize;
}
else
{
plaintextLimit -= plaintextLimit % blockSize;
plaintextLimit -= macSize;
}
// Minimum 1 byte of padding
--plaintextLimit;
// An explicit IV consumes 1 block
if (m_useExplicitIV)
{
plaintextLimit -= blockSize;
}
return plaintextLimit;
}
public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, byte[] plaintext, int offset, int len)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return EncodePlaintext(seqNo, contentType, recordVersion, headerAllocation, plaintext.AsSpan(offset, len));
#else
int blockSize = m_encryptCipher.GetBlockSize();
int macSize = m_writeMac.Size;
int enc_input_length = len;
if (!m_encryptThenMac)
{
enc_input_length += macSize;
}
int padding_length = blockSize - (enc_input_length % blockSize);
if (m_useExtraPadding)
{
// Add a random number of extra blocks worth of padding
int maxExtraPadBlocks = (256 - padding_length) / blockSize;
int actualExtraPadBlocks = ChooseExtraPadBlocks(maxExtraPadBlocks);
padding_length += actualExtraPadBlocks * blockSize;
}
int totalSize = len + macSize + padding_length;
if (m_useExplicitIV)
{
totalSize += blockSize;
}
byte[] outBuf = new byte[headerAllocation + totalSize];
int outOff = headerAllocation;
if (m_useExplicitIV)
{
// Technically the explicit IV will be the encryption of this nonce
byte[] explicitIV = m_cryptoParams.NonceGenerator.GenerateNonce(blockSize);
Array.Copy(explicitIV, 0, outBuf, outOff, blockSize);
outOff += blockSize;
}
Array.Copy(plaintext, offset, outBuf, outOff, len);
outOff += len;
if (!m_encryptThenMac)
{
byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, plaintext, offset, len);
Array.Copy(mac, 0, outBuf, outOff, mac.Length);
outOff += mac.Length;
}
byte padByte = (byte)(padding_length - 1);
for (int i = 0; i < padding_length; ++i)
{
outBuf[outOff++] = padByte;
}
m_encryptCipher.DoFinal(outBuf, headerAllocation, outOff - headerAllocation, outBuf, headerAllocation);
if (m_encryptThenMac)
{
byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, outBuf, headerAllocation,
outOff - headerAllocation);
Array.Copy(mac, 0, outBuf, outOff, mac.Length);
outOff += mac.Length;
}
if (outOff != outBuf.Length)
throw new TlsFatalAlert(AlertDescription.internal_error);
return new TlsEncodeResult(outBuf, 0, outBuf.Length, contentType);
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public virtual TlsEncodeResult EncodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion,
int headerAllocation, ReadOnlySpan<byte> plaintext)
{
int blockSize = m_encryptCipher.GetBlockSize();
int macSize = m_writeMac.Size;
int enc_input_length = plaintext.Length;
if (!m_encryptThenMac)
{
enc_input_length += macSize;
}
int padding_length = blockSize - (enc_input_length % blockSize);
if (m_useExtraPadding)
{
// Add a random number of extra blocks worth of padding
int maxExtraPadBlocks = (256 - padding_length) / blockSize;
int actualExtraPadBlocks = ChooseExtraPadBlocks(maxExtraPadBlocks);
padding_length += actualExtraPadBlocks * blockSize;
}
int totalSize = plaintext.Length + macSize + padding_length;
if (m_useExplicitIV)
{
totalSize += blockSize;
}
byte[] outBuf = new byte[headerAllocation + totalSize];
int outOff = headerAllocation;
if (m_useExplicitIV)
{
// Technically the explicit IV will be the encryption of this nonce
byte[] explicitIV = m_cryptoParams.NonceGenerator.GenerateNonce(blockSize);
Array.Copy(explicitIV, 0, outBuf, outOff, blockSize);
outOff += blockSize;
}
plaintext.CopyTo(outBuf.AsSpan(outOff));
outOff += plaintext.Length;
if (!m_encryptThenMac)
{
byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, plaintext);
mac.CopyTo(outBuf.AsSpan(outOff));
outOff += mac.Length;
}
byte padByte = (byte)(padding_length - 1);
for (int i = 0; i < padding_length; ++i)
{
outBuf[outOff++] = padByte;
}
m_encryptCipher.DoFinal(outBuf, headerAllocation, outOff - headerAllocation, outBuf, headerAllocation);
if (m_encryptThenMac)
{
byte[] mac = m_writeMac.CalculateMac(seqNo, contentType, outBuf, headerAllocation,
outOff - headerAllocation);
Array.Copy(mac, 0, outBuf, outOff, mac.Length);
outOff += mac.Length;
}
if (outOff != outBuf.Length)
throw new TlsFatalAlert(AlertDescription.internal_error);
return new TlsEncodeResult(outBuf, 0, outBuf.Length, contentType);
}
#endif
public virtual TlsDecodeResult DecodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion,
byte[] ciphertext, int offset, int len)
{
int blockSize = m_decryptCipher.GetBlockSize();
int macSize = m_readMac.Size;
int minLen = blockSize;
if (m_encryptThenMac)
{
minLen += macSize;
}
else
{
minLen = System.Math.Max(minLen, macSize + 1);
}
if (m_useExplicitIV)
{
minLen += blockSize;
}
if (len < minLen)
throw new TlsFatalAlert(AlertDescription.decode_error);
int blocks_length = len;
if (m_encryptThenMac)
{
blocks_length -= macSize;
}
if (blocks_length % blockSize != 0)
throw new TlsFatalAlert(AlertDescription.decryption_failed);
if (m_encryptThenMac)
{
byte[] expectedMac = m_readMac.CalculateMac(seqNo, recordType, ciphertext, offset, len - macSize);
bool checkMac = TlsUtilities.ConstantTimeAreEqual(macSize, expectedMac, 0, ciphertext,
offset + len - macSize);
if (!checkMac)
{
/*
* RFC 7366 3. The MAC SHALL be evaluated before any further processing such as
* decryption is performed, and if the MAC verification fails, then processing SHALL
* terminate immediately. For TLS, a fatal bad_record_mac MUST be generated [2]. For
* DTLS, the record MUST be discarded, and a fatal bad_record_mac MAY be generated
* [4]. This immediate response to a bad MAC eliminates any timing channels that may
* be available through the use of manipulated packet data.
*/
throw new TlsFatalAlert(AlertDescription.bad_record_mac);
}
}
m_decryptCipher.DoFinal(ciphertext, offset, blocks_length, ciphertext, offset);
if (m_useExplicitIV)
{
offset += blockSize;
blocks_length -= blockSize;
}
// If there's anything wrong with the padding, this will return zero
int totalPad = CheckPaddingConstantTime(ciphertext, offset, blocks_length, blockSize,
m_encryptThenMac ? 0 : macSize);
bool badMac = (totalPad == 0);
int dec_output_length = blocks_length - totalPad;
if (!m_encryptThenMac)
{
dec_output_length -= macSize;
byte[] expectedMac = m_readMac.CalculateMacConstantTime(seqNo, recordType, ciphertext, offset,
dec_output_length, blocks_length - macSize, m_randomData);
badMac |= !TlsUtilities.ConstantTimeAreEqual(macSize, expectedMac, 0, ciphertext,
offset + dec_output_length);
}
if (badMac)
throw new TlsFatalAlert(AlertDescription.bad_record_mac);
return new TlsDecodeResult(ciphertext, offset, dec_output_length, recordType);
}
public virtual void RekeyDecoder()
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
public virtual void RekeyEncoder()
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
public virtual bool UsesOpaqueRecordType
{
get { return false; }
}
protected virtual int CheckPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize)
{
int end = off + len;
byte lastByte = buf[end - 1];
int padlen = lastByte & 0xff;
int totalPad = padlen + 1;
int dummyIndex = 0;
byte padDiff = 0;
int totalPadLimit = System.Math.Min(m_acceptExtraPadding ? 256 : blockSize, len - macSize);
if (totalPad > totalPadLimit)
{
totalPad = 0;
}
else
{
int padPos = end - totalPad;
do
{
padDiff |= (byte)(buf[padPos++] ^ lastByte);
}
while (padPos < end);
dummyIndex = totalPad;
if (padDiff != 0)
{
totalPad = 0;
}
}
// Run some extra dummy checks so the number of checks is always constant
{
byte[] dummyPad = m_randomData;
while (dummyIndex < 256)
{
padDiff |= (byte)(dummyPad[dummyIndex++] ^ lastByte);
}
// Ensure the above loop is not eliminated
dummyPad[0] ^= padDiff;
}
return totalPad;
}
protected virtual int ChooseExtraPadBlocks(int max)
{
byte[] random = m_cryptoParams.NonceGenerator.GenerateNonce(4);
int x = (int)Pack.LE_To_UInt32(random, 0);
int n = Integers.NumberOfTrailingZeros(x);
return System.Math.Min(n, max);
}
protected virtual int GetCiphertextLength(int blockSize, int macSize, int maxPadding, int plaintextLength)
{
int ciphertextLength = plaintextLength;
// An explicit IV consumes 1 block
if (m_useExplicitIV)
{
ciphertextLength += blockSize;
}
// Leave room for the MAC and (block-aligning) padding
ciphertextLength += maxPadding;
if (m_encryptThenMac)
{
ciphertextLength -= (ciphertextLength % blockSize);
ciphertextLength += macSize;
}
else
{
ciphertextLength += macSize;
ciphertextLength -= (ciphertextLength % blockSize);
}
return ciphertextLength;
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20ab76109ec6a50438d1f788603eeb49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
namespace BestHTTP.Connections.TLS.Crypto.Impl
{
internal sealed class FastTlsBlockCipherImpl
: TlsBlockCipherImpl
{
private readonly bool m_isEncrypting;
private readonly IBlockCipher m_cipher;
private KeyParameter key;
internal FastTlsBlockCipherImpl(IBlockCipher cipher, bool isEncrypting)
{
this.m_cipher = cipher;
this.m_isEncrypting = isEncrypting;
}
public void SetKey(byte[] key, int keyOff, int keyLen)
{
this.key = new KeyParameter(key, keyOff, keyLen);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public void SetKey(ReadOnlySpan<byte> key)
{
this.key = new KeyParameter(key);
}
#endif
public void Init(byte[] iv, int ivOff, int ivLen)
{
m_cipher.Init(m_isEncrypting, new ParametersWithIV(key, iv, ivOff, ivLen));
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public void Init(ReadOnlySpan<byte> iv)
{
m_cipher.Init(m_isEncrypting, new ParametersWithIV(key, iv));
}
#endif
public int DoFinal(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
{
int blockSize = m_cipher.GetBlockSize();
for (int i = 0; i < inputLength; i += blockSize)
{
m_cipher.ProcessBlock(input, inputOffset + i, output, outputOffset + i);
}
return inputLength;
}
public int GetBlockSize()
{
return m_cipher.GetBlockSize();
}
}
}
#pragma warning restore
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 942c0f75d0ed2dc4297fa1c7114d7f16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Collections.Generic;
using BestHTTP.Connections.TLS.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
namespace BestHTTP.Connections.TLS
{
public class DefaultTls13Client : AbstractTls13Client
{
public DefaultTls13Client(HTTPRequest request, List<ServerName> sniServerNames, List<ProtocolName> protocols)
: base(request, sniServerNames, protocols, new FastTlsCrypto(new SecureRandom()))
{
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c429a6a1f0a28754fb08d39cb6314c09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
using System;
using System.Diagnostics;
using System.IO;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders;
// https://www.m00nie.com/2015/05/decrypt-https-ssltls-with-wireshark/
// https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
// https://github.com/bcgit/bc-csharp/issues/343
namespace BestHTTP.Connections.TLS
{
/// <summary>
/// https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
/// </summary>
internal enum Labels
{
CLIENT_RANDOM,
CLIENT_EARLY_TRAFFIC_SECRET,
CLIENT_HANDSHAKE_TRAFFIC_SECRET,
SERVER_HANDSHAKE_TRAFFIC_SECRET,
CLIENT_TRAFFIC_SECRET_0,
SERVER_TRAFFIC_SECRET_0,
EARLY_EXPORTER_SECRET,
EXPORTER_SECRET
}
internal static class KeyLogFileWriter
{
private static string GetKeylogFileName() => Environment.GetEnvironmentVariable("SSLKEYLOGFILE", EnvironmentVariableTarget.User);
[Conditional("UNITY_EDITOR")]
public static void WriteLabel(Labels label, byte[] clientRandom, TlsSecret secret)
{
if (clientRandom != null && secret != null)
{
string SSLKEYLOGFILE = GetKeylogFileName();
if (!string.IsNullOrEmpty(SSLKEYLOGFILE))
using (var writer = new StreamWriter(System.IO.File.Open(SSLKEYLOGFILE, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)))
writer.WriteLine($"{label} {Hex.ToHexString(clientRandom)} {Hex.ToHexString((secret as AbstractTlsSecret).CopyData())}");
}
}
[Conditional("UNITY_EDITOR")]
public static void WriteLabel(Labels label, SecurityParameters securityParameters)
{
try
{
TlsSecret secret = null;
switch (label)
{
case Labels.CLIENT_RANDOM: secret = securityParameters.MasterSecret; break;
case Labels.CLIENT_HANDSHAKE_TRAFFIC_SECRET: secret = securityParameters.TrafficSecretClient; break;
case Labels.SERVER_HANDSHAKE_TRAFFIC_SECRET: secret = securityParameters.TrafficSecretServer; break;
case Labels.CLIENT_TRAFFIC_SECRET_0: secret = securityParameters.TrafficSecretClient; break;
case Labels.SERVER_TRAFFIC_SECRET_0: secret = securityParameters.TrafficSecretServer; break;
case Labels.EXPORTER_SECRET: secret = securityParameters.ExporterMasterSecret; break;
case Labels.CLIENT_EARLY_TRAFFIC_SECRET: break;
case Labels.EARLY_EXPORTER_SECRET: break;
}
if (secret != null)
WriteLabel(label, securityParameters.ClientRandom, secret);
}
catch
{ }
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a73956af7ab6d8b46bdc431620279764
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: