using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using System; using System.Security.Cryptography; using System.Threading; namespace Shadowsocks.Encryption { 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[EncryptorBase.MD5Length]; Md5Hasher.Value.TryComputeHash(b, hash, out _); return hash; } // currently useless, just keep api same public static Span MD5(Span span) { Span hash = new byte[EncryptorBase.MD5Length]; Md5Hasher.Value.TryComputeHash(span, hash, out _); return hash; } public static byte[] HKDF(int keylen, byte[] master, byte[] salt, byte[] info) { byte[] ret = new byte[keylen]; IDigest degist = new Sha1Digest(); HkdfParameters parameters = new HkdfParameters(master, salt, info); HkdfBytesGenerator 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) { 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(Span salt) { for (var i = 0; i < salt.Length; ++i) { if (++salt[i] != 0) { break; } } } } }