Browse Source

span based cipher api

pull/2865/head
Student Main 5 years ago
parent
commit
35633053e1
8 changed files with 77 additions and 33 deletions
  1. +1
    -3
      shadowsocks-csharp/Controller/Service/PACServer.cs
  2. +0
    -1
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  3. +12
    -5
      shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
  4. +8
    -0
      shadowsocks-csharp/Encryption/CipherInfo.cs
  5. +33
    -0
      shadowsocks-csharp/Encryption/CryptoUtils.cs
  6. +9
    -11
      shadowsocks-csharp/Encryption/EncryptorFactory.cs
  7. +14
    -12
      shadowsocks-csharp/Encryption/RNG.cs
  8. +0
    -1
      test/CryptographyTest.cs

+ 1
- 3
shadowsocks-csharp/Controller/Service/PACServer.cs View File

@@ -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;
}


+ 0
- 1
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -325,7 +325,6 @@ namespace Shadowsocks.Controller
{
SystemProxy.Update(_config, true, null);
}
Encryption.RNG.Close();
}
private void StopPlugins()


+ 12
- 5
shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs View File

@@ -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
/// <summary>
/// Perform AEAD UDP packet encryption
/// </summary>
/// payload => [salt][encrypted payload][tag]
/// <param name="buf"></param>
/// <param name="length"></param>
/// <param name="outbuf"></param>
/// <param name="outlength"></param>
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;
}
}


+ 8
- 0
shadowsocks-csharp/Encryption/CipherInfo.cs View File

@@ -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}";
}
}
}

+ 33
- 0
shadowsocks-csharp/Encryption/CryptoUtils.cs View File

@@ -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<byte> MD5(Span<byte> 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<byte> HKDF(int keylen, Span<byte> master, Span<byte> salt, Span<byte> 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<byte> salt)
{
bool o = true; // overflow flag
for (int i = 0; i < salt.Length; i++)
{
if (!o) continue;
salt[i]++;
o = salt[i] == 0;
}
}
}
}

+ 9
- 11
shadowsocks-csharp/Encryption/EncryptorFactory.cs View File

@@ -9,6 +9,8 @@ namespace Shadowsocks.Encryption
{
public static class EncryptorFactory
{
public static string DefaultCipher = "chacha20-ietf-poly1305";
private static Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>();
private static Dictionary<string, CipherInfo> ciphers = new Dictionary<string, CipherInfo>();
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];
}


+ 14
- 12
shadowsocks-csharp/Encryption/RNG.cs View File

@@ -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<byte> span)
{
_rng?.Dispose();
_rng = null;
_rng.GetBytes(span);
}
public static void Reload()
public static Span<byte> GetSpan(int length)
{
Close();
Init();
Span<byte> 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);


+ 0
- 1
test/CryptographyTest.cs View File

@@ -107,7 +107,6 @@ namespace Shadowsocks.Test
{
t.Join();
}
RNG.Close();
Assert.IsFalse(encryptionFailed);
}


Loading…
Cancel
Save