Browse Source

Replace BouncyCastle with CryptoBase

Shadowsocks.Protocol
pull/3084/head
Bruce Wayne 3 years ago
parent
commit
7f14d04c8a
No known key found for this signature in database GPG Key ID: 6D396097F05051BF
4 changed files with 49 additions and 82 deletions
  1. +1
    -1
      Shadowsocks.Protocol/Shadowsocks.Protocol.csproj
  2. +14
    -5
      Shadowsocks.Protocol/Shadowsocks/AeadClient.cs
  3. +32
    -75
      Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs
  4. +2
    -1
      Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs

+ 1
- 1
Shadowsocks.Protocol/Shadowsocks.Protocol.csproj View File

@@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.8" />
<PackageReference Include="CryptoBase" Version="1.1.1" />
<PackageReference Include="Pipelines.Sockets.Unofficial" Version="2.2.0" /> <PackageReference Include="Pipelines.Sockets.Unofficial" Version="2.2.0" />
</ItemGroup> </ItemGroup>




+ 14
- 5
Shadowsocks.Protocol/Shadowsocks/AeadClient.cs View File

@@ -1,11 +1,11 @@
using Shadowsocks.Protocol.Shadowsocks.Crypto; using Shadowsocks.Protocol.Shadowsocks.Crypto;
using System; using System;
using System.Collections.Generic;
using System.IO.Pipelines; using System.IO.Pipelines;
using System.Net; using System.Net;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Security.Cryptography;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic;


namespace Shadowsocks.Protocol.Shadowsocks namespace Shadowsocks.Protocol.Shadowsocks
{ {
@@ -13,7 +13,14 @@ namespace Shadowsocks.Protocol.Shadowsocks
{ {
private CryptoParameter cryptoParameter; private CryptoParameter cryptoParameter;
private readonly byte[] mainKey; private readonly byte[] mainKey;
private static readonly byte[] _ssSubKeyInfo = Encoding.ASCII.GetBytes("ss-subkey");

/// <summary>
/// ss-subkey
/// </summary>
private static ReadOnlySpan<byte> _ssSubKeyInfo => new byte[]
{
0x73, 0x73, 0x2d, 0x73, 0x75, 0x62, 0x6b, 0x65, 0x79
};


public AeadClient(CryptoParameter parameter, string password) public AeadClient(CryptoParameter parameter, string password)
{ {
@@ -40,7 +47,8 @@ namespace Shadowsocks.Protocol.Shadowsocks
var salt = new SaltMessage(16, true); var salt = new SaltMessage(16, true);
await pmp.WriteAsync(salt); 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); up.Init(key, null);
Memory<byte> nonce = new byte[cryptoParameter.NonceSize]; Memory<byte> nonce = new byte[cryptoParameter.NonceSize];
nonce.Span.Fill(0); nonce.Span.Fill(0);
@@ -74,7 +82,8 @@ namespace Shadowsocks.Protocol.Shadowsocks
var pmp = new ProtocolMessagePipe(server); var pmp = new ProtocolMessagePipe(server);
var salt = await pmp.ReadAsync(new SaltMessage(cryptoParameter.KeySize)); 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); down.Init(key, null);
Memory<byte> nonce = new byte[cryptoParameter.NonceSize]; Memory<byte> nonce = new byte[cryptoParameter.NonceSize];
nonce.Span.Fill(0); nonce.Span.Fill(0);


+ 32
- 75
Shadowsocks.Protocol/Shadowsocks/Crypto/CryptoUtils.cs View File

@@ -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;
using System.Security.Cryptography;
using System.Buffers;
using System.Text; using System.Text;
using System.Threading;


namespace Shadowsocks.Protocol.Shadowsocks.Crypto namespace Shadowsocks.Protocol.Shadowsocks.Crypto
{ {
public static class CryptoUtils public static class CryptoUtils
{ {
private static readonly ThreadLocal<MD5> Md5Hasher = new ThreadLocal<MD5>(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<byte> MD5(Span<byte> span)
{
Span<byte> 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<byte> HKDF(int keylen, Span<byte> master, Span<byte> salt, Span<byte> 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) 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 key = new byte[keylen];
var pw = Encoding.UTF8.GetBytes(password);
var result = new byte[password.Length + 16];
var i = 0;
var md5sum = Array.Empty<byte>();
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<byte> salt)
{
for (var i = 0; i < salt.Length; ++i)
var pwBuffer = ArrayPool<byte>.Shared.Rent(pwMaxSize);
var resultBuffer = ArrayPool<byte>.Shared.Rent(pwMaxSize + md5Length);
try
{ {
if (++salt[i] != 0)
var pwLength = Encoding.UTF8.GetBytes(password, pwBuffer);
var pw = pwBuffer.AsSpan(0, pwLength);
Span<byte> 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<byte> span)
{
using (var rng = RandomNumberGenerator.Create())
finally
{ {
rng.GetBytes(span);
ArrayPool<byte>.Shared.Return(pwBuffer);
ArrayPool<byte>.Shared.Return(resultBuffer);
} }
} }
} }


+ 2
- 1
Shadowsocks.Protocol/Shadowsocks/SaltMessage.cs View File

@@ -1,6 +1,7 @@
using Shadowsocks.Protocol.Shadowsocks.Crypto; using Shadowsocks.Protocol.Shadowsocks.Crypto;
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;


namespace Shadowsocks.Protocol.Shadowsocks namespace Shadowsocks.Protocol.Shadowsocks
{ {
@@ -15,7 +16,7 @@ namespace Shadowsocks.Protocol.Shadowsocks
if (roll) if (roll)
{ {
Salt = new byte[length]; Salt = new byte[length];
CryptoUtils.RandomSpan(Salt.Span);
RandomNumberGenerator.Fill(Salt.Span);
} }
} }




Loading…
Cancel
Save