<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" />

SCrypt

public class SCrypt
Implementation of the scrypt a password-based key derivation function.
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Math.Raw; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Generators { public class SCrypt { public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen) { if (P == null) throw new ArgumentNullException("Passphrase P must be provided."); if (S == null) throw new ArgumentNullException("Salt S must be provided."); if (N <= 1 || !IsPowerOf2(N)) throw new ArgumentException("Cost parameter N must be > 1 and a power of 2."); if (r == 1 && N >= 65536) throw new ArgumentException("Cost parameter N must be > 1 and < 65536."); if (r < 1) throw new ArgumentException("Block size r must be >= 1."); int num = 2147483647 / (128 * r * 8); if (p < 1 || p > num) throw new ArgumentException("Parallelisation parameter p must be >= 1 and <= " + num.ToString() + " (based on block size r of " + r.ToString() + ")"); if (dkLen < 1) throw new ArgumentException("Generated key length dkLen must be >= 1."); return MFcrypt(P, S, N, r, p, dkLen); } private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen) { int num = r * 128; byte[] array = SingleIterationPBKDF2(P, S, p * num); uint[] array2 = null; try { int num2 = array.Length >> 2; array2 = new uint[num2]; Pack.LE_To_UInt32(array, 0, array2); int num3 = 0; int num4 = N * r; while (N - num3 > 2 && num4 > 1024) { num3++; num4 >>= 1; } int num5 = num >> 2; for (int i = 0; i < num2; i += num5) { SMix(array2, i, N, num3, r); } Pack.UInt32_To_LE(array2, array, 0); return SingleIterationPBKDF2(P, array, dkLen); } finally { ClearAll(array, array2); } } private static byte[] SingleIterationPBKDF2(byte[] P, byte[] S, int dkLen) { Pkcs5S2ParametersGenerator pkcs5S2ParametersGenerator = new Pkcs5S2ParametersGenerator(new Sha256Digest()); pkcs5S2ParametersGenerator.Init(P, S, 1); return ((KeyParameter)pkcs5S2ParametersGenerator.GenerateDerivedMacParameters(dkLen * 8)).GetKey(); } private static void SMix(uint[] B, int BOff, int N, int d, int r) { int num = Integers.NumberOfTrailingZeros(N); int num2 = N >> d; int num3 = 1 << d; int num4 = num2 - 1; int num5 = num - d; int num6 = r * 32; uint[] array = new uint[num6]; uint[][] array2 = new uint[num3][]; try { Span<uint> span = B.AsSpan(BOff, num6); for (int i = 0; i < num3; i++) { uint[] array3 = array2[i] = new uint[num2 * num6]; Nat.Copy(num6, span, array3); int num7 = 0; for (int j = 1; j < num2; j++) { BlockMix(array3.AsSpan(num7, num6), array3.AsSpan(num7 + num6)); num7 += num6; } Span<uint> span2 = array3.AsSpan(); int num8 = num6; int length = span2.Length; int num9 = length - num8; BlockMix(span2.Slice(num9, length - num9), span); } uint num10 = (uint)(N - 1); for (int k = 0; k < N; k++) { int num11 = (int)(span[num6 - 16] & num10); uint[] array4 = array2[num11 >> num5]; int start = (num11 & num4) * num6; Nat.Xor(num6, array4.AsSpan(start), span, array); BlockMix(array, span); } } finally { Array[] arrays = array2; ClearAll(arrays); Clear(array); } } private static void BlockMix(Span<uint> B, Span<uint> Y) { int length = B.Length; int num = length >> 1; int length2 = B.Length; int num2 = length2 - 16; Span<uint> span = B.Slice(num2, length2 - num2); for (int i = 0; i < length; i += 32) { num2 = i; Span<uint> span2 = B.Slice(num2, B.Length - num2); num2 = i >> 1; Span<uint> span3 = Y.Slice(num2, Y.Length - num2); Nat512.Xor(span, span2, span3); Salsa20Engine.SalsaCore(8, span3, span3); Span<uint> span4 = span2.Slice(16, span2.Length - 16); num2 = num; span = span3.Slice(num2, span3.Length - num2); Nat512.Xor(span3, span4, span); Salsa20Engine.SalsaCore(8, span, span); } } private static void Clear(Array array) { if (array != null) Array.Clear(array, 0, array.Length); } private static void ClearAll(params Array[] arrays) { for (int i = 0; i < arrays.Length; i++) { Clear(arrays[i]); } } private static bool IsPowerOf2(int x) { return (x & (x - 1)) == 0; } } }