From e6e9fc85883d3ab7734a2412dbc052d97d3852e7 Mon Sep 17 00:00:00 2001 From: noisyfox Date: Tue, 30 Aug 2016 17:24:00 +1000 Subject: [PATCH] Refactor to make OTA code more independent and clear. and misc changes --- shadowsocks-csharp/Encryption/IVEncryptor.cs | 96 ++++++++++--------- .../Encryption/MbedTLSEncryptor.cs | 15 +-- 2 files changed, 56 insertions(+), 55 deletions(-) diff --git a/shadowsocks-csharp/Encryption/IVEncryptor.cs b/shadowsocks-csharp/Encryption/IVEncryptor.cs index 8376073f..15087605 100755 --- a/shadowsocks-csharp/Encryption/IVEncryptor.cs +++ b/shadowsocks-csharp/Encryption/IVEncryptor.cs @@ -14,15 +14,7 @@ namespace Shadowsocks.Encryption public const int MAX_KEY_LENGTH = 64; public const int MAX_IV_LENGTH = 16; - public const int ONETIMEAUTH_FLAG = 0x10; - public const int ADDRTYPE_MASK = 0xF; - - public const int ONETIMEAUTH_BYTES = 10; - - public const int CLEN_BYTES = 2; - public const int AUTH_BYTES = ONETIMEAUTH_BYTES + CLEN_BYTES; - - protected static readonly byte[] tempbuf = new byte[MAX_INPUT_SIZE]; + protected static byte[] tempbuf = new byte[MAX_INPUT_SIZE]; protected Dictionary> ciphers; protected Dictionary ciphersDetail; @@ -40,8 +32,6 @@ namespace Shadowsocks.Encryption protected byte[] _key; protected int keyLen; protected int ivLen; - protected uint counter = 0; - protected byte[] _keyBuffer = null; public IVEncryptor(string method, string password, bool onetimeauth, bool isudp) : base(method, password, onetimeauth, isudp) @@ -76,7 +66,7 @@ namespace Shadowsocks.Encryption }); } - protected static void bytesToKey(byte[] password, byte[] key) + protected void bytesToKey(byte[] password, byte[] key) { byte[] result = new byte[password.Length + 16]; int i = 0; @@ -98,14 +88,6 @@ namespace Shadowsocks.Encryption } } - protected static void randBytes(byte[] buf, int length) - { - byte[] temp = new byte[length]; - RNGCryptoServiceProvider rngServiceProvider = new RNGCryptoServiceProvider(); - rngServiceProvider.GetBytes(temp); - temp.CopyTo(buf, 0); - } - protected virtual void initCipher(byte[] iv, bool isCipher) { if (ivLen > 0) @@ -125,7 +107,20 @@ namespace Shadowsocks.Encryption protected abstract void cipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf); - protected int getHeadLen(byte[] buf, int length) + #region OneTimeAuth + + public const int ONETIMEAUTH_FLAG = 0x10; + public const int ADDRTYPE_MASK = 0xF; + + public const int ONETIMEAUTH_BYTES = 10; + + public const int CLEN_BYTES = 2; + public const int AUTH_BYTES = ONETIMEAUTH_BYTES + CLEN_BYTES; + + private uint _otaChunkCounter; + private byte[] _otaChunkKeyBuffer; + + protected int OtaGetHeadLen(byte[] buf, int length) { int len = 0; int atyp = length > 0 ? (buf[0] & ADDRTYPE_MASK) : 0; @@ -147,7 +142,7 @@ namespace Shadowsocks.Encryption return len; } - protected byte[] genOnetimeAuthHash(byte[] msg, int msg_len) + private byte[] OtaGenHash(byte[] msg, int msg_len) { byte[] auth = new byte[ONETIMEAUTH_BYTES]; byte[] hash = new byte[20]; @@ -160,39 +155,40 @@ namespace Shadowsocks.Encryption return auth; } - protected void updateKeyBuffer() + private void OtaUpdateKeyBuffer() { - if (_keyBuffer == null) + if (_otaChunkKeyBuffer == null) { - _keyBuffer = new byte[MAX_IV_LENGTH + 4]; - Buffer.BlockCopy(_encryptIV, 0, _keyBuffer, 0, ivLen); + _otaChunkKeyBuffer = new byte[MAX_IV_LENGTH + 4]; + Buffer.BlockCopy(_encryptIV, 0, _otaChunkKeyBuffer, 0, ivLen); } - byte[] counter_bytes = BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder((int)counter)); - Buffer.BlockCopy(counter_bytes, 0, _keyBuffer, ivLen, 4); - counter++; + byte[] counter_bytes = BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder((int)_otaChunkCounter)); + Buffer.BlockCopy(counter_bytes, 0, _otaChunkKeyBuffer, ivLen, 4); + _otaChunkCounter++; } - protected byte[] genHash(byte[] buf, int offset, int len) + private byte[] OtaGenChunkHash(byte[] buf, int offset, int len) { byte[] hash = new byte[20]; - updateKeyBuffer(); - Sodium.ss_sha1_hmac_ex(_keyBuffer, (uint)_keyBuffer.Length, + OtaUpdateKeyBuffer(); + Sodium.ss_sha1_hmac_ex(_otaChunkKeyBuffer, (uint)_otaChunkKeyBuffer.Length, buf, offset, (uint)len, hash); return hash; } - protected void reactBuffer4TCP(byte[] buf, ref int length) + private void OtaAuthBuffer4Tcp(byte[] buf, ref int length) { if (!_encryptIVSent) { - int headLen = getHeadLen(buf, length); + int headLen = OtaGetHeadLen(buf, length); int dataLen = length - headLen; buf[0] |= ONETIMEAUTH_FLAG; - byte[] hash = genOnetimeAuthHash(buf, headLen); + byte[] hash = OtaGenHash(buf, headLen); Buffer.BlockCopy(buf, headLen, buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); Buffer.BlockCopy(hash, 0, buf, headLen, ONETIMEAUTH_BYTES); - hash = genHash(buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); + + hash = OtaGenChunkHash(buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); Buffer.BlockCopy(hash, 0, buf, headLen + ONETIMEAUTH_BYTES + CLEN_BYTES, ONETIMEAUTH_BYTES); byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)dataLen)); Buffer.BlockCopy(lenBytes, 0, buf, headLen + ONETIMEAUTH_BYTES, CLEN_BYTES); @@ -200,7 +196,7 @@ namespace Shadowsocks.Encryption } else { - byte[] hash = genHash(buf, 0, length); + byte[] hash = OtaGenChunkHash(buf, 0, length); Buffer.BlockCopy(buf, 0, buf, AUTH_BYTES, length); byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)length)); Buffer.BlockCopy(lenBytes, 0, buf, 0, CLEN_BYTES); @@ -209,36 +205,48 @@ namespace Shadowsocks.Encryption } } - protected void reactBuffer4UDP(byte[] buf, ref int length) + private void OtaAuthBuffer4Udp(byte[] buf, ref int length) { buf[0] |= ONETIMEAUTH_FLAG; - byte[] hash = genOnetimeAuthHash(buf, length); + byte[] hash = OtaGenHash(buf, length); Buffer.BlockCopy(hash, 0, buf, length, ONETIMEAUTH_BYTES); length += ONETIMEAUTH_BYTES; } - protected void reactBuffer(byte[] buf, ref int length) + private void OtaAuthBuffer(byte[] buf, ref int length) { if (OnetimeAuth && ivLen > 0) { if (!IsUDP) { - reactBuffer4TCP(buf, ref length); + OtaAuthBuffer4Tcp(buf, ref length); } else { - reactBuffer4UDP(buf, ref length); + OtaAuthBuffer4Udp(buf, ref length); } } } + #endregion + + protected static void randBytes(byte[] buf, int length) + { + byte[] temp = new byte[length]; + RNGCryptoServiceProvider rngServiceProvider = new RNGCryptoServiceProvider(); + rngServiceProvider.GetBytes(temp); + temp.CopyTo(buf, 0); + } + public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { if (!_encryptIVSent) { + // Generate IV randBytes(outbuf, ivLen); initCipher(outbuf, true); - reactBuffer(buf, ref length); + outlength = length + ivLen; + OtaAuthBuffer(buf, ref length); _encryptIVSent = true; lock (tempbuf) { @@ -249,7 +257,7 @@ namespace Shadowsocks.Encryption } else { - reactBuffer(buf, ref length); + OtaAuthBuffer(buf, ref length); outlength = length; cipherUpdate(true, length, buf, outbuf); } diff --git a/shadowsocks-csharp/Encryption/MbedTLSEncryptor.cs b/shadowsocks-csharp/Encryption/MbedTLSEncryptor.cs index 9931991d..d5d3728c 100644 --- a/shadowsocks-csharp/Encryption/MbedTLSEncryptor.cs +++ b/shadowsocks-csharp/Encryption/MbedTLSEncryptor.cs @@ -83,7 +83,8 @@ namespace Shadowsocks.Encryption * == MBEDTLS_{EN,DE}CRYPT * */ - if (MbedTLS.cipher_setkey(ctx, realkey, keyLen * 8, isCipher ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT) != 0 ) + if (MbedTLS.cipher_setkey(ctx, realkey, keyLen * 8, + isCipher ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT) != 0 ) throw new Exception("Cannot set mbed TLS cipher key"); if (MbedTLS.cipher_set_iv(ctx, iv, ivLen) != 0) throw new Exception("Cannot set mbed TLS cipher IV"); @@ -98,16 +99,8 @@ namespace Shadowsocks.Encryption { throw new ObjectDisposedException(this.ToString()); } - IntPtr ctx; - if (isCipher) - { - ctx = _encryptCtx; - } - else - { - ctx = _decryptCtx; - } - if (MbedTLS.cipher_update(ctx, buf, length, outbuf, ref length) != 0 ) + if (MbedTLS.cipher_update(isCipher ? _encryptCtx : _decryptCtx, + buf, length, outbuf, ref length) != 0 ) throw new Exception("Cannot update mbed TLS cipher context"); }