From 35633053e17e8cece697dd27ec96ea770e6f8706 Mon Sep 17 00:00:00 2001 From: Student Main Date: Sun, 22 Mar 2020 12:22:15 +0800 Subject: [PATCH] span based cipher api --- .../Controller/Service/PACServer.cs | 4 +-- .../Controller/ShadowsocksController.cs | 1 - .../Encryption/AEAD/AEADEncryptor.cs | 17 +++++++--- shadowsocks-csharp/Encryption/CipherInfo.cs | 8 +++++ shadowsocks-csharp/Encryption/CryptoUtils.cs | 33 +++++++++++++++++++ .../Encryption/EncryptorFactory.cs | 20 +++++------ shadowsocks-csharp/Encryption/RNG.cs | 26 ++++++++------- test/CryptographyTest.cs | 1 - 8 files changed, 77 insertions(+), 33 deletions(-) diff --git a/shadowsocks-csharp/Controller/Service/PACServer.cs b/shadowsocks-csharp/Controller/Service/PACServer.cs index b17fece0..9e02b68d 100644 --- a/shadowsocks-csharp/Controller/Service/PACServer.cs +++ b/shadowsocks-csharp/Controller/Service/PACServer.cs @@ -22,9 +22,7 @@ namespace Shadowsocks.Controller { if (string.IsNullOrEmpty(_cachedPacSecret)) { - var rd = new byte[32]; - RNG.GetBytes(rd); - _cachedPacSecret = HttpServerUtilityUrlToken.Encode(rd); + _cachedPacSecret = HttpServerUtilityUrlToken.Encode(RNG.GetBytes(32)); } return _cachedPacSecret; } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index f4ea1294..548d9f17 100644 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -325,7 +325,6 @@ namespace Shadowsocks.Controller { SystemProxy.Update(_config, true, null); } - Encryption.RNG.Close(); } private void StopPlugins() diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs index daa3ff07..924dfa8e 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs @@ -178,8 +178,7 @@ namespace Shadowsocks.Encryption.AEAD { _encryptSaltSent = true; // Generate salt - byte[] saltBytes = new byte[saltLen]; - RNG.GetBytes(saltBytes, saltLen); + byte[] saltBytes = RNG.GetBytes(saltLen); InitCipher(saltBytes, true, false); Array.Copy(saltBytes, 0, outbuf, 0, saltLen); outlength = saltLen; @@ -336,11 +335,19 @@ namespace Shadowsocks.Encryption.AEAD #endregion #region UDP - + /// + /// Perform AEAD UDP packet encryption + /// + /// payload => [salt][encrypted payload][tag] + /// + /// + /// + /// public override void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength) { // Generate salt - RNG.GetBytes(outbuf, saltLen); + //RNG.GetBytes(outbuf, saltLen); + RNG.GetSpan(outbuf.AsSpan().Slice(0, saltLen)); InitCipher(outbuf, true, true); //uint olen = 0; lock (_udpTmpBuf) @@ -351,7 +358,7 @@ namespace Shadowsocks.Encryption.AEAD //Debug.Assert(olen == length + tagLen); Buffer.BlockCopy(cipher, 0, outbuf, saltLen, length + tagLen); //Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, saltLen, (int)olen); - outlength = (int)(saltLen + cipher.Length); + outlength = saltLen + cipher.Length; } } diff --git a/shadowsocks-csharp/Encryption/CipherInfo.cs b/shadowsocks-csharp/Encryption/CipherInfo.cs index 79753cbd..1f3b8939 100644 --- a/shadowsocks-csharp/Encryption/CipherInfo.cs +++ b/shadowsocks-csharp/Encryption/CipherInfo.cs @@ -35,6 +35,7 @@ namespace Shadowsocks.Encryption public class StreamCipherParameter : CipherParameter { public int IvSize; + public override string ToString() => $"stream (key:{KeySize * 8}, iv:{IvSize * 8})"; } public class AEADCipherParameter : CipherParameter @@ -42,6 +43,7 @@ namespace Shadowsocks.Encryption public int SaltSize; public int TagSize; public int NonceSize; + public override string ToString() => $"aead (key:{KeySize * 8}, salt:{SaltSize * 8}, tag:{TagSize * 8}, nonce:{NonceSize * 8})"; } public class CipherInfo @@ -87,5 +89,11 @@ namespace Shadowsocks.Encryption { return StandardState == CipherStandardState.InUse ? Name : $"{Name} ({I18N.GetString("deprecated")})"; } + public string ToString(bool verbose) + { + if (!verbose) return ToString(); + + return $"{Name} {StandardState} {CipherParameter}"; + } } } \ No newline at end of file diff --git a/shadowsocks-csharp/Encryption/CryptoUtils.cs b/shadowsocks-csharp/Encryption/CryptoUtils.cs index cd4fe394..1a31a84e 100644 --- a/shadowsocks-csharp/Encryption/CryptoUtils.cs +++ b/shadowsocks-csharp/Encryption/CryptoUtils.cs @@ -2,6 +2,7 @@ using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; +using System; namespace Shadowsocks.Encryption { @@ -15,6 +16,16 @@ namespace Shadowsocks.Encryption md5.DoFinal(r, 0); return r; } + // currently useless, just keep api same + public static Span MD5(Span span) + { + byte[] b = span.ToArray(); + MD5Digest md5 = new MD5Digest(); + md5.BlockUpdate(b, 0, b.Length); + byte[] r = new byte[16]; + md5.DoFinal(r, 0); + return r; + } public static byte[] HKDF(int keylen, byte[] master, byte[] salt, byte[] info) { @@ -26,6 +37,17 @@ namespace Shadowsocks.Encryption hkdf.GenerateBytes(ret, 0, keylen); return ret; } + // currently useless, just keep api same, again + public static Span HKDF(int keylen, Span master, Span salt, Span info) + { + byte[] ret = new byte[keylen]; + IDigest degist = new Sha1Digest(); + HkdfParameters parameters = new HkdfParameters(master.ToArray(), salt.ToArray(), info.ToArray()); + HkdfBytesGenerator hkdf = new HkdfBytesGenerator(degist); + hkdf.Init(parameters); + hkdf.GenerateBytes(ret, 0, keylen); + return ret.AsSpan(); + } public static void SodiumIncrement(byte[] salt) { @@ -38,5 +60,16 @@ namespace Shadowsocks.Encryption o = salt[i] == 0; } } + + public static void SodiumIncrement(Span salt) + { + bool o = true; // overflow flag + for (int i = 0; i < salt.Length; i++) + { + if (!o) continue; + salt[i]++; + o = salt[i] == 0; + } + } } } diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs index c9eadb7f..a2c239a2 100644 --- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs +++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs @@ -9,6 +9,8 @@ namespace Shadowsocks.Encryption { public static class EncryptorFactory { + public static string DefaultCipher = "chacha20-ietf-poly1305"; + private static Dictionary _registeredEncryptors = new Dictionary(); private static Dictionary ciphers = new Dictionary(); private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; @@ -48,15 +50,6 @@ namespace Shadowsocks.Encryption _registeredEncryptors.Add(method.Key, typeof(AEADNaClEncryptor)); } } - foreach (var method in StreamRc4NativeEncryptor.SupportedCiphers()) - { - if (!_registeredEncryptors.ContainsKey(method.Key)) - { - ciphers.Add(method.Key, method.Value); - _registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); - } - } - } public static IEncryptor GetEncryptor(string method, string password) @@ -67,7 +60,11 @@ namespace Shadowsocks.Encryption } method = method.ToLowerInvariant(); - Type t = _registeredEncryptors[method]; + bool ok = _registeredEncryptors.TryGetValue(method, out Type t); + if (!ok) + { + t = _registeredEncryptors[DefaultCipher]; + } ConstructorInfo c = t.GetConstructor(ConstructorTypes); if (c == null) throw new System.Exception("Invalid ctor"); @@ -83,7 +80,7 @@ namespace Shadowsocks.Encryption sb.AppendLine("Registered Encryptor Info"); foreach (var encryptor in _registeredEncryptors) { - sb.AppendLine(String.Format("{0}=>{1}", encryptor.Key, encryptor.Value.Name)); + sb.AppendLine($"{ciphers[encryptor.Key].ToString(true)} => {encryptor.Value.Name}"); } // use ----- instead of =======, so when user paste it to Github, it won't became title sb.AppendLine("-------------------------"); @@ -92,6 +89,7 @@ namespace Shadowsocks.Encryption public static CipherInfo GetCipherInfo(string name) { + // TODO: Replace cipher when required not exist return ciphers[name]; } diff --git a/shadowsocks-csharp/Encryption/RNG.cs b/shadowsocks-csharp/Encryption/RNG.cs index cd6c49f3..276a9b1c 100644 --- a/shadowsocks-csharp/Encryption/RNG.cs +++ b/shadowsocks-csharp/Encryption/RNG.cs @@ -5,33 +5,35 @@ namespace Shadowsocks.Encryption { public static class RNG { - private static RNGCryptoServiceProvider _rng = null; + private static RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); - public static void Init() + public static void Reload() { - _rng = _rng ?? new RNGCryptoServiceProvider(); + _rng.Dispose(); + _rng = new RNGCryptoServiceProvider(); } - public static void Close() + public static void GetSpan(Span span) { - _rng?.Dispose(); - _rng = null; + _rng.GetBytes(span); } - public static void Reload() + public static Span GetSpan(int length) { - Close(); - Init(); + Span span = new byte[length]; + _rng.GetBytes(span); + return span; } - public static void GetBytes(byte[] buf) + public static byte[] GetBytes(int length) { - GetBytes(buf, buf.Length); + byte[] buf = new byte[length]; + _rng.GetBytes(buf); + return buf; } public static void GetBytes(byte[] buf, int len) { - if (_rng == null) Init(); try { _rng.GetBytes(buf, 0, len); diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index 189449cf..ed194f3a 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -107,7 +107,6 @@ namespace Shadowsocks.Test { t.Join(); } - RNG.Close(); Assert.IsFalse(encryptionFailed); }