diff --git a/Shadowsocks.Protocol/Shadowsocks.Protocol.csproj b/Shadowsocks.Protocol/Shadowsocks.Protocol.csproj
index ea0f2c32..7351ea35 100644
--- a/Shadowsocks.Protocol/Shadowsocks.Protocol.csproj
+++ b/Shadowsocks.Protocol/Shadowsocks.Protocol.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/Shadowsocks.Protocol/Shadowsocks/AeadClient.cs b/Shadowsocks.Protocol/Shadowsocks/AeadClient.cs
index 97d6eaea..a6b72215 100644
--- a/Shadowsocks.Protocol/Shadowsocks/AeadClient.cs
+++ b/Shadowsocks.Protocol/Shadowsocks/AeadClient.cs
@@ -1,11 +1,11 @@
using Shadowsocks.Protocol.Shadowsocks.Crypto;
using System;
+using System.Collections.Generic;
using System.IO.Pipelines;
using System.Net;
using System.Runtime.InteropServices;
-using System.Text;
+using System.Security.Cryptography;
using System.Threading.Tasks;
-using System.Collections.Generic;
namespace Shadowsocks.Protocol.Shadowsocks
{
@@ -13,7 +13,14 @@ namespace Shadowsocks.Protocol.Shadowsocks
{
private CryptoParameter cryptoParameter;
private readonly byte[] mainKey;
- private static readonly byte[] _ssSubKeyInfo = Encoding.ASCII.GetBytes("ss-subkey");
+
+ ///
+ /// ss-subkey
+ ///
+ private static ReadOnlySpan _ssSubKeyInfo => new byte[]
+ {
+ 0x73, 0x73, 0x2d, 0x73, 0x75, 0x62, 0x6b, 0x65, 0x79
+ };
public AeadClient(CryptoParameter parameter, string password)
{
@@ -40,7 +47,8 @@ namespace Shadowsocks.Protocol.Shadowsocks
var salt = new SaltMessage(16, true);
await pmp.WriteAsync(salt);
- var key = CryptoUtils.HKDF(cryptoParameter.KeySize, mainKey, salt.Salt.ToArray(), _ssSubKeyInfo);
+ var key = new byte[cryptoParameter.KeySize];
+ HKDF.DeriveKey(HashAlgorithmName.SHA1, mainKey, key, salt.Salt.Span, _ssSubKeyInfo);
up.Init(key, null);
Memory nonce = new byte[cryptoParameter.NonceSize];
nonce.Span.Fill(0);
@@ -74,7 +82,8 @@ namespace Shadowsocks.Protocol.Shadowsocks
var pmp = new ProtocolMessagePipe(server);
var salt = await pmp.ReadAsync(new SaltMessage(cryptoParameter.KeySize));
- var key = CryptoUtils.HKDF(cryptoParameter.KeySize, mainKey, salt.Salt.ToArray(), _ssSubKeyInfo);
+ var key = new byte[cryptoParameter.KeySize];
+ HKDF.DeriveKey(HashAlgorithmName.SHA1, mainKey, key, salt.Salt.Span, _ssSubKeyInfo);
down.Init(key, null);
Memory nonce = new byte[cryptoParameter.NonceSize];
nonce.Span.Fill(0);
diff --git a/Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs b/Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs
index d7fae32e..4df67a0d 100644
--- a/Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs
+++ b/Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs
@@ -1,94 +1,51 @@
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Generators;
-using Org.BouncyCastle.Crypto.Parameters;
+using CryptoBase.Digests.MD5;
using System;
-using System.Security.Cryptography;
+using System.Buffers;
using System.Text;
-using System.Threading;
namespace Shadowsocks.Protocol.Shadowsocks.Crypto
{
public static class CryptoUtils
{
- private static readonly ThreadLocal Md5Hasher = new ThreadLocal(System.Security.Cryptography.MD5.Create);
-
- public static byte[] MD5(byte[] b)
- {
- var hash = new byte[16];
- Md5Hasher.Value?.TryComputeHash(b, hash, out _);
- return hash;
- }
- // currently useless, just keep api same
- public static Span MD5(Span span)
- {
- Span hash = new byte[16];
- Md5Hasher.Value?.TryComputeHash(span, hash, out _);
- return hash;
- }
-
- public static byte[] HKDF(int keylen, byte[] master, byte[] salt, byte[] info)
- {
- var ret = new byte[keylen];
- var degist = new Sha1Digest();
- var parameters = new HkdfParameters(master, salt, info);
- var hkdf = new HkdfBytesGenerator(degist);
- hkdf.Init(parameters);
- 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)
- {
- var ret = new byte[keylen];
- var degist = new Sha1Digest();
- var parameters = new HkdfParameters(master.ToArray(), salt.ToArray(), info.ToArray());
- var hkdf = new HkdfBytesGenerator(degist);
- hkdf.Init(parameters);
- hkdf.GenerateBytes(ret, 0, keylen);
- return ret.AsSpan();
- }
-
public static byte[] SSKDF(string password, int keylen)
{
+ const int md5Length = 16;
+ var pwMaxSize = Encoding.UTF8.GetMaxByteCount(password.Length);
var key = new byte[keylen];
- var pw = Encoding.UTF8.GetBytes(password);
- var result = new byte[password.Length + 16];
- var i = 0;
- var md5sum = Array.Empty();
- while (i < keylen)
- {
- if (i == 0)
- {
- md5sum = MD5(pw);
- }
- else
- {
- Array.Copy(md5sum, 0, result, 0, 16);
- Array.Copy(pw, 0, result, 16, password.Length);
- md5sum = MD5(result);
- }
- Array.Copy(md5sum, 0, key, i, Math.Min(16, keylen - i));
- i += 16;
- }
- return key;
- }
- public static void SodiumIncrement(Span salt)
- {
- for (var i = 0; i < salt.Length; ++i)
+ var pwBuffer = ArrayPool.Shared.Rent(pwMaxSize);
+ var resultBuffer = ArrayPool.Shared.Rent(pwMaxSize + md5Length);
+ try
{
- if (++salt[i] != 0)
+ var pwLength = Encoding.UTF8.GetBytes(password, pwBuffer);
+ var pw = pwBuffer.AsSpan(0, pwLength);
+ Span md5Sum = stackalloc byte[md5Length];
+ var result = resultBuffer.AsSpan(0, pwLength + md5Length);
+ var i = 0;
+ while (i < keylen)
{
- break;
+ if (i == 0)
+ {
+ MD5Utils.Default(pw, md5Sum);
+ }
+ else
+ {
+ md5Sum.CopyTo(result);
+ pw.CopyTo(result.Slice(md5Length));
+ MD5Utils.Default(result, md5Sum);
+ }
+
+ var length = Math.Min(16, keylen - i);
+ md5Sum.Slice(0, length).CopyTo(key.AsSpan(i, length));
+
+ i += md5Length;
}
+ return key;
}
- }
-
- public static void RandomSpan(Span span)
- {
- using (var rng = RandomNumberGenerator.Create())
+ finally
{
- rng.GetBytes(span);
+ ArrayPool.Shared.Return(pwBuffer);
+ ArrayPool.Shared.Return(resultBuffer);
}
}
}
diff --git a/Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs b/Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs
index 4e3ffe97..75236238 100644
--- a/Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs
+++ b/Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs
@@ -1,6 +1,7 @@
using Shadowsocks.Protocol.Shadowsocks.Crypto;
using System;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace Shadowsocks.Protocol.Shadowsocks
{
@@ -15,7 +16,7 @@ namespace Shadowsocks.Protocol.Shadowsocks
if (roll)
{
Salt = new byte[length];
- CryptoUtils.RandomSpan(Salt.Span);
+ RandomNumberGenerator.Fill(Salt.Span);
}
}